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