ccxt-ir 4.3.46.0.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccxt/__init__.py +358 -0
- ccxt/abantether.py +316 -0
- ccxt/abstract/__init__.py +0 -0
- ccxt/abstract/abantether.py +5 -0
- ccxt/abstract/ace.py +15 -0
- ccxt/abstract/afratether.py +6 -0
- ccxt/abstract/alpaca.py +70 -0
- ccxt/abstract/arzinja.py +5 -0
- ccxt/abstract/arzplus.py +7 -0
- ccxt/abstract/ascendex.py +77 -0
- ccxt/abstract/bequant.py +115 -0
- ccxt/abstract/bigone.py +45 -0
- ccxt/abstract/binance.py +712 -0
- ccxt/abstract/binancecoinm.py +712 -0
- ccxt/abstract/binanceus.py +764 -0
- ccxt/abstract/binanceusdm.py +712 -0
- ccxt/abstract/bingx.py +113 -0
- ccxt/abstract/bit2c.py +27 -0
- ccxt/abstract/bitbank.py +27 -0
- ccxt/abstract/bitbay.py +53 -0
- ccxt/abstract/bitbns.py +40 -0
- ccxt/abstract/bitcoincom.py +115 -0
- ccxt/abstract/bitfinex.py +69 -0
- ccxt/abstract/bitfinex2.py +139 -0
- ccxt/abstract/bitflyer.py +38 -0
- ccxt/abstract/bitget.py +508 -0
- ccxt/abstract/bithumb.py +32 -0
- ccxt/abstract/bitimen.py +7 -0
- ccxt/abstract/bitir.py +7 -0
- ccxt/abstract/bitmart.py +99 -0
- ccxt/abstract/bitmex.py +97 -0
- ccxt/abstract/bitopro.py +29 -0
- ccxt/abstract/bitpanda.py +35 -0
- ccxt/abstract/bitpin.py +7 -0
- ccxt/abstract/bitrue.py +72 -0
- ccxt/abstract/bitso.py +43 -0
- ccxt/abstract/bitstamp.py +258 -0
- ccxt/abstract/bitteam.py +29 -0
- ccxt/abstract/bitvavo.py +27 -0
- ccxt/abstract/bl3p.py +19 -0
- ccxt/abstract/blockchaincom.py +28 -0
- ccxt/abstract/blofin.py +37 -0
- ccxt/abstract/btcalpha.py +18 -0
- ccxt/abstract/btcbox.py +13 -0
- ccxt/abstract/btcmarkets.py +39 -0
- ccxt/abstract/btcturk.py +20 -0
- ccxt/abstract/bybit.py +298 -0
- ccxt/abstract/cex.py +33 -0
- ccxt/abstract/coinbase.py +94 -0
- ccxt/abstract/coinbaseadvanced.py +94 -0
- ccxt/abstract/coinbaseexchange.py +67 -0
- ccxt/abstract/coinbaseinternational.py +39 -0
- ccxt/abstract/coincatch.py +94 -0
- ccxt/abstract/coincheck.py +33 -0
- ccxt/abstract/coinex.py +237 -0
- ccxt/abstract/coinlist.py +54 -0
- ccxt/abstract/coinmate.py +62 -0
- ccxt/abstract/coinmetro.py +34 -0
- ccxt/abstract/coinone.py +67 -0
- ccxt/abstract/coinsph.py +54 -0
- ccxt/abstract/coinspot.py +28 -0
- ccxt/abstract/cryptocom.py +107 -0
- ccxt/abstract/currencycom.py +68 -0
- ccxt/abstract/delta.py +50 -0
- ccxt/abstract/deribit.py +125 -0
- ccxt/abstract/digifinex.py +91 -0
- ccxt/abstract/eterex.py +5 -0
- ccxt/abstract/excoino.py +7 -0
- ccxt/abstract/exir.py +8 -0
- ccxt/abstract/exmo.py +55 -0
- ccxt/abstract/exnovin.py +6 -0
- ccxt/abstract/farhadexchange.py +5 -0
- ccxt/abstract/fmfwio.py +115 -0
- ccxt/abstract/gate.py +265 -0
- ccxt/abstract/gateio.py +265 -0
- ccxt/abstract/gemini.py +58 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/hitbtc.py +115 -0
- ccxt/abstract/hitbtc3.py +115 -0
- ccxt/abstract/hitobit.py +8 -0
- ccxt/abstract/hollaex.py +33 -0
- ccxt/abstract/htx.py +548 -0
- ccxt/abstract/huobi.py +548 -0
- ccxt/abstract/huobijp.py +114 -0
- ccxt/abstract/hyperliquid.py +6 -0
- ccxt/abstract/idex.py +26 -0
- ccxt/abstract/independentreserve.py +37 -0
- ccxt/abstract/indodax.py +26 -0
- ccxt/abstract/jibitex.py +7 -0
- ccxt/abstract/kraken.py +57 -0
- ccxt/abstract/krakenfutures.py +38 -0
- ccxt/abstract/kucoin.py +214 -0
- ccxt/abstract/kucoinfutures.py +233 -0
- ccxt/abstract/kuna.py +182 -0
- ccxt/abstract/latoken.py +56 -0
- ccxt/abstract/lbank.py +61 -0
- ccxt/abstract/luno.py +37 -0
- ccxt/abstract/lykke.py +29 -0
- ccxt/abstract/mercado.py +25 -0
- ccxt/abstract/mexc.py +178 -0
- ccxt/abstract/ndax.py +97 -0
- ccxt/abstract/nobitex.py +7 -0
- ccxt/abstract/novadax.py +29 -0
- ccxt/abstract/oceanex.py +22 -0
- ccxt/abstract/okcoin.py +74 -0
- ccxt/abstract/okexchange.py +8 -0
- ccxt/abstract/okx.py +324 -0
- ccxt/abstract/ompfinex.py +7 -0
- ccxt/abstract/onetrading.py +35 -0
- ccxt/abstract/oxfun.py +34 -0
- ccxt/abstract/p2b.py +22 -0
- ccxt/abstract/paradex.py +40 -0
- ccxt/abstract/paymium.py +28 -0
- ccxt/abstract/phemex.py +115 -0
- ccxt/abstract/poloniex.py +69 -0
- ccxt/abstract/poloniexfutures.py +48 -0
- ccxt/abstract/probit.py +23 -0
- ccxt/abstract/ramzinex.py +7 -0
- ccxt/abstract/sarmayex.py +5 -0
- ccxt/abstract/sarrafex.py +7 -0
- ccxt/abstract/tabdeal.py +7 -0
- ccxt/abstract/tetherland.py +5 -0
- ccxt/abstract/timex.py +62 -0
- ccxt/abstract/tokocrypto.py +37 -0
- ccxt/abstract/tradeogre.py +16 -0
- ccxt/abstract/twox.py +5 -0
- ccxt/abstract/ubitex.py +7 -0
- ccxt/abstract/upbit.py +38 -0
- ccxt/abstract/vertex.py +19 -0
- ccxt/abstract/wallex.py +8 -0
- ccxt/abstract/wavesexchange.py +154 -0
- ccxt/abstract/wazirx.py +30 -0
- ccxt/abstract/whitebit.py +98 -0
- ccxt/abstract/woo.py +83 -0
- ccxt/abstract/woofipro.py +119 -0
- ccxt/abstract/xt.py +152 -0
- ccxt/abstract/yobit.py +16 -0
- ccxt/abstract/zaif.py +38 -0
- ccxt/abstract/zonda.py +53 -0
- ccxt/ace.py +1012 -0
- ccxt/afratether.py +293 -0
- ccxt/alpaca.py +1083 -0
- ccxt/arzinja.py +285 -0
- ccxt/arzplus.py +412 -0
- ccxt/ascendex.py +3330 -0
- ccxt/async_support/__init__.py +337 -0
- ccxt/async_support/abantether.py +316 -0
- ccxt/async_support/ace.py +1012 -0
- ccxt/async_support/afratether.py +293 -0
- ccxt/async_support/alpaca.py +1083 -0
- ccxt/async_support/arzinja.py +285 -0
- ccxt/async_support/arzplus.py +412 -0
- ccxt/async_support/ascendex.py +3330 -0
- ccxt/async_support/base/__init__.py +1 -0
- ccxt/async_support/base/exchange.py +1966 -0
- ccxt/async_support/base/throttler.py +50 -0
- ccxt/async_support/base/ws/__init__.py +38 -0
- ccxt/async_support/base/ws/aiohttp_client.py +125 -0
- ccxt/async_support/base/ws/cache.py +212 -0
- ccxt/async_support/base/ws/client.py +193 -0
- ccxt/async_support/base/ws/fast_client.py +96 -0
- ccxt/async_support/base/ws/functions.py +59 -0
- ccxt/async_support/base/ws/future.py +58 -0
- ccxt/async_support/base/ws/order_book.py +78 -0
- ccxt/async_support/base/ws/order_book_side.py +174 -0
- ccxt/async_support/bequant.py +33 -0
- ccxt/async_support/bigone.py +2113 -0
- ccxt/async_support/binance.py +12234 -0
- ccxt/async_support/binancecoinm.py +45 -0
- ccxt/async_support/binanceus.py +211 -0
- ccxt/async_support/binanceusdm.py +58 -0
- ccxt/async_support/bingx.py +4325 -0
- ccxt/async_support/bit2c.py +866 -0
- ccxt/async_support/bitbank.py +1001 -0
- ccxt/async_support/bitbay.py +17 -0
- ccxt/async_support/bitbns.py +1154 -0
- ccxt/async_support/bitcoincom.py +17 -0
- ccxt/async_support/bitfinex.py +1617 -0
- ccxt/async_support/bitfinex2.py +3552 -0
- ccxt/async_support/bitflyer.py +995 -0
- ccxt/async_support/bitget.py +8273 -0
- ccxt/async_support/bithumb.py +1061 -0
- ccxt/async_support/bitimen.py +401 -0
- ccxt/async_support/bitir.py +490 -0
- ccxt/async_support/bitmart.py +4415 -0
- ccxt/async_support/bitmex.py +2756 -0
- ccxt/async_support/bitopro.py +1630 -0
- ccxt/async_support/bitpanda.py +16 -0
- ccxt/async_support/bitpin.py +454 -0
- ccxt/async_support/bitrue.py +3027 -0
- ccxt/async_support/bitso.py +1670 -0
- ccxt/async_support/bitstamp.py +2203 -0
- ccxt/async_support/bitteam.py +2239 -0
- ccxt/async_support/bitvavo.py +1968 -0
- ccxt/async_support/bl3p.py +485 -0
- ccxt/async_support/blockchaincom.py +1104 -0
- ccxt/async_support/blofin.py +2066 -0
- ccxt/async_support/btcalpha.py +891 -0
- ccxt/async_support/btcbox.py +544 -0
- ccxt/async_support/btcmarkets.py +1221 -0
- ccxt/async_support/btcturk.py +911 -0
- ccxt/async_support/bybit.py +8159 -0
- ccxt/async_support/cex.py +1605 -0
- ccxt/async_support/coinbase.py +4475 -0
- ccxt/async_support/coinbaseadvanced.py +17 -0
- ccxt/async_support/coinbaseexchange.py +1734 -0
- ccxt/async_support/coinbaseinternational.py +1899 -0
- ccxt/async_support/coincatch.py +5069 -0
- ccxt/async_support/coincheck.py +815 -0
- ccxt/async_support/coinex.py +5526 -0
- ccxt/async_support/coinlist.py +2243 -0
- ccxt/async_support/coinmate.py +1067 -0
- ccxt/async_support/coinmetro.py +1797 -0
- ccxt/async_support/coinone.py +1127 -0
- ccxt/async_support/coinsph.py +1850 -0
- ccxt/async_support/coinspot.py +534 -0
- ccxt/async_support/cryptocom.py +2822 -0
- ccxt/async_support/currencycom.py +1950 -0
- ccxt/async_support/delta.py +3376 -0
- ccxt/async_support/deribit.py +3437 -0
- ccxt/async_support/digifinex.py +3960 -0
- ccxt/async_support/eterex.py +286 -0
- ccxt/async_support/excoino.py +399 -0
- ccxt/async_support/exir.py +375 -0
- ccxt/async_support/exmo.py +2462 -0
- ccxt/async_support/exnovin.py +360 -0
- ccxt/async_support/farhadexchange.py +266 -0
- ccxt/async_support/fmfwio.py +34 -0
- ccxt/async_support/gate.py +6976 -0
- ccxt/async_support/gateio.py +16 -0
- ccxt/async_support/gemini.py +1825 -0
- ccxt/async_support/hashkey.py +4150 -0
- ccxt/async_support/hitbtc.py +3423 -0
- ccxt/async_support/hitbtc3.py +16 -0
- ccxt/async_support/hitobit.py +391 -0
- ccxt/async_support/hollaex.py +1813 -0
- ccxt/async_support/htx.py +8506 -0
- ccxt/async_support/huobi.py +16 -0
- ccxt/async_support/huobijp.py +1801 -0
- ccxt/async_support/hyperliquid.py +2431 -0
- ccxt/async_support/idex.py +1766 -0
- ccxt/async_support/independentreserve.py +784 -0
- ccxt/async_support/indodax.py +1247 -0
- ccxt/async_support/jibitex.py +395 -0
- ccxt/async_support/kraken.py +2894 -0
- ccxt/async_support/krakenfutures.py +2601 -0
- ccxt/async_support/kucoin.py +4602 -0
- ccxt/async_support/kucoinfutures.py +2698 -0
- ccxt/async_support/kuna.py +1841 -0
- ccxt/async_support/latoken.py +1664 -0
- ccxt/async_support/lbank.py +2683 -0
- ccxt/async_support/luno.py +1067 -0
- ccxt/async_support/lykke.py +1270 -0
- ccxt/async_support/mercado.py +842 -0
- ccxt/async_support/mexc.py +5369 -0
- ccxt/async_support/ndax.py +2354 -0
- ccxt/async_support/nobitex.py +419 -0
- ccxt/async_support/novadax.py +1484 -0
- ccxt/async_support/oceanex.py +903 -0
- ccxt/async_support/okcoin.py +2936 -0
- ccxt/async_support/okexchange.py +349 -0
- ccxt/async_support/okx.py +7827 -0
- ccxt/async_support/ompfinex.py +472 -0
- ccxt/async_support/onetrading.py +1911 -0
- ccxt/async_support/oxfun.py +2773 -0
- ccxt/async_support/p2b.py +1194 -0
- ccxt/async_support/paradex.py +2015 -0
- ccxt/async_support/paymium.py +564 -0
- ccxt/async_support/phemex.py +4473 -0
- ccxt/async_support/poloniex.py +2232 -0
- ccxt/async_support/poloniexfutures.py +1717 -0
- ccxt/async_support/probit.py +1734 -0
- ccxt/async_support/ramzinex.py +476 -0
- ccxt/async_support/sarmayex.py +357 -0
- ccxt/async_support/sarrafex.py +478 -0
- ccxt/async_support/tabdeal.py +364 -0
- ccxt/async_support/tetherland.py +349 -0
- ccxt/async_support/timex.py +1593 -0
- ccxt/async_support/tokocrypto.py +2405 -0
- ccxt/async_support/tradeogre.py +608 -0
- ccxt/async_support/twox.py +326 -0
- ccxt/async_support/ubitex.py +409 -0
- ccxt/async_support/upbit.py +1833 -0
- ccxt/async_support/vertex.py +2922 -0
- ccxt/async_support/wallex.py +445 -0
- ccxt/async_support/wavesexchange.py +2473 -0
- ccxt/async_support/wazirx.py +1224 -0
- ccxt/async_support/whitebit.py +2469 -0
- ccxt/async_support/woo.py +3114 -0
- ccxt/async_support/woofipro.py +2533 -0
- ccxt/async_support/xt.py +4454 -0
- ccxt/async_support/yobit.py +1283 -0
- ccxt/async_support/zaif.py +725 -0
- ccxt/async_support/zonda.py +1828 -0
- ccxt/base/__init__.py +27 -0
- ccxt/base/decimal_to_precision.py +174 -0
- ccxt/base/errors.py +242 -0
- ccxt/base/exchange.py +5941 -0
- ccxt/base/precise.py +287 -0
- ccxt/base/types.py +502 -0
- ccxt/bequant.py +33 -0
- ccxt/bigone.py +2112 -0
- ccxt/binance.py +12233 -0
- ccxt/binancecoinm.py +45 -0
- ccxt/binanceus.py +211 -0
- ccxt/binanceusdm.py +58 -0
- ccxt/bingx.py +4324 -0
- ccxt/bit2c.py +866 -0
- ccxt/bitbank.py +1001 -0
- ccxt/bitbay.py +17 -0
- ccxt/bitbns.py +1154 -0
- ccxt/bitcoincom.py +17 -0
- ccxt/bitfinex.py +1617 -0
- ccxt/bitfinex2.py +3552 -0
- ccxt/bitflyer.py +995 -0
- ccxt/bitget.py +8272 -0
- ccxt/bithumb.py +1061 -0
- ccxt/bitimen.py +401 -0
- ccxt/bitir.py +490 -0
- ccxt/bitmart.py +4415 -0
- ccxt/bitmex.py +2756 -0
- ccxt/bitopro.py +1630 -0
- ccxt/bitpanda.py +16 -0
- ccxt/bitpin.py +454 -0
- ccxt/bitrue.py +3026 -0
- ccxt/bitso.py +1670 -0
- ccxt/bitstamp.py +2203 -0
- ccxt/bitteam.py +2239 -0
- ccxt/bitvavo.py +1968 -0
- ccxt/bl3p.py +485 -0
- ccxt/blockchaincom.py +1104 -0
- ccxt/blofin.py +2066 -0
- ccxt/btcalpha.py +891 -0
- ccxt/btcbox.py +544 -0
- ccxt/btcmarkets.py +1221 -0
- ccxt/btcturk.py +911 -0
- ccxt/bybit.py +8158 -0
- ccxt/cex.py +1605 -0
- ccxt/coinbase.py +4474 -0
- ccxt/coinbaseadvanced.py +17 -0
- ccxt/coinbaseexchange.py +1734 -0
- ccxt/coinbaseinternational.py +1899 -0
- ccxt/coincatch.py +5069 -0
- ccxt/coincheck.py +815 -0
- ccxt/coinex.py +5525 -0
- ccxt/coinlist.py +2243 -0
- ccxt/coinmate.py +1067 -0
- ccxt/coinmetro.py +1797 -0
- ccxt/coinone.py +1127 -0
- ccxt/coinsph.py +1850 -0
- ccxt/coinspot.py +534 -0
- ccxt/cryptocom.py +2822 -0
- ccxt/currencycom.py +1950 -0
- ccxt/delta.py +3376 -0
- ccxt/deribit.py +3437 -0
- ccxt/digifinex.py +3959 -0
- ccxt/eterex.py +286 -0
- ccxt/excoino.py +399 -0
- ccxt/exir.py +375 -0
- ccxt/exmo.py +2462 -0
- ccxt/exnovin.py +360 -0
- ccxt/farhadexchange.py +266 -0
- ccxt/fmfwio.py +34 -0
- ccxt/gate.py +6975 -0
- ccxt/gateio.py +16 -0
- ccxt/gemini.py +1824 -0
- ccxt/hashkey.py +4150 -0
- ccxt/hitbtc.py +3423 -0
- ccxt/hitbtc3.py +16 -0
- ccxt/hitobit.py +391 -0
- ccxt/hollaex.py +1813 -0
- ccxt/htx.py +8505 -0
- ccxt/huobi.py +16 -0
- ccxt/huobijp.py +1801 -0
- ccxt/hyperliquid.py +2430 -0
- ccxt/idex.py +1766 -0
- ccxt/independentreserve.py +784 -0
- ccxt/indodax.py +1247 -0
- ccxt/jibitex.py +395 -0
- ccxt/kraken.py +2894 -0
- ccxt/krakenfutures.py +2601 -0
- ccxt/kucoin.py +4601 -0
- ccxt/kucoinfutures.py +2698 -0
- ccxt/kuna.py +1841 -0
- ccxt/latoken.py +1664 -0
- ccxt/lbank.py +2682 -0
- ccxt/luno.py +1067 -0
- ccxt/lykke.py +1270 -0
- ccxt/mercado.py +842 -0
- ccxt/mexc.py +5369 -0
- ccxt/ndax.py +2354 -0
- ccxt/nobitex.py +419 -0
- ccxt/novadax.py +1484 -0
- ccxt/oceanex.py +903 -0
- ccxt/okcoin.py +2936 -0
- ccxt/okexchange.py +349 -0
- ccxt/okx.py +7826 -0
- ccxt/ompfinex.py +472 -0
- ccxt/onetrading.py +1911 -0
- ccxt/oxfun.py +2772 -0
- ccxt/p2b.py +1194 -0
- ccxt/paradex.py +2015 -0
- ccxt/paymium.py +564 -0
- ccxt/phemex.py +4473 -0
- ccxt/poloniex.py +2232 -0
- ccxt/poloniexfutures.py +1717 -0
- ccxt/pro/__init__.py +149 -0
- ccxt/pro/alpaca.py +685 -0
- ccxt/pro/ascendex.py +916 -0
- ccxt/pro/bequant.py +38 -0
- ccxt/pro/binance.py +3488 -0
- ccxt/pro/binancecoinm.py +28 -0
- ccxt/pro/binanceus.py +48 -0
- ccxt/pro/binanceusdm.py +31 -0
- ccxt/pro/bingx.py +1264 -0
- ccxt/pro/bitcoincom.py +34 -0
- ccxt/pro/bitfinex.py +621 -0
- ccxt/pro/bitfinex2.py +1083 -0
- ccxt/pro/bitget.py +1692 -0
- ccxt/pro/bithumb.py +368 -0
- ccxt/pro/bitmart.py +1449 -0
- ccxt/pro/bitmex.py +1656 -0
- ccxt/pro/bitopro.py +445 -0
- ccxt/pro/bitpanda.py +15 -0
- ccxt/pro/bitrue.py +447 -0
- ccxt/pro/bitstamp.py +522 -0
- ccxt/pro/bitvavo.py +1270 -0
- ccxt/pro/blockchaincom.py +738 -0
- ccxt/pro/blofin.py +692 -0
- ccxt/pro/bybit.py +2000 -0
- ccxt/pro/cex.py +1440 -0
- ccxt/pro/coinbase.py +678 -0
- ccxt/pro/coinbaseadvanced.py +16 -0
- ccxt/pro/coinbaseexchange.py +895 -0
- ccxt/pro/coinbaseinternational.py +620 -0
- ccxt/pro/coincatch.py +1464 -0
- ccxt/pro/coincheck.py +199 -0
- ccxt/pro/coinex.py +1061 -0
- ccxt/pro/coinone.py +395 -0
- ccxt/pro/cryptocom.py +947 -0
- ccxt/pro/currencycom.py +536 -0
- ccxt/pro/deribit.py +892 -0
- ccxt/pro/exmo.py +629 -0
- ccxt/pro/gate.py +1416 -0
- ccxt/pro/gateio.py +15 -0
- ccxt/pro/gemini.py +865 -0
- ccxt/pro/hashkey.py +802 -0
- ccxt/pro/hitbtc.py +1216 -0
- ccxt/pro/hollaex.py +563 -0
- ccxt/pro/htx.py +2215 -0
- ccxt/pro/huobi.py +15 -0
- ccxt/pro/huobijp.py +570 -0
- ccxt/pro/hyperliquid.py +525 -0
- ccxt/pro/idex.py +672 -0
- ccxt/pro/independentreserve.py +270 -0
- ccxt/pro/kraken.py +1356 -0
- ccxt/pro/krakenfutures.py +1492 -0
- ccxt/pro/kucoin.py +1133 -0
- ccxt/pro/kucoinfutures.py +1081 -0
- ccxt/pro/lbank.py +843 -0
- ccxt/pro/luno.py +303 -0
- ccxt/pro/mexc.py +1122 -0
- ccxt/pro/ndax.py +506 -0
- ccxt/pro/okcoin.py +698 -0
- ccxt/pro/okx.py +1851 -0
- ccxt/pro/onetrading.py +1275 -0
- ccxt/pro/oxfun.py +950 -0
- ccxt/pro/p2b.py +419 -0
- ccxt/pro/paradex.py +352 -0
- ccxt/pro/phemex.py +1441 -0
- ccxt/pro/poloniex.py +1166 -0
- ccxt/pro/poloniexfutures.py +990 -0
- ccxt/pro/probit.py +551 -0
- ccxt/pro/upbit.py +520 -0
- ccxt/pro/vertex.py +943 -0
- ccxt/pro/wazirx.py +749 -0
- ccxt/pro/whitebit.py +864 -0
- ccxt/pro/woo.py +1078 -0
- ccxt/pro/woofipro.py +1183 -0
- ccxt/pro/xt.py +1067 -0
- ccxt/probit.py +1734 -0
- ccxt/ramzinex.py +476 -0
- ccxt/sarmayex.py +357 -0
- ccxt/sarrafex.py +478 -0
- ccxt/static_dependencies/__init__.py +1 -0
- ccxt/static_dependencies/ecdsa/__init__.py +14 -0
- ccxt/static_dependencies/ecdsa/_version.py +520 -0
- ccxt/static_dependencies/ecdsa/curves.py +56 -0
- ccxt/static_dependencies/ecdsa/der.py +221 -0
- ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
- ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
- ccxt/static_dependencies/ecdsa/keys.py +332 -0
- ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
- ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
- ccxt/static_dependencies/ecdsa/util.py +266 -0
- ccxt/static_dependencies/ethereum/__init__.py +7 -0
- ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
- ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
- ccxt/static_dependencies/ethereum/abi/base.py +152 -0
- ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
- ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
- ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
- ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
- ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
- ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
- ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
- ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
- ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
- ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
- ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
- ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
- ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
- ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
- ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
- ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
- ccxt/static_dependencies/ethereum/account/messages.py +263 -0
- ccxt/static_dependencies/ethereum/account/py.typed +0 -0
- ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
- ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
- ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
- ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
- ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
- ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
- ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
- ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
- ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
- ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
- ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
- ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
- ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
- ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
- ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
- ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
- ccxt/static_dependencies/ethereum/utils/address.py +171 -0
- ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
- ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
- ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
- ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
- ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
- ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
- ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
- ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
- ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
- ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
- ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
- ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
- ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
- ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
- ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
- ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
- ccxt/static_dependencies/ethereum/utils/types.py +54 -0
- ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
- ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
- ccxt/static_dependencies/ethereum/utils/units.py +31 -0
- ccxt/static_dependencies/keccak/__init__.py +3 -0
- ccxt/static_dependencies/keccak/keccak.py +197 -0
- ccxt/static_dependencies/lark/__init__.py +38 -0
- ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- ccxt/static_dependencies/lark/ast_utils.py +59 -0
- ccxt/static_dependencies/lark/common.py +86 -0
- ccxt/static_dependencies/lark/exceptions.py +292 -0
- ccxt/static_dependencies/lark/grammar.py +130 -0
- ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- ccxt/static_dependencies/lark/indenter.py +143 -0
- ccxt/static_dependencies/lark/lark.py +658 -0
- ccxt/static_dependencies/lark/lexer.py +678 -0
- ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- ccxt/static_dependencies/lark/reconstruct.py +107 -0
- ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- ccxt/static_dependencies/lark/tree.py +267 -0
- ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- ccxt/static_dependencies/lark/tree_templates.py +180 -0
- ccxt/static_dependencies/lark/utils.py +343 -0
- ccxt/static_dependencies/lark/visitors.py +596 -0
- ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- ccxt/static_dependencies/marshmallow/base.py +65 -0
- ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- ccxt/static_dependencies/marshmallow/types.py +12 -0
- ccxt/static_dependencies/marshmallow/utils.py +378 -0
- ccxt/static_dependencies/marshmallow/validate.py +678 -0
- ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- ccxt/static_dependencies/msgpack/__init__.py +55 -0
- ccxt/static_dependencies/msgpack/exceptions.py +48 -0
- ccxt/static_dependencies/msgpack/ext.py +168 -0
- ccxt/static_dependencies/msgpack/fallback.py +951 -0
- ccxt/static_dependencies/parsimonious/__init__.py +10 -0
- ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
- ccxt/static_dependencies/parsimonious/expressions.py +479 -0
- ccxt/static_dependencies/parsimonious/grammar.py +487 -0
- ccxt/static_dependencies/parsimonious/nodes.py +325 -0
- ccxt/static_dependencies/parsimonious/utils.py +40 -0
- ccxt/static_dependencies/starknet/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- ccxt/static_dependencies/starknet/common.py +15 -0
- ccxt/static_dependencies/starknet/constants.py +39 -0
- ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- ccxt/static_dependencies/starknet/hash/address.py +79 -0
- ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- ccxt/static_dependencies/starkware/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- ccxt/static_dependencies/sympy/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- ccxt/static_dependencies/toolz/__init__.py +26 -0
- ccxt/static_dependencies/toolz/_signatures.py +784 -0
- ccxt/static_dependencies/toolz/_version.py +520 -0
- ccxt/static_dependencies/toolz/compatibility.py +30 -0
- ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
- ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
- ccxt/static_dependencies/toolz/curried/operator.py +22 -0
- ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
- ccxt/static_dependencies/toolz/functoolz.py +1049 -0
- ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
- ccxt/static_dependencies/toolz/recipes.py +46 -0
- ccxt/static_dependencies/toolz/utils.py +9 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/tabdeal.py +364 -0
- ccxt/test/__init__.py +3 -0
- ccxt/test/base/__init__.py +29 -0
- ccxt/test/base/test_account.py +26 -0
- ccxt/test/base/test_balance.py +56 -0
- ccxt/test/base/test_borrow_interest.py +35 -0
- ccxt/test/base/test_borrow_rate.py +32 -0
- ccxt/test/base/test_calculate_fee.py +51 -0
- ccxt/test/base/test_crypto.py +127 -0
- ccxt/test/base/test_currency.py +76 -0
- ccxt/test/base/test_datetime.py +109 -0
- ccxt/test/base/test_decimal_to_precision.py +392 -0
- ccxt/test/base/test_deep_extend.py +68 -0
- ccxt/test/base/test_deposit_withdrawal.py +50 -0
- ccxt/test/base/test_exchange_datetime_functions.py +76 -0
- ccxt/test/base/test_funding_rate_history.py +29 -0
- ccxt/test/base/test_last_price.py +31 -0
- ccxt/test/base/test_ledger_entry.py +45 -0
- ccxt/test/base/test_ledger_item.py +48 -0
- ccxt/test/base/test_leverage_tier.py +33 -0
- ccxt/test/base/test_liquidation.py +50 -0
- ccxt/test/base/test_margin_mode.py +24 -0
- ccxt/test/base/test_margin_modification.py +35 -0
- ccxt/test/base/test_market.py +193 -0
- ccxt/test/base/test_number.py +411 -0
- ccxt/test/base/test_ohlcv.py +33 -0
- ccxt/test/base/test_open_interest.py +32 -0
- ccxt/test/base/test_order.py +64 -0
- ccxt/test/base/test_order_book.py +69 -0
- ccxt/test/base/test_position.py +60 -0
- ccxt/test/base/test_shared_methods.py +353 -0
- ccxt/test/base/test_status.py +24 -0
- ccxt/test/base/test_throttle.py +126 -0
- ccxt/test/base/test_ticker.py +92 -0
- ccxt/test/base/test_trade.py +47 -0
- ccxt/test/base/test_trading_fee.py +26 -0
- ccxt/test/base/test_transaction.py +39 -0
- ccxt/test/test_async.py +1649 -0
- ccxt/test/test_sync.py +1648 -0
- ccxt/test/tests_async.py +1558 -0
- ccxt/test/tests_helpers.py +287 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/tests_sync.py +1555 -0
- ccxt/tetherland.py +349 -0
- ccxt/timex.py +1593 -0
- ccxt/tokocrypto.py +2405 -0
- ccxt/tradeogre.py +608 -0
- ccxt/twox.py +326 -0
- ccxt/ubitex.py +409 -0
- ccxt/upbit.py +1833 -0
- ccxt/vertex.py +2922 -0
- ccxt/wallex.py +445 -0
- ccxt/wavesexchange.py +2472 -0
- ccxt/wazirx.py +1224 -0
- ccxt/whitebit.py +2469 -0
- ccxt/woo.py +3114 -0
- ccxt/woofipro.py +2533 -0
- ccxt/xt.py +4453 -0
- ccxt/yobit.py +1283 -0
- ccxt/zaif.py +725 -0
- ccxt/zonda.py +1828 -0
- ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
- ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
- ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
- ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
- ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
ccxt/hyperliquid.py
ADDED
|
@@ -0,0 +1,2430 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
|
4
|
+
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
|
5
|
+
|
|
6
|
+
from ccxt.base.exchange import Exchange
|
|
7
|
+
from ccxt.abstract.hyperliquid import ImplicitAPI
|
|
8
|
+
from ccxt.base.types import Balances, Currencies, Currency, Int, MarginModification, Market, Num, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Str, Strings, Trade, Transaction, TransferEntry
|
|
9
|
+
from typing import List
|
|
10
|
+
from ccxt.base.errors import ExchangeError
|
|
11
|
+
from ccxt.base.errors import ArgumentsRequired
|
|
12
|
+
from ccxt.base.errors import BadRequest
|
|
13
|
+
from ccxt.base.errors import InvalidOrder
|
|
14
|
+
from ccxt.base.errors import OrderNotFound
|
|
15
|
+
from ccxt.base.errors import NotSupported
|
|
16
|
+
from ccxt.base.decimal_to_precision import ROUND
|
|
17
|
+
from ccxt.base.decimal_to_precision import DECIMAL_PLACES
|
|
18
|
+
from ccxt.base.decimal_to_precision import SIGNIFICANT_DIGITS
|
|
19
|
+
from ccxt.base.decimal_to_precision import TICK_SIZE
|
|
20
|
+
from ccxt.base.precise import Precise
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class hyperliquid(Exchange, ImplicitAPI):
|
|
24
|
+
|
|
25
|
+
def describe(self):
|
|
26
|
+
return self.deep_extend(super(hyperliquid, self).describe(), {
|
|
27
|
+
'id': 'hyperliquid',
|
|
28
|
+
'name': 'Hyperliquid',
|
|
29
|
+
'countries': [],
|
|
30
|
+
'version': 'v1',
|
|
31
|
+
'rateLimit': 50, # 1200 requests per minute, 20 request per second
|
|
32
|
+
'certified': False,
|
|
33
|
+
'pro': True,
|
|
34
|
+
'dex': True,
|
|
35
|
+
'has': {
|
|
36
|
+
'CORS': None,
|
|
37
|
+
'spot': True,
|
|
38
|
+
'margin': False,
|
|
39
|
+
'swap': True,
|
|
40
|
+
'future': True,
|
|
41
|
+
'option': False,
|
|
42
|
+
'addMargin': True,
|
|
43
|
+
'borrowCrossMargin': False,
|
|
44
|
+
'borrowIsolatedMargin': False,
|
|
45
|
+
'cancelAllOrders': False,
|
|
46
|
+
'cancelAllOrdersAfter': True,
|
|
47
|
+
'cancelOrder': True,
|
|
48
|
+
'cancelOrders': True,
|
|
49
|
+
'cancelOrdersForSymbols': True,
|
|
50
|
+
'closeAllPositions': False,
|
|
51
|
+
'closePosition': False,
|
|
52
|
+
'createMarketBuyOrderWithCost': False,
|
|
53
|
+
'createMarketOrderWithCost': False,
|
|
54
|
+
'createMarketSellOrderWithCost': False,
|
|
55
|
+
'createOrder': True,
|
|
56
|
+
'createOrders': True,
|
|
57
|
+
'createReduceOnlyOrder': True,
|
|
58
|
+
'editOrder': True,
|
|
59
|
+
'fetchAccounts': False,
|
|
60
|
+
'fetchBalance': True,
|
|
61
|
+
'fetchBorrowInterest': False,
|
|
62
|
+
'fetchBorrowRateHistories': False,
|
|
63
|
+
'fetchBorrowRateHistory': False,
|
|
64
|
+
'fetchCanceledOrders': False,
|
|
65
|
+
'fetchClosedOrders': True,
|
|
66
|
+
'fetchCrossBorrowRate': False,
|
|
67
|
+
'fetchCrossBorrowRates': False,
|
|
68
|
+
'fetchCurrencies': True,
|
|
69
|
+
'fetchDepositAddress': False,
|
|
70
|
+
'fetchDepositAddresses': False,
|
|
71
|
+
'fetchDeposits': False,
|
|
72
|
+
'fetchDepositWithdrawFee': 'emulated',
|
|
73
|
+
'fetchDepositWithdrawFees': False,
|
|
74
|
+
'fetchFundingHistory': False,
|
|
75
|
+
'fetchFundingRate': False,
|
|
76
|
+
'fetchFundingRateHistory': True,
|
|
77
|
+
'fetchFundingRates': False,
|
|
78
|
+
'fetchIndexOHLCV': False,
|
|
79
|
+
'fetchIsolatedBorrowRate': False,
|
|
80
|
+
'fetchIsolatedBorrowRates': False,
|
|
81
|
+
'fetchLedger': False,
|
|
82
|
+
'fetchLeverage': False,
|
|
83
|
+
'fetchLeverageTiers': False,
|
|
84
|
+
'fetchLiquidations': False,
|
|
85
|
+
'fetchMarginMode': None,
|
|
86
|
+
'fetchMarketLeverageTiers': False,
|
|
87
|
+
'fetchMarkets': True,
|
|
88
|
+
'fetchMarkOHLCV': False,
|
|
89
|
+
'fetchMyLiquidations': False,
|
|
90
|
+
'fetchMyTrades': True,
|
|
91
|
+
'fetchOHLCV': True,
|
|
92
|
+
'fetchOpenInterest': False,
|
|
93
|
+
'fetchOpenInterestHistory': False,
|
|
94
|
+
'fetchOpenOrders': True,
|
|
95
|
+
'fetchOrder': True,
|
|
96
|
+
'fetchOrderBook': True,
|
|
97
|
+
'fetchOrders': False,
|
|
98
|
+
'fetchOrderTrades': False,
|
|
99
|
+
'fetchPosition': True,
|
|
100
|
+
'fetchPositionMode': False,
|
|
101
|
+
'fetchPositions': True,
|
|
102
|
+
'fetchPositionsRisk': False,
|
|
103
|
+
'fetchPremiumIndexOHLCV': False,
|
|
104
|
+
'fetchTicker': False,
|
|
105
|
+
'fetchTickers': False,
|
|
106
|
+
'fetchTime': False,
|
|
107
|
+
'fetchTrades': True,
|
|
108
|
+
'fetchTradingFee': False,
|
|
109
|
+
'fetchTradingFees': False,
|
|
110
|
+
'fetchTransfer': False,
|
|
111
|
+
'fetchTransfers': False,
|
|
112
|
+
'fetchWithdrawal': False,
|
|
113
|
+
'fetchWithdrawals': False,
|
|
114
|
+
'reduceMargin': True,
|
|
115
|
+
'repayCrossMargin': False,
|
|
116
|
+
'repayIsolatedMargin': False,
|
|
117
|
+
'sandbox': True,
|
|
118
|
+
'setLeverage': True,
|
|
119
|
+
'setMarginMode': True,
|
|
120
|
+
'setPositionMode': False,
|
|
121
|
+
'transfer': True,
|
|
122
|
+
'withdraw': True,
|
|
123
|
+
},
|
|
124
|
+
'timeframes': {
|
|
125
|
+
'1m': '1m',
|
|
126
|
+
'3m': '3m',
|
|
127
|
+
'5m': '5m',
|
|
128
|
+
'15m': '15m',
|
|
129
|
+
'30m': '30m',
|
|
130
|
+
'1h': '1h',
|
|
131
|
+
'2h': '2h',
|
|
132
|
+
'4h': '4h',
|
|
133
|
+
'6h': '6h',
|
|
134
|
+
'12h': '12h',
|
|
135
|
+
'1d': '1d',
|
|
136
|
+
'3d': '3d',
|
|
137
|
+
'1w': '1w',
|
|
138
|
+
'1M': '1m',
|
|
139
|
+
},
|
|
140
|
+
'hostname': 'hyperliquid.xyz',
|
|
141
|
+
'urls': {
|
|
142
|
+
'logo': 'https://github.com/ccxt/ccxt/assets/43336371/b371bc6c-4a8c-489f-87f4-20a913dd8d4b',
|
|
143
|
+
'api': {
|
|
144
|
+
'public': 'https://api.{hostname}',
|
|
145
|
+
'private': 'https://api.{hostname}',
|
|
146
|
+
},
|
|
147
|
+
'test': {
|
|
148
|
+
'public': 'https://api.hyperliquid-testnet.xyz',
|
|
149
|
+
'private': 'https://api.hyperliquid-testnet.xyz',
|
|
150
|
+
},
|
|
151
|
+
'www': 'https://hyperliquid.xyz',
|
|
152
|
+
'doc': 'https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api',
|
|
153
|
+
'fees': 'https://hyperliquid.gitbook.io/hyperliquid-docs/trading/fees',
|
|
154
|
+
'referral': 'https://app.hyperliquid.xyz/',
|
|
155
|
+
},
|
|
156
|
+
'api': {
|
|
157
|
+
'public': {
|
|
158
|
+
'post': {
|
|
159
|
+
'info': 1,
|
|
160
|
+
},
|
|
161
|
+
},
|
|
162
|
+
'private': {
|
|
163
|
+
'post': {
|
|
164
|
+
'exchange': 1,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
'fees': {
|
|
169
|
+
'swap': {
|
|
170
|
+
'taker': self.parse_number('0.00035'),
|
|
171
|
+
'maker': self.parse_number('0.0001'),
|
|
172
|
+
},
|
|
173
|
+
'spot': {
|
|
174
|
+
'taker': self.parse_number('0.00035'),
|
|
175
|
+
'maker': self.parse_number('0.0001'),
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
'requiredCredentials': {
|
|
179
|
+
'apiKey': False,
|
|
180
|
+
'secret': False,
|
|
181
|
+
'walletAddress': True,
|
|
182
|
+
'privateKey': True,
|
|
183
|
+
},
|
|
184
|
+
'exceptions': {
|
|
185
|
+
'exact': {
|
|
186
|
+
},
|
|
187
|
+
'broad': {
|
|
188
|
+
'Price must be divisible by tick size.': InvalidOrder,
|
|
189
|
+
'Order must have minimum value of $10': InvalidOrder,
|
|
190
|
+
'Insufficient margin to place order.': InvalidOrder,
|
|
191
|
+
'Reduce only order would increase position.': InvalidOrder,
|
|
192
|
+
'Post only order would have immediately matched,': InvalidOrder,
|
|
193
|
+
'Order could not immediately match against any resting orders.': InvalidOrder,
|
|
194
|
+
'Invalid TP/SL price.': InvalidOrder,
|
|
195
|
+
'No liquidity available for market order.': InvalidOrder,
|
|
196
|
+
'Order was never placed, already canceled, or filled.': OrderNotFound,
|
|
197
|
+
'User or API Wallet ': InvalidOrder,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
'precisionMode': TICK_SIZE,
|
|
201
|
+
'commonCurrencies': {
|
|
202
|
+
},
|
|
203
|
+
'options': {
|
|
204
|
+
'defaultType': 'swap',
|
|
205
|
+
'sandboxMode': False,
|
|
206
|
+
'defaultSlippage': 0.05,
|
|
207
|
+
'zeroAddress': '0x0000000000000000000000000000000000000000',
|
|
208
|
+
},
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
def set_sandbox_mode(self, enabled):
|
|
212
|
+
super(hyperliquid, self).set_sandbox_mode(enabled)
|
|
213
|
+
self.options['sandboxMode'] = enabled
|
|
214
|
+
|
|
215
|
+
def fetch_currencies(self, params={}) -> Currencies:
|
|
216
|
+
"""
|
|
217
|
+
fetches all available currencies on an exchange
|
|
218
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-exchange-metadata
|
|
219
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
220
|
+
:returns dict: an associative dictionary of currencies
|
|
221
|
+
"""
|
|
222
|
+
request: dict = {
|
|
223
|
+
'type': 'meta',
|
|
224
|
+
}
|
|
225
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
226
|
+
#
|
|
227
|
+
# [
|
|
228
|
+
# {
|
|
229
|
+
# "universe": [
|
|
230
|
+
# {
|
|
231
|
+
# "maxLeverage": 50,
|
|
232
|
+
# "name": "SOL",
|
|
233
|
+
# "onlyIsolated": False,
|
|
234
|
+
# "szDecimals": 2
|
|
235
|
+
# }
|
|
236
|
+
# ]
|
|
237
|
+
# }
|
|
238
|
+
# ]
|
|
239
|
+
#
|
|
240
|
+
meta = self.safe_list(response, 'universe', [])
|
|
241
|
+
result: dict = {}
|
|
242
|
+
for i in range(0, len(meta)):
|
|
243
|
+
data = self.safe_dict(meta, i, {})
|
|
244
|
+
id = i
|
|
245
|
+
name = self.safe_string(data, 'name')
|
|
246
|
+
code = self.safe_currency_code(name)
|
|
247
|
+
result[code] = {
|
|
248
|
+
'id': id,
|
|
249
|
+
'name': name,
|
|
250
|
+
'code': code,
|
|
251
|
+
'precision': None,
|
|
252
|
+
'info': data,
|
|
253
|
+
'active': None,
|
|
254
|
+
'deposit': None,
|
|
255
|
+
'withdraw': None,
|
|
256
|
+
'networks': None,
|
|
257
|
+
'fee': None,
|
|
258
|
+
# 'fees': fees,
|
|
259
|
+
'limits': None,
|
|
260
|
+
}
|
|
261
|
+
return result
|
|
262
|
+
|
|
263
|
+
def fetch_markets(self, params={}) -> List[Market]:
|
|
264
|
+
"""
|
|
265
|
+
retrieves data on all markets for hyperliquid
|
|
266
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
|
267
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
268
|
+
:returns dict[]: an array of objects representing market data
|
|
269
|
+
"""
|
|
270
|
+
rawPromises = [
|
|
271
|
+
self.fetch_swap_markets(params),
|
|
272
|
+
self.fetch_spot_markets(params),
|
|
273
|
+
]
|
|
274
|
+
promises = rawPromises
|
|
275
|
+
swapMarkets = promises[0]
|
|
276
|
+
spotMarkets = promises[1]
|
|
277
|
+
return self.array_concat(swapMarkets, spotMarkets)
|
|
278
|
+
|
|
279
|
+
def fetch_swap_markets(self, params={}) -> List[Market]:
|
|
280
|
+
"""
|
|
281
|
+
retrieves data on all swap markets for hyperliquid
|
|
282
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
|
283
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
284
|
+
:returns dict[]: an array of objects representing market data
|
|
285
|
+
"""
|
|
286
|
+
request: dict = {
|
|
287
|
+
'type': 'metaAndAssetCtxs',
|
|
288
|
+
}
|
|
289
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
290
|
+
#
|
|
291
|
+
# [
|
|
292
|
+
# {
|
|
293
|
+
# "universe": [
|
|
294
|
+
# {
|
|
295
|
+
# "maxLeverage": 50,
|
|
296
|
+
# "name": "SOL",
|
|
297
|
+
# "onlyIsolated": False,
|
|
298
|
+
# "szDecimals": 2
|
|
299
|
+
# }
|
|
300
|
+
# ]
|
|
301
|
+
# },
|
|
302
|
+
# [
|
|
303
|
+
# {
|
|
304
|
+
# "dayNtlVlm": "9450588.2273",
|
|
305
|
+
# "funding": "0.0000198",
|
|
306
|
+
# "impactPxs": [
|
|
307
|
+
# "108.04",
|
|
308
|
+
# "108.06"
|
|
309
|
+
# ],
|
|
310
|
+
# "markPx": "108.04",
|
|
311
|
+
# "midPx": "108.05",
|
|
312
|
+
# "openInterest": "10764.48",
|
|
313
|
+
# "oraclePx": "107.99",
|
|
314
|
+
# "premium": "0.00055561",
|
|
315
|
+
# "prevDayPx": "111.81"
|
|
316
|
+
# }
|
|
317
|
+
# ]
|
|
318
|
+
# ]
|
|
319
|
+
#
|
|
320
|
+
#
|
|
321
|
+
meta = self.safe_dict(response, 0, {})
|
|
322
|
+
meta = self.safe_list(meta, 'universe', [])
|
|
323
|
+
assetCtxs = self.safe_dict(response, 1, {})
|
|
324
|
+
result = []
|
|
325
|
+
for i in range(0, len(meta)):
|
|
326
|
+
data = self.extend(
|
|
327
|
+
self.safe_dict(meta, i, {}),
|
|
328
|
+
self.safe_dict(assetCtxs, i, {})
|
|
329
|
+
)
|
|
330
|
+
data['baseId'] = i
|
|
331
|
+
result.append(data)
|
|
332
|
+
return self.parse_markets(result)
|
|
333
|
+
|
|
334
|
+
def fetch_spot_markets(self, params={}) -> List[Market]:
|
|
335
|
+
"""
|
|
336
|
+
retrieves data on all spot markets for hyperliquid
|
|
337
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-asset-contexts-includes-mark-price-current-funding-open-interest-etc
|
|
338
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
339
|
+
:returns dict[]: an array of objects representing market data
|
|
340
|
+
"""
|
|
341
|
+
request: dict = {
|
|
342
|
+
'type': 'spotMetaAndAssetCtxs',
|
|
343
|
+
}
|
|
344
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
345
|
+
#
|
|
346
|
+
# [
|
|
347
|
+
# {
|
|
348
|
+
# 'tokens': [
|
|
349
|
+
# {
|
|
350
|
+
# 'name': 'USDC',
|
|
351
|
+
# 'szDecimals': '8',
|
|
352
|
+
# 'weiDecimals': '8',
|
|
353
|
+
# },
|
|
354
|
+
# {
|
|
355
|
+
# 'name': 'PURR',
|
|
356
|
+
# 'szDecimals': '0',
|
|
357
|
+
# 'weiDecimals': '5',
|
|
358
|
+
# },
|
|
359
|
+
# ],
|
|
360
|
+
# 'universe': [
|
|
361
|
+
# {
|
|
362
|
+
# 'name': 'PURR/USDC',
|
|
363
|
+
# 'tokens': [
|
|
364
|
+
# 1,
|
|
365
|
+
# 0,
|
|
366
|
+
# ],
|
|
367
|
+
# },
|
|
368
|
+
# ],
|
|
369
|
+
# },
|
|
370
|
+
# [
|
|
371
|
+
# {
|
|
372
|
+
# 'dayNtlVlm': '264250385.14640012',
|
|
373
|
+
# 'markPx': '0.018314',
|
|
374
|
+
# 'midPx': '0.0182235',
|
|
375
|
+
# 'prevDayPx': '0.017427',
|
|
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
|
+
# }
|
|
436
|
+
# ]
|
|
437
|
+
# ]
|
|
438
|
+
#
|
|
439
|
+
# response differs depending on the environment(mainnet vs sandbox)
|
|
440
|
+
first = self.safe_dict(response, 0, {})
|
|
441
|
+
meta = self.safe_list_2(first, 'universe', 'spot_infos', [])
|
|
442
|
+
tokens = self.safe_list_2(first, 'tokens', 'token_infos', [])
|
|
443
|
+
markets = []
|
|
444
|
+
for i in range(0, len(meta)):
|
|
445
|
+
market = self.safe_dict(meta, i, {})
|
|
446
|
+
marketName = self.safe_string(market, 'name')
|
|
447
|
+
if marketName.find('/') < 0:
|
|
448
|
+
# there are some weird spot markets in testnet, eg @2
|
|
449
|
+
continue
|
|
450
|
+
marketParts = marketName.split('/')
|
|
451
|
+
baseName = self.safe_string(marketParts, 0)
|
|
452
|
+
quoteId = self.safe_string(marketParts, 1)
|
|
453
|
+
base = self.safe_currency_code(baseName)
|
|
454
|
+
quote = self.safe_currency_code(quoteId)
|
|
455
|
+
symbol = base + '/' + quote
|
|
456
|
+
fees = self.safe_dict(self.fees, 'spot', {})
|
|
457
|
+
taker = self.safe_number(fees, 'taker')
|
|
458
|
+
maker = self.safe_number(fees, 'maker')
|
|
459
|
+
tokensPos = self.safe_list(market, 'tokens', [])
|
|
460
|
+
baseTokenPos = self.safe_integer(tokensPos, 0)
|
|
461
|
+
# quoteTokenPos = self.safe_integer(tokensPos, 1)
|
|
462
|
+
baseTokenInfo = self.safe_dict(tokens, baseTokenPos, {})
|
|
463
|
+
# quoteTokenInfo = self.safe_dict(tokens, quoteTokenPos, {})
|
|
464
|
+
innerBaseTokenInfo = self.safe_dict(baseTokenInfo, 'spec', baseTokenInfo)
|
|
465
|
+
# innerQuoteTokenInfo = self.safe_dict(quoteTokenInfo, 'spec', quoteTokenInfo)
|
|
466
|
+
amountPrecision = self.parse_number(self.parse_precision(self.safe_string(innerBaseTokenInfo, 'szDecimals')))
|
|
467
|
+
# quotePrecision = self.parse_number(self.parse_precision(self.safe_string(innerQuoteTokenInfo, 'szDecimals')))
|
|
468
|
+
baseId = self.number_to_string(i + 10000)
|
|
469
|
+
markets.append(self.safe_market_structure({
|
|
470
|
+
'id': marketName,
|
|
471
|
+
'symbol': symbol,
|
|
472
|
+
'base': base,
|
|
473
|
+
'quote': quote,
|
|
474
|
+
'settle': None,
|
|
475
|
+
'baseId': baseId,
|
|
476
|
+
'quoteId': quoteId,
|
|
477
|
+
'settleId': None,
|
|
478
|
+
'type': 'spot',
|
|
479
|
+
'spot': True,
|
|
480
|
+
'subType': None,
|
|
481
|
+
'margin': None,
|
|
482
|
+
'swap': False,
|
|
483
|
+
'future': False,
|
|
484
|
+
'option': False,
|
|
485
|
+
'active': True,
|
|
486
|
+
'contract': False,
|
|
487
|
+
'linear': None,
|
|
488
|
+
'inverse': None,
|
|
489
|
+
'taker': taker,
|
|
490
|
+
'maker': maker,
|
|
491
|
+
'contractSize': None,
|
|
492
|
+
'expiry': None,
|
|
493
|
+
'expiryDatetime': None,
|
|
494
|
+
'strike': None,
|
|
495
|
+
'optionType': None,
|
|
496
|
+
'precision': {
|
|
497
|
+
'amount': amountPrecision, # decimal places
|
|
498
|
+
'price': 5, # significant digits
|
|
499
|
+
},
|
|
500
|
+
'limits': {
|
|
501
|
+
'leverage': {
|
|
502
|
+
'min': None,
|
|
503
|
+
'max': None,
|
|
504
|
+
},
|
|
505
|
+
'amount': {
|
|
506
|
+
'min': None,
|
|
507
|
+
'max': None,
|
|
508
|
+
},
|
|
509
|
+
'price': {
|
|
510
|
+
'min': None,
|
|
511
|
+
'max': None,
|
|
512
|
+
},
|
|
513
|
+
'cost': {
|
|
514
|
+
'min': None,
|
|
515
|
+
'max': None,
|
|
516
|
+
},
|
|
517
|
+
},
|
|
518
|
+
'created': None,
|
|
519
|
+
'info': market,
|
|
520
|
+
}))
|
|
521
|
+
return markets
|
|
522
|
+
|
|
523
|
+
def parse_market(self, market: dict) -> Market:
|
|
524
|
+
#
|
|
525
|
+
# {
|
|
526
|
+
# "maxLeverage": "50",
|
|
527
|
+
# "name": "ETH",
|
|
528
|
+
# "onlyIsolated": False,
|
|
529
|
+
# "szDecimals": "4",
|
|
530
|
+
# "dayNtlVlm": "1709813.11535",
|
|
531
|
+
# "funding": "0.00004807",
|
|
532
|
+
# "impactPxs": [
|
|
533
|
+
# "2369.3",
|
|
534
|
+
# "2369.6"
|
|
535
|
+
# ],
|
|
536
|
+
# "markPx": "2369.6",
|
|
537
|
+
# "midPx": "2369.45",
|
|
538
|
+
# "openInterest": "1815.4712",
|
|
539
|
+
# "oraclePx": "2367.3",
|
|
540
|
+
# "premium": "0.00090821",
|
|
541
|
+
# "prevDayPx": "2381.5"
|
|
542
|
+
# }
|
|
543
|
+
#
|
|
544
|
+
quoteId = 'USDC'
|
|
545
|
+
base = self.safe_string(market, 'name')
|
|
546
|
+
quote = self.safe_currency_code(quoteId)
|
|
547
|
+
baseId = self.safe_string(market, 'baseId')
|
|
548
|
+
settleId = 'USDC'
|
|
549
|
+
settle = self.safe_currency_code(settleId)
|
|
550
|
+
symbol = base + '/' + quote
|
|
551
|
+
contract = True
|
|
552
|
+
swap = True
|
|
553
|
+
if contract:
|
|
554
|
+
if swap:
|
|
555
|
+
symbol = symbol + ':' + settle
|
|
556
|
+
fees = self.safe_dict(self.fees, 'swap', {})
|
|
557
|
+
taker = self.safe_number(fees, 'taker')
|
|
558
|
+
maker = self.safe_number(fees, 'maker')
|
|
559
|
+
return {
|
|
560
|
+
'id': baseId,
|
|
561
|
+
'symbol': symbol,
|
|
562
|
+
'base': base,
|
|
563
|
+
'quote': quote,
|
|
564
|
+
'settle': settle,
|
|
565
|
+
'baseId': baseId,
|
|
566
|
+
'quoteId': quoteId,
|
|
567
|
+
'settleId': settleId,
|
|
568
|
+
'type': 'swap',
|
|
569
|
+
'spot': False,
|
|
570
|
+
'margin': None,
|
|
571
|
+
'swap': swap,
|
|
572
|
+
'future': False,
|
|
573
|
+
'option': False,
|
|
574
|
+
'active': True,
|
|
575
|
+
'contract': contract,
|
|
576
|
+
'linear': True,
|
|
577
|
+
'inverse': False,
|
|
578
|
+
'taker': taker,
|
|
579
|
+
'maker': maker,
|
|
580
|
+
'contractSize': self.parse_number('1'),
|
|
581
|
+
'expiry': None,
|
|
582
|
+
'expiryDatetime': None,
|
|
583
|
+
'strike': None,
|
|
584
|
+
'optionType': None,
|
|
585
|
+
'precision': {
|
|
586
|
+
'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'szDecimals'))), # decimal places
|
|
587
|
+
'price': 5, # significant digits
|
|
588
|
+
},
|
|
589
|
+
'limits': {
|
|
590
|
+
'leverage': {
|
|
591
|
+
'min': None,
|
|
592
|
+
'max': None,
|
|
593
|
+
},
|
|
594
|
+
'amount': {
|
|
595
|
+
'min': None,
|
|
596
|
+
'max': None,
|
|
597
|
+
},
|
|
598
|
+
'price': {
|
|
599
|
+
'min': None,
|
|
600
|
+
'max': None,
|
|
601
|
+
},
|
|
602
|
+
'cost': {
|
|
603
|
+
'min': None,
|
|
604
|
+
'max': None,
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
'created': None,
|
|
608
|
+
'info': market,
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
def fetch_balance(self, params={}) -> Balances:
|
|
612
|
+
"""
|
|
613
|
+
query for balance and get the amount of funds available for trading or funds locked in orders
|
|
614
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-state
|
|
615
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
616
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
617
|
+
:param str [params.type]: wallet type, ['spot', 'swap'], defaults to swap
|
|
618
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
|
619
|
+
"""
|
|
620
|
+
userAddress = None
|
|
621
|
+
userAddress, params = self.handle_public_address('fetchBalance', params)
|
|
622
|
+
type = None
|
|
623
|
+
type, params = self.handle_market_type_and_params('fetchBalance', None, params)
|
|
624
|
+
isSpot = (type == 'spot')
|
|
625
|
+
reqType = 'spotClearinghouseState' if (isSpot) else 'clearinghouseState'
|
|
626
|
+
request: dict = {
|
|
627
|
+
'type': reqType,
|
|
628
|
+
'user': userAddress,
|
|
629
|
+
}
|
|
630
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
631
|
+
#
|
|
632
|
+
# {
|
|
633
|
+
# "assetPositions": [],
|
|
634
|
+
# "crossMaintenanceMarginUsed": "0.0",
|
|
635
|
+
# "crossMarginSummary": {
|
|
636
|
+
# "accountValue": "100.0",
|
|
637
|
+
# "totalMarginUsed": "0.0",
|
|
638
|
+
# "totalNtlPos": "0.0",
|
|
639
|
+
# "totalRawUsd": "100.0"
|
|
640
|
+
# },
|
|
641
|
+
# "marginSummary": {
|
|
642
|
+
# "accountValue": "100.0",
|
|
643
|
+
# "totalMarginUsed": "0.0",
|
|
644
|
+
# "totalNtlPos": "0.0",
|
|
645
|
+
# "totalRawUsd": "100.0"
|
|
646
|
+
# },
|
|
647
|
+
# "time": "1704261007014",
|
|
648
|
+
# "withdrawable": "100.0"
|
|
649
|
+
# }
|
|
650
|
+
# spot
|
|
651
|
+
#
|
|
652
|
+
# {
|
|
653
|
+
# "balances":[
|
|
654
|
+
# {
|
|
655
|
+
# "coin":"USDC",
|
|
656
|
+
# "hold":"0.0",
|
|
657
|
+
# "total":"1481.844"
|
|
658
|
+
# },
|
|
659
|
+
# {
|
|
660
|
+
# "coin":"PURR",
|
|
661
|
+
# "hold":"0.0",
|
|
662
|
+
# "total":"999.65004"
|
|
663
|
+
# }
|
|
664
|
+
# }
|
|
665
|
+
#
|
|
666
|
+
balances = self.safe_list(response, 'balances')
|
|
667
|
+
if balances is not None:
|
|
668
|
+
spotBalances: dict = {'info': response}
|
|
669
|
+
for i in range(0, len(balances)):
|
|
670
|
+
balance = balances[i]
|
|
671
|
+
code = self.safe_currency_code(self.safe_string(balance, 'coin'))
|
|
672
|
+
account = self.account()
|
|
673
|
+
total = self.safe_string(balance, 'total')
|
|
674
|
+
free = self.safe_string(balance, 'hold')
|
|
675
|
+
account['total'] = total
|
|
676
|
+
account['free'] = free
|
|
677
|
+
spotBalances[code] = account
|
|
678
|
+
return self.safe_balance(spotBalances)
|
|
679
|
+
data = self.safe_dict(response, 'marginSummary', {})
|
|
680
|
+
result: dict = {
|
|
681
|
+
'info': response,
|
|
682
|
+
'USDC': {
|
|
683
|
+
'total': self.safe_float(data, 'accountValue'),
|
|
684
|
+
'used': self.safe_float(data, 'totalMarginUsed'),
|
|
685
|
+
},
|
|
686
|
+
}
|
|
687
|
+
timestamp = self.safe_integer(response, 'time')
|
|
688
|
+
result['timestamp'] = timestamp
|
|
689
|
+
result['datetime'] = self.iso8601(timestamp)
|
|
690
|
+
return self.safe_balance(result)
|
|
691
|
+
|
|
692
|
+
def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
|
693
|
+
"""
|
|
694
|
+
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
695
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#info
|
|
696
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
|
697
|
+
:param int [limit]: the maximum amount of order book entries to return
|
|
698
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
699
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
700
|
+
"""
|
|
701
|
+
self.load_markets()
|
|
702
|
+
market = self.market(symbol)
|
|
703
|
+
request: dict = {
|
|
704
|
+
'type': 'l2Book',
|
|
705
|
+
'coin': market['base'] if market['swap'] else market['id'],
|
|
706
|
+
}
|
|
707
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
708
|
+
#
|
|
709
|
+
# {
|
|
710
|
+
# "coin": "ETH",
|
|
711
|
+
# "levels": [
|
|
712
|
+
# [
|
|
713
|
+
# {
|
|
714
|
+
# "n": "2",
|
|
715
|
+
# "px": "2216.2",
|
|
716
|
+
# "sz": "74.0637"
|
|
717
|
+
# }
|
|
718
|
+
# ],
|
|
719
|
+
# [
|
|
720
|
+
# {
|
|
721
|
+
# "n": "2",
|
|
722
|
+
# "px": "2216.5",
|
|
723
|
+
# "sz": "70.5893"
|
|
724
|
+
# }
|
|
725
|
+
# ]
|
|
726
|
+
# ],
|
|
727
|
+
# "time": "1704290104840"
|
|
728
|
+
# }
|
|
729
|
+
#
|
|
730
|
+
data = self.safe_list(response, 'levels', [])
|
|
731
|
+
result: dict = {
|
|
732
|
+
'bids': self.safe_list(data, 0, []),
|
|
733
|
+
'asks': self.safe_list(data, 1, []),
|
|
734
|
+
}
|
|
735
|
+
timestamp = self.safe_integer(response, 'time')
|
|
736
|
+
return self.parse_order_book(result, market['symbol'], timestamp, 'bids', 'asks', 'px', 'sz')
|
|
737
|
+
|
|
738
|
+
def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
739
|
+
"""
|
|
740
|
+
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
741
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#info-1
|
|
742
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
743
|
+
:param str timeframe: the length of time each candle represents, support '1m', '15m', '1h', '1d'
|
|
744
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
745
|
+
:param int [limit]: the maximum amount of candles to fetch
|
|
746
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
747
|
+
:param int [params.until]: timestamp in ms of the latest candle to fetch
|
|
748
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
749
|
+
"""
|
|
750
|
+
self.load_markets()
|
|
751
|
+
market = self.market(symbol)
|
|
752
|
+
until = self.safe_integer(params, 'until', self.milliseconds())
|
|
753
|
+
if since is None:
|
|
754
|
+
since = 0
|
|
755
|
+
if limit is None:
|
|
756
|
+
limit = 500
|
|
757
|
+
params = self.omit(params, ['until'])
|
|
758
|
+
request: dict = {
|
|
759
|
+
'type': 'candleSnapshot',
|
|
760
|
+
'req': {
|
|
761
|
+
'coin': market['base'] if market['swap'] else market['id'],
|
|
762
|
+
'interval': timeframe,
|
|
763
|
+
'startTime': since,
|
|
764
|
+
'endTime': until,
|
|
765
|
+
},
|
|
766
|
+
}
|
|
767
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
768
|
+
#
|
|
769
|
+
# [
|
|
770
|
+
# {
|
|
771
|
+
# "T": 1704287699999,
|
|
772
|
+
# "c": "2226.4",
|
|
773
|
+
# "h": "2247.9",
|
|
774
|
+
# "i": "15m",
|
|
775
|
+
# "l": "2224.6",
|
|
776
|
+
# "n": 46,
|
|
777
|
+
# "o": "2247.9",
|
|
778
|
+
# "s": "ETH",
|
|
779
|
+
# "t": 1704286800000,
|
|
780
|
+
# "v": "591.6427"
|
|
781
|
+
# }
|
|
782
|
+
# ]
|
|
783
|
+
#
|
|
784
|
+
return self.parse_ohlcvs(response, market, timeframe, since, limit)
|
|
785
|
+
|
|
786
|
+
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
|
787
|
+
#
|
|
788
|
+
# {
|
|
789
|
+
# "T": 1704287699999,
|
|
790
|
+
# "c": "2226.4",
|
|
791
|
+
# "h": "2247.9",
|
|
792
|
+
# "i": "15m",
|
|
793
|
+
# "l": "2224.6",
|
|
794
|
+
# "n": 46,
|
|
795
|
+
# "o": "2247.9",
|
|
796
|
+
# "s": "ETH",
|
|
797
|
+
# "t": 1704286800000,
|
|
798
|
+
# "v": "591.6427"
|
|
799
|
+
# }
|
|
800
|
+
#
|
|
801
|
+
return [
|
|
802
|
+
self.safe_integer(ohlcv, 't'),
|
|
803
|
+
self.safe_number(ohlcv, 'o'),
|
|
804
|
+
self.safe_number(ohlcv, 'h'),
|
|
805
|
+
self.safe_number(ohlcv, 'l'),
|
|
806
|
+
self.safe_number(ohlcv, 'c'),
|
|
807
|
+
self.safe_number(ohlcv, 'v'),
|
|
808
|
+
]
|
|
809
|
+
|
|
810
|
+
def fetch_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
811
|
+
"""
|
|
812
|
+
get the list of most recent trades for a particular symbol
|
|
813
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills
|
|
814
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills-by-time
|
|
815
|
+
:param str symbol: unified market symbol
|
|
816
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
|
817
|
+
:param int [limit]: the maximum number of trades structures to retrieve
|
|
818
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
819
|
+
:param int [params.until]: timestamp in ms of the latest trade
|
|
820
|
+
:param str [params.address]: wallet address that made trades
|
|
821
|
+
:param str [params.user]: wallet address that made trades
|
|
822
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
823
|
+
"""
|
|
824
|
+
userAddress = None
|
|
825
|
+
userAddress, params = self.handle_public_address('fetchTrades', params)
|
|
826
|
+
self.load_markets()
|
|
827
|
+
market = self.safe_market(symbol)
|
|
828
|
+
request: dict = {
|
|
829
|
+
'user': userAddress,
|
|
830
|
+
}
|
|
831
|
+
if since is not None:
|
|
832
|
+
request['type'] = 'userFillsByTime'
|
|
833
|
+
request['startTime'] = since
|
|
834
|
+
else:
|
|
835
|
+
request['type'] = 'userFills'
|
|
836
|
+
until = self.safe_integer(params, 'until')
|
|
837
|
+
params = self.omit(params, 'until')
|
|
838
|
+
if until is not None:
|
|
839
|
+
request['endTime'] = until
|
|
840
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
841
|
+
#
|
|
842
|
+
# [
|
|
843
|
+
# {
|
|
844
|
+
# "closedPnl": "0.19343",
|
|
845
|
+
# "coin": "ETH",
|
|
846
|
+
# "crossed": True,
|
|
847
|
+
# "dir": "Close Long",
|
|
848
|
+
# "fee": "0.050062",
|
|
849
|
+
# "hash": "0x09d77c96791e98b5775a04092584ab010d009445119c71e4005c0d634ea322bc",
|
|
850
|
+
# "liquidationMarkPx": null,
|
|
851
|
+
# "oid": 3929354691,
|
|
852
|
+
# "px": "2381.1",
|
|
853
|
+
# "side": "A",
|
|
854
|
+
# "startPosition": "0.0841",
|
|
855
|
+
# "sz": "0.0841",
|
|
856
|
+
# "tid": 128423918764978,
|
|
857
|
+
# "time": 1704262888911
|
|
858
|
+
# }
|
|
859
|
+
# ]
|
|
860
|
+
#
|
|
861
|
+
return self.parse_trades(response, market, since, limit)
|
|
862
|
+
|
|
863
|
+
def amount_to_precision(self, symbol, amount):
|
|
864
|
+
market = self.market(symbol)
|
|
865
|
+
if market['spot']:
|
|
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)
|
|
868
|
+
|
|
869
|
+
def price_to_precision(self, symbol: str, price) -> str:
|
|
870
|
+
market = self.market(symbol)
|
|
871
|
+
result = self.decimal_to_precision(price, ROUND, market['precision']['price'], SIGNIFICANT_DIGITS, self.paddingMode)
|
|
872
|
+
decimalParsedResult = self.decimal_to_precision(result, ROUND, 6, DECIMAL_PLACES, self.paddingMode)
|
|
873
|
+
return decimalParsedResult
|
|
874
|
+
|
|
875
|
+
def hash_message(self, message):
|
|
876
|
+
return '0x' + self.hash(message, 'keccak', 'hex')
|
|
877
|
+
|
|
878
|
+
def sign_hash(self, hash, privateKey):
|
|
879
|
+
signature = self.ecdsa(hash[-64:], privateKey[-64:], 'secp256k1', None)
|
|
880
|
+
return {
|
|
881
|
+
'r': '0x' + signature['r'],
|
|
882
|
+
's': '0x' + signature['s'],
|
|
883
|
+
'v': self.sum(27, signature['v']),
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
def sign_message(self, message, privateKey):
|
|
887
|
+
return self.sign_hash(self.hash_message(message), privateKey[-64:])
|
|
888
|
+
|
|
889
|
+
def construct_phantom_agent(self, hash, isTestnet=True):
|
|
890
|
+
source = 'b' if (isTestnet) else 'a'
|
|
891
|
+
return {
|
|
892
|
+
'source': source,
|
|
893
|
+
'connectionId': hash,
|
|
894
|
+
}
|
|
895
|
+
|
|
896
|
+
def action_hash(self, action, vaultAddress, nonce):
|
|
897
|
+
dataBinary = self.packb(action)
|
|
898
|
+
dataHex = self.binary_to_base16(dataBinary)
|
|
899
|
+
data = dataHex
|
|
900
|
+
data += '00000' + self.int_to_base16(nonce)
|
|
901
|
+
if vaultAddress is None:
|
|
902
|
+
data += '00'
|
|
903
|
+
else:
|
|
904
|
+
data += '01'
|
|
905
|
+
data += vaultAddress
|
|
906
|
+
return self.hash(self.base16_to_binary(data), 'keccak', 'binary')
|
|
907
|
+
|
|
908
|
+
def sign_l1_action(self, action, nonce, vaultAdress=None) -> object:
|
|
909
|
+
hash = self.action_hash(action, vaultAdress, nonce)
|
|
910
|
+
isTestnet = self.safe_bool(self.options, 'sandboxMode', False)
|
|
911
|
+
phantomAgent = self.construct_phantom_agent(hash, isTestnet)
|
|
912
|
+
# data: Dict = {
|
|
913
|
+
# 'domain': {
|
|
914
|
+
# 'chainId': 1337,
|
|
915
|
+
# 'name': 'Exchange',
|
|
916
|
+
# 'verifyingContract': '0x0000000000000000000000000000000000000000',
|
|
917
|
+
# 'version': '1',
|
|
918
|
+
# },
|
|
919
|
+
# 'types': {
|
|
920
|
+
# 'Agent': [
|
|
921
|
+
# {'name': 'source', 'type': 'string'},
|
|
922
|
+
# {'name': 'connectionId', 'type': 'bytes32'},
|
|
923
|
+
# ],
|
|
924
|
+
# 'EIP712Domain': [
|
|
925
|
+
# {'name': 'name', 'type': 'string'},
|
|
926
|
+
# {'name': 'version', 'type': 'string'},
|
|
927
|
+
# {'name': 'chainId', 'type': 'uint256'},
|
|
928
|
+
# {'name': 'verifyingContract', 'type': 'address'},
|
|
929
|
+
# ],
|
|
930
|
+
# },
|
|
931
|
+
# 'primaryType': 'Agent',
|
|
932
|
+
# 'message': phantomAgent,
|
|
933
|
+
# }
|
|
934
|
+
zeroAddress = self.safe_string(self.options, 'zeroAddress')
|
|
935
|
+
chainId = 1337 # check self out
|
|
936
|
+
domain: dict = {
|
|
937
|
+
'chainId': chainId,
|
|
938
|
+
'name': 'Exchange',
|
|
939
|
+
'verifyingContract': zeroAddress,
|
|
940
|
+
'version': '1',
|
|
941
|
+
}
|
|
942
|
+
messageTypes: dict = {
|
|
943
|
+
'Agent': [
|
|
944
|
+
{'name': 'source', 'type': 'string'},
|
|
945
|
+
{'name': 'connectionId', 'type': 'bytes32'},
|
|
946
|
+
],
|
|
947
|
+
}
|
|
948
|
+
msg = self.eth_encode_structured_data(domain, messageTypes, phantomAgent)
|
|
949
|
+
signature = self.sign_message(msg, self.privateKey)
|
|
950
|
+
return signature
|
|
951
|
+
|
|
952
|
+
def sign_user_signed_action(self, messageTypes, message):
|
|
953
|
+
zeroAddress = self.safe_string(self.options, 'zeroAddress')
|
|
954
|
+
chainId = 421614 # check self out
|
|
955
|
+
domain: dict = {
|
|
956
|
+
'chainId': chainId,
|
|
957
|
+
'name': 'HyperliquidSignTransaction',
|
|
958
|
+
'verifyingContract': zeroAddress,
|
|
959
|
+
'version': '1',
|
|
960
|
+
}
|
|
961
|
+
msg = self.eth_encode_structured_data(domain, messageTypes, message)
|
|
962
|
+
signature = self.sign_message(msg, self.privateKey)
|
|
963
|
+
return signature
|
|
964
|
+
|
|
965
|
+
def build_transfer_sig(self, message):
|
|
966
|
+
messageTypes: dict = {
|
|
967
|
+
'HyperliquidTransaction:UsdSend': [
|
|
968
|
+
{'name': 'hyperliquidChain', 'type': 'string'},
|
|
969
|
+
{'name': 'destination', 'type': 'string'},
|
|
970
|
+
{'name': 'amount', 'type': 'string'},
|
|
971
|
+
{'name': 'time', 'type': 'uint64'},
|
|
972
|
+
],
|
|
973
|
+
}
|
|
974
|
+
return self.sign_user_signed_action(messageTypes, message)
|
|
975
|
+
|
|
976
|
+
def build_withdraw_sig(self, message):
|
|
977
|
+
messageTypes: dict = {
|
|
978
|
+
'HyperliquidTransaction:Withdraw': [
|
|
979
|
+
{'name': 'hyperliquidChain', 'type': 'string'},
|
|
980
|
+
{'name': 'destination', 'type': 'string'},
|
|
981
|
+
{'name': 'amount', 'type': 'string'},
|
|
982
|
+
{'name': 'time', 'type': 'uint64'},
|
|
983
|
+
],
|
|
984
|
+
}
|
|
985
|
+
return self.sign_user_signed_action(messageTypes, message)
|
|
986
|
+
|
|
987
|
+
def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
988
|
+
"""
|
|
989
|
+
create a trade order
|
|
990
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
|
991
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
992
|
+
:param str type: 'market' or 'limit'
|
|
993
|
+
:param str side: 'buy' or 'sell'
|
|
994
|
+
: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 fullfilled, in units of the quote currency, ignored in market orders
|
|
996
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
997
|
+
:param str [params.timeInForce]: 'Gtc', 'Ioc', 'Alo'
|
|
998
|
+
:param bool [params.postOnly]: True or False whether the order is post-only
|
|
999
|
+
:param bool [params.reduceOnly]: True or False whether the order is reduce-only
|
|
1000
|
+
:param float [params.triggerPrice]: The price at which a trigger order is triggered at
|
|
1001
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1002
|
+
:param str [params.slippage]: the slippage for market order
|
|
1003
|
+
:param str [params.vaultAddress]: the vault address for order
|
|
1004
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1005
|
+
"""
|
|
1006
|
+
self.load_markets()
|
|
1007
|
+
market = self.market(symbol)
|
|
1008
|
+
vaultAddress = self.safe_string(params, 'vaultAddress')
|
|
1009
|
+
params = self.omit(params, 'vaultAddress')
|
|
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
|
|
1025
|
+
|
|
1026
|
+
def create_orders(self, orders: List[OrderRequest], params={}):
|
|
1027
|
+
"""
|
|
1028
|
+
create a list of trade orders
|
|
1029
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#place-an-order
|
|
1030
|
+
: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
|
|
1031
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1032
|
+
"""
|
|
1033
|
+
self.check_required_credentials()
|
|
1034
|
+
self.load_markets()
|
|
1035
|
+
defaultSlippage = self.safe_string(self.options, 'defaultSlippage')
|
|
1036
|
+
defaultSlippage = self.safe_string(params, 'slippage', defaultSlippage)
|
|
1037
|
+
hasClientOrderId = False
|
|
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))
|
|
1138
|
+
#
|
|
1139
|
+
# {
|
|
1140
|
+
# "status": "ok",
|
|
1141
|
+
# "response": {
|
|
1142
|
+
# "type": "order",
|
|
1143
|
+
# "data": {
|
|
1144
|
+
# "statuses": [
|
|
1145
|
+
# {
|
|
1146
|
+
# "resting": {
|
|
1147
|
+
# "oid": 5063830287
|
|
1148
|
+
# }
|
|
1149
|
+
# }
|
|
1150
|
+
# ]
|
|
1151
|
+
# }
|
|
1152
|
+
# }
|
|
1153
|
+
# }
|
|
1154
|
+
#
|
|
1155
|
+
responseObj = self.safe_dict(response, 'response', {})
|
|
1156
|
+
data = self.safe_dict(responseObj, 'data', {})
|
|
1157
|
+
statuses = self.safe_list(data, 'statuses', [])
|
|
1158
|
+
return self.parse_orders(statuses, None)
|
|
1159
|
+
|
|
1160
|
+
def cancel_order(self, id: str, symbol: Str = None, params={}):
|
|
1161
|
+
"""
|
|
1162
|
+
cancels an open order
|
|
1163
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
|
1164
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
|
1165
|
+
:param str id: order id
|
|
1166
|
+
:param str symbol: unified symbol of the market the order was made in
|
|
1167
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1168
|
+
:param str [params.clientOrderId]: client order id,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1169
|
+
:param str [params.vaultAddress]: the vault address for order
|
|
1170
|
+
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1171
|
+
"""
|
|
1172
|
+
return self.cancel_orders([id], symbol, params)
|
|
1173
|
+
|
|
1174
|
+
def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
|
|
1175
|
+
"""
|
|
1176
|
+
cancel multiple orders
|
|
1177
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
|
1178
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
|
1179
|
+
:param str[] ids: order ids
|
|
1180
|
+
:param str [symbol]: unified market symbol
|
|
1181
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1182
|
+
:param string|str[] [params.clientOrderId]: client order ids,(optional 128 bit hex string e.g. 0x1234567890abcdef1234567890abcdef)
|
|
1183
|
+
:param str [params.vaultAddress]: the vault address
|
|
1184
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1185
|
+
"""
|
|
1186
|
+
self.check_required_credentials()
|
|
1187
|
+
if symbol is None:
|
|
1188
|
+
raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
|
|
1189
|
+
self.load_markets()
|
|
1190
|
+
market = self.market(symbol)
|
|
1191
|
+
clientOrderId = self.safe_value_2(params, 'clientOrderId', 'client_id')
|
|
1192
|
+
params = self.omit(params, ['clientOrderId', 'client_id'])
|
|
1193
|
+
nonce = self.milliseconds()
|
|
1194
|
+
request: dict = {
|
|
1195
|
+
'nonce': nonce,
|
|
1196
|
+
# 'vaultAddress': vaultAddress,
|
|
1197
|
+
}
|
|
1198
|
+
cancelReq = []
|
|
1199
|
+
cancelAction: dict = {
|
|
1200
|
+
'type': '',
|
|
1201
|
+
'cancels': [],
|
|
1202
|
+
}
|
|
1203
|
+
baseId = self.parse_to_numeric(market['baseId'])
|
|
1204
|
+
if clientOrderId is not None:
|
|
1205
|
+
if not isinstance(clientOrderId, list):
|
|
1206
|
+
clientOrderId = [clientOrderId]
|
|
1207
|
+
cancelAction['type'] = 'cancelByCloid'
|
|
1208
|
+
for i in range(0, len(clientOrderId)):
|
|
1209
|
+
cancelReq.append({
|
|
1210
|
+
'asset': baseId,
|
|
1211
|
+
'cloid': clientOrderId[i],
|
|
1212
|
+
})
|
|
1213
|
+
else:
|
|
1214
|
+
cancelAction['type'] = 'cancel'
|
|
1215
|
+
for i in range(0, len(ids)):
|
|
1216
|
+
cancelReq.append({
|
|
1217
|
+
'a': baseId,
|
|
1218
|
+
'o': self.parse_to_numeric(ids[i]),
|
|
1219
|
+
})
|
|
1220
|
+
cancelAction['cancels'] = cancelReq
|
|
1221
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
|
1222
|
+
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
|
1223
|
+
request['action'] = cancelAction
|
|
1224
|
+
request['signature'] = signature
|
|
1225
|
+
if vaultAddress is not None:
|
|
1226
|
+
params = self.omit(params, 'vaultAddress')
|
|
1227
|
+
request['vaultAddress'] = vaultAddress
|
|
1228
|
+
response = self.privatePostExchange(self.extend(request, params))
|
|
1229
|
+
#
|
|
1230
|
+
# {
|
|
1231
|
+
# "status":"ok",
|
|
1232
|
+
# "response":{
|
|
1233
|
+
# "type":"cancel",
|
|
1234
|
+
# "data":{
|
|
1235
|
+
# "statuses":[
|
|
1236
|
+
# "success"
|
|
1237
|
+
# ]
|
|
1238
|
+
# }
|
|
1239
|
+
# }
|
|
1240
|
+
# }
|
|
1241
|
+
#
|
|
1242
|
+
return response
|
|
1243
|
+
|
|
1244
|
+
def cancel_orders_for_symbols(self, orders: List[CancellationRequest], params={}):
|
|
1245
|
+
"""
|
|
1246
|
+
cancel multiple orders for multiple symbols
|
|
1247
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s
|
|
1248
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#cancel-order-s-by-cloid
|
|
1249
|
+
:param CancellationRequest[] orders: each order should contain the parameters required by cancelOrder namely id and symbol
|
|
1250
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1251
|
+
:param str [params.vaultAddress]: the vault address
|
|
1252
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1253
|
+
"""
|
|
1254
|
+
self.check_required_credentials()
|
|
1255
|
+
self.load_markets()
|
|
1256
|
+
nonce = self.milliseconds()
|
|
1257
|
+
request: dict = {
|
|
1258
|
+
'nonce': nonce,
|
|
1259
|
+
# 'vaultAddress': vaultAddress,
|
|
1260
|
+
}
|
|
1261
|
+
cancelReq = []
|
|
1262
|
+
cancelAction: dict = {
|
|
1263
|
+
'type': '',
|
|
1264
|
+
'cancels': [],
|
|
1265
|
+
}
|
|
1266
|
+
cancelByCloid = False
|
|
1267
|
+
for i in range(0, len(orders)):
|
|
1268
|
+
order = orders[i]
|
|
1269
|
+
clientOrderId = self.safe_string(order, 'clientOrderId')
|
|
1270
|
+
if clientOrderId is not None:
|
|
1271
|
+
cancelByCloid = True
|
|
1272
|
+
id = self.safe_string(order, 'id')
|
|
1273
|
+
symbol = self.safe_string(order, 'symbol')
|
|
1274
|
+
if symbol is None:
|
|
1275
|
+
raise ArgumentsRequired(self.id + ' cancelOrdersForSymbols() requires a symbol argument in each order')
|
|
1276
|
+
if id is not None and cancelByCloid:
|
|
1277
|
+
raise BadRequest(self.id + ' cancelOrdersForSymbols() all orders must have either id or clientOrderId')
|
|
1278
|
+
assetKey = 'asset' if cancelByCloid else 'a'
|
|
1279
|
+
idKey = 'cloid' if cancelByCloid else 'o'
|
|
1280
|
+
market = self.market(symbol)
|
|
1281
|
+
cancelObj: dict = {}
|
|
1282
|
+
cancelObj[assetKey] = self.parse_to_numeric(market['baseId'])
|
|
1283
|
+
cancelObj[idKey] = clientOrderId if cancelByCloid else self.parse_to_numeric(id)
|
|
1284
|
+
cancelReq.append(cancelObj)
|
|
1285
|
+
cancelAction['type'] = 'cancelByCloid' if cancelByCloid else 'cancel'
|
|
1286
|
+
cancelAction['cancels'] = cancelReq
|
|
1287
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
|
1288
|
+
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
|
1289
|
+
request['action'] = cancelAction
|
|
1290
|
+
request['signature'] = signature
|
|
1291
|
+
if vaultAddress is not None:
|
|
1292
|
+
params = self.omit(params, 'vaultAddress')
|
|
1293
|
+
request['vaultAddress'] = vaultAddress
|
|
1294
|
+
response = self.privatePostExchange(self.extend(request, params))
|
|
1295
|
+
#
|
|
1296
|
+
# {
|
|
1297
|
+
# "status":"ok",
|
|
1298
|
+
# "response":{
|
|
1299
|
+
# "type":"cancel",
|
|
1300
|
+
# "data":{
|
|
1301
|
+
# "statuses":[
|
|
1302
|
+
# "success"
|
|
1303
|
+
# ]
|
|
1304
|
+
# }
|
|
1305
|
+
# }
|
|
1306
|
+
# }
|
|
1307
|
+
#
|
|
1308
|
+
return response
|
|
1309
|
+
|
|
1310
|
+
def cancel_all_orders_after(self, timeout: Int, params={}):
|
|
1311
|
+
"""
|
|
1312
|
+
dead man's switch, cancel all orders after the given timeout
|
|
1313
|
+
:param number timeout: time in milliseconds, 0 represents cancel the timer
|
|
1314
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1315
|
+
:param str [params.vaultAddress]: the vault address
|
|
1316
|
+
:returns dict: the api result
|
|
1317
|
+
"""
|
|
1318
|
+
self.check_required_credentials()
|
|
1319
|
+
self.load_markets()
|
|
1320
|
+
params = self.omit(params, ['clientOrderId', 'client_id'])
|
|
1321
|
+
nonce = self.milliseconds()
|
|
1322
|
+
request: dict = {
|
|
1323
|
+
'nonce': nonce,
|
|
1324
|
+
# 'vaultAddress': vaultAddress,
|
|
1325
|
+
}
|
|
1326
|
+
cancelAction: dict = {
|
|
1327
|
+
'type': 'scheduleCancel',
|
|
1328
|
+
'time': nonce + timeout,
|
|
1329
|
+
}
|
|
1330
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
|
1331
|
+
signature = self.sign_l1_action(cancelAction, nonce, vaultAddress)
|
|
1332
|
+
request['action'] = cancelAction
|
|
1333
|
+
request['signature'] = signature
|
|
1334
|
+
if vaultAddress is not None:
|
|
1335
|
+
params = self.omit(params, 'vaultAddress')
|
|
1336
|
+
request['vaultAddress'] = vaultAddress
|
|
1337
|
+
response = self.privatePostExchange(self.extend(request, params))
|
|
1338
|
+
#
|
|
1339
|
+
# {
|
|
1340
|
+
# "status":"err",
|
|
1341
|
+
# "response":"Cannot set scheduled cancel time until enough volume traded. Required: $1000000. Traded: $373.47205."
|
|
1342
|
+
# }
|
|
1343
|
+
#
|
|
1344
|
+
return response
|
|
1345
|
+
|
|
1346
|
+
def edit_order(self, id: str, symbol: str, type: str, side: str, amount: Num = None, price: Num = None, params={}):
|
|
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
|
+
"""
|
|
1366
|
+
self.check_required_credentials()
|
|
1367
|
+
if id is None:
|
|
1368
|
+
raise ArgumentsRequired(self.id + ' editOrder() requires an id argument')
|
|
1369
|
+
self.load_markets()
|
|
1370
|
+
market = self.market(symbol)
|
|
1371
|
+
type = type.upper()
|
|
1372
|
+
isMarket = (type == 'MARKET')
|
|
1373
|
+
side = side.upper()
|
|
1374
|
+
isBuy = (side == 'BUY')
|
|
1375
|
+
defaultSlippage = self.safe_string(self.options, 'defaultSlippage')
|
|
1376
|
+
slippage = self.safe_string(params, 'slippage', defaultSlippage)
|
|
1377
|
+
defaultTimeInForce = 'ioc' if (isMarket) else 'gtc'
|
|
1378
|
+
postOnly = self.safe_bool(params, 'postOnly', False)
|
|
1379
|
+
if postOnly:
|
|
1380
|
+
defaultTimeInForce = 'alo'
|
|
1381
|
+
timeInForce = self.safe_string_lower(params, 'timeInForce', defaultTimeInForce)
|
|
1382
|
+
timeInForce = self.capitalize(timeInForce)
|
|
1383
|
+
clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_id')
|
|
1384
|
+
triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
|
|
1385
|
+
stopLossPrice = self.safe_string(params, 'stopLossPrice', triggerPrice)
|
|
1386
|
+
takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
|
|
1387
|
+
isTrigger = (stopLossPrice or takeProfitPrice)
|
|
1388
|
+
params = self.omit(params, ['slippage', 'timeInForce', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'clientOrderId', 'client_id'])
|
|
1389
|
+
px = str(price)
|
|
1390
|
+
if isMarket:
|
|
1391
|
+
px = str(Precise.string_mul(price), Precise.string_add('1', slippage)) if (isBuy) else str(Precise.string_mul(price), Precise.string_sub('1', slippage))
|
|
1392
|
+
else:
|
|
1393
|
+
px = self.price_to_precision(symbol, str(price))
|
|
1394
|
+
sz = self.amount_to_precision(symbol, amount)
|
|
1395
|
+
reduceOnly = self.safe_bool(params, 'reduceOnly', False)
|
|
1396
|
+
orderType: dict = {}
|
|
1397
|
+
if isTrigger:
|
|
1398
|
+
isTp = False
|
|
1399
|
+
if takeProfitPrice is not None:
|
|
1400
|
+
triggerPrice = self.price_to_precision(symbol, takeProfitPrice)
|
|
1401
|
+
isTp = True
|
|
1402
|
+
else:
|
|
1403
|
+
triggerPrice = self.price_to_precision(symbol, stopLossPrice)
|
|
1404
|
+
orderType['trigger'] = {
|
|
1405
|
+
'isMarket': isMarket,
|
|
1406
|
+
'triggerPx': triggerPrice,
|
|
1407
|
+
'tpsl': 'tp' if (isTp) else 'sl',
|
|
1408
|
+
}
|
|
1409
|
+
else:
|
|
1410
|
+
orderType['limit'] = {
|
|
1411
|
+
'tif': timeInForce,
|
|
1412
|
+
}
|
|
1413
|
+
if triggerPrice is None:
|
|
1414
|
+
triggerPrice = '0'
|
|
1415
|
+
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
|
+
modifyAction: dict = {
|
|
1432
|
+
'type': 'batchModify',
|
|
1433
|
+
'modifies': [modifyReq],
|
|
1434
|
+
}
|
|
1435
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
|
1436
|
+
signature = self.sign_l1_action(modifyAction, nonce, vaultAddress)
|
|
1437
|
+
request: dict = {
|
|
1438
|
+
'action': modifyAction,
|
|
1439
|
+
'nonce': nonce,
|
|
1440
|
+
'signature': signature,
|
|
1441
|
+
# 'vaultAddress': vaultAddress,
|
|
1442
|
+
}
|
|
1443
|
+
if vaultAddress is not None:
|
|
1444
|
+
params = self.omit(params, 'vaultAddress')
|
|
1445
|
+
request['vaultAddress'] = vaultAddress
|
|
1446
|
+
response = self.privatePostExchange(self.extend(request, params))
|
|
1447
|
+
#
|
|
1448
|
+
# {
|
|
1449
|
+
# "status": "ok",
|
|
1450
|
+
# "response": {
|
|
1451
|
+
# "type": "order",
|
|
1452
|
+
# "data": {
|
|
1453
|
+
# "statuses": [
|
|
1454
|
+
# {
|
|
1455
|
+
# "resting": {
|
|
1456
|
+
# "oid": 5063830287
|
|
1457
|
+
# }
|
|
1458
|
+
# }
|
|
1459
|
+
# ]
|
|
1460
|
+
# }
|
|
1461
|
+
# }
|
|
1462
|
+
# }
|
|
1463
|
+
# when the order is filled immediately
|
|
1464
|
+
# {
|
|
1465
|
+
# "status":"ok",
|
|
1466
|
+
# "response":{
|
|
1467
|
+
# "type":"order",
|
|
1468
|
+
# "data":{
|
|
1469
|
+
# "statuses":[
|
|
1470
|
+
# {
|
|
1471
|
+
# "filled":{
|
|
1472
|
+
# "totalSz":"0.1",
|
|
1473
|
+
# "avgPx":"100.84",
|
|
1474
|
+
# "oid":6195281425
|
|
1475
|
+
# }
|
|
1476
|
+
# }
|
|
1477
|
+
# ]
|
|
1478
|
+
# }
|
|
1479
|
+
# }
|
|
1480
|
+
# }
|
|
1481
|
+
#
|
|
1482
|
+
responseObject = self.safe_dict(response, 'response', {})
|
|
1483
|
+
dataObject = self.safe_dict(responseObject, 'data', {})
|
|
1484
|
+
statuses = self.safe_list(dataObject, 'statuses', [])
|
|
1485
|
+
first = self.safe_dict(statuses, 0, {})
|
|
1486
|
+
return self.parse_order(first, market)
|
|
1487
|
+
|
|
1488
|
+
def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1489
|
+
"""
|
|
1490
|
+
fetches historical funding rate prices
|
|
1491
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-historical-funding-rates
|
|
1492
|
+
:param str symbol: unified symbol of the market to fetch the funding rate history for
|
|
1493
|
+
:param int [since]: timestamp in ms of the earliest funding rate to fetch
|
|
1494
|
+
:param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
|
|
1495
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1496
|
+
:param int [params.until]: timestamp in ms of the latest funding rate
|
|
1497
|
+
:returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
|
|
1498
|
+
"""
|
|
1499
|
+
self.load_markets()
|
|
1500
|
+
market = self.market(symbol)
|
|
1501
|
+
request: dict = {
|
|
1502
|
+
'type': 'fundingHistory',
|
|
1503
|
+
'coin': market['base'],
|
|
1504
|
+
}
|
|
1505
|
+
if since is not None:
|
|
1506
|
+
request['startTime'] = since
|
|
1507
|
+
else:
|
|
1508
|
+
request['startTime'] = self.milliseconds() - 100 * 60 * 60 * 1000
|
|
1509
|
+
until = self.safe_integer(params, 'until')
|
|
1510
|
+
params = self.omit(params, 'until')
|
|
1511
|
+
if until is not None:
|
|
1512
|
+
request['endTime'] = until
|
|
1513
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
1514
|
+
#
|
|
1515
|
+
# [
|
|
1516
|
+
# {
|
|
1517
|
+
# "coin": "ETH",
|
|
1518
|
+
# "fundingRate": "0.0000125",
|
|
1519
|
+
# "premium": "0.00057962",
|
|
1520
|
+
# "time": 1704290400031
|
|
1521
|
+
# }
|
|
1522
|
+
# ]
|
|
1523
|
+
#
|
|
1524
|
+
result = []
|
|
1525
|
+
for i in range(0, len(response)):
|
|
1526
|
+
entry = response[i]
|
|
1527
|
+
timestamp = self.safe_integer(entry, 'time')
|
|
1528
|
+
result.append({
|
|
1529
|
+
'info': entry,
|
|
1530
|
+
'symbol': self.safe_symbol(None, market),
|
|
1531
|
+
'fundingRate': self.safe_number(entry, 'fundingRate'),
|
|
1532
|
+
'timestamp': timestamp,
|
|
1533
|
+
'datetime': self.iso8601(timestamp),
|
|
1534
|
+
})
|
|
1535
|
+
sorted = self.sort_by(result, 'timestamp')
|
|
1536
|
+
return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
|
|
1537
|
+
|
|
1538
|
+
def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1539
|
+
"""
|
|
1540
|
+
fetch all unfilled currently open orders
|
|
1541
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-open-orders
|
|
1542
|
+
:param str symbol: unified market symbol
|
|
1543
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
|
1544
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
|
1545
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1546
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
1547
|
+
:param str [params.method]: 'openOrders' or 'frontendOpenOrders' default is 'frontendOpenOrders'
|
|
1548
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1549
|
+
"""
|
|
1550
|
+
userAddress = None
|
|
1551
|
+
userAddress, params = self.handle_public_address('fetchOpenOrders', params)
|
|
1552
|
+
method = None
|
|
1553
|
+
method, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'method', 'frontendOpenOrders')
|
|
1554
|
+
self.load_markets()
|
|
1555
|
+
market = self.safe_market(symbol)
|
|
1556
|
+
request: dict = {
|
|
1557
|
+
'type': method,
|
|
1558
|
+
'user': userAddress,
|
|
1559
|
+
}
|
|
1560
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
1561
|
+
#
|
|
1562
|
+
# [
|
|
1563
|
+
# {
|
|
1564
|
+
# "coin": "ETH",
|
|
1565
|
+
# "limitPx": "2000.0",
|
|
1566
|
+
# "oid": 3991946565,
|
|
1567
|
+
# "origSz": "0.1",
|
|
1568
|
+
# "side": "B",
|
|
1569
|
+
# "sz": "0.1",
|
|
1570
|
+
# "timestamp": 1704346468838
|
|
1571
|
+
# }
|
|
1572
|
+
# ]
|
|
1573
|
+
#
|
|
1574
|
+
return self.parse_orders(response, market, since, limit)
|
|
1575
|
+
|
|
1576
|
+
def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1577
|
+
"""
|
|
1578
|
+
fetch all unfilled currently closed orders
|
|
1579
|
+
:param str symbol: unified market symbol
|
|
1580
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
|
1581
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
|
1582
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1583
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
1584
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1585
|
+
"""
|
|
1586
|
+
userAddress = None
|
|
1587
|
+
userAddress, params = self.handle_public_address('fetchClosedOrders', params)
|
|
1588
|
+
self.load_markets()
|
|
1589
|
+
market = self.safe_market(symbol)
|
|
1590
|
+
request: dict = {
|
|
1591
|
+
'type': 'historicalOrders',
|
|
1592
|
+
'user': userAddress,
|
|
1593
|
+
}
|
|
1594
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
1595
|
+
#
|
|
1596
|
+
# [
|
|
1597
|
+
# {
|
|
1598
|
+
# "coin": "ETH",
|
|
1599
|
+
# "limitPx": "2000.0",
|
|
1600
|
+
# "oid": 3991946565,
|
|
1601
|
+
# "origSz": "0.1",
|
|
1602
|
+
# "side": "B",
|
|
1603
|
+
# "sz": "0.1",
|
|
1604
|
+
# "timestamp": 1704346468838
|
|
1605
|
+
# }
|
|
1606
|
+
# ]
|
|
1607
|
+
#
|
|
1608
|
+
return self.parse_orders(response, market, since, limit)
|
|
1609
|
+
|
|
1610
|
+
def fetch_order(self, id: str, symbol: Str = None, params={}):
|
|
1611
|
+
"""
|
|
1612
|
+
fetches information on an order made by the user
|
|
1613
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#query-order-status-by-oid-or-cloid
|
|
1614
|
+
:param str symbol: unified symbol of the market the order was made in
|
|
1615
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1616
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
1617
|
+
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1618
|
+
"""
|
|
1619
|
+
userAddress = None
|
|
1620
|
+
userAddress, params = self.handle_public_address('fetchOrder', params)
|
|
1621
|
+
self.load_markets()
|
|
1622
|
+
market = self.safe_market(symbol)
|
|
1623
|
+
request: dict = {
|
|
1624
|
+
'type': 'orderStatus',
|
|
1625
|
+
'oid': self.parse_to_numeric(id),
|
|
1626
|
+
'user': userAddress,
|
|
1627
|
+
}
|
|
1628
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
1629
|
+
#
|
|
1630
|
+
# {
|
|
1631
|
+
# "order": {
|
|
1632
|
+
# "order": {
|
|
1633
|
+
# "children": [],
|
|
1634
|
+
# "cloid": null,
|
|
1635
|
+
# "coin": "ETH",
|
|
1636
|
+
# "isPositionTpsl": False,
|
|
1637
|
+
# "isTrigger": False,
|
|
1638
|
+
# "limitPx": "2000.0",
|
|
1639
|
+
# "oid": "3991946565",
|
|
1640
|
+
# "orderType": "Limit",
|
|
1641
|
+
# "origSz": "0.1",
|
|
1642
|
+
# "reduceOnly": False,
|
|
1643
|
+
# "side": "B",
|
|
1644
|
+
# "sz": "0.1",
|
|
1645
|
+
# "tif": "Gtc",
|
|
1646
|
+
# "timestamp": "1704346468838",
|
|
1647
|
+
# "triggerCondition": "N/A",
|
|
1648
|
+
# "triggerPx": "0.0"
|
|
1649
|
+
# },
|
|
1650
|
+
# "status": "open",
|
|
1651
|
+
# "statusTimestamp": "1704346468838"
|
|
1652
|
+
# },
|
|
1653
|
+
# "status": "order"
|
|
1654
|
+
# }
|
|
1655
|
+
#
|
|
1656
|
+
data = self.safe_dict(response, 'order')
|
|
1657
|
+
return self.parse_order(data, market)
|
|
1658
|
+
|
|
1659
|
+
def parse_order(self, order: dict, market: Market = None) -> Order:
|
|
1660
|
+
#
|
|
1661
|
+
# fetchOpenOrders
|
|
1662
|
+
#
|
|
1663
|
+
# {
|
|
1664
|
+
# "coin": "ETH",
|
|
1665
|
+
# "limitPx": "2000.0",
|
|
1666
|
+
# "oid": 3991946565,
|
|
1667
|
+
# "origSz": "0.1",
|
|
1668
|
+
# "side": "B",
|
|
1669
|
+
# "sz": "0.1",
|
|
1670
|
+
# "timestamp": 1704346468838
|
|
1671
|
+
# }
|
|
1672
|
+
# fetchClosedorders
|
|
1673
|
+
# {
|
|
1674
|
+
# "cloid": null,
|
|
1675
|
+
# "closedPnl": "0.0",
|
|
1676
|
+
# "coin": "SOL",
|
|
1677
|
+
# "crossed": True,
|
|
1678
|
+
# "dir": "Open Long",
|
|
1679
|
+
# "fee": "0.003879",
|
|
1680
|
+
# "hash": "0x4a2647998682b7f07bc5040ab531e1011400f9a51bfa0346a0b41ebe510e8875",
|
|
1681
|
+
# "liquidationMarkPx": null,
|
|
1682
|
+
# "oid": "6463280784",
|
|
1683
|
+
# "px": "110.83",
|
|
1684
|
+
# "side": "B",
|
|
1685
|
+
# "startPosition": "1.64",
|
|
1686
|
+
# "sz": "0.1",
|
|
1687
|
+
# "tid": "232174667018988",
|
|
1688
|
+
# "time": "1709142268394"
|
|
1689
|
+
# }
|
|
1690
|
+
#
|
|
1691
|
+
# fetchOrder
|
|
1692
|
+
#
|
|
1693
|
+
# {
|
|
1694
|
+
# "order": {
|
|
1695
|
+
# "children": [],
|
|
1696
|
+
# "cloid": null,
|
|
1697
|
+
# "coin": "ETH",
|
|
1698
|
+
# "isPositionTpsl": False,
|
|
1699
|
+
# "isTrigger": False,
|
|
1700
|
+
# "limitPx": "2000.0",
|
|
1701
|
+
# "oid": "3991946565",
|
|
1702
|
+
# "orderType": "Limit",
|
|
1703
|
+
# "origSz": "0.1",
|
|
1704
|
+
# "reduceOnly": False,
|
|
1705
|
+
# "side": "B",
|
|
1706
|
+
# "sz": "0.1",
|
|
1707
|
+
# "tif": "Gtc",
|
|
1708
|
+
# "timestamp": "1704346468838",
|
|
1709
|
+
# "triggerCondition": "N/A",
|
|
1710
|
+
# "triggerPx": "0.0"
|
|
1711
|
+
# },
|
|
1712
|
+
# "status": "open",
|
|
1713
|
+
# "statusTimestamp": "1704346468838"
|
|
1714
|
+
# }
|
|
1715
|
+
#
|
|
1716
|
+
# createOrder
|
|
1717
|
+
#
|
|
1718
|
+
# {
|
|
1719
|
+
# "resting": {
|
|
1720
|
+
# "oid": 5063830287
|
|
1721
|
+
# }
|
|
1722
|
+
# }
|
|
1723
|
+
#
|
|
1724
|
+
# {
|
|
1725
|
+
# "filled":{
|
|
1726
|
+
# "totalSz":"0.1",
|
|
1727
|
+
# "avgPx":"100.84",
|
|
1728
|
+
# "oid":6195281425
|
|
1729
|
+
# }
|
|
1730
|
+
# }
|
|
1731
|
+
# frontendOrder
|
|
1732
|
+
# {
|
|
1733
|
+
# "children": [],
|
|
1734
|
+
# "cloid": null,
|
|
1735
|
+
# "coin": "BLUR",
|
|
1736
|
+
# "isPositionTpsl": False,
|
|
1737
|
+
# "isTrigger": True,
|
|
1738
|
+
# "limitPx": "0.5",
|
|
1739
|
+
# "oid": 8670487141,
|
|
1740
|
+
# "orderType": "Stop Limit",
|
|
1741
|
+
# "origSz": "20.0",
|
|
1742
|
+
# "reduceOnly": False,
|
|
1743
|
+
# "side": "B",
|
|
1744
|
+
# "sz": "20.0",
|
|
1745
|
+
# "tif": null,
|
|
1746
|
+
# "timestamp": 1715523663687,
|
|
1747
|
+
# "triggerCondition": "Price above 0.6",
|
|
1748
|
+
# "triggerPx": "0.6"
|
|
1749
|
+
# }
|
|
1750
|
+
#
|
|
1751
|
+
entry = self.safe_dict_n(order, ['order', 'resting', 'filled'])
|
|
1752
|
+
if entry is None:
|
|
1753
|
+
entry = order
|
|
1754
|
+
coin = self.safe_string(entry, 'coin')
|
|
1755
|
+
marketId = None
|
|
1756
|
+
if coin is not None:
|
|
1757
|
+
if coin.find('/') > -1:
|
|
1758
|
+
marketId = coin
|
|
1759
|
+
else:
|
|
1760
|
+
marketId = coin + '/USDC:USDC'
|
|
1761
|
+
if self.safe_string(entry, 'id') is None:
|
|
1762
|
+
market = self.safe_market(marketId, None)
|
|
1763
|
+
else:
|
|
1764
|
+
market = self.safe_market(marketId, market)
|
|
1765
|
+
symbol = market['symbol']
|
|
1766
|
+
timestamp = self.safe_integer_2(order, 'timestamp', 'statusTimestamp')
|
|
1767
|
+
status = self.safe_string(order, 'status')
|
|
1768
|
+
side = self.safe_string(entry, 'side')
|
|
1769
|
+
if side is not None:
|
|
1770
|
+
side = 'sell' if (side == 'A') else 'buy'
|
|
1771
|
+
return self.safe_order({
|
|
1772
|
+
'info': order,
|
|
1773
|
+
'id': self.safe_string(entry, 'oid'),
|
|
1774
|
+
'clientOrderId': self.safe_string(entry, 'cloid'),
|
|
1775
|
+
'timestamp': timestamp,
|
|
1776
|
+
'datetime': self.iso8601(timestamp),
|
|
1777
|
+
'lastTradeTimestamp': None,
|
|
1778
|
+
'lastUpdateTimestamp': None,
|
|
1779
|
+
'symbol': symbol,
|
|
1780
|
+
'type': self.parse_order_type(self.safe_string_lower(entry, 'orderType')),
|
|
1781
|
+
'timeInForce': self.safe_string_upper(entry, 'tif'),
|
|
1782
|
+
'postOnly': None,
|
|
1783
|
+
'reduceOnly': self.safe_bool(entry, 'reduceOnly'),
|
|
1784
|
+
'side': side,
|
|
1785
|
+
'price': self.safe_number(entry, 'limitPx'),
|
|
1786
|
+
'triggerPrice': self.safe_number(entry, 'triggerPx') if self.safe_bool(entry, 'isTrigger') else None,
|
|
1787
|
+
'amount': self.safe_number_2(entry, 'sz', 'totalSz'),
|
|
1788
|
+
'cost': None,
|
|
1789
|
+
'average': self.safe_number(entry, 'avgPx'),
|
|
1790
|
+
'filled': None,
|
|
1791
|
+
'remaining': None,
|
|
1792
|
+
'status': self.parse_order_status(status),
|
|
1793
|
+
'fee': None,
|
|
1794
|
+
'trades': None,
|
|
1795
|
+
}, market)
|
|
1796
|
+
|
|
1797
|
+
def parse_order_status(self, status: Str):
|
|
1798
|
+
statuses: dict = {
|
|
1799
|
+
'triggered': 'open',
|
|
1800
|
+
'filled': 'closed',
|
|
1801
|
+
}
|
|
1802
|
+
return self.safe_string(statuses, status, status)
|
|
1803
|
+
|
|
1804
|
+
def parse_order_type(self, status):
|
|
1805
|
+
statuses: dict = {
|
|
1806
|
+
'stop limit': 'limit',
|
|
1807
|
+
'stop market': 'market',
|
|
1808
|
+
}
|
|
1809
|
+
return self.safe_string(statuses, status, status)
|
|
1810
|
+
|
|
1811
|
+
def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1812
|
+
"""
|
|
1813
|
+
fetch all trades made by the user
|
|
1814
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills
|
|
1815
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-fills-by-time
|
|
1816
|
+
:param str symbol: unified market symbol
|
|
1817
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
|
1818
|
+
:param int [limit]: the maximum number of trades structures to retrieve
|
|
1819
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1820
|
+
:param int [params.until]: timestamp in ms of the latest trade
|
|
1821
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
1822
|
+
"""
|
|
1823
|
+
userAddress = None
|
|
1824
|
+
userAddress, params = self.handle_public_address('fetchMyTrades', params)
|
|
1825
|
+
self.load_markets()
|
|
1826
|
+
market = self.safe_market(symbol)
|
|
1827
|
+
request: dict = {
|
|
1828
|
+
'user': userAddress,
|
|
1829
|
+
}
|
|
1830
|
+
if since is not None:
|
|
1831
|
+
request['type'] = 'userFillsByTime'
|
|
1832
|
+
request['startTime'] = since
|
|
1833
|
+
else:
|
|
1834
|
+
request['type'] = 'userFills'
|
|
1835
|
+
until = self.safe_integer(params, 'until')
|
|
1836
|
+
params = self.omit(params, 'until')
|
|
1837
|
+
if until is not None:
|
|
1838
|
+
request['endTime'] = until
|
|
1839
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
1840
|
+
#
|
|
1841
|
+
# [
|
|
1842
|
+
# {
|
|
1843
|
+
# "closedPnl": "0.19343",
|
|
1844
|
+
# "coin": "ETH",
|
|
1845
|
+
# "crossed": True,
|
|
1846
|
+
# "dir": "Close Long",
|
|
1847
|
+
# "fee": "0.050062",
|
|
1848
|
+
# "hash": "0x09d77c96791e98b5775a04092584ab010d009445119c71e4005c0d634ea322bc",
|
|
1849
|
+
# "liquidationMarkPx": null,
|
|
1850
|
+
# "oid": 3929354691,
|
|
1851
|
+
# "px": "2381.1",
|
|
1852
|
+
# "side": "A",
|
|
1853
|
+
# "startPosition": "0.0841",
|
|
1854
|
+
# "sz": "0.0841",
|
|
1855
|
+
# "tid": 128423918764978,
|
|
1856
|
+
# "time": 1704262888911
|
|
1857
|
+
# }
|
|
1858
|
+
# ]
|
|
1859
|
+
#
|
|
1860
|
+
return self.parse_trades(response, market, since, limit)
|
|
1861
|
+
|
|
1862
|
+
def parse_trade(self, trade: dict, market: Market = None) -> Trade:
|
|
1863
|
+
#
|
|
1864
|
+
# {
|
|
1865
|
+
# "closedPnl": "0.19343",
|
|
1866
|
+
# "coin": "ETH",
|
|
1867
|
+
# "crossed": True,
|
|
1868
|
+
# "dir": "Close Long",
|
|
1869
|
+
# "fee": "0.050062",
|
|
1870
|
+
# "hash": "0x09d77c96791e98b5775a04092584ab010d009445119c71e4005c0d634ea322bc",
|
|
1871
|
+
# "liquidationMarkPx": null,
|
|
1872
|
+
# "oid": 3929354691,
|
|
1873
|
+
# "px": "2381.1",
|
|
1874
|
+
# "side": "A",
|
|
1875
|
+
# "startPosition": "0.0841",
|
|
1876
|
+
# "sz": "0.0841",
|
|
1877
|
+
# "tid": 128423918764978,
|
|
1878
|
+
# "time": 1704262888911
|
|
1879
|
+
# }
|
|
1880
|
+
#
|
|
1881
|
+
timestamp = self.safe_integer(trade, 'time')
|
|
1882
|
+
price = self.safe_string(trade, 'px')
|
|
1883
|
+
amount = self.safe_string(trade, 'sz')
|
|
1884
|
+
coin = self.safe_string(trade, 'coin')
|
|
1885
|
+
marketId = coin + '/USDC:USDC'
|
|
1886
|
+
market = self.safe_market(marketId, None)
|
|
1887
|
+
symbol = market['symbol']
|
|
1888
|
+
id = self.safe_string(trade, 'tid')
|
|
1889
|
+
side = self.safe_string(trade, 'side')
|
|
1890
|
+
if side is not None:
|
|
1891
|
+
side = 'sell' if (side == 'A') else 'buy'
|
|
1892
|
+
fee = self.safe_string(trade, 'fee')
|
|
1893
|
+
return self.safe_trade({
|
|
1894
|
+
'info': trade,
|
|
1895
|
+
'timestamp': timestamp,
|
|
1896
|
+
'datetime': self.iso8601(timestamp),
|
|
1897
|
+
'symbol': symbol,
|
|
1898
|
+
'id': id,
|
|
1899
|
+
'order': self.safe_string(trade, 'oid'),
|
|
1900
|
+
'type': None,
|
|
1901
|
+
'side': side,
|
|
1902
|
+
'takerOrMaker': None,
|
|
1903
|
+
'price': price,
|
|
1904
|
+
'amount': amount,
|
|
1905
|
+
'cost': None,
|
|
1906
|
+
'fee': {'cost': fee, 'currency': 'USDC'},
|
|
1907
|
+
}, market)
|
|
1908
|
+
|
|
1909
|
+
def fetch_position(self, symbol: str, params={}):
|
|
1910
|
+
"""
|
|
1911
|
+
fetch data on an open position
|
|
1912
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-state
|
|
1913
|
+
:param str symbol: unified market symbol of the market the position is held in
|
|
1914
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1915
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
1916
|
+
:returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
|
1917
|
+
"""
|
|
1918
|
+
positions = self.fetch_positions([symbol], params)
|
|
1919
|
+
return self.safe_dict(positions, 0, {})
|
|
1920
|
+
|
|
1921
|
+
def fetch_positions(self, symbols: Strings = None, params={}):
|
|
1922
|
+
"""
|
|
1923
|
+
fetch all open positions
|
|
1924
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/info-endpoint#retrieve-a-users-state
|
|
1925
|
+
:param str[] [symbols]: list of unified market symbols
|
|
1926
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1927
|
+
:param str [params.user]: user address, will default to self.walletAddress if not provided
|
|
1928
|
+
:returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
|
1929
|
+
"""
|
|
1930
|
+
self.load_markets()
|
|
1931
|
+
userAddress = None
|
|
1932
|
+
userAddress, params = self.handle_public_address('fetchPositions', params)
|
|
1933
|
+
symbols = self.market_symbols(symbols)
|
|
1934
|
+
request: dict = {
|
|
1935
|
+
'type': 'clearinghouseState',
|
|
1936
|
+
'user': userAddress,
|
|
1937
|
+
}
|
|
1938
|
+
response = self.publicPostInfo(self.extend(request, params))
|
|
1939
|
+
#
|
|
1940
|
+
# {
|
|
1941
|
+
# "assetPositions": [
|
|
1942
|
+
# {
|
|
1943
|
+
# "position": {
|
|
1944
|
+
# "coin": "ETH",
|
|
1945
|
+
# "cumFunding": {
|
|
1946
|
+
# "allTime": "0.0",
|
|
1947
|
+
# "sinceChange": "0.0",
|
|
1948
|
+
# "sinceOpen": "0.0"
|
|
1949
|
+
# },
|
|
1950
|
+
# "entryPx": "2213.9",
|
|
1951
|
+
# "leverage": {
|
|
1952
|
+
# "rawUsd": "-475.23904",
|
|
1953
|
+
# "type": "isolated",
|
|
1954
|
+
# "value": "20"
|
|
1955
|
+
# },
|
|
1956
|
+
# "liquidationPx": "2125.00856238",
|
|
1957
|
+
# "marginUsed": "24.88097",
|
|
1958
|
+
# "maxLeverage": "50",
|
|
1959
|
+
# "positionValue": "500.12001",
|
|
1960
|
+
# "returnOnEquity": "0.0",
|
|
1961
|
+
# "szi": "0.2259",
|
|
1962
|
+
# "unrealizedPnl": "0.0"
|
|
1963
|
+
# },
|
|
1964
|
+
# "type": "oneWay"
|
|
1965
|
+
# }
|
|
1966
|
+
# ],
|
|
1967
|
+
# "crossMaintenanceMarginUsed": "0.0",
|
|
1968
|
+
# "crossMarginSummary": {
|
|
1969
|
+
# "accountValue": "100.0",
|
|
1970
|
+
# "totalMarginUsed": "0.0",
|
|
1971
|
+
# "totalNtlPos": "0.0",
|
|
1972
|
+
# "totalRawUsd": "100.0"
|
|
1973
|
+
# },
|
|
1974
|
+
# "marginSummary": {
|
|
1975
|
+
# "accountValue": "100.0",
|
|
1976
|
+
# "totalMarginUsed": "0.0",
|
|
1977
|
+
# "totalNtlPos": "0.0",
|
|
1978
|
+
# "totalRawUsd": "100.0"
|
|
1979
|
+
# },
|
|
1980
|
+
# "time": "1704261007014",
|
|
1981
|
+
# "withdrawable": "100.0"
|
|
1982
|
+
# }
|
|
1983
|
+
#
|
|
1984
|
+
data = self.safe_list(response, 'assetPositions', [])
|
|
1985
|
+
result = []
|
|
1986
|
+
for i in range(0, len(data)):
|
|
1987
|
+
result.append(self.parse_position(data[i], None))
|
|
1988
|
+
return self.filter_by_array_positions(result, 'symbol', symbols, False)
|
|
1989
|
+
|
|
1990
|
+
def parse_position(self, position: dict, market: Market = None):
|
|
1991
|
+
#
|
|
1992
|
+
# {
|
|
1993
|
+
# "position": {
|
|
1994
|
+
# "coin": "ETH",
|
|
1995
|
+
# "cumFunding": {
|
|
1996
|
+
# "allTime": "0.0",
|
|
1997
|
+
# "sinceChange": "0.0",
|
|
1998
|
+
# "sinceOpen": "0.0"
|
|
1999
|
+
# },
|
|
2000
|
+
# "entryPx": "2213.9",
|
|
2001
|
+
# "leverage": {
|
|
2002
|
+
# "rawUsd": "-475.23904",
|
|
2003
|
+
# "type": "isolated",
|
|
2004
|
+
# "value": "20"
|
|
2005
|
+
# },
|
|
2006
|
+
# "liquidationPx": "2125.00856238",
|
|
2007
|
+
# "marginUsed": "24.88097",
|
|
2008
|
+
# "maxLeverage": "50",
|
|
2009
|
+
# "positionValue": "500.12001",
|
|
2010
|
+
# "returnOnEquity": "0.0",
|
|
2011
|
+
# "szi": "0.2259",
|
|
2012
|
+
# "unrealizedPnl": "0.0"
|
|
2013
|
+
# },
|
|
2014
|
+
# "type": "oneWay"
|
|
2015
|
+
# }
|
|
2016
|
+
#
|
|
2017
|
+
entry = self.safe_dict(position, 'position', {})
|
|
2018
|
+
coin = self.safe_string(entry, 'coin')
|
|
2019
|
+
marketId = coin + '/USDC:USDC'
|
|
2020
|
+
market = self.safe_market(marketId, None)
|
|
2021
|
+
symbol = market['symbol']
|
|
2022
|
+
leverage = self.safe_dict(entry, 'leverage', {})
|
|
2023
|
+
isIsolated = (self.safe_string(leverage, 'type') == 'isolated')
|
|
2024
|
+
quantity = self.safe_number(leverage, 'rawUsd')
|
|
2025
|
+
side = None
|
|
2026
|
+
if quantity is not None:
|
|
2027
|
+
side = 'short' if (quantity > 0) else 'long'
|
|
2028
|
+
unrealizedPnl = self.safe_number(entry, 'unrealizedPnl')
|
|
2029
|
+
initialMargin = self.safe_number(entry, 'marginUsed')
|
|
2030
|
+
percentage = unrealizedPnl / initialMargin * 100
|
|
2031
|
+
return self.safe_position({
|
|
2032
|
+
'info': position,
|
|
2033
|
+
'id': None,
|
|
2034
|
+
'symbol': symbol,
|
|
2035
|
+
'timestamp': None,
|
|
2036
|
+
'datetime': None,
|
|
2037
|
+
'isolated': isIsolated,
|
|
2038
|
+
'hedged': None,
|
|
2039
|
+
'side': side,
|
|
2040
|
+
'contracts': self.safe_number(entry, 'szi'),
|
|
2041
|
+
'contractSize': None,
|
|
2042
|
+
'entryPrice': self.safe_number(entry, 'entryPx'),
|
|
2043
|
+
'markPrice': None,
|
|
2044
|
+
'notional': self.safe_number(entry, 'positionValue'),
|
|
2045
|
+
'leverage': self.safe_number(leverage, 'value'),
|
|
2046
|
+
'collateral': None,
|
|
2047
|
+
'initialMargin': initialMargin,
|
|
2048
|
+
'maintenanceMargin': None,
|
|
2049
|
+
'initialMarginPercentage': None,
|
|
2050
|
+
'maintenanceMarginPercentage': None,
|
|
2051
|
+
'unrealizedPnl': unrealizedPnl,
|
|
2052
|
+
'liquidationPrice': self.safe_number(entry, 'liquidationPx'),
|
|
2053
|
+
'marginMode': None,
|
|
2054
|
+
'percentage': percentage,
|
|
2055
|
+
})
|
|
2056
|
+
|
|
2057
|
+
def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
|
|
2058
|
+
"""
|
|
2059
|
+
set margin mode(symbol)
|
|
2060
|
+
:param str marginMode: margin mode must be either [isolated, cross]
|
|
2061
|
+
:param str symbol: unified market symbol of the market the position is held in, default is None
|
|
2062
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2063
|
+
:param str [params.leverage]: the rate of leverage, is required if setting trade mode(symbol)
|
|
2064
|
+
:returns dict: response from the exchange
|
|
2065
|
+
"""
|
|
2066
|
+
if symbol is None:
|
|
2067
|
+
raise ArgumentsRequired(self.id + ' setMarginMode() requires a symbol argument')
|
|
2068
|
+
self.load_markets()
|
|
2069
|
+
market = self.market(symbol)
|
|
2070
|
+
leverage = self.safe_integer(params, 'leverage')
|
|
2071
|
+
if leverage is None:
|
|
2072
|
+
raise ArgumentsRequired(self.id + ' setMarginMode() requires a leverage parameter')
|
|
2073
|
+
asset = self.parse_to_int(market['baseId'])
|
|
2074
|
+
isCross = (marginMode == 'cross')
|
|
2075
|
+
nonce = self.milliseconds()
|
|
2076
|
+
params = self.omit(params, ['leverage'])
|
|
2077
|
+
updateAction: dict = {
|
|
2078
|
+
'type': 'updateLeverage',
|
|
2079
|
+
'asset': asset,
|
|
2080
|
+
'isCross': isCross,
|
|
2081
|
+
'leverage': leverage,
|
|
2082
|
+
}
|
|
2083
|
+
vaultAddress = self.safe_string(params, 'vaultAddress')
|
|
2084
|
+
if vaultAddress is not None:
|
|
2085
|
+
params = self.omit(params, 'vaultAddress')
|
|
2086
|
+
if vaultAddress.startswith('0x'):
|
|
2087
|
+
vaultAddress = vaultAddress.replace('0x', '')
|
|
2088
|
+
extendedAction = self.extend(updateAction, params)
|
|
2089
|
+
signature = self.sign_l1_action(extendedAction, nonce, vaultAddress)
|
|
2090
|
+
request: dict = {
|
|
2091
|
+
'action': extendedAction,
|
|
2092
|
+
'nonce': nonce,
|
|
2093
|
+
'signature': signature,
|
|
2094
|
+
# 'vaultAddress': vaultAddress,
|
|
2095
|
+
}
|
|
2096
|
+
if vaultAddress is not None:
|
|
2097
|
+
request['vaultAddress'] = vaultAddress
|
|
2098
|
+
response = self.privatePostExchange(request)
|
|
2099
|
+
#
|
|
2100
|
+
# {
|
|
2101
|
+
# 'response': {
|
|
2102
|
+
# 'type': 'default'
|
|
2103
|
+
# },
|
|
2104
|
+
# 'status': 'ok'
|
|
2105
|
+
# }
|
|
2106
|
+
#
|
|
2107
|
+
return response
|
|
2108
|
+
|
|
2109
|
+
def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
|
|
2110
|
+
"""
|
|
2111
|
+
set the level of leverage for a market
|
|
2112
|
+
:param float leverage: the rate of leverage
|
|
2113
|
+
:param str symbol: unified market symbol
|
|
2114
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2115
|
+
:param str [params.marginMode]: margin mode must be either [isolated, cross], default is cross
|
|
2116
|
+
:returns dict: response from the exchange
|
|
2117
|
+
"""
|
|
2118
|
+
if symbol is None:
|
|
2119
|
+
raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
|
|
2120
|
+
self.load_markets()
|
|
2121
|
+
market = self.market(symbol)
|
|
2122
|
+
marginMode = self.safe_string(params, 'marginMode', 'cross')
|
|
2123
|
+
isCross = (marginMode == 'cross')
|
|
2124
|
+
asset = self.parse_to_int(market['baseId'])
|
|
2125
|
+
nonce = self.milliseconds()
|
|
2126
|
+
params = self.omit(params, 'marginMode')
|
|
2127
|
+
updateAction: dict = {
|
|
2128
|
+
'type': 'updateLeverage',
|
|
2129
|
+
'asset': asset,
|
|
2130
|
+
'isCross': isCross,
|
|
2131
|
+
'leverage': leverage,
|
|
2132
|
+
}
|
|
2133
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
|
2134
|
+
signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
|
|
2135
|
+
request: dict = {
|
|
2136
|
+
'action': updateAction,
|
|
2137
|
+
'nonce': nonce,
|
|
2138
|
+
'signature': signature,
|
|
2139
|
+
# 'vaultAddress': vaultAddress,
|
|
2140
|
+
}
|
|
2141
|
+
if vaultAddress is not None:
|
|
2142
|
+
params = self.omit(params, 'vaultAddress')
|
|
2143
|
+
request['vaultAddress'] = vaultAddress
|
|
2144
|
+
response = self.privatePostExchange(self.extend(request, params))
|
|
2145
|
+
#
|
|
2146
|
+
# {
|
|
2147
|
+
# 'response': {
|
|
2148
|
+
# 'type': 'default'
|
|
2149
|
+
# },
|
|
2150
|
+
# 'status': 'ok'
|
|
2151
|
+
# }
|
|
2152
|
+
#
|
|
2153
|
+
return response
|
|
2154
|
+
|
|
2155
|
+
def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
|
|
2156
|
+
"""
|
|
2157
|
+
add margin
|
|
2158
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
|
|
2159
|
+
:param str symbol: unified market symbol
|
|
2160
|
+
:param float amount: amount of margin to add
|
|
2161
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2162
|
+
:returns dict: a `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
|
|
2163
|
+
"""
|
|
2164
|
+
return self.modify_margin_helper(symbol, amount, 'add', params)
|
|
2165
|
+
|
|
2166
|
+
def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
|
|
2167
|
+
"""
|
|
2168
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#update-isolated-margin
|
|
2169
|
+
remove margin from a position
|
|
2170
|
+
:param str symbol: unified market symbol
|
|
2171
|
+
:param float amount: the amount of margin to remove
|
|
2172
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2173
|
+
:returns dict: a `margin structure <https://docs.ccxt.com/#/?id=reduce-margin-structure>`
|
|
2174
|
+
"""
|
|
2175
|
+
return self.modify_margin_helper(symbol, amount, 'reduce', params)
|
|
2176
|
+
|
|
2177
|
+
def modify_margin_helper(self, symbol: str, amount, type, params={}) -> MarginModification:
|
|
2178
|
+
self.load_markets()
|
|
2179
|
+
market = self.market(symbol)
|
|
2180
|
+
asset = self.parse_to_int(market['baseId'])
|
|
2181
|
+
sz = self.parse_to_int(Precise.string_mul(self.amount_to_precision(symbol, amount), '1000000'))
|
|
2182
|
+
if type == 'reduce':
|
|
2183
|
+
sz = -sz
|
|
2184
|
+
nonce = self.milliseconds()
|
|
2185
|
+
updateAction: dict = {
|
|
2186
|
+
'type': 'updateIsolatedMargin',
|
|
2187
|
+
'asset': asset,
|
|
2188
|
+
'isBuy': True,
|
|
2189
|
+
'ntli': sz,
|
|
2190
|
+
}
|
|
2191
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
|
2192
|
+
signature = self.sign_l1_action(updateAction, nonce, vaultAddress)
|
|
2193
|
+
request: dict = {
|
|
2194
|
+
'action': updateAction,
|
|
2195
|
+
'nonce': nonce,
|
|
2196
|
+
'signature': signature,
|
|
2197
|
+
# 'vaultAddress': vaultAddress,
|
|
2198
|
+
}
|
|
2199
|
+
if vaultAddress is not None:
|
|
2200
|
+
params = self.omit(params, 'vaultAddress')
|
|
2201
|
+
request['vaultAddress'] = vaultAddress
|
|
2202
|
+
response = self.privatePostExchange(self.extend(request, params))
|
|
2203
|
+
#
|
|
2204
|
+
# {
|
|
2205
|
+
# 'response': {
|
|
2206
|
+
# 'type': 'default'
|
|
2207
|
+
# },
|
|
2208
|
+
# 'status': 'ok'
|
|
2209
|
+
# }
|
|
2210
|
+
#
|
|
2211
|
+
return self.extend(self.parse_margin_modification(response, market), {
|
|
2212
|
+
'code': self.safe_string(response, 'status'),
|
|
2213
|
+
})
|
|
2214
|
+
|
|
2215
|
+
def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
|
|
2216
|
+
#
|
|
2217
|
+
# {
|
|
2218
|
+
# 'type': 'default'
|
|
2219
|
+
# }
|
|
2220
|
+
#
|
|
2221
|
+
return {
|
|
2222
|
+
'info': data,
|
|
2223
|
+
'symbol': self.safe_symbol(None, market),
|
|
2224
|
+
'type': None,
|
|
2225
|
+
'marginMode': 'isolated',
|
|
2226
|
+
'amount': None,
|
|
2227
|
+
'total': None,
|
|
2228
|
+
'code': self.safe_string(market, 'settle'),
|
|
2229
|
+
'status': None,
|
|
2230
|
+
'timestamp': None,
|
|
2231
|
+
'datetime': None,
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2234
|
+
def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
|
2235
|
+
"""
|
|
2236
|
+
transfer currency internally between wallets on the same account
|
|
2237
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#l1-usdc-transfer
|
|
2238
|
+
:param str code: unified currency code
|
|
2239
|
+
:param float amount: amount to transfer
|
|
2240
|
+
:param str fromAccount: account to transfer from *spot, swap*
|
|
2241
|
+
:param str toAccount: account to transfer to *swap, spot or address*
|
|
2242
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2243
|
+
:param str [params.vaultAddress]: the vault address for order
|
|
2244
|
+
:returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
|
2245
|
+
"""
|
|
2246
|
+
self.check_required_credentials()
|
|
2247
|
+
self.load_markets()
|
|
2248
|
+
isSandboxMode = self.safe_bool(self.options, 'sandboxMode')
|
|
2249
|
+
nonce = self.milliseconds()
|
|
2250
|
+
if self.in_array(fromAccount, ['spot', 'swap', 'perp']):
|
|
2251
|
+
# handle swap <> spot account transfer
|
|
2252
|
+
if not self.in_array(toAccount, ['spot', 'swap', 'perp']):
|
|
2253
|
+
raise NotSupported(self.id + 'transfer() only support spot <> swap transfer')
|
|
2254
|
+
vaultAddress = self.format_vault_address(self.safe_string(params, 'vaultAddress'))
|
|
2255
|
+
params = self.omit(params, 'vaultAddress')
|
|
2256
|
+
toPerp = (toAccount == 'perp') or (toAccount == 'swap')
|
|
2257
|
+
action: dict = {
|
|
2258
|
+
'type': 'spotUser',
|
|
2259
|
+
'classTransfer': {
|
|
2260
|
+
'usdc': amount,
|
|
2261
|
+
'toPerp': toPerp,
|
|
2262
|
+
},
|
|
2263
|
+
}
|
|
2264
|
+
signature = self.sign_l1_action(action, nonce, vaultAddress)
|
|
2265
|
+
innerRequest: dict = {
|
|
2266
|
+
'action': self.extend(action, params),
|
|
2267
|
+
'nonce': nonce,
|
|
2268
|
+
'signature': signature,
|
|
2269
|
+
}
|
|
2270
|
+
if vaultAddress is not None:
|
|
2271
|
+
innerRequest['vaultAddress'] = vaultAddress
|
|
2272
|
+
transferResponse = self.privatePostExchange(innerRequest)
|
|
2273
|
+
return transferResponse
|
|
2274
|
+
# handle sub-account/different account transfer
|
|
2275
|
+
self.check_address(toAccount)
|
|
2276
|
+
if code is not None:
|
|
2277
|
+
code = code.upper()
|
|
2278
|
+
if code != 'USDC':
|
|
2279
|
+
raise NotSupported(self.id + 'transfer() only support USDC')
|
|
2280
|
+
payload: dict = {
|
|
2281
|
+
'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
|
|
2282
|
+
'destination': toAccount,
|
|
2283
|
+
'amount': self.number_to_string(amount),
|
|
2284
|
+
'time': nonce,
|
|
2285
|
+
}
|
|
2286
|
+
sig = self.build_transfer_sig(payload)
|
|
2287
|
+
request: dict = {
|
|
2288
|
+
'action': {
|
|
2289
|
+
'hyperliquidChain': payload['hyperliquidChain'],
|
|
2290
|
+
'signatureChainId': '0x66eee', # check self out
|
|
2291
|
+
'destination': toAccount,
|
|
2292
|
+
'amount': str(amount),
|
|
2293
|
+
'time': nonce,
|
|
2294
|
+
'type': 'usdSend',
|
|
2295
|
+
},
|
|
2296
|
+
'nonce': nonce,
|
|
2297
|
+
'signature': sig,
|
|
2298
|
+
}
|
|
2299
|
+
response = self.privatePostExchange(self.extend(request, params))
|
|
2300
|
+
return response
|
|
2301
|
+
|
|
2302
|
+
def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
|
|
2303
|
+
"""
|
|
2304
|
+
make a withdrawal(only support USDC)
|
|
2305
|
+
:see: https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/exchange-endpoint#initiate-a-withdrawal-request
|
|
2306
|
+
:param str code: unified currency code
|
|
2307
|
+
:param float amount: the amount to withdraw
|
|
2308
|
+
:param str address: the address to withdraw to
|
|
2309
|
+
:param str tag:
|
|
2310
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2311
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2312
|
+
"""
|
|
2313
|
+
self.check_required_credentials()
|
|
2314
|
+
self.load_markets()
|
|
2315
|
+
self.check_address(address)
|
|
2316
|
+
if code is not None:
|
|
2317
|
+
code = code.upper()
|
|
2318
|
+
if code != 'USDC':
|
|
2319
|
+
raise NotSupported(self.id + 'withdraw() only support USDC')
|
|
2320
|
+
isSandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
|
|
2321
|
+
nonce = self.milliseconds()
|
|
2322
|
+
payload: dict = {
|
|
2323
|
+
'hyperliquidChain': 'Testnet' if isSandboxMode else 'Mainnet',
|
|
2324
|
+
'destination': address,
|
|
2325
|
+
'amount': str(amount),
|
|
2326
|
+
'time': nonce,
|
|
2327
|
+
}
|
|
2328
|
+
sig = self.build_withdraw_sig(payload)
|
|
2329
|
+
request: dict = {
|
|
2330
|
+
'action': {
|
|
2331
|
+
'hyperliquidChain': payload['hyperliquidChain'],
|
|
2332
|
+
'signatureChainId': '0x66eee', # check self out
|
|
2333
|
+
'destination': address,
|
|
2334
|
+
'amount': str(amount),
|
|
2335
|
+
'time': nonce,
|
|
2336
|
+
'type': 'withdraw3',
|
|
2337
|
+
},
|
|
2338
|
+
'nonce': nonce,
|
|
2339
|
+
'signature': sig,
|
|
2340
|
+
}
|
|
2341
|
+
response = self.privatePostExchange(self.extend(request, params))
|
|
2342
|
+
return self.parse_transaction(response)
|
|
2343
|
+
|
|
2344
|
+
def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
|
|
2345
|
+
#
|
|
2346
|
+
# {status: 'ok', response: {type: 'default'}}
|
|
2347
|
+
#
|
|
2348
|
+
return {
|
|
2349
|
+
'info': transaction,
|
|
2350
|
+
'id': None,
|
|
2351
|
+
'txid': None,
|
|
2352
|
+
'timestamp': None,
|
|
2353
|
+
'datetime': None,
|
|
2354
|
+
'network': None,
|
|
2355
|
+
'address': None,
|
|
2356
|
+
'addressTo': None,
|
|
2357
|
+
'addressFrom': None,
|
|
2358
|
+
'tag': None,
|
|
2359
|
+
'tagTo': None,
|
|
2360
|
+
'tagFrom': None,
|
|
2361
|
+
'type': None,
|
|
2362
|
+
'amount': None,
|
|
2363
|
+
'currency': None,
|
|
2364
|
+
'status': self.safe_string(transaction, 'status'),
|
|
2365
|
+
'updated': None,
|
|
2366
|
+
'comment': None,
|
|
2367
|
+
'internal': None,
|
|
2368
|
+
'fee': None,
|
|
2369
|
+
}
|
|
2370
|
+
|
|
2371
|
+
def format_vault_address(self, address: Str = None):
|
|
2372
|
+
if address is None:
|
|
2373
|
+
return None
|
|
2374
|
+
if address.startswith('0x'):
|
|
2375
|
+
return address.replace('0x', '')
|
|
2376
|
+
return address
|
|
2377
|
+
|
|
2378
|
+
def handle_public_address(self, methodName: str, params: dict):
|
|
2379
|
+
userAux = None
|
|
2380
|
+
userAux, params = self.handle_option_and_params(params, methodName, 'user')
|
|
2381
|
+
user = userAux
|
|
2382
|
+
user, params = self.handle_option_and_params(params, methodName, 'address', userAux)
|
|
2383
|
+
if (user is not None) and (user != ''):
|
|
2384
|
+
return [user, params]
|
|
2385
|
+
if (self.walletAddress is not None) and (self.walletAddress != ''):
|
|
2386
|
+
return [self.walletAddress, params]
|
|
2387
|
+
raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a user parameter inside \'params\' or the wallet address set')
|
|
2388
|
+
|
|
2389
|
+
def coin_to_market_id(self, coin: Str):
|
|
2390
|
+
if coin.find('/') > -1:
|
|
2391
|
+
return coin # spot
|
|
2392
|
+
return coin + '/USDC:USDC'
|
|
2393
|
+
|
|
2394
|
+
def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
|
|
2395
|
+
if not response:
|
|
2396
|
+
return None # fallback to default error handler
|
|
2397
|
+
# {"status":"err","response":"User or API Wallet 0xb8a6f8b26223de27c31938d56e470a5b832703a5 does not exist."}
|
|
2398
|
+
#
|
|
2399
|
+
# {
|
|
2400
|
+
# status: 'ok',
|
|
2401
|
+
# response: {type: 'order', data: {statuses: [{error: 'Insufficient margin to place order. asset=4'}]}}
|
|
2402
|
+
# }
|
|
2403
|
+
#
|
|
2404
|
+
status = self.safe_string(response, 'status', '')
|
|
2405
|
+
message = None
|
|
2406
|
+
if status == 'err':
|
|
2407
|
+
message = self.safe_string(response, 'response')
|
|
2408
|
+
else:
|
|
2409
|
+
responsePayload = self.safe_dict(response, 'response', {})
|
|
2410
|
+
data = self.safe_dict(responsePayload, 'data', {})
|
|
2411
|
+
statuses = self.safe_list(data, 'statuses', [])
|
|
2412
|
+
firstStatus = self.safe_dict(statuses, 0)
|
|
2413
|
+
message = self.safe_string(firstStatus, 'error')
|
|
2414
|
+
feedback = self.id + ' ' + body
|
|
2415
|
+
nonEmptyMessage = ((message is not None) and (message != ''))
|
|
2416
|
+
if nonEmptyMessage:
|
|
2417
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
|
|
2418
|
+
self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
|
|
2419
|
+
if nonEmptyMessage:
|
|
2420
|
+
raise ExchangeError(feedback) # unknown message
|
|
2421
|
+
return None
|
|
2422
|
+
|
|
2423
|
+
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
|
2424
|
+
url = self.implode_hostname(self.urls['api'][api]) + '/' + path
|
|
2425
|
+
if method == 'POST':
|
|
2426
|
+
headers = {
|
|
2427
|
+
'Content-Type': 'application/json',
|
|
2428
|
+
}
|
|
2429
|
+
body = self.json(params)
|
|
2430
|
+
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|