ccxt 4.2.76__py2.py3-none-any.whl → 4.4.48__py2.py3-none-any.whl

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