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