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
@@ -0,0 +1,4164 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.hashkey import ImplicitAPI
8
+ import hashlib
9
+ from ccxt.base.types import Account, Balances, Bool, Currencies, Currency, DepositAddress, Int, LastPrice, LastPrices, LedgerEntry, Leverage, LeverageTier, LeverageTiers, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade, TradingFeeInterface, TradingFees, Transaction, TransferEntry
10
+ from typing import List
11
+ from ccxt.base.errors import ExchangeError
12
+ from ccxt.base.errors import AuthenticationError
13
+ from ccxt.base.errors import PermissionDenied
14
+ from ccxt.base.errors import AccountNotEnabled
15
+ from ccxt.base.errors import AccountSuspended
16
+ from ccxt.base.errors import ArgumentsRequired
17
+ from ccxt.base.errors import BadRequest
18
+ from ccxt.base.errors import BadSymbol
19
+ from ccxt.base.errors import OperationRejected
20
+ from ccxt.base.errors import InsufficientFunds
21
+ from ccxt.base.errors import InvalidAddress
22
+ from ccxt.base.errors import InvalidOrder
23
+ from ccxt.base.errors import OrderNotFound
24
+ from ccxt.base.errors import OrderImmediatelyFillable
25
+ from ccxt.base.errors import OrderNotFillable
26
+ from ccxt.base.errors import DuplicateOrderId
27
+ from ccxt.base.errors import ContractUnavailable
28
+ from ccxt.base.errors import NotSupported
29
+ from ccxt.base.errors import OperationFailed
30
+ from ccxt.base.errors import DDoSProtection
31
+ from ccxt.base.errors import RateLimitExceeded
32
+ from ccxt.base.errors import ExchangeNotAvailable
33
+ from ccxt.base.errors import InvalidNonce
34
+ from ccxt.base.errors import RequestTimeout
35
+ from ccxt.base.decimal_to_precision import TICK_SIZE
36
+ from ccxt.base.precise import Precise
37
+
38
+
39
+ class hashkey(Exchange, ImplicitAPI):
40
+
41
+ def describe(self):
42
+ return self.deep_extend(super(hashkey, self).describe(), {
43
+ 'id': 'hashkey',
44
+ 'name': 'HashKey Global',
45
+ 'countries': ['BM'], # Bermuda
46
+ 'rateLimit': 100,
47
+ 'version': 'v1',
48
+ 'certified': True,
49
+ 'pro': True,
50
+ 'has': {
51
+ 'CORS': None,
52
+ 'spot': True,
53
+ 'margin': False,
54
+ 'swap': False,
55
+ 'future': False,
56
+ 'option': False,
57
+ 'addMargin': False,
58
+ 'cancelAllOrders': True,
59
+ 'cancelAllOrdersAfter': False,
60
+ 'cancelOrder': True,
61
+ 'cancelOrders': True,
62
+ 'cancelWithdraw': False,
63
+ 'closePosition': False,
64
+ 'createConvertTrade': False,
65
+ 'createDepositAddress': False,
66
+ 'createMarketBuyOrderWithCost': True,
67
+ 'createMarketOrder': True,
68
+ 'createMarketOrderWithCost': False,
69
+ 'createMarketSellOrderWithCost': False,
70
+ 'createOrder': True,
71
+ 'createOrderWithTakeProfitAndStopLoss': False,
72
+ 'createReduceOnlyOrder': True,
73
+ 'createStopLimitOrder': True,
74
+ 'createStopLossOrder': False,
75
+ 'createStopMarketOrder': True,
76
+ 'createStopOrder': True,
77
+ 'createTakeProfitOrder': False,
78
+ 'createTrailingAmountOrder': False,
79
+ 'createTrailingPercentOrder': False,
80
+ 'createTriggerOrder': True,
81
+ 'fetchAccounts': True,
82
+ 'fetchBalance': True,
83
+ 'fetchCanceledAndClosedOrders': True,
84
+ 'fetchCanceledOrders': True,
85
+ 'fetchClosedOrder': True,
86
+ 'fetchClosedOrders': False,
87
+ 'fetchConvertCurrencies': False,
88
+ 'fetchConvertQuote': False,
89
+ 'fetchConvertTrade': False,
90
+ 'fetchConvertTradeHistory': False,
91
+ 'fetchCurrencies': True,
92
+ 'fetchDepositAddress': True,
93
+ 'fetchDepositAddresses': False,
94
+ 'fetchDepositAddressesByNetwork': False,
95
+ 'fetchDeposits': True,
96
+ 'fetchDepositsWithdrawals': False,
97
+ 'fetchFundingHistory': False,
98
+ 'fetchFundingRate': True,
99
+ 'fetchFundingRateHistory': True,
100
+ 'fetchFundingRates': True,
101
+ 'fetchIndexOHLCV': False,
102
+ 'fetchLedger': True,
103
+ 'fetchLeverage': True,
104
+ 'fetchLeverageTiers': True,
105
+ 'fetchMarginAdjustmentHistory': False,
106
+ 'fetchMarginMode': False,
107
+ 'fetchMarketLeverageTiers': 'emulated',
108
+ 'fetchMarkets': True,
109
+ 'fetchMarkOHLCV': False,
110
+ 'fetchMyTrades': True,
111
+ 'fetchOHLCV': True,
112
+ 'fetchOpenInterestHistory': False,
113
+ 'fetchOpenOrder': False,
114
+ 'fetchOpenOrders': True,
115
+ 'fetchOrder': True,
116
+ 'fetchOrderBook': True,
117
+ 'fetchOrders': False,
118
+ 'fetchOrderTrades': False,
119
+ 'fetchPosition': False,
120
+ 'fetchPositionHistory': False,
121
+ 'fetchPositionMode': False,
122
+ 'fetchPositions': True,
123
+ 'fetchPositionsForSymbol': True,
124
+ 'fetchPositionsHistory': False,
125
+ 'fetchPremiumIndexOHLCV': False,
126
+ 'fetchStatus': True,
127
+ 'fetchTicker': True,
128
+ 'fetchTickers': True,
129
+ 'fetchTime': True,
130
+ 'fetchTrades': True,
131
+ 'fetchTradingFee': True, # emulated for spot markets
132
+ 'fetchTradingFees': True, # for spot markets only
133
+ 'fetchTransactions': False,
134
+ 'fetchTransfers': False,
135
+ 'fetchWithdrawals': True,
136
+ 'reduceMargin': False,
137
+ 'sandbox': False,
138
+ 'setLeverage': True,
139
+ 'setMargin': False,
140
+ 'setPositionMode': False,
141
+ 'transfer': True,
142
+ 'withdraw': True,
143
+ },
144
+ 'timeframes': {
145
+ '1m': '1m',
146
+ '3m': '3m',
147
+ '5m': '5m',
148
+ '15m': '15m',
149
+ '30m': '30m',
150
+ '1h': '1h',
151
+ '2h': '2h',
152
+ '4h': '4h',
153
+ '6h': '6h',
154
+ '8h': '8h',
155
+ '12h': '12h',
156
+ '1d': '1d',
157
+ '1w': '1w',
158
+ '1M': '1M',
159
+ },
160
+ 'urls': {
161
+ 'logo': 'https://github.com/user-attachments/assets/6dd6127b-cc19-4a13-9b29-a98d81f80e98',
162
+ 'api': {
163
+ 'public': 'https://api-glb.hashkey.com',
164
+ 'private': 'https://api-glb.hashkey.com',
165
+ },
166
+ 'test': {
167
+ 'public': 'https://api-glb.sim.hashkeydev.com',
168
+ 'private': 'https://api-glb.sim.hashkeydev.com',
169
+ },
170
+ 'www': 'https://global.hashkey.com/',
171
+ 'doc': 'https://hashkeyglobal-apidoc.readme.io/',
172
+ 'fees': 'https://support.global.hashkey.com/hc/en-us/articles/13199900083612-HashKey-Global-Fee-Structure',
173
+ 'referral': 'https://global.hashkey.com/en-US/register/invite?invite_code=82FQUN',
174
+ },
175
+ 'api': {
176
+ 'public': {
177
+ 'get': {
178
+ 'api/v1/exchangeInfo': 5,
179
+ 'quote/v1/depth': 1,
180
+ 'quote/v1/trades': 1,
181
+ 'quote/v1/klines': 1,
182
+ 'quote/v1/ticker/24hr': 1,
183
+ 'quote/v1/ticker/price': 1,
184
+ 'quote/v1/ticker/bookTicker': 1, # not unified
185
+ 'quote/v1/depth/merged': 1,
186
+ 'quote/v1/markPrice': 1,
187
+ 'quote/v1/index': 1,
188
+ 'api/v1/futures/fundingRate': 1,
189
+ 'api/v1/futures/historyFundingRate': 1,
190
+ 'api/v1/ping': 1,
191
+ 'api/v1/time': 1,
192
+ },
193
+ },
194
+ 'private': {
195
+ 'get': {
196
+ 'api/v1/spot/order': 1,
197
+ 'api/v1/spot/openOrders': 1,
198
+ 'api/v1/spot/tradeOrders': 5,
199
+ 'api/v1/futures/leverage': 1,
200
+ 'api/v1/futures/order': 1,
201
+ 'api/v1/futures/openOrders': 1,
202
+ 'api/v1/futures/userTrades': 1,
203
+ 'api/v1/futures/positions': 1,
204
+ 'api/v1/futures/historyOrders': 1,
205
+ 'api/v1/futures/balance': 1,
206
+ 'api/v1/futures/liquidationAssignStatus': 1,
207
+ 'api/v1/futures/riskLimit': 1,
208
+ 'api/v1/futures/commissionRate': 1,
209
+ 'api/v1/futures/getBestOrder': 1,
210
+ 'api/v1/account/vipInfo': 1,
211
+ 'api/v1/account': 1,
212
+ 'api/v1/account/trades': 5,
213
+ 'api/v1/account/type': 5,
214
+ 'api/v1/account/checkApiKey': 1,
215
+ 'api/v1/account/balanceFlow': 5,
216
+ 'api/v1/spot/subAccount/openOrders': 1,
217
+ 'api/v1/spot/subAccount/tradeOrders': 1,
218
+ 'api/v1/subAccount/trades': 1,
219
+ 'api/v1/futures/subAccount/openOrders': 1,
220
+ 'api/v1/futures/subAccount/historyOrders': 1,
221
+ 'api/v1/futures/subAccount/userTrades': 1,
222
+ 'api/v1/account/deposit/address': 1,
223
+ 'api/v1/account/depositOrders': 1,
224
+ 'api/v1/account/withdrawOrders': 1,
225
+ },
226
+ 'post': {
227
+ 'api/v1/userDataStream': 1,
228
+ 'api/v1/spot/orderTest': 1,
229
+ 'api/v1/spot/order': 1,
230
+ 'api/v1.1/spot/order': 1,
231
+ 'api/v1/spot/batchOrders': 5,
232
+ 'api/v1/futures/leverage': 1,
233
+ 'api/v1/futures/order': 1,
234
+ 'api/v1/futures/position/trading-stop': 3,
235
+ 'api/v1/futures/batchOrders': 5,
236
+ 'api/v1/account/assetTransfer': 1,
237
+ 'api/v1/account/authAddress': 1,
238
+ 'api/v1/account/withdraw': 1,
239
+ },
240
+ 'put': {
241
+ 'api/v1/userDataStream': 1,
242
+ },
243
+ 'delete': {
244
+ 'api/v1/spot/order': 1,
245
+ 'api/v1/spot/openOrders': 5,
246
+ 'api/v1/spot/cancelOrderByIds': 5,
247
+ 'api/v1/futures/order': 1,
248
+ 'api/v1/futures/batchOrders': 1,
249
+ 'api/v1/futures/cancelOrderByIds': 1,
250
+ 'api/v1/userDataStream': 1,
251
+ },
252
+ },
253
+ },
254
+ 'fees': {
255
+ 'trading': {
256
+ 'spot': {
257
+ 'tierBased': True,
258
+ 'percentage': True,
259
+ 'feeSide': 'get',
260
+ 'maker': self.parse_number('0.0012'),
261
+ 'taker': self.parse_number('0.0012'),
262
+ 'tiers': {
263
+ 'maker': [
264
+ [self.parse_number('0'), self.parse_number('0.0012')],
265
+ [self.parse_number('1000000'), self.parse_number('0.00080')],
266
+ [self.parse_number('5000000'), self.parse_number('0.00070')],
267
+ [self.parse_number('10000000'), self.parse_number('0.00060')],
268
+ [self.parse_number('50000000'), self.parse_number('0.00040')],
269
+ [self.parse_number('200000000'), self.parse_number('0.00030')],
270
+ [self.parse_number('400000000'), self.parse_number('0.00010')],
271
+ [self.parse_number('800000000'), self.parse_number('0.00')],
272
+ ],
273
+ 'taker': [
274
+ [self.parse_number('0'), self.parse_number('0.0012')],
275
+ [self.parse_number('1000000'), self.parse_number('0.00090')],
276
+ [self.parse_number('5000000'), self.parse_number('0.00085')],
277
+ [self.parse_number('10000000'), self.parse_number('0.00075')],
278
+ [self.parse_number('50000000'), self.parse_number('0.00065')],
279
+ [self.parse_number('200000000'), self.parse_number('0.00045')],
280
+ [self.parse_number('400000000'), self.parse_number('0.00040')],
281
+ [self.parse_number('800000000'), self.parse_number('0.00035')],
282
+ ],
283
+ },
284
+ },
285
+ 'swap': {
286
+ 'tierBased': True,
287
+ 'percentage': True,
288
+ 'feeSide': 'get',
289
+ 'maker': self.parse_number('0.00025'),
290
+ 'taker': self.parse_number('0.00060'),
291
+ 'tiers': {
292
+ 'maker': [
293
+ [self.parse_number('0'), self.parse_number('0.00025')],
294
+ [self.parse_number('1000000'), self.parse_number('0.00016')],
295
+ [self.parse_number('5000000'), self.parse_number('0.00014')],
296
+ [self.parse_number('10000000'), self.parse_number('0.00012')],
297
+ [self.parse_number('50000000'), self.parse_number('0.000080')],
298
+ [self.parse_number('200000000'), self.parse_number('0.000060')],
299
+ [self.parse_number('400000000'), self.parse_number('0.000020')],
300
+ [self.parse_number('800000000'), self.parse_number('0.00')],
301
+ ],
302
+ 'taker': [
303
+ [self.parse_number('0'), self.parse_number('0.00060')],
304
+ [self.parse_number('1000000'), self.parse_number('0.00050')],
305
+ [self.parse_number('5000000'), self.parse_number('0.00045')],
306
+ [self.parse_number('10000000'), self.parse_number('0.00040')],
307
+ [self.parse_number('50000000'), self.parse_number('0.00035')],
308
+ [self.parse_number('200000000'), self.parse_number('0.00030')],
309
+ [self.parse_number('400000000'), self.parse_number('0.00025')],
310
+ [self.parse_number('800000000'), self.parse_number('0.00020')],
311
+ ],
312
+ },
313
+ },
314
+ },
315
+ },
316
+ 'options': {
317
+ 'broker': '10000700011',
318
+ 'recvWindow': None,
319
+ 'sandboxMode': False,
320
+ 'networks': {
321
+ 'BTC': 'BTC',
322
+ 'ERC20': 'ETH',
323
+ 'AVAX': 'AvalancheC',
324
+ 'SOL': 'Solana',
325
+ 'MATIC': 'Polygon',
326
+ 'ATOM': 'Cosmos',
327
+ 'DOT': 'Polkadot',
328
+ 'LTC': 'LTC',
329
+ 'OPTIMISM': 'Optimism',
330
+ 'ARB': 'Arbitrum',
331
+ 'DOGE': 'Dogecoin',
332
+ 'TRC20': 'Tron',
333
+ 'ZKSYNC': 'zkSync',
334
+ 'TON': 'TON',
335
+ 'KLAYTN': 'Klaytn',
336
+ 'MERLINCHAIN': 'Merlin Chain',
337
+ },
338
+ 'networksById': {
339
+ 'BTC': 'BTC',
340
+ 'Bitcoin': 'BTC',
341
+ 'ETH': 'ERC20',
342
+ 'ERC20': 'ERC20',
343
+ 'AvalancheC': 'AVAX',
344
+ 'AVAX C-Chain': 'AVAX',
345
+ 'Solana': 'SOL',
346
+ 'Cosmos': 'ATOM',
347
+ 'Arbitrum': 'ARB',
348
+ 'Polygon': 'MATIC',
349
+ 'Optimism': 'OPTIMISM',
350
+ 'Polkadot': 'DOT',
351
+ 'LTC': 'LTC',
352
+ 'Litecoin': 'LTC',
353
+ 'Dogecoin': 'DOGE',
354
+ 'Merlin Chain': 'MERLINCHAIN',
355
+ 'zkSync': 'ZKSYNC',
356
+ 'TRC20': 'TRC20',
357
+ 'Tron': 'TRC20',
358
+ 'TON': 'TON',
359
+ 'BSC(BEP20)': 'BSC',
360
+ 'Klaytn': 'KLAYTN',
361
+ },
362
+ 'defaultNetwork': 'ERC20',
363
+ },
364
+ 'features': {
365
+ 'default': {
366
+ 'sandbox': True,
367
+ 'createOrder': {
368
+ 'marginMode': False,
369
+ 'triggerPrice': False,
370
+ 'triggerPriceType': None,
371
+ 'triggerDirection': False,
372
+ 'stopLossPrice': False,
373
+ 'takeProfitPrice': False,
374
+ 'attachedStopLossTakeProfit': None,
375
+ 'timeInForce': {
376
+ 'IOC': True,
377
+ 'FOK': True,
378
+ 'PO': True,
379
+ 'GTD': False,
380
+ },
381
+ 'hedged': False,
382
+ 'trailing': False,
383
+ 'leverage': False,
384
+ 'marketBuyByCost': True,
385
+ 'marketBuyRequiresPrice': True, # todo fix
386
+ 'selfTradePrevention': True, # todo implement
387
+ 'iceberg': False,
388
+ },
389
+ 'createOrders': {
390
+ 'max': 20,
391
+ },
392
+ 'fetchMyTrades': {
393
+ 'marginMode': False,
394
+ 'limit': 1000,
395
+ 'daysBack': 30,
396
+ 'untilDays': 30,
397
+ },
398
+ 'fetchOrder': {
399
+ 'marginMode': False,
400
+ 'trigger': False,
401
+ 'trailing': False,
402
+ },
403
+ 'fetchOpenOrders': {
404
+ 'marginMode': False,
405
+ 'limit': 1000,
406
+ 'trigger': False,
407
+ 'trailing': False,
408
+ },
409
+ 'fetchOrders': None,
410
+ 'fetchClosedOrders': None, # todo
411
+ 'fetchOHLCV': {
412
+ 'limit': 1000,
413
+ },
414
+ },
415
+ 'spot': {
416
+ 'extends': 'default',
417
+ },
418
+ 'forDerivatives': {
419
+ 'extends': 'default',
420
+ 'createOrder': {
421
+ 'triggerPrice': True,
422
+ 'selfTradePrevention': True,
423
+ },
424
+ 'fetchOpenOrders': {
425
+ 'trigger': True,
426
+ 'limit': 500,
427
+ },
428
+ },
429
+ 'swap': {
430
+ 'linear': {
431
+ 'extends': 'forDerivatives',
432
+ },
433
+ 'inverse': None,
434
+ },
435
+ 'future': {
436
+ 'linear': None,
437
+ 'inverse': None,
438
+ },
439
+ },
440
+ 'commonCurrencies': {},
441
+ 'exceptions': {
442
+ 'exact': {
443
+ '0001': BadRequest, # Required field '%s' missing or invalid.
444
+ '0002': AuthenticationError, # Incorrect signature
445
+ '0003': RateLimitExceeded, # Rate limit exceeded
446
+ '0102': AuthenticationError, # Invalid APIKey
447
+ '0103': AuthenticationError, # APIKey expired
448
+ '0104': PermissionDenied, # The accountId defined is not permissible
449
+ '0201': ExchangeError, # Instrument not found
450
+ '0202': PermissionDenied, # Invalid IP
451
+ '0206': BadRequest, # Unsupported order type
452
+ '0207': BadRequest, # Invalid price
453
+ '0209': BadRequest, # Invalid price precision
454
+ '0210': BadRequest, # Price outside of allowed range
455
+ '0211': OrderNotFound, # Order not found
456
+ '0401': InsufficientFunds, # Insufficient asset
457
+ '0402': BadRequest, # Invalid asset
458
+ '-1000': ExchangeError, # An unknown error occurred while processing the request
459
+ '-1001': ExchangeError, # Internal error
460
+ '-100010': BadSymbol, # Invalid Symbols!
461
+ '-100012': BadSymbol, # Parameter symbol [str] missing!
462
+ '-1002': AuthenticationError, # Unauthorized operation
463
+ '-1004': BadRequest, # Bad request
464
+ '-1005': PermissionDenied, # No permission
465
+ '-1006': ExchangeError, # Execution status unknown
466
+ '-1007': RequestTimeout, # Timeout waiting for response from server
467
+ '-1014': InvalidOrder, # Unsupported order combination
468
+ '-1015': InvalidOrder, # Too many new orders
469
+ '-1020': OperationRejected, # Unsupported operation
470
+ '-1021': InvalidNonce, # Timestamp for self request is outside of the recvWindow
471
+ '-1024': BadRequest, # Duplicate request
472
+ '-1101': ExchangeNotAvailable, # Feature has been offline
473
+ '-1115': InvalidOrder, # Invalid timeInForce
474
+ '-1117': InvalidOrder, # Invalid order side
475
+ '-1123': InvalidOrder, # Invalid client order id
476
+ '-1124': InvalidOrder, # Invalid price
477
+ '-1126': InvalidOrder, # Invalid quantity
478
+ '-1129': BadRequest, # Invalid parameters, quantity and amount are not allowed to be sent at the same time.
479
+ '-1130': BadRequest, # Illegal parameter '%s'
480
+ '-1132': BadRequest, # Order price greater than the maximum
481
+ '-1133': BadRequest, # Order price lower than the minimum
482
+ '-1135': BadRequest, # Order quantity greater than the maximum
483
+ '-1136': BadRequest, # Order quantity lower than the minimum
484
+ '-1138': InvalidOrder, # Order has been partially cancelled
485
+ '-1137': InvalidOrder, # Order quantity precision too large
486
+ '-1139': OrderImmediatelyFillable, # Order has been filled
487
+ '-1140': InvalidOrder, # Order amount lower than the minimum
488
+ '-1141': DuplicateOrderId, # Duplicate order
489
+ '-1142': OrderNotFillable, # Order has been cancelled
490
+ '-1143': OrderNotFound, # Order not found on order book
491
+ '-1144': OperationRejected, # Order has been locked
492
+ '-1145': NotSupported, # Cancellation on self order type not supported
493
+ '-1146': RequestTimeout, # Order creation timeout
494
+ '-1147': RequestTimeout, # Order cancellation timeout
495
+ '-1148': InvalidOrder, # Order amount precision too large
496
+ '-1149': OperationRejected, # Order creation failed
497
+ '-1150': OperationFailed, # Order cancellation failed
498
+ '-1151': OperationRejected, # The trading pair is not open yet
499
+ '-1152': AccountNotEnabled, # User does not exist
500
+ '-1153': InvalidOrder, # Invalid price type
501
+ '-1154': InvalidOrder, # Invalid position side
502
+ '-1155': OperationRejected, # The trading pair is not available for api trading
503
+ '-1156': OperationFailed, # Limit maker order creation failed
504
+ '-1157': OperationFailed, # Modify futures margin failed
505
+ '-1158': OperationFailed, # Reduce margin is forbidden
506
+ '-1159': AccountNotEnabled, # Finance account already exists
507
+ '-1160': AccountNotEnabled, # Account does not exist
508
+ '-1161': OperationFailed, # Balance transfer failed
509
+ '-1162': ContractUnavailable, # Unsupport contract address
510
+ '-1163': InvalidAddress, # Illegal withdrawal address
511
+ '-1164': OperationFailed, # Withdraw failed
512
+ '-1165': ArgumentsRequired, # Withdrawal amount cannot be null
513
+ '-1166': OperationRejected, # Withdrawal amount exceeds the daily limit
514
+ '-1167': BadRequest, # Withdrawal amount less than the minimum
515
+ '-1168': BadRequest, # Illegal withdrawal amount
516
+ '-1169': PermissionDenied, # Withdraw not allowed
517
+ '-1170': PermissionDenied, # Deposit not allowed
518
+ '-1171': PermissionDenied, # Withdrawal address not in whitelist
519
+ '-1172': BadRequest, # Invalid from account id
520
+ '-1173': BadRequest, # Invalid to account i
521
+ '-1174': PermissionDenied, # Transfer not allowed between the same account
522
+ '-1175': BadRequest, # Invalid fiat deposit status
523
+ '-1176': BadRequest, # Invalid fiat withdrawal status
524
+ '-1177': InvalidOrder, # Invalid fiat order type
525
+ '-1178': AccountNotEnabled, # Brokerage account does not exist
526
+ '-1179': AccountSuspended, # Address owner is not True
527
+ '-1181': ExchangeError, # System error
528
+ '-1193': OperationRejected, # Order creation count exceeds the limit
529
+ '-1194': OperationRejected, # Market order creation forbidden
530
+ '-1195': BadRequest, # Market order long position cannot exceed %s above the market price
531
+ '-1196': BadRequest, # Market order short position cannot be below %s of the market price
532
+ '-1200': BadRequest, # Order buy quantity too small
533
+ '-1201': BadRequest, # Order buy quantity too large
534
+ '-1202': BadRequest, # Order sell quantity too small
535
+ '-1203': BadRequest, # Order sell quantity too large
536
+ '-1204': BadRequest, # From account must be a main account
537
+ '-1205': AccountNotEnabled, # Account not authorized
538
+ '-1206': BadRequest, # Order amount greater than the maximum
539
+ '-1207': BadRequest, # The status of deposit is invalid
540
+ '-1208': BadRequest, # The orderType of fiat is invalid
541
+ '-1209': BadRequest, # The status of withdraw is invalid
542
+ '-2001': ExchangeNotAvailable, # Platform is yet to open trading
543
+ '-2002': OperationFailed, # The number of open orders exceeds the limit 300
544
+ '-2003': OperationFailed, # Position size cannot meet target leverage
545
+ '-2004': OperationFailed, # Adjust leverage fail
546
+ '-2005': RequestTimeout, # Adjust leverage timeout
547
+ '-2010': OperationRejected, # New order rejected
548
+ '-2011': OperationRejected, # Order cancellation rejected
549
+ '-2016': OperationRejected, # API key creation exceeds the limit
550
+ '-2017': OperationRejected, # Open orders exceeds the limit of the trading pair
551
+ '-2018': OperationRejected, # Trade user creation exceeds the limit
552
+ '-2019': PermissionDenied, # Trader and omnibus user not allowed to login app
553
+ '-2020': PermissionDenied, # Not allowed to trade self trading pair
554
+ '-2021': PermissionDenied, # Not allowed to trade self trading pair
555
+ '-2022': OperationRejected, # Order batch size exceeds the limit
556
+ '-2023': AuthenticationError, # Need to pass KYC verification
557
+ '-2024': AccountNotEnabled, # Fiat account does not exist
558
+ '-2025': AccountNotEnabled, # Custody account not exist
559
+ '-2026': BadRequest, # Invalid type
560
+ '-2027': OperationRejected, # Exceed maximum time range of 30 days
561
+ '-2028': OperationRejected, # The search is limited to data within the last one month
562
+ '-2029': OperationRejected, # The search is limited to data within the last three months
563
+ '-2030': InsufficientFunds, # Insufficient margin
564
+ '-2031': NotSupported, # Leverage reduction is not supported in Isolated Margin Mode with open positions
565
+ '-2032': OperationRejected, # After the transaction, your %s position will account for %s of the total position, which poses concentration risk. Do you want to continue with the transaction?
566
+ '-2033': OperationFailed, # Order creation failed. Please verify if the order parameters comply with the trading rules
567
+ '-2034': InsufficientFunds, # Trade account holding limit is zero
568
+ '-2035': OperationRejected, # The sub account has been frozen and cannot transfer
569
+ '-2036': NotSupported, # We do not support queries for records exceeding 30 days
570
+ '-2037': ExchangeError, # Position and order data error
571
+ '-2038': InsufficientFunds, # Insufficient margin
572
+ '-2039': NotSupported, # Leverage reduction is not supported in Isolated Margin Mode with open positions
573
+ '-2040': ExchangeNotAvailable, # There is a request being processed. Please try again later
574
+ '-2041': BadRequest, # Token does not exist
575
+ '-2042': OperationRejected, # You have passed the trade limit, please pay attention to the risks
576
+ '-2043': OperationRejected, # Maximum allowed leverage reached, please lower your leverage
577
+ '-2044': BadRequest, # This order price is unreasonable to exceed(or be lower than) the liquidation price
578
+ '-2045': BadRequest, # Price too low, please order again!
579
+ '-2046': BadRequest, # Price too high, please order again!
580
+ '-2048': BadRequest, # Exceed the maximum number of conditional orders of %s
581
+ '-2049': BadRequest, # Create stop order buy price too big
582
+ '-2050': BadRequest, # Create stop order sell price too small
583
+ '-2051': OperationRejected, # Create order rejected
584
+ '-2052': OperationRejected, # Create stop profit-loss plan order reject
585
+ '-2053': OperationRejected, # Position not enough
586
+ '-2054': BadRequest, # Invalid long stop profit price
587
+ '-2055': BadRequest, # Invalid long stop loss price
588
+ '-2056': BadRequest, # Invalid short stop profit price
589
+ '-2057': BadRequest, # Invalid short stop loss price
590
+ '-3117': PermissionDenied, # Invalid permission
591
+ '-3143': PermissionDenied, # According to KYC and risk assessment, your trading account has exceeded the limit.
592
+ '-3144': PermissionDenied, # Currently, your trading account has exceeded its limit and is temporarily unable to perform transfers
593
+ '-3145': DDoSProtection, # Please DO NOT submit request too frequently
594
+ '-4001': BadRequest, # Invalid asset
595
+ '-4002': BadRequest, # Withdrawal amount less than Minimum Withdrawal Amount
596
+ '-4003': InsufficientFunds, # Insufficient Balance
597
+ '-4004': BadRequest, # Invalid bank account number
598
+ '-4005': BadRequest, # Assets are not listed
599
+ '-4006': AccountNotEnabled, # KYC is not certified
600
+ '-4007': NotSupported, # Withdrawal channels are not supported
601
+ '-4008': AccountNotEnabled, # This currency does not support self customer type
602
+ '-4009': PermissionDenied, # No withdrawal permission
603
+ '-4010': PermissionDenied, # Withdrawals on the same day exceed the maximum limit for a single day
604
+ '-4011': ExchangeError, # System error
605
+ '-4012': ExchangeError, # Parameter error
606
+ '-4013': OperationFailed, # Withdraw repeatly
607
+ },
608
+ 'broad': {},
609
+ },
610
+ 'precisionMode': TICK_SIZE,
611
+ })
612
+
613
+ async def fetch_time(self, params={}) -> Int:
614
+ """
615
+ fetches the current integer timestamp in milliseconds from the exchange server
616
+
617
+ https://hashkeyglobal-apidoc.readme.io/reference/check-server-time
618
+
619
+ :param dict [params]: extra parameters specific to the exchange API endpoint
620
+ :returns int: the current integer timestamp in milliseconds from the exchange server
621
+ """
622
+ response = await self.publicGetApiV1Time(params)
623
+ #
624
+ # {
625
+ # "serverTime": 1721661553214
626
+ # }
627
+ #
628
+ return self.safe_integer(response, 'serverTime')
629
+
630
+ async def fetch_status(self, params={}):
631
+ """
632
+ the latest known information on the availability of the exchange API
633
+
634
+ https://hashkeyglobal-apidoc.readme.io/reference/test-connectivity
635
+
636
+ :param dict [params]: extra parameters specific to the exchange API endpoint
637
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
638
+ """
639
+ response = await self.publicGetApiV1Ping(params)
640
+ #
641
+ # {}
642
+ #
643
+ return {
644
+ 'status': 'ok',
645
+ 'updated': None,
646
+ 'eta': None,
647
+ 'url': None,
648
+ 'info': response,
649
+ }
650
+
651
+ async def fetch_markets(self, params={}) -> List[Market]:
652
+ """
653
+ retrieves data on all markets for the exchange
654
+
655
+ https://hashkeyglobal-apidoc.readme.io/reference/exchangeinfo
656
+
657
+ :param dict [params]: extra parameters specific to the exchange API endpoint
658
+ :param str [params.symbol]: the id of the market to fetch
659
+ :returns dict[]: an array of objects representing market data
660
+ """
661
+ request: dict = {}
662
+ response = await self.publicGetApiV1ExchangeInfo(self.extend(request, params))
663
+ #
664
+ # {
665
+ # "timezone": "UTC",
666
+ # "serverTime": "1721661653952",
667
+ # "brokerFilters": [],
668
+ # "symbols": [
669
+ # {
670
+ # "symbol": "BTCUSDT",
671
+ # "symbolName": "BTCUSDT",
672
+ # "status": "TRADING",
673
+ # "baseAsset": "BTC",
674
+ # "baseAssetName": "BTC",
675
+ # "baseAssetPrecision": "0.00001",
676
+ # "quoteAsset": "USDT",
677
+ # "quoteAssetName": "USDT",
678
+ # "quotePrecision": "0.0000001",
679
+ # "retailAllowed": True,
680
+ # "piAllowed": True,
681
+ # "corporateAllowed": True,
682
+ # "omnibusAllowed": True,
683
+ # "icebergAllowed": False,
684
+ # "isAggregate": False,
685
+ # "allowMargin": False,
686
+ # "filters": [
687
+ # {
688
+ # "minPrice": "0.01",
689
+ # "maxPrice": "100000.00000000",
690
+ # "tickSize": "0.01",
691
+ # "filterType": "PRICE_FILTER"
692
+ # },
693
+ # {
694
+ # "minQty": "0.00001",
695
+ # "maxQty": "8",
696
+ # "stepSize": "0.00001",
697
+ # "marketOrderMinQty": "0.00001",
698
+ # "marketOrderMaxQty": "4",
699
+ # "filterType": "LOT_SIZE"
700
+ # },
701
+ # {
702
+ # "minNotional": "1",
703
+ # "filterType": "MIN_NOTIONAL"
704
+ # },
705
+ # {
706
+ # "minAmount": "1",
707
+ # "maxAmount": "400000",
708
+ # "minBuyPrice": "0",
709
+ # "marketOrderMinAmount": "1",
710
+ # "marketOrderMaxAmount": "200000",
711
+ # "filterType": "TRADE_AMOUNT"
712
+ # },
713
+ # {
714
+ # "maxSellPrice": "0",
715
+ # "buyPriceUpRate": "0.1",
716
+ # "sellPriceDownRate": "0.1",
717
+ # "filterType": "LIMIT_TRADING"
718
+ # },
719
+ # {
720
+ # "buyPriceUpRate": "0.1",
721
+ # "sellPriceDownRate": "0.1",
722
+ # "filterType": "MARKET_TRADING"
723
+ # },
724
+ # {
725
+ # "noAllowMarketStartTime": "1710485700000",
726
+ # "noAllowMarketEndTime": "1710486000000",
727
+ # "limitOrderStartTime": "0",
728
+ # "limitOrderEndTime": "0",
729
+ # "limitMinPrice": "0",
730
+ # "limitMaxPrice": "0",
731
+ # "filterType": "OPEN_QUOTE"
732
+ # }
733
+ # ]
734
+ # }
735
+ # ],
736
+ # "options": [],
737
+ # "contracts": [
738
+ # {
739
+ # "filters": [
740
+ # {
741
+ # "minPrice": "0.1",
742
+ # "maxPrice": "100000.00000000",
743
+ # "tickSize": "0.1",
744
+ # "filterType": "PRICE_FILTER"
745
+ # },
746
+ # {
747
+ # "minQty": "0.001",
748
+ # "maxQty": "10",
749
+ # "stepSize": "0.001",
750
+ # "marketOrderMinQty": "0",
751
+ # "marketOrderMaxQty": "0",
752
+ # "filterType": "LOT_SIZE"
753
+ # },
754
+ # {
755
+ # "minNotional": "0",
756
+ # "filterType": "MIN_NOTIONAL"
757
+ # },
758
+ # {
759
+ # "maxSellPrice": "999999",
760
+ # "buyPriceUpRate": "0.05",
761
+ # "sellPriceDownRate": "0.05",
762
+ # "maxEntrustNum": 200,
763
+ # "maxConditionNum": 200,
764
+ # "filterType": "LIMIT_TRADING"
765
+ # },
766
+ # {
767
+ # "buyPriceUpRate": "0.05",
768
+ # "sellPriceDownRate": "0.05",
769
+ # "filterType": "MARKET_TRADING"
770
+ # },
771
+ # {
772
+ # "noAllowMarketStartTime": "0",
773
+ # "noAllowMarketEndTime": "0",
774
+ # "limitOrderStartTime": "0",
775
+ # "limitOrderEndTime": "0",
776
+ # "limitMinPrice": "0",
777
+ # "limitMaxPrice": "0",
778
+ # "filterType": "OPEN_QUOTE"
779
+ # }
780
+ # ],
781
+ # "exchangeId": "301",
782
+ # "symbol": "BTCUSDT-PERPETUAL",
783
+ # "symbolName": "BTCUSDT-PERPETUAL",
784
+ # "status": "TRADING",
785
+ # "baseAsset": "BTCUSDT-PERPETUAL",
786
+ # "baseAssetPrecision": "0.001",
787
+ # "quoteAsset": "USDT",
788
+ # "quoteAssetPrecision": "0.1",
789
+ # "icebergAllowed": False,
790
+ # "inverse": False,
791
+ # "index": "USDT",
792
+ # "marginToken": "USDT",
793
+ # "marginPrecision": "0.0001",
794
+ # "contractMultiplier": "0.001",
795
+ # "underlying": "BTC",
796
+ # "riskLimits": [
797
+ # {
798
+ # "riskLimitId": "200000722",
799
+ # "quantity": "1000.00",
800
+ # "initialMargin": "0.10",
801
+ # "maintMargin": "0.005",
802
+ # "isWhite": False
803
+ # },
804
+ # {
805
+ # "riskLimitId": "200000723",
806
+ # "quantity": "2000.00",
807
+ # "initialMargin": "0.10",
808
+ # "maintMargin": "0.01",
809
+ # "isWhite": False
810
+ # }
811
+ # ]
812
+ # }
813
+ # ],
814
+ # "coins": [
815
+ # {
816
+ # "orgId": "9001",
817
+ # "coinId": "BTC",
818
+ # "coinName": "BTC",
819
+ # "coinFullName": "Bitcoin",
820
+ # "allowWithdraw": True,
821
+ # "allowDeposit": True,
822
+ # "tokenType": "CHAIN_TOKEN",
823
+ # "chainTypes": [
824
+ # {
825
+ # "chainType": "Bitcoin",
826
+ # "withdrawFee": "0",
827
+ # "minWithdrawQuantity": "0.002",
828
+ # "maxWithdrawQuantity": "0",
829
+ # "minDepositQuantity": "0.0005",
830
+ # "allowDeposit": True,
831
+ # "allowWithdraw": True
832
+ # }
833
+ # ]
834
+ # }
835
+ # ]
836
+ # }
837
+ #
838
+ spotMarkets = self.safe_list(response, 'symbols', [])
839
+ swapMarkets = self.safe_list(response, 'contracts', [])
840
+ markets = self.array_concat(spotMarkets, swapMarkets)
841
+ if self.is_empty(markets):
842
+ markets = [response] # if user provides params.symbol the exchange returns a single object insted of list of objects
843
+ return self.parse_markets(markets)
844
+
845
+ def parse_market(self, market: dict) -> Market:
846
+ # spot
847
+ # {
848
+ # "symbol": "BTCUSDT",
849
+ # "symbolName": "BTCUSDT",
850
+ # "status": "TRADING",
851
+ # "baseAsset": "BTC",
852
+ # "baseAssetName": "BTC",
853
+ # "baseAssetPrecision": "0.00001",
854
+ # "quoteAsset": "USDT",
855
+ # "quoteAssetName": "USDT",
856
+ # "quotePrecision": "0.0000001",
857
+ # "retailAllowed": True,
858
+ # "piAllowed": True,
859
+ # "corporateAllowed": True,
860
+ # "omnibusAllowed": True,
861
+ # "icebergAllowed": False,
862
+ # "isAggregate": False,
863
+ # "allowMargin": False,
864
+ # "filters": [
865
+ # {
866
+ # "minPrice": "0.01",
867
+ # "maxPrice": "100000.00000000",
868
+ # "tickSize": "0.01",
869
+ # "filterType": "PRICE_FILTER"
870
+ # },
871
+ # {
872
+ # "minQty": "0.00001",
873
+ # "maxQty": "8",
874
+ # "stepSize": "0.00001",
875
+ # "marketOrderMinQty": "0.00001",
876
+ # "marketOrderMaxQty": "4",
877
+ # "filterType": "LOT_SIZE"
878
+ # },
879
+ # {
880
+ # "minNotional": "1",
881
+ # "filterType": "MIN_NOTIONAL"
882
+ # },
883
+ # {
884
+ # "minAmount": "1",
885
+ # "maxAmount": "400000",
886
+ # "minBuyPrice": "0",
887
+ # "marketOrderMinAmount": "1",
888
+ # "marketOrderMaxAmount": "200000",
889
+ # "filterType": "TRADE_AMOUNT"
890
+ # },
891
+ # {
892
+ # "maxSellPrice": "0",
893
+ # "buyPriceUpRate": "0.1",
894
+ # "sellPriceDownRate": "0.1",
895
+ # "filterType": "LIMIT_TRADING"
896
+ # },
897
+ # {
898
+ # "buyPriceUpRate": "0.1",
899
+ # "sellPriceDownRate": "0.1",
900
+ # "filterType": "MARKET_TRADING"
901
+ # },
902
+ # {
903
+ # "noAllowMarketStartTime": "1710485700000",
904
+ # "noAllowMarketEndTime": "1710486000000",
905
+ # "limitOrderStartTime": "0",
906
+ # "limitOrderEndTime": "0",
907
+ # "limitMinPrice": "0",
908
+ # "limitMaxPrice": "0",
909
+ # "filterType": "OPEN_QUOTE"
910
+ # }
911
+ # ]
912
+ # }
913
+ #
914
+ # swap
915
+ # {
916
+ # "filters": [
917
+ # {
918
+ # "minPrice": "0.1",
919
+ # "maxPrice": "100000.00000000",
920
+ # "tickSize": "0.1",
921
+ # "filterType": "PRICE_FILTER"
922
+ # },
923
+ # {
924
+ # "minQty": "0.001",
925
+ # "maxQty": "10",
926
+ # "stepSize": "0.001",
927
+ # "marketOrderMinQty": "0",
928
+ # "marketOrderMaxQty": "0",
929
+ # "filterType": "LOT_SIZE"
930
+ # },
931
+ # {
932
+ # "minNotional": "0",
933
+ # "filterType": "MIN_NOTIONAL"
934
+ # },
935
+ # {
936
+ # "maxSellPrice": "999999",
937
+ # "buyPriceUpRate": "0.05",
938
+ # "sellPriceDownRate": "0.05",
939
+ # "maxEntrustNum": 200,
940
+ # "maxConditionNum": 200,
941
+ # "filterType": "LIMIT_TRADING"
942
+ # },
943
+ # {
944
+ # "buyPriceUpRate": "0.05",
945
+ # "sellPriceDownRate": "0.05",
946
+ # "filterType": "MARKET_TRADING"
947
+ # },
948
+ # {
949
+ # "noAllowMarketStartTime": "0",
950
+ # "noAllowMarketEndTime": "0",
951
+ # "limitOrderStartTime": "0",
952
+ # "limitOrderEndTime": "0",
953
+ # "limitMinPrice": "0",
954
+ # "limitMaxPrice": "0",
955
+ # "filterType": "OPEN_QUOTE"
956
+ # }
957
+ # ],
958
+ # "exchangeId": "301",
959
+ # "symbol": "BTCUSDT-PERPETUAL",
960
+ # "symbolName": "BTCUSDT-PERPETUAL",
961
+ # "status": "TRADING",
962
+ # "baseAsset": "BTCUSDT-PERPETUAL",
963
+ # "baseAssetPrecision": "0.001",
964
+ # "quoteAsset": "USDT",
965
+ # "quoteAssetPrecision": "0.1",
966
+ # "icebergAllowed": False,
967
+ # "inverse": False,
968
+ # "index": "USDT",
969
+ # "marginToken": "USDT",
970
+ # "marginPrecision": "0.0001",
971
+ # "contractMultiplier": "0.001",
972
+ # "underlying": "BTC",
973
+ # "riskLimits": [
974
+ # {
975
+ # "riskLimitId": "200000722",
976
+ # "quantity": "1000.00",
977
+ # "initialMargin": "0.10",
978
+ # "maintMargin": "0.005",
979
+ # "isWhite": False
980
+ # },
981
+ # {
982
+ # "riskLimitId": "200000723",
983
+ # "quantity": "2000.00",
984
+ # "initialMargin": "0.10",
985
+ # "maintMargin": "0.01",
986
+ # "isWhite": False
987
+ # }
988
+ # ]
989
+ # }
990
+ #
991
+ marketId = self.safe_string(market, 'symbol')
992
+ quoteId = self.safe_string(market, 'quoteAsset')
993
+ quote = self.safe_currency_code(quoteId)
994
+ settleId = self.safe_string(market, 'marginToken')
995
+ settle = self.safe_currency_code(settleId)
996
+ baseId = self.safe_string(market, 'baseAsset')
997
+ marketType = 'spot'
998
+ isSpot = True
999
+ isSwap = False
1000
+ suffix = ''
1001
+ parts = marketId.split('-')
1002
+ secondPart = self.safe_string(parts, 1)
1003
+ if secondPart == 'PERPETUAL':
1004
+ marketType = 'swap'
1005
+ isSpot = False
1006
+ isSwap = True
1007
+ baseId = self.safe_string(market, 'underlying')
1008
+ suffix += ':' + settleId
1009
+ base = self.safe_currency_code(baseId)
1010
+ symbol = base + '/' + quote + suffix
1011
+ status = self.safe_string(market, 'status')
1012
+ active = status == 'TRADING'
1013
+ isLinear: Bool = None
1014
+ subType = None
1015
+ isInverse = self.safe_bool(market, 'inverse')
1016
+ if isInverse is not None:
1017
+ if isInverse:
1018
+ isLinear = False
1019
+ subType = 'inverse'
1020
+ else:
1021
+ isLinear = True
1022
+ subType = 'linear'
1023
+ filtersList = self.safe_list(market, 'filters', [])
1024
+ filters = self.index_by(filtersList, 'filterType')
1025
+ priceFilter = self.safe_dict(filters, 'PRICE_FILTER', {})
1026
+ amountFilter = self.safe_dict(filters, 'LOT_SIZE', {})
1027
+ costFilter = self.safe_dict(filters, 'MIN_NOTIONAL', {})
1028
+ minCostString = self.omit_zero(self.safe_string(costFilter, 'min_notional'))
1029
+ contractSizeString = self.safe_string(market, 'contractMultiplier')
1030
+ amountPrecisionString = self.safe_string(amountFilter, 'stepSize')
1031
+ amountMinLimitString = self.safe_string(amountFilter, 'minQty')
1032
+ amountMaxLimitString = self.safe_string(amountFilter, 'maxQty')
1033
+ minLeverage: Int = None
1034
+ maxLeverage: Int = None
1035
+ if isSwap:
1036
+ amountPrecisionString = Precise.string_div(amountPrecisionString, contractSizeString)
1037
+ amountMinLimitString = Precise.string_div(amountMinLimitString, contractSizeString)
1038
+ amountMaxLimitString = Precise.string_div(amountMaxLimitString, contractSizeString)
1039
+ riskLimits = self.safe_list(market, 'riskLimits')
1040
+ if riskLimits is not None:
1041
+ first = self.safe_dict(riskLimits, 0)
1042
+ arrayLength = len(riskLimits)
1043
+ last = self.safe_dict(riskLimits, arrayLength - 1)
1044
+ minInitialMargin = self.safe_string(first, 'initialMargin')
1045
+ maxInitialMargin = self.safe_string(last, 'initialMargin')
1046
+ if Precise.string_gt(minInitialMargin, maxInitialMargin):
1047
+ minInitialMargin, maxInitialMargin = [maxInitialMargin, minInitialMargin]
1048
+ minLeverage = self.parse_to_int(Precise.string_div('1', maxInitialMargin))
1049
+ maxLeverage = self.parse_to_int(Precise.string_div('1', minInitialMargin))
1050
+ tradingFees = self.safe_dict(self.fees, 'trading')
1051
+ fees = self.safe_dict(tradingFees, 'spot') if isSpot else self.safe_dict(tradingFees, 'swap')
1052
+ return self.safe_market_structure({
1053
+ 'id': marketId,
1054
+ 'symbol': symbol,
1055
+ 'base': base,
1056
+ 'quote': quote,
1057
+ 'baseId': baseId,
1058
+ 'quoteId': quoteId,
1059
+ 'active': active,
1060
+ 'type': marketType,
1061
+ 'subType': subType,
1062
+ 'spot': isSpot,
1063
+ 'margin': self.safe_bool(market, 'allowMargin'),
1064
+ 'swap': isSwap,
1065
+ 'future': False,
1066
+ 'option': False,
1067
+ 'contract': isSwap,
1068
+ 'settle': settle,
1069
+ 'settleId': settleId,
1070
+ 'contractSize': self.parse_number(contractSizeString),
1071
+ 'linear': isLinear,
1072
+ 'inverse': isInverse,
1073
+ 'taker': self.safe_number(fees, 'taker'),
1074
+ 'maker': self.safe_number(fees, 'maker'),
1075
+ 'percentage': self.safe_bool(fees, 'percentage'),
1076
+ 'tierBased': self.safe_bool(fees, 'tierBased'),
1077
+ 'feeSide': self.safe_string(fees, 'feeSide'),
1078
+ 'expiry': None,
1079
+ 'expiryDatetime': None,
1080
+ 'strike': None,
1081
+ 'optionType': None,
1082
+ 'precision': {
1083
+ 'amount': self.parse_number(amountPrecisionString),
1084
+ 'price': self.safe_number(priceFilter, 'tickSize'),
1085
+ },
1086
+ 'limits': {
1087
+ 'amount': {
1088
+ 'min': self.parse_number(amountMinLimitString),
1089
+ 'max': self.parse_number(amountMaxLimitString),
1090
+ },
1091
+ 'price': {
1092
+ 'min': self.safe_number(priceFilter, 'minPrice'),
1093
+ 'max': self.safe_number(priceFilter, 'maxPrice'),
1094
+ },
1095
+ 'leverage': {
1096
+ 'min': minLeverage,
1097
+ 'max': maxLeverage,
1098
+ },
1099
+ 'cost': {
1100
+ 'min': self.parse_number(minCostString),
1101
+ 'max': None,
1102
+ },
1103
+ },
1104
+ 'created': None,
1105
+ 'info': market,
1106
+ })
1107
+
1108
+ async def fetch_currencies(self, params={}) -> Currencies:
1109
+ """
1110
+ fetches all available currencies on an exchange
1111
+
1112
+ https://hashkeyglobal-apidoc.readme.io/reference/exchangeinfo
1113
+
1114
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1115
+ :returns dict: an associative dictionary of currencies
1116
+ """
1117
+ response = await self.publicGetApiV1ExchangeInfo(params)
1118
+ coins = self.safe_list(response, 'coins')
1119
+ #
1120
+ # {
1121
+ # ...
1122
+ # "coins": [
1123
+ # {
1124
+ # "orgId": "9001",
1125
+ # "coinId": "BTC",
1126
+ # "coinName": "BTC",
1127
+ # "coinFullName": "Bitcoin",
1128
+ # "allowWithdraw": True,
1129
+ # "allowDeposit": True,
1130
+ # "tokenType": "CHAIN_TOKEN",
1131
+ # "chainTypes": [
1132
+ # {
1133
+ # "chainType": "Bitcoin",
1134
+ # "withdrawFee": "0",
1135
+ # "minWithdrawQuantity": "0.002",
1136
+ # "maxWithdrawQuantity": "0",
1137
+ # "minDepositQuantity": "0.0005",
1138
+ # "allowDeposit": True,
1139
+ # "allowWithdraw": True
1140
+ # }
1141
+ # ]
1142
+ # }
1143
+ # ]
1144
+ # }
1145
+ #
1146
+ result: dict = {}
1147
+ for i in range(0, len(coins)):
1148
+ currecy = coins[i]
1149
+ currencyId = self.safe_string(currecy, 'coinId')
1150
+ code = self.safe_currency_code(currencyId)
1151
+ allowWithdraw = self.safe_bool(currecy, 'allowWithdraw')
1152
+ allowDeposit = self.safe_bool(currecy, 'allowDeposit')
1153
+ networks = self.safe_list(currecy, 'chainTypes')
1154
+ networksById = self.safe_dict(self.options, 'networksById')
1155
+ parsedNetworks: dict = {}
1156
+ for j in range(0, len(networks)):
1157
+ network = networks[j]
1158
+ networkId = self.safe_string(network, 'chainType')
1159
+ networkName = self.safe_string(networksById, networkId, networkId)
1160
+ maxWithdrawQuantity = self.omit_zero(self.safe_string(network, 'maxWithdrawQuantity'))
1161
+ networkDeposit = self.safe_bool(network, 'allowDeposit')
1162
+ networkWithdraw = self.safe_bool(network, 'allowWithdraw')
1163
+ parsedNetworks[networkName] = {
1164
+ 'id': networkId,
1165
+ 'network': networkName,
1166
+ 'limits': {
1167
+ 'withdraw': {
1168
+ 'min': self.safe_number(network, 'minWithdrawQuantity'),
1169
+ 'max': self.parse_number(maxWithdrawQuantity),
1170
+ },
1171
+ 'deposit': {
1172
+ 'min': self.safe_number(network, 'minDepositQuantity'),
1173
+ 'max': None,
1174
+ },
1175
+ },
1176
+ 'active': networkDeposit and networkWithdraw,
1177
+ 'deposit': networkDeposit,
1178
+ 'withdraw': networkWithdraw,
1179
+ 'fee': self.safe_number(network, 'withdrawFee'),
1180
+ 'precision': None,
1181
+ 'info': network,
1182
+ }
1183
+ result[code] = {
1184
+ 'id': currencyId,
1185
+ 'code': code,
1186
+ 'precision': None,
1187
+ 'type': self.parse_currency_type(self.safe_string(currecy, 'tokenType')),
1188
+ 'name': self.safe_string(currecy, 'coinFullName'),
1189
+ 'active': allowWithdraw and allowDeposit,
1190
+ 'deposit': allowDeposit,
1191
+ 'withdraw': allowWithdraw,
1192
+ 'fee': None,
1193
+ 'limits': {
1194
+ 'deposit': {
1195
+ 'min': None,
1196
+ 'max': None,
1197
+ },
1198
+ 'withdraw': {
1199
+ 'min': None,
1200
+ 'max': None,
1201
+ },
1202
+ },
1203
+ 'networks': parsedNetworks,
1204
+ 'info': currecy,
1205
+ }
1206
+ return result
1207
+
1208
+ def parse_currency_type(self, type):
1209
+ types = {
1210
+ 'CHAIN_TOKEN': 'crypto',
1211
+ 'ERC20_TOKEN': 'crypto',
1212
+ 'BSC_TOKEN': 'crypto',
1213
+ 'REAL_MONEY': 'fiat',
1214
+ }
1215
+ return self.safe_string(types, type)
1216
+
1217
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1218
+ """
1219
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1220
+
1221
+ https://hashkeyglobal-apidoc.readme.io/reference/get-order-book
1222
+
1223
+ :param str symbol: unified symbol of the market to fetch the order book for
1224
+ :param int [limit]: the maximum amount of order book entries to return(maximum value is 200)
1225
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1226
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1227
+ """
1228
+ await self.load_markets()
1229
+ market = self.market(symbol)
1230
+ request: dict = {
1231
+ 'symbol': market['id'],
1232
+ }
1233
+ if limit is not None:
1234
+ request['limit'] = limit
1235
+ response = await self.publicGetQuoteV1Depth(self.extend(request, params))
1236
+ #
1237
+ # {
1238
+ # "t": 1721681436393,
1239
+ # "b": [
1240
+ # ["67902.49", "0.00112"],
1241
+ # ["67901.08", "0.01014"]
1242
+ # ...
1243
+ # ],
1244
+ # "a": [
1245
+ # ["67905.99", "0.87134"],
1246
+ # ["67906", "0.57361"]
1247
+ # ...
1248
+ # ]
1249
+ # }
1250
+ #
1251
+ timestamp = self.safe_integer(response, 't')
1252
+ return self.parse_order_book(response, symbol, timestamp, 'b', 'a')
1253
+
1254
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1255
+ """
1256
+ get the list of most recent trades for a particular symbol
1257
+
1258
+ https://hashkeyglobal-apidoc.readme.io/reference/get-recent-trade-list
1259
+
1260
+ :param str symbol: unified symbol of the market to fetch trades for
1261
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1262
+ :param int [limit]: the maximum amount of trades to fetch(maximum value is 100)
1263
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1264
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1265
+ """
1266
+ await self.load_markets()
1267
+ market = self.market(symbol)
1268
+ request: dict = {
1269
+ 'symbol': market['id'],
1270
+ }
1271
+ if limit is not None:
1272
+ request['limit'] = limit
1273
+ response = await self.publicGetQuoteV1Trades(self.extend(request, params))
1274
+ #
1275
+ # [
1276
+ # {
1277
+ # "t": 1721682745779,
1278
+ # "p": "67835.99",
1279
+ # "q": "0.00017",
1280
+ # "ibm": True
1281
+ # },
1282
+ # ...
1283
+ # ]
1284
+ #
1285
+ return self.parse_trades(response, market, since, limit)
1286
+
1287
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1288
+ """
1289
+ fetch all trades made by the user
1290
+
1291
+ https://hashkeyglobal-apidoc.readme.io/reference/get-account-trade-list
1292
+ https://hashkeyglobal-apidoc.readme.io/reference/query-futures-trades
1293
+ https://hashkeyglobal-apidoc.readme.io/reference/get-sub-account-user
1294
+
1295
+ :param str symbol: *is mandatory for swap markets* unified market symbol
1296
+ :param int [since]: the earliest time in ms to fetch trades for
1297
+ :param int [limit]: the maximum amount of trades to fetch(default 200, max 500)
1298
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1299
+ :param str [params.type]: 'spot' or 'swap' - the type of the market to fetch trades for(default 'spot')
1300
+ :param int [params.until]: the latest time in ms to fetch trades for, only supports the last 30 days timeframe
1301
+ :param str [params.fromId]: srarting trade id
1302
+ :param str [params.toId]: ending trade id
1303
+ :param str [params.clientOrderId]: *spot markets only* filter trades by orderId
1304
+ :param str [params.accountId]: account id to fetch the orders from
1305
+ :returns Trade[]: a list of `trade structures <https://github.com/ccxt/ccxt/wiki/Manual#trade-structure>`
1306
+ """
1307
+ methodName = 'fetchMyTrades'
1308
+ await self.load_markets()
1309
+ request: dict = {}
1310
+ market: Market = None
1311
+ if symbol is not None:
1312
+ market = self.market(symbol)
1313
+ marketType = 'spot'
1314
+ marketType, params = self.handle_market_type_and_params(methodName, market, params)
1315
+ if since is not None:
1316
+ request['startTime'] = since
1317
+ if limit is not None:
1318
+ request['limit'] = limit
1319
+ until: Int = None
1320
+ until, params = self.handle_option_and_params(params, methodName, 'until')
1321
+ if until is not None:
1322
+ request['endTime'] = until
1323
+ accountId: Str = None
1324
+ accountId, params = self.handle_option_and_params(params, methodName, 'accountId')
1325
+ response = None
1326
+ if marketType == 'spot':
1327
+ if market is not None:
1328
+ request['symbol'] = market['id']
1329
+ if accountId is not None:
1330
+ request['accountId'] = accountId
1331
+ response = await self.privateGetApiV1AccountTrades(self.extend(request, params))
1332
+ #
1333
+ # [
1334
+ # {
1335
+ # "id": "1739352552862964736",
1336
+ # "clientOrderId": "1722082982086472",
1337
+ # "ticketId": "1739352552795029504",
1338
+ # "symbol": "ETHUSDT",
1339
+ # "symbolName": "ETHUSDT",
1340
+ # "orderId": "1739352552762301440",
1341
+ # "matchOrderId": "0",
1342
+ # "price": "3289.96",
1343
+ # "qty": "0.001",
1344
+ # "commission": "0.0000012",
1345
+ # "commissionAsset": "ETH",
1346
+ # "time": "1722082982097",
1347
+ # "isBuyer": True,
1348
+ # "isMaker": False,
1349
+ # "fee": {
1350
+ # "feeCoinId": "ETH",
1351
+ # "feeCoinName": "ETH",
1352
+ # "fee": "0.0000012"
1353
+ # },
1354
+ # "feeCoinId": "ETH",
1355
+ # "feeAmount": "0.0000012",
1356
+ # "makerRebate": "0"
1357
+ # },
1358
+ # ...
1359
+ # ]
1360
+ #
1361
+ elif marketType == 'swap':
1362
+ if symbol is None:
1363
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a symbol argument for swap markets')
1364
+ request['symbol'] = market['id']
1365
+ if accountId is not None:
1366
+ request['subAccountId'] = accountId
1367
+ response = await self.privateGetApiV1FuturesSubAccountUserTrades(self.extend(request, params))
1368
+ else:
1369
+ response = await self.privateGetApiV1FuturesUserTrades(self.extend(request, params))
1370
+ #
1371
+ # [
1372
+ # {
1373
+ # "time": "1722429951648",
1374
+ # "tradeId": "1742263144691139328",
1375
+ # "orderId": "1742263144028363776",
1376
+ # "symbol": "ETHUSDT-PERPETUAL",
1377
+ # "price": "3327.54",
1378
+ # "quantity": "4",
1379
+ # "commissionAsset": "USDT",
1380
+ # "commission": "0.00798609",
1381
+ # "makerRebate": "0",
1382
+ # "type": "LIMIT",
1383
+ # "side": "BUY_OPEN",
1384
+ # "realizedPnl": "0",
1385
+ # "isMarker": False
1386
+ # }
1387
+ # ]
1388
+ #
1389
+ else:
1390
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets')
1391
+ return self.parse_trades(response, market, since, limit)
1392
+
1393
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1394
+ #
1395
+ # fetchTrades
1396
+ #
1397
+ # {
1398
+ # "t": 1721682745779,
1399
+ # "p": "67835.99",
1400
+ # "q": "0.00017",
1401
+ # "ibm": True
1402
+ # }
1403
+ #
1404
+ # fetchMyTrades spot
1405
+ #
1406
+ # {
1407
+ # "id": "1739352552862964736",
1408
+ # "clientOrderId": "1722082982086472",
1409
+ # "ticketId": "1739352552795029504",
1410
+ # "symbol": "ETHUSDT",
1411
+ # "symbolName": "ETHUSDT",
1412
+ # "orderId": "1739352552762301440",
1413
+ # "matchOrderId": "0",
1414
+ # "price": "3289.96",
1415
+ # "qty": "0.001",
1416
+ # "commission": "0.0000012",
1417
+ # "commissionAsset": "ETH",
1418
+ # "time": "1722082982097",
1419
+ # "isBuyer": True,
1420
+ # "isMaker": False,
1421
+ # "fee": {
1422
+ # "feeCoinId": "ETH",
1423
+ # "feeCoinName": "ETH",
1424
+ # "fee": "0.0000012"
1425
+ # },
1426
+ # "feeCoinId": "ETH",
1427
+ # "feeAmount": "0.0000012",
1428
+ # "makerRebate": "0"
1429
+ # }
1430
+ #
1431
+ # fetchMyTrades swap
1432
+ # {
1433
+ # "time": "1722429951648",
1434
+ # "tradeId": "1742263144691139328",
1435
+ # "orderId": "1742263144028363776",
1436
+ # "symbol": "ETHUSDT-PERPETUAL",
1437
+ # "price": "3327.54",
1438
+ # "quantity": "4",
1439
+ # "commissionAsset": "USDT",
1440
+ # "commission": "0.00798609",
1441
+ # "makerRebate": "0",
1442
+ # "type": "LIMIT",
1443
+ # "side": "BUY_OPEN",
1444
+ # "realizedPnl": "0",
1445
+ # "isMarker": False
1446
+ # }
1447
+ timestamp = self.safe_integer_2(trade, 't', 'time')
1448
+ marketId = self.safe_string(trade, 'symbol')
1449
+ market = self.safe_market(marketId, market)
1450
+ side = self.safe_string_lower(trade, 'side') # swap trades have side param
1451
+ if side is not None:
1452
+ side = self.safe_string(side.split('_'), 0)
1453
+ isBuyer = self.safe_bool(trade, 'isBuyer')
1454
+ if isBuyer is not None:
1455
+ side = 'buy' if isBuyer else 'sell'
1456
+ takerOrMaker = None
1457
+ isMaker = self.safe_bool_n(trade, ['isMaker', 'isMarker'])
1458
+ if isMaker is not None:
1459
+ takerOrMaker = 'maker' if isMaker else 'taker'
1460
+ isBuyerMaker = self.safe_bool(trade, 'ibm')
1461
+ # if public trade
1462
+ if isBuyerMaker is not None:
1463
+ takerOrMaker = 'taker'
1464
+ side = 'sell' if isBuyerMaker else 'buy'
1465
+ feeCost = self.safe_string(trade, 'commission')
1466
+ feeCurrncyId = self.safe_string(trade, 'commissionAsset')
1467
+ feeInfo = self.safe_dict(trade, 'fee')
1468
+ fee = None
1469
+ if feeInfo is not None:
1470
+ feeCost = self.safe_string(feeInfo, 'fee')
1471
+ feeCurrncyId = self.safe_string(feeInfo, 'feeCoinId')
1472
+ if feeCost is not None:
1473
+ fee = {
1474
+ 'cost': self.parse_number(feeCost),
1475
+ 'currency': self.safe_currency_code(feeCurrncyId),
1476
+ }
1477
+ return self.safe_trade({
1478
+ 'id': self.safe_string_2(trade, 'id', 'tradeId'),
1479
+ 'timestamp': timestamp,
1480
+ 'datetime': self.iso8601(timestamp),
1481
+ 'symbol': market['symbol'],
1482
+ 'side': side,
1483
+ 'price': self.safe_string_2(trade, 'p', 'price'),
1484
+ 'amount': self.safe_string_n(trade, ['q', 'qty', 'quantity']),
1485
+ 'cost': None,
1486
+ 'takerOrMaker': takerOrMaker,
1487
+ 'type': None,
1488
+ 'order': self.safe_string(trade, 'orderId'),
1489
+ 'fee': fee,
1490
+ 'info': trade,
1491
+ }, market)
1492
+
1493
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1494
+ """
1495
+
1496
+ https://hashkeyglobal-apidoc.readme.io/reference/get-kline
1497
+
1498
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1499
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1500
+ :param str timeframe: the length of time each candle represents
1501
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1502
+ :param int [limit]: the maximum amount of candles to fetch
1503
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1504
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
1505
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1506
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1507
+ """
1508
+ methodName = 'fetchOHLCV'
1509
+ await self.load_markets()
1510
+ paginate = False
1511
+ paginate, params = self.handle_option_and_params(params, methodName, 'paginate')
1512
+ if paginate:
1513
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1000)
1514
+ market = self.market(symbol)
1515
+ timeframe = self.safe_string(self.timeframes, timeframe, timeframe)
1516
+ request: dict = {
1517
+ 'symbol': market['id'],
1518
+ 'interval': timeframe,
1519
+ }
1520
+ if since is not None:
1521
+ request['startTime'] = since
1522
+ if limit is not None:
1523
+ request['limit'] = limit
1524
+ until: Int = None
1525
+ until, params = self.handle_option_and_params(params, methodName, 'until')
1526
+ if until is not None:
1527
+ request['endTime'] = until
1528
+ response = await self.publicGetQuoteV1Klines(self.extend(request, params))
1529
+ #
1530
+ # [
1531
+ # [
1532
+ # 1721684280000,
1533
+ # "67832.49",
1534
+ # "67862.5",
1535
+ # "67832.49",
1536
+ # "67861.44",
1537
+ # "0.01122",0,
1538
+ # "761.2763533",68,
1539
+ # "0.00561",
1540
+ # "380.640643"
1541
+ # ],
1542
+ # ...
1543
+ # ]
1544
+ #
1545
+ return self.parse_ohlcvs(response, market, timeframe, since, limit)
1546
+
1547
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1548
+ #
1549
+ # [
1550
+ # 1721684280000,
1551
+ # "67832.49",
1552
+ # "67862.5",
1553
+ # "67832.49",
1554
+ # "67861.44",
1555
+ # "0.01122",0,
1556
+ # "761.2763533",68,
1557
+ # "0.00561",
1558
+ # "380.640643"
1559
+ # ]
1560
+ #
1561
+ return [
1562
+ self.safe_integer(ohlcv, 0),
1563
+ self.safe_number(ohlcv, 1),
1564
+ self.safe_number(ohlcv, 2),
1565
+ self.safe_number(ohlcv, 3),
1566
+ self.safe_number(ohlcv, 4),
1567
+ self.safe_number(ohlcv, 5),
1568
+ ]
1569
+
1570
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1571
+ """
1572
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1573
+
1574
+ https://hashkeyglobal-apidoc.readme.io/reference/get-24hr-ticker-price-change
1575
+
1576
+ :param str symbol: unified symbol of the market to fetch the ticker for
1577
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1578
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1579
+ """
1580
+ await self.load_markets()
1581
+ market = self.market(symbol)
1582
+ request: dict = {
1583
+ 'symbol': market['id'],
1584
+ }
1585
+ response = await self.publicGetQuoteV1Ticker24hr(self.extend(request, params))
1586
+ #
1587
+ # [
1588
+ # {
1589
+ # "t": 1721685896846,
1590
+ # "s": "BTCUSDT-PERPETUAL",
1591
+ # "c": "67756.7",
1592
+ # "h": "68479.9",
1593
+ # "l": "66594.3",
1594
+ # "o": "68279.7",
1595
+ # "b": "67756.6",
1596
+ # "a": "67756.7",
1597
+ # "v": "1604722",
1598
+ # "qv": "108827258.7761"
1599
+ # }
1600
+ # ]
1601
+ #
1602
+ ticker = self.safe_dict(response, 0, {})
1603
+ return self.parse_ticker(ticker, market)
1604
+
1605
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1606
+ """
1607
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1608
+
1609
+ https://hashkeyglobal-apidoc.readme.io/reference/get-24hr-ticker-price-change
1610
+
1611
+ :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1612
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1613
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1614
+ """
1615
+ await self.load_markets()
1616
+ symbols = self.market_symbols(symbols)
1617
+ response = await self.publicGetQuoteV1Ticker24hr(params)
1618
+ return self.parse_tickers(response, symbols)
1619
+
1620
+ def parse_ticker(self, ticker, market: Market = None) -> Ticker:
1621
+ #
1622
+ # {
1623
+ # "t": 1721685896846,
1624
+ # "s": "BTCUSDT-PERPETUAL",
1625
+ # "c": "67756.7",
1626
+ # "h": "68479.9",
1627
+ # "l": "66594.3",
1628
+ # "o": "68279.7",
1629
+ # "b": "67756.6",
1630
+ # "a": "67756.7",
1631
+ # "v": "1604722",
1632
+ # "qv": "108827258.7761"
1633
+ # }
1634
+ #
1635
+ timestamp = self.safe_integer(ticker, 't')
1636
+ marketId = self.safe_string(ticker, 's')
1637
+ market = self.safe_market(marketId, market)
1638
+ symbol = market['symbol']
1639
+ last = self.safe_string(ticker, 'c')
1640
+ return self.safe_ticker({
1641
+ 'symbol': symbol,
1642
+ 'timestamp': timestamp,
1643
+ 'datetime': self.iso8601(timestamp),
1644
+ 'high': self.safe_string(ticker, 'h'),
1645
+ 'low': self.safe_string(ticker, 'l'),
1646
+ 'bid': self.safe_string(ticker, 'b'),
1647
+ 'bidVolume': None,
1648
+ 'ask': self.safe_string(ticker, 'a'),
1649
+ 'askVolume': None,
1650
+ 'vwap': None,
1651
+ 'open': self.safe_string(ticker, 'o'),
1652
+ 'close': last,
1653
+ 'last': last,
1654
+ 'previousClose': None,
1655
+ 'change': None,
1656
+ 'percentage': None,
1657
+ 'average': None,
1658
+ 'baseVolume': self.safe_string(ticker, 'v'),
1659
+ 'quoteVolume': self.safe_string(ticker, 'qv'),
1660
+ 'info': ticker,
1661
+ }, market)
1662
+
1663
+ async def fetch_last_prices(self, symbols: Strings = None, params={}) -> LastPrices:
1664
+ """
1665
+ fetches the last price for multiple markets
1666
+
1667
+ https://hashkeyglobal-apidoc.readme.io/reference/get-symbol-price-ticker
1668
+
1669
+ :param str[] [symbols]: unified symbols of the markets to fetch the last prices
1670
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1671
+ :param str [params.symbol]: the id of the market to fetch last price for
1672
+ :returns dict: a dictionary of lastprices structures
1673
+ """
1674
+ await self.load_markets()
1675
+ symbols = self.market_symbols(symbols)
1676
+ request: dict = {}
1677
+ response = await self.publicGetQuoteV1TickerPrice(self.extend(request, params))
1678
+ #
1679
+ # [
1680
+ # {
1681
+ # "s": "BTCUSDT-PERPETUAL",
1682
+ # "p": "64871"
1683
+ # },
1684
+ # ...
1685
+ # ]
1686
+ #
1687
+ return self.parse_last_prices(response, symbols)
1688
+
1689
+ def parse_last_price(self, entry, market: Market = None) -> LastPrice:
1690
+ marketId = self.safe_string(entry, 's')
1691
+ market = self.safe_market(marketId, market)
1692
+ return {
1693
+ 'symbol': market['symbol'],
1694
+ 'timestamp': None,
1695
+ 'datetime': None,
1696
+ 'price': self.safe_number(entry, 'p'),
1697
+ 'side': None,
1698
+ 'info': entry,
1699
+ }
1700
+
1701
+ async def fetch_balance(self, params={}) -> Balances:
1702
+ """
1703
+ query for balance and get the amount of funds available for trading or funds locked in orders
1704
+
1705
+ https://hashkeyglobal-apidoc.readme.io/reference/get-account-information
1706
+
1707
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1708
+ :param str [params.accountId]: account ID, for Master Key only
1709
+ :param str [params.type]: 'spot' or 'swap' - the type of the market to fetch balance for(default 'spot')
1710
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1711
+ """
1712
+ await self.load_markets()
1713
+ request: dict = {}
1714
+ methodName = 'fetchBalance'
1715
+ marketType = 'spot'
1716
+ marketType, params = self.handle_market_type_and_params(methodName, None, params, marketType)
1717
+ if marketType == 'swap':
1718
+ response = await self.privateGetApiV1FuturesBalance(params)
1719
+ #
1720
+ # [
1721
+ # {
1722
+ # "balance": "30.63364672",
1723
+ # "availableBalance": "28.85635534",
1724
+ # "positionMargin": "4.3421",
1725
+ # "orderMargin": "0",
1726
+ # "asset": "USDT",
1727
+ # "crossUnRealizedPnl": "2.5649"
1728
+ # }
1729
+ # ]
1730
+ #
1731
+ balance = self.safe_dict(response, 0, {})
1732
+ return self.parse_swap_balance(balance)
1733
+ elif marketType == 'spot':
1734
+ response = await self.privateGetApiV1Account(self.extend(request, params))
1735
+ #
1736
+ # {
1737
+ # "balances": [
1738
+ # {
1739
+ # "asset":"USDT",
1740
+ # "assetId":"USDT",
1741
+ # "assetName":"USDT",
1742
+ # "total":"40",
1743
+ # "free":"40",
1744
+ # "locked":"0"
1745
+ # },
1746
+ # ...
1747
+ # ],
1748
+ # "userId": "1732885739572845312"
1749
+ # }
1750
+ #
1751
+ return self.parse_balance(response)
1752
+ else:
1753
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets')
1754
+
1755
+ def parse_balance(self, balance) -> Balances:
1756
+ #
1757
+ # {
1758
+ # "balances": [
1759
+ # {
1760
+ # "asset":"USDT",
1761
+ # "assetId":"USDT",
1762
+ # "assetName":"USDT",
1763
+ # "total":"40",
1764
+ # "free":"40",
1765
+ # "locked":"0"
1766
+ # },
1767
+ # ...
1768
+ # ],
1769
+ # "userId": "1732885739572845312"
1770
+ # }
1771
+ #
1772
+ result: dict = {
1773
+ 'info': balance,
1774
+ }
1775
+ balances = self.safe_list(balance, 'balances', [])
1776
+ for i in range(0, len(balances)):
1777
+ balanceEntry = balances[i]
1778
+ currencyId = self.safe_string(balanceEntry, 'asset')
1779
+ code = self.safe_currency_code(currencyId)
1780
+ account = self.account()
1781
+ account['total'] = self.safe_string(balanceEntry, 'total')
1782
+ account['free'] = self.safe_string(balanceEntry, 'free')
1783
+ account['used'] = self.safe_string(balanceEntry, 'locked')
1784
+ result[code] = account
1785
+ return self.safe_balance(result)
1786
+
1787
+ def parse_swap_balance(self, balance) -> Balances:
1788
+ #
1789
+ # {
1790
+ # "balance": "30.63364672",
1791
+ # "availableBalance": "28.85635534",
1792
+ # "positionMargin": "4.3421",
1793
+ # "orderMargin": "0",
1794
+ # "asset": "USDT",
1795
+ # "crossUnRealizedPnl": "2.5649"
1796
+ # }
1797
+ #
1798
+ currencyId = self.safe_string(balance, 'asset')
1799
+ code = self.safe_currency_code(currencyId)
1800
+ account = self.account()
1801
+ account['total'] = self.safe_string(balance, 'balance')
1802
+ positionMargin = self.safe_string(balance, 'positionMargin')
1803
+ orderMargin = self.safe_string(balance, 'orderMargin')
1804
+ account['used'] = Precise.string_add(positionMargin, orderMargin)
1805
+ result: dict = {
1806
+ 'info': balance,
1807
+ }
1808
+ result[code] = account
1809
+ return self.safe_balance(result)
1810
+
1811
+ async def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
1812
+ """
1813
+ fetch the deposit address for a currency associated with self account
1814
+
1815
+ https://hashkeyglobal-apidoc.readme.io/reference/get-deposit-address
1816
+
1817
+ :param str code: unified currency code(default is 'USDT')
1818
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1819
+ :param str [params.network]: network for fetch deposit address(default is 'ETH')
1820
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1821
+ """
1822
+ await self.load_markets()
1823
+ currency = self.currency(code)
1824
+ request: dict = {
1825
+ 'coin': currency['id'],
1826
+ }
1827
+ networkCode: Str = None
1828
+ networkCode, params = self.handle_network_code_and_params(params)
1829
+ if networkCode is None:
1830
+ networkCode = self.default_network_code(code)
1831
+ request['chainType'] = self.network_code_to_id(networkCode, code)
1832
+ response = await self.privateGetApiV1AccountDepositAddress(self.extend(request, params))
1833
+ #
1834
+ # {
1835
+ # "canDeposit": True,
1836
+ # "address": "0x61AAd7F763e2C7fF1CC996918740F67f9dC8BF4e",
1837
+ # "addressExt": "",
1838
+ # "minQuantity": "1",
1839
+ # "needAddressTag": False,
1840
+ # "requiredConfirmTimes": 64,
1841
+ # "canWithdrawConfirmTimes": 64,
1842
+ # "coinType": "ERC20_TOKEN"
1843
+ # }
1844
+ #
1845
+ depositAddress = self.parse_deposit_address(response, currency)
1846
+ depositAddress['network'] = networkCode
1847
+ return depositAddress
1848
+
1849
+ def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
1850
+ #
1851
+ # {
1852
+ # "canDeposit": True,
1853
+ # "address": "0x61AAd7F763e2C7fF1CC996918740F67f9dC8BF4e",
1854
+ # "addressExt": "",
1855
+ # "minQuantity": "1",
1856
+ # "needAddressTag": False,
1857
+ # "requiredConfirmTimes": 64,
1858
+ # "canWithdrawConfirmTimes": 64,
1859
+ # "coinType": "ERC20_TOKEN"
1860
+ # }
1861
+ #
1862
+ address = self.safe_string(depositAddress, 'address')
1863
+ self.check_address(address)
1864
+ tag = self.safe_string(depositAddress, 'addressExt')
1865
+ if tag == '':
1866
+ tag = None
1867
+ return {
1868
+ 'info': depositAddress,
1869
+ 'currency': currency['code'],
1870
+ 'network': None,
1871
+ 'address': address,
1872
+ 'tag': tag,
1873
+ }
1874
+
1875
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1876
+ """
1877
+ fetch all deposits made to an account
1878
+
1879
+ https://hashkeyglobal-apidoc.readme.io/reference/get-deposit-history
1880
+
1881
+ :param str code: unified currency code of the currency transferred
1882
+ :param int [since]: the earliest time in ms to fetch transfers for(default 24 hours ago)
1883
+ :param int [limit]: the maximum number of transfer structures to retrieve(default 50, max 200)
1884
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1885
+ :param int [params.until]: the latest time in ms to fetch transfers for(default time now)
1886
+ :param int [params.fromId]: starting ID(To be released)
1887
+ :returns dict[]: a list of `transfer structures <https://docs.ccxt.com/#/?id=transfer-structure>`
1888
+ """
1889
+ methodName = 'fetchDeposits'
1890
+ await self.load_markets()
1891
+ request: dict = {}
1892
+ currency: Currency = None
1893
+ if code is not None:
1894
+ currency = self.currency(code)
1895
+ request['coin'] = currency['id']
1896
+ if since is not None:
1897
+ request['startTime'] = since
1898
+ if limit is not None:
1899
+ request['limit'] = limit
1900
+ until: Int = None
1901
+ until, params = self.handle_option_and_params(params, methodName, 'until')
1902
+ if until is not None:
1903
+ request['endTime'] = until
1904
+ response = await self.privateGetApiV1AccountDepositOrders(self.extend(request, params))
1905
+ #
1906
+ # [
1907
+ # {
1908
+ # "time": "1721641082163",
1909
+ # "coin": "TRXUSDT",
1910
+ # "coinName": "TRXUSDT",
1911
+ # "address": "TBA6CypYJizwA9XdC7Ubgc5F1bxrQ7SqPt",
1912
+ # "quantity": "86.00000000000000000000",
1913
+ # "status": 4,
1914
+ # "statusCode": "4",
1915
+ # "txId": "0970c14da4d7412295fa7b21c03a08da319e746a0d59ef14462a74183d118da4"
1916
+ # }
1917
+ # ]
1918
+ #
1919
+ return self.parse_transactions(response, currency, since, limit, {'type': 'deposit'})
1920
+
1921
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
1922
+ """
1923
+ fetch all withdrawals made from an account
1924
+
1925
+ https://hashkeyglobal-apidoc.readme.io/reference/withdrawal-records
1926
+
1927
+ :param str code: unified currency code of the currency transferred
1928
+ :param int [since]: the earliest time in ms to fetch transfers for(default 24 hours ago)
1929
+ :param int [limit]: the maximum number of transfer structures to retrieve(default 50, max 200)
1930
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1931
+ :param int [params.until]: the latest time in ms to fetch transfers for(default time now)
1932
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
1933
+ """
1934
+ methodName = 'fetchWithdrawals'
1935
+ await self.load_markets()
1936
+ request: dict = {}
1937
+ currency: Currency = None
1938
+ if code is not None:
1939
+ currency = self.currency(code)
1940
+ request['coin'] = currency['id']
1941
+ if since is not None:
1942
+ request['startTime'] = since
1943
+ if limit is not None:
1944
+ request['limit'] = limit
1945
+ until: Int = None
1946
+ until, params = self.handle_option_and_params(params, methodName, 'until')
1947
+ if until is not None:
1948
+ request['endTime'] = until
1949
+ response = await self.privateGetApiV1AccountWithdrawOrders(self.extend(request, params))
1950
+ #
1951
+ # [
1952
+ # {
1953
+ # "time": "1723545505366",
1954
+ # "id": "W611267400947572736",
1955
+ # "coin": "USDT",
1956
+ # "coinId": "USDT",
1957
+ # "coinName": "USDT",
1958
+ # "address": "TQbkBMnWnJNGTAUpFS4kvv4NRLzUAnGAes",
1959
+ # "quantity": "2.00000000",
1960
+ # "arriveQuantity": "2.00000000",
1961
+ # "txId": "f83f94e7d2e81fbec98c66c25d6615872cc2d426145629b6cf22e5e0a0753715",
1962
+ # "addressUrl": "TQbkBMnWnJNGTAUpFS4kvv4NRLzUAnGAes",
1963
+ # "feeCoinId": "USDT",
1964
+ # "feeCoinName": "USDT",
1965
+ # "fee": "1.00000000",
1966
+ # "remark": "",
1967
+ # "platform": ""
1968
+ # }
1969
+ # ]
1970
+ #
1971
+ return self.parse_transactions(response, currency, since, limit, {'type': 'withdrawal'})
1972
+
1973
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
1974
+ """
1975
+ make a withdrawal
1976
+
1977
+ https://hashkeyglobal-apidoc.readme.io/reference/withdraw
1978
+
1979
+ :param str code: unified currency code
1980
+ :param float amount: the amount to withdraw
1981
+ :param str address: the address to withdraw to
1982
+ :param str tag:
1983
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1984
+ :param str [params.network]: network for withdraw
1985
+ :param str [params.clientOrderId]: client order id
1986
+ :param str [params.platform]: the platform to withdraw to(hashkey, HashKey HK)
1987
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
1988
+ """
1989
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
1990
+ await self.load_markets()
1991
+ currency = self.currency(code)
1992
+ request: dict = {
1993
+ 'coin': currency['id'],
1994
+ 'address': address,
1995
+ 'quantity': amount,
1996
+ }
1997
+ if tag is not None:
1998
+ request['addressExt'] = tag
1999
+ networkCode: Str = None
2000
+ networkCode, params = self.handle_network_code_and_params(params)
2001
+ if networkCode is not None:
2002
+ request['chainType'] = self.network_code_to_id(networkCode)
2003
+ response = await self.privatePostApiV1AccountWithdraw(self.extend(request, params))
2004
+ #
2005
+ # {
2006
+ # "success": True,
2007
+ # "id": "0",
2008
+ # "orderId": "W611267400947572736",
2009
+ # "accountId": "1732885739589466115"
2010
+ # }
2011
+ #
2012
+ return self.parse_transaction(response, currency)
2013
+
2014
+ def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
2015
+ #
2016
+ # fetchDeposits
2017
+ # {
2018
+ # "time": "1721641082163",
2019
+ # "coin": "TRXUSDT", # todo how to parse it?
2020
+ # "coinName": "TRXUSDT",
2021
+ # "address": "TBA6CypYJizwA9XdC7Ubgc5F1bxrQ7SqPt",
2022
+ # "quantity": "86.00000000000000000000",
2023
+ # "status": 4,
2024
+ # "statusCode": "4",
2025
+ # "txId": "0970c14da4d7412295fa7b21c03a08da319e746a0d59ef14462a74183d118da4"
2026
+ # }
2027
+ #
2028
+ # fetchWithdrawals
2029
+ # {
2030
+ # "time": "1723545505366",
2031
+ # "id": "W611267400947572736",
2032
+ # "coin": "USDT",
2033
+ # "coinId": "USDT",
2034
+ # "coinName": "USDT",
2035
+ # "address": "TQbkBMnWnJNGTAUpFS4kvv4NRLzUAnGAes",
2036
+ # "quantity": "2.00000000",
2037
+ # "arriveQuantity": "2.00000000",
2038
+ # "txId": "f83f94e7d2e81fbec98c66c25d6615872cc2d426145629b6cf22e5e0a0753715",
2039
+ # "addressUrl": "TQbkBMnWnJNGTAUpFS4kvv4NRLzUAnGAes",
2040
+ # "feeCoinId": "USDT",
2041
+ # "feeCoinName": "USDT",
2042
+ # "fee": "1.00000000",
2043
+ # "remark": "",
2044
+ # "platform": ""
2045
+ # }
2046
+ #
2047
+ # withdraw
2048
+ # {
2049
+ # "success": True,
2050
+ # "id": "0",
2051
+ # "orderId": "W611267400947572736",
2052
+ # "accountId": "1732885739589466115"
2053
+ # }
2054
+ #
2055
+ id = self.safe_string_2(transaction, 'id', 'orderId')
2056
+ address = self.safe_string(transaction, 'address')
2057
+ status = self.safe_string(transaction, 'status') # for fetchDeposits
2058
+ if status is None:
2059
+ success = self.safe_bool(transaction, 'success', False) # for withdraw
2060
+ if success:
2061
+ status = 'ok'
2062
+ else:
2063
+ addressUrl = self.safe_string(transaction, 'addressUrl') # for fetchWithdrawals
2064
+ if addressUrl is not None:
2065
+ status = 'ok'
2066
+ txid = self.safe_string(transaction, 'txId')
2067
+ coin = self.safe_string(transaction, 'coin')
2068
+ code = self.safe_currency_code(coin, currency)
2069
+ timestamp = self.safe_integer(transaction, 'time')
2070
+ amount = self.safe_number(transaction, 'quantity')
2071
+ feeCost = self.safe_number(transaction, 'fee')
2072
+ fee = None
2073
+ if feeCost is not None:
2074
+ fee = {
2075
+ 'cost': feeCost,
2076
+ 'currency': code,
2077
+ }
2078
+ return {
2079
+ 'info': transaction,
2080
+ 'id': id,
2081
+ 'txid': txid,
2082
+ 'timestamp': timestamp,
2083
+ 'datetime': self.iso8601(timestamp),
2084
+ 'network': None,
2085
+ 'address': address,
2086
+ 'addressTo': None,
2087
+ 'addressFrom': None,
2088
+ 'tag': None,
2089
+ 'tagTo': None,
2090
+ 'tagFrom': None,
2091
+ 'type': None,
2092
+ 'amount': amount,
2093
+ 'currency': code,
2094
+ 'status': self.parse_transaction_status(status),
2095
+ 'updated': None,
2096
+ 'internal': None,
2097
+ 'comment': None,
2098
+ 'fee': fee,
2099
+ }
2100
+
2101
+ def parse_transaction_status(self, status):
2102
+ statuses: dict = {
2103
+ '1': 'pending',
2104
+ '2': 'pending',
2105
+ '3': 'failed',
2106
+ '4': 'ok',
2107
+ '5': 'pending',
2108
+ '6': 'ok',
2109
+ '7': 'failed',
2110
+ '8': 'cancelled',
2111
+ '9': 'failed',
2112
+ '10': 'failed',
2113
+ 'successful': 'ok',
2114
+ 'success': 'ok',
2115
+ }
2116
+ return self.safe_string(statuses, status, status)
2117
+
2118
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
2119
+ """
2120
+ transfer currency internally between wallets on the same account
2121
+
2122
+ https://hashkeyglobal-apidoc.readme.io/reference/new-account-transfer
2123
+
2124
+ :param str code: unified currency code
2125
+ :param float amount: amount to transfer
2126
+ :param str fromAccount: account id to transfer from
2127
+ :param str toAccount: account id to transfer to
2128
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2129
+ :param str [params.clientOrderId]: a unique id for the transfer
2130
+ :param str [params.remark]: a note for the transfer
2131
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
2132
+ """
2133
+ await self.load_markets()
2134
+ currency = self.currency(code)
2135
+ request: dict = {
2136
+ 'coin': currency['id'],
2137
+ 'quantity': self.currency_to_precision(code, amount),
2138
+ 'fromAccountId': fromAccount,
2139
+ 'toAccountId': toAccount,
2140
+ }
2141
+ response = await self.privatePostApiV1AccountAssetTransfer(self.extend(request, params))
2142
+ #
2143
+ # {
2144
+ # "success": True,
2145
+ # "timestamp": 1722260230773,
2146
+ # "clientOrderId": "",
2147
+ # "orderId": "1740839420695806720"
2148
+ # }
2149
+ #
2150
+ return self.parse_transfer(response, currency)
2151
+
2152
+ def parse_transfer(self, transfer, currency: Currency = None):
2153
+ timestamp = self.safe_integer(transfer, 'timestamp')
2154
+ currencyId = self.safe_string(currency, 'id')
2155
+ status: Str = None
2156
+ success = self.safe_bool(transfer, 'success', False)
2157
+ if success:
2158
+ status = 'ok'
2159
+ return {
2160
+ 'id': self.safe_string(transfer, 'orderId'),
2161
+ 'timestamp': timestamp,
2162
+ 'datetime': self.iso8601(timestamp),
2163
+ 'currency': self.safe_currency_code(currencyId, currency),
2164
+ 'amount': None,
2165
+ 'fromAccount': None,
2166
+ 'toAccount': None,
2167
+ 'status': status,
2168
+ 'info': transfer,
2169
+ }
2170
+
2171
+ async def fetch_accounts(self, params={}) -> List[Account]:
2172
+ """
2173
+ fetch all the accounts associated with a profile
2174
+
2175
+ https://hashkeyglobal-apidoc.readme.io/reference/query-sub-account
2176
+
2177
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2178
+ :returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
2179
+ """
2180
+ await self.load_markets()
2181
+ response = await self.privateGetApiV1AccountType(params)
2182
+ #
2183
+ # [
2184
+ # {
2185
+ # "accountId": "1732885739589466112",
2186
+ # "accountLabel": "Main Trading Account",
2187
+ # "accountType": 1,
2188
+ # "accountIndex": 0
2189
+ # },
2190
+ # ...
2191
+ # ]
2192
+ #
2193
+ return self.parse_accounts(response, params)
2194
+
2195
+ def parse_account(self, account):
2196
+ accountLabel = self.safe_string(account, 'accountLabel')
2197
+ label = ''
2198
+ if accountLabel == 'Main Trading Account' or accountLabel == 'Main Future Account':
2199
+ label = 'main'
2200
+ elif accountLabel == 'Sub Main Trading Account' or accountLabel == 'Sub Main Future Account':
2201
+ label = 'sub'
2202
+ accountType = self.parse_account_type(self.safe_string(account, 'accountType'))
2203
+ type = label + ' ' + accountType
2204
+ return {
2205
+ 'id': self.safe_string(account, 'accountId'),
2206
+ 'type': type,
2207
+ 'code': None,
2208
+ 'info': account,
2209
+ }
2210
+
2211
+ def parse_account_type(self, type):
2212
+ types: dict = {
2213
+ '1': 'spot account',
2214
+ '3': 'swap account',
2215
+ '5': 'custody account',
2216
+ '6': 'fiat account',
2217
+ }
2218
+ return self.safe_string(types, type, type)
2219
+
2220
+ def encode_account_type(self, type):
2221
+ types = {
2222
+ 'spot': '1',
2223
+ 'swap': '3',
2224
+ 'custody': '5',
2225
+ }
2226
+ return self.safe_integer(types, type, type)
2227
+
2228
+ def encode_flow_type(self, type):
2229
+ types = {
2230
+ 'trade': '1',
2231
+ 'fee': '3',
2232
+ 'transfer': '51',
2233
+ 'deposit': '900',
2234
+ 'withdraw': '904',
2235
+ }
2236
+ return self.safe_integer(types, type, type)
2237
+
2238
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
2239
+ """
2240
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
2241
+
2242
+ https://hashkeyglobal-apidoc.readme.io/reference/get-account-transaction-list
2243
+
2244
+ :param str [code]: unified currency code, default is None(not used)
2245
+ :param int [since]: timestamp in ms of the earliest ledger entry, default is None
2246
+ :param int [limit]: max number of ledger entries to return, default is None
2247
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2248
+ :param int [params.until]: the latest time in ms to fetch entries for
2249
+ :param int [params.flowType]: trade, fee, transfer, deposit, withdrawal
2250
+ :param int [params.accountType]: spot, swap, custody
2251
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
2252
+ """
2253
+ methodName = 'fetchLedger'
2254
+ if since is None:
2255
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a since argument')
2256
+ until: Int = None
2257
+ until, params = self.handle_option_and_params(params, methodName, 'until')
2258
+ if until is None:
2259
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() requires an until argument')
2260
+ await self.load_markets()
2261
+ currency = self.currency(code)
2262
+ request = {}
2263
+ request['startTime'] = since
2264
+ if limit is not None:
2265
+ request['limit'] = limit
2266
+ request['endTime'] = until
2267
+ flowType = None
2268
+ flowType, params = self.handle_option_and_params(params, methodName, 'flowType')
2269
+ if flowType is not None:
2270
+ request['flowType'] = self.encode_flow_type(flowType)
2271
+ accountType = None
2272
+ accountType, params = self.handle_option_and_params(params, methodName, 'accountType')
2273
+ if accountType is not None:
2274
+ request['accountType'] = self.encode_account_type(accountType)
2275
+ response = await self.privateGetApiV1AccountBalanceFlow(self.extend(request, params))
2276
+ #
2277
+ # [
2278
+ # {
2279
+ # "id": "1740844413612065537",
2280
+ # "accountId": "1732885739589466112",
2281
+ # "coin": "USDT",
2282
+ # "coinId": "USDT",
2283
+ # "coinName": "USDT",
2284
+ # "flowTypeValue": 51,
2285
+ # "flowType": "USER_ACCOUNT_TRANSFER",
2286
+ # "flowName": "",
2287
+ # "change": "-1",
2288
+ # "total": "8.015680088",
2289
+ # "created": "1722260825765"
2290
+ # },
2291
+ # ...
2292
+ # ]
2293
+ #
2294
+ return self.parse_ledger(response, currency, since, limit)
2295
+
2296
+ def parse_ledger_entry_type(self, type):
2297
+ types: dict = {
2298
+ '1': 'trade', # transfer
2299
+ '2': 'fee', # trade
2300
+ '51': 'transfer',
2301
+ '900': 'deposit',
2302
+ '904': 'withdraw',
2303
+ }
2304
+ return self.safe_string(types, type, type)
2305
+
2306
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
2307
+ #
2308
+ # {
2309
+ # "id": "1740844413612065537",
2310
+ # "accountId": "1732885739589466112",
2311
+ # "coin": "USDT",
2312
+ # "coinId": "USDT",
2313
+ # "coinName": "USDT",
2314
+ # "flowTypeValue": 51,
2315
+ # "flowType": "USER_ACCOUNT_TRANSFER",
2316
+ # "flowName": "",
2317
+ # "change": "-1",
2318
+ # "total": "8.015680088",
2319
+ # "created": "1722260825765"
2320
+ # }
2321
+ #
2322
+ id = self.safe_string(item, 'id')
2323
+ account = self.safe_string(item, 'accountId')
2324
+ timestamp = self.safe_integer(item, 'created')
2325
+ type = self.parse_ledger_entry_type(self.safe_string(item, 'flowTypeValue'))
2326
+ currencyId = self.safe_string(item, 'coin')
2327
+ code = self.safe_currency_code(currencyId, currency)
2328
+ currency = self.safe_currency(currencyId, currency)
2329
+ amountString = self.safe_string(item, 'change')
2330
+ amount = self.parse_number(amountString)
2331
+ direction = 'in'
2332
+ if amountString.find('-') >= 0:
2333
+ direction = 'out'
2334
+ afterString = self.safe_string(item, 'total')
2335
+ after = self.parse_number(afterString)
2336
+ status = 'ok'
2337
+ return self.safe_ledger_entry({
2338
+ 'info': item,
2339
+ 'id': id,
2340
+ 'timestamp': timestamp,
2341
+ 'datetime': self.iso8601(timestamp),
2342
+ 'account': account,
2343
+ 'direction': direction,
2344
+ 'referenceId': None,
2345
+ 'referenceAccount': None,
2346
+ 'type': type,
2347
+ 'currency': code,
2348
+ 'symbol': None,
2349
+ 'amount': amount,
2350
+ 'before': None,
2351
+ 'after': after,
2352
+ 'status': status,
2353
+ 'fee': None,
2354
+ }, currency)
2355
+
2356
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
2357
+ """
2358
+ create a trade order
2359
+
2360
+ https://hashkeyglobal-apidoc.readme.io/reference/test-new-order
2361
+ https://hashkeyglobal-apidoc.readme.io/reference/create-order
2362
+ https://hashkeyglobal-apidoc.readme.io/reference/create-new-futures-order
2363
+
2364
+ :param str symbol: unified symbol of the market to create an order in
2365
+ :param str type: 'market' or 'limit' or 'LIMIT_MAKER' for spot, 'market' or 'limit' or 'STOP' for swap
2366
+ :param str side: 'buy' or 'sell'
2367
+ :param float amount: how much of you want to trade in units of the base currency
2368
+ :param float [price]: the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2369
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2370
+ :param float [params.cost]: *spot market buy only* the quote quantity that can be used alternative for the amount
2371
+ :param boolean [params.test]: *spot markets only* whether to use the test endpoint or not, default is False
2372
+ :param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
2373
+ :param str [params.timeInForce]: "GTC" or "IOC" or "PO" for spot, 'GTC' or 'FOK' or 'IOC' or 'LIMIT_MAKER' or 'PO' for swap
2374
+ :param str [params.clientOrderId]: a unique id for the order - is mandatory for swap
2375
+ :param float [params.triggerPrice]: *swap markets only* The price at which a trigger order is triggered at
2376
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2377
+ """
2378
+ await self.load_markets()
2379
+ market = self.market(symbol)
2380
+ if market['spot']:
2381
+ return await self.create_spot_order(symbol, type, side, amount, price, params)
2382
+ elif market['swap']:
2383
+ return await self.create_swap_order(symbol, type, side, amount, price, params)
2384
+ else:
2385
+ raise NotSupported(self.id + ' createOrder() is not supported for ' + market['type'] + ' type of markets')
2386
+
2387
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}) -> Order:
2388
+ """
2389
+ create a market buy order by providing the symbol and cost
2390
+ :param str symbol: unified symbol of the market to create an order in
2391
+ :param float cost: how much you want to trade in units of the quote currency
2392
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2393
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2394
+ """
2395
+ await self.load_markets()
2396
+ market = self.market(symbol)
2397
+ if not market['spot']:
2398
+ raise NotSupported(self.id + ' createMarketBuyOrderWithCost() is supported for spot markets only')
2399
+ req = {
2400
+ 'cost': cost,
2401
+ }
2402
+ return await self.create_order(symbol, 'market', 'buy', cost, None, self.extend(req, params))
2403
+
2404
+ async def create_spot_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
2405
+ """
2406
+ create a trade order on spot market
2407
+
2408
+ https://hashkeyglobal-apidoc.readme.io/reference/test-new-order
2409
+ https://hashkeyglobal-apidoc.readme.io/reference/create-order
2410
+
2411
+ :param str symbol: unified symbol of the market to create an order in
2412
+ :param str type: 'market' or 'limit' or 'LIMIT_MAKER'
2413
+ :param str side: 'buy' or 'sell'
2414
+ :param float amount: how much of you want to trade in units of the base currency
2415
+ :param float [price]: the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2416
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2417
+ :param float [params.cost]: *market buy only* the quote quantity that can be used alternative for the amount
2418
+ :param bool [params.test]: whether to use the test endpoint or not, default is False
2419
+ :param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
2420
+ :param str [params.timeInForce]: 'GTC', 'IOC', or 'PO'
2421
+ :param str [params.clientOrderId]: a unique id for the order
2422
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2423
+ """
2424
+ triggerPrice = self.safe_string_2(params, 'stopPrice', 'triggerPrice')
2425
+ if triggerPrice is not None:
2426
+ raise NotSupported(self.id + ' trigger orders are not supported for spot markets')
2427
+ await self.load_markets()
2428
+ market = self.market(symbol)
2429
+ isMarketBuy = (type == 'market') and (side == 'buy')
2430
+ cost = self.safe_string(params, 'cost')
2431
+ if (not isMarketBuy) and (cost is not None):
2432
+ raise NotSupported(self.id + ' createOrder() supports cost parameter for spot market buy orders only')
2433
+ request: dict = self.create_spot_order_request(symbol, type, side, amount, price, params)
2434
+ response: dict = {}
2435
+ test = self.safe_bool(params, 'test')
2436
+ if test:
2437
+ params = self.omit(params, 'test')
2438
+ response = await self.privatePostApiV1SpotOrderTest(request)
2439
+ elif isMarketBuy and (cost is None):
2440
+ response = await self.privatePostApiV11SpotOrder(request) # the endpoint for market buy orders by amount
2441
+ #
2442
+ # {
2443
+ # "accountId": "1732885739589466112",
2444
+ # "symbol": "ETHUSDT",
2445
+ # "symbolName": "ETHUSDT",
2446
+ # "clientOrderId": "1722005792096557",
2447
+ # "orderId": "1738705036219839744",
2448
+ # "transactTime": "1722005792106",
2449
+ # "price": "0",
2450
+ # "origQty": "0.006",
2451
+ # "executedQty": "0.0059",
2452
+ # "status": "FILLED",
2453
+ # "timeInForce": "IOC",
2454
+ # "type": "MARKET",
2455
+ # "side": "BUY",
2456
+ # "reqAmount": "0",
2457
+ # "concentration": ""
2458
+ # }
2459
+ #
2460
+ else:
2461
+ response = await self.privatePostApiV1SpotOrder(request) # the endpoint for market buy orders by cost and other orders
2462
+ #
2463
+ # market buy
2464
+ # {
2465
+ # "accountId": "1732885739589466112",
2466
+ # "symbol": "ETHUSDT",
2467
+ # "symbolName": "ETHUSDT",
2468
+ # "clientOrderId": "1722004623170558",
2469
+ # "orderId": "1738695230608169984",
2470
+ # "transactTime": "1722004623186",
2471
+ # "price": "0",
2472
+ # "origQty": "0",
2473
+ # "executedQty": "0.0061",
2474
+ # "status": "FILLED",
2475
+ # "timeInForce": "IOC",
2476
+ # "type": "MARKET",
2477
+ # "side": "BUY",
2478
+ # "reqAmount": "20",
2479
+ # "concentration": ""
2480
+ # }
2481
+ #
2482
+ # market sell
2483
+ # {
2484
+ # "accountId": "1732885739589466112",
2485
+ # "symbol": "ETHUSDT",
2486
+ # "symbolName": "ETHUSDT",
2487
+ # "clientOrderId": "1722005654516362",
2488
+ # "orderId": "1738703882140316928",
2489
+ # "transactTime": "1722005654529",
2490
+ # "price": "0",
2491
+ # "origQty": "0.006",
2492
+ # "executedQty": "0.006",
2493
+ # "status": "FILLED",
2494
+ # "timeInForce": "IOC",
2495
+ # "type": "MARKET",
2496
+ # "side": "SELL",
2497
+ # "reqAmount": "0",
2498
+ # "concentration": ""
2499
+ # }
2500
+ #
2501
+ # limit
2502
+ # {
2503
+ # "accountId": "1732885739589466112",
2504
+ # "symbol": "ETHUSDT",
2505
+ # "symbolName": "ETHUSDT",
2506
+ # "clientOrderId": "1722006209978370",
2507
+ # "orderId": "1738708541676585728",
2508
+ # "transactTime": "1722006209989",
2509
+ # "price": "5000",
2510
+ # "origQty": "0.005",
2511
+ # "executedQty": "0",
2512
+ # "status": "NEW",
2513
+ # "timeInForce": "GTC",
2514
+ # "type": "LIMIT_MAKER",
2515
+ # "side": "SELL",
2516
+ # "reqAmount": "0",
2517
+ # "concentration": ""
2518
+ # }
2519
+ #
2520
+ return self.parse_order(response, market)
2521
+
2522
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> dict:
2523
+ market = self.market(symbol)
2524
+ if market['spot']:
2525
+ return self.create_spot_order_request(symbol, type, side, amount, price, params)
2526
+ elif market['swap']:
2527
+ return self.create_swap_order_request(symbol, type, side, amount, price, params)
2528
+ else:
2529
+ raise NotSupported(self.id + ' ' + 'createOrderRequest() is not supported for ' + market['type'] + ' type of markets')
2530
+
2531
+ def create_spot_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> dict:
2532
+ """
2533
+ @ignore
2534
+ helper function to build request
2535
+ :param str symbol: unified symbol of the market to create an order in
2536
+ :param str type: 'market' or 'limit' or 'LIMIT_MAKER'
2537
+ :param str side: 'buy' or 'sell'
2538
+ :param float amount: how much of you want to trade in units of the base currency
2539
+ :param float [price]: the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2540
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2541
+ :param float [params.cost]: *market buy only* the quote quantity that can be used alternative for the amount
2542
+ :param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
2543
+ :param str [params.timeInForce]: "GTC", "IOC", or "PO"
2544
+ :param str [params.clientOrderId]: a unique id for the order
2545
+ :returns dict: request to be sent to the exchange
2546
+ """
2547
+ market = self.market(symbol)
2548
+ type = type.upper()
2549
+ request: dict = {
2550
+ 'symbol': market['id'],
2551
+ 'side': side.upper(),
2552
+ 'type': type,
2553
+ }
2554
+ if amount is not None:
2555
+ request['quantity'] = self.amount_to_precision(symbol, amount)
2556
+ cost: Str = None
2557
+ cost, params = self.handle_param_string(params, 'cost')
2558
+ if cost is not None:
2559
+ request['quantity'] = self.cost_to_precision(symbol, cost)
2560
+ if price is not None:
2561
+ request['price'] = self.price_to_precision(symbol, price)
2562
+ isMarketOrder = type == 'MARKET'
2563
+ postOnly = False
2564
+ postOnly, params = self.handle_post_only(isMarketOrder, type == 'LIMIT_MAKER', params)
2565
+ if postOnly and (type == 'LIMIT'):
2566
+ request['type'] = 'LIMIT_MAKER'
2567
+ clientOrderId: Str = None
2568
+ clientOrderId, params = self.handle_param_string(params, 'clientOrderId')
2569
+ if clientOrderId is not None:
2570
+ params['newClientOrderId'] = clientOrderId
2571
+ return self.extend(request, params)
2572
+
2573
+ def create_swap_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> dict:
2574
+ """
2575
+ @ignore
2576
+ helper function to build request
2577
+ :param str symbol: unified symbol of the market to create an order in
2578
+ :param str type: 'market' or 'limit' or 'STOP'
2579
+ :param str side: 'buy' or 'sell'
2580
+ :param float amount: how much of you want to trade in units of the base currency
2581
+ :param float [price]: the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2582
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2583
+ :param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
2584
+ :param bool [params.reduceOnly]: True or False whether the order is reduce only
2585
+ :param float [params.triggerPrice]: The price at which a trigger order is triggered at
2586
+ :param str [params.timeInForce]: 'GTC', 'FOK', 'IOC', 'LIMIT_MAKER' or 'PO'
2587
+ :param str [params.clientOrderId]: a unique id for the order
2588
+ :returns dict: request to be sent to the exchange
2589
+ """
2590
+ market = self.market(symbol)
2591
+ request: dict = {
2592
+ 'symbol': market['id'],
2593
+ 'type': 'LIMIT',
2594
+ 'quantity': self.amount_to_precision(symbol, amount),
2595
+ }
2596
+ isMarketOrder = type == 'market'
2597
+ if isMarketOrder:
2598
+ request['priceType'] = 'MARKET'
2599
+ if price is not None:
2600
+ request['price'] = self.price_to_precision(symbol, price)
2601
+ request['priceType'] = 'INPUT'
2602
+ reduceOnly = False
2603
+ reduceOnly, params = self.handle_param_bool(params, 'reduceOnly', reduceOnly)
2604
+ suffix = '_OPEN'
2605
+ if reduceOnly:
2606
+ suffix = '_CLOSE'
2607
+ request['side'] = side.upper() + suffix
2608
+ timeInForce: Str = None
2609
+ timeInForce, params = self.handle_param_string(params, 'timeInForce')
2610
+ postOnly = False
2611
+ postOnly, params = self.handle_post_only(isMarketOrder, timeInForce == 'LIMIT_MAKER', params)
2612
+ if postOnly:
2613
+ timeInForce = 'LIMIT_MAKER'
2614
+ if timeInForce is not None:
2615
+ request['timeInForce'] = timeInForce
2616
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2617
+ if clientOrderId is None:
2618
+ request['clientOrderId'] = self.uuid()
2619
+ triggerPrice = self.safe_string(params, 'triggerPrice')
2620
+ if triggerPrice is not None:
2621
+ request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
2622
+ request['type'] = 'STOP'
2623
+ params = self.omit(params, 'triggerPrice')
2624
+ return self.extend(request, params)
2625
+
2626
+ async def create_swap_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
2627
+ """
2628
+ create a trade order on swap market
2629
+
2630
+ https://hashkeyglobal-apidoc.readme.io/reference/create-new-futures-order
2631
+
2632
+ :param str symbol: unified symbol of the market to create an order in
2633
+ :param str type: 'market' or 'limit' or 'STOP'
2634
+ :param str side: 'buy' or 'sell'
2635
+ :param float amount: how much of you want to trade in units of the base currency
2636
+ :param float [price]: the price that the order is to be fulfilled, in units of the quote currency, ignored in market orders
2637
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2638
+ :param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
2639
+ :param bool [params.reduceOnly]: True or False whether the order is reduce only
2640
+ :param float [params.triggerPrice]: The price at which a trigger order is triggered at
2641
+ :param str [params.timeInForce]: 'GTC', 'FOK', 'IOC', 'LIMIT_MAKER' or 'PO'
2642
+ :param str [params.clientOrderId]: a unique id for the order
2643
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2644
+ """
2645
+ await self.load_markets()
2646
+ market = self.market(symbol)
2647
+ request = self.create_swap_order_request(symbol, type, side, amount, price, params)
2648
+ response = await self.privatePostApiV1FuturesOrder(self.extend(request, params))
2649
+ #
2650
+ # {
2651
+ # "time": "1722429951611",
2652
+ # "updateTime": "1722429951648",
2653
+ # "orderId": "1742263144028363776",
2654
+ # "clientOrderId": "1722429950315",
2655
+ # "symbol": "ETHUSDT-PERPETUAL",
2656
+ # "price": "3460.62",
2657
+ # "leverage": "5",
2658
+ # "origQty": "10",
2659
+ # "executedQty": "10",
2660
+ # "avgPrice": "0",
2661
+ # "marginLocked": "6.9212",
2662
+ # "type": "LIMIT",
2663
+ # "side": "BUY_OPEN",
2664
+ # "timeInForce": "IOC",
2665
+ # "status": "FILLED",
2666
+ # "priceType": "MARKET",
2667
+ # "contractMultiplier": "0.00100000"
2668
+ # }
2669
+ #
2670
+ return self.parse_order(response, market)
2671
+
2672
+ async def create_orders(self, orders: List[OrderRequest], params={}):
2673
+ """
2674
+ create a list of trade orders(all orders should be of the same symbol)
2675
+
2676
+ https://hashkeyglobal-apidoc.readme.io/reference/create-multiple-orders
2677
+ https://hashkeyglobal-apidoc.readme.io/reference/batch-create-new-futures-order
2678
+
2679
+ :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
2680
+ :param dict [params]: extra parameters specific to the api endpoint
2681
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2682
+ """
2683
+ await self.load_markets()
2684
+ ordersRequests = []
2685
+ for i in range(0, len(orders)):
2686
+ rawOrder = orders[i]
2687
+ symbol = self.safe_string(rawOrder, 'symbol')
2688
+ type = self.safe_string(rawOrder, 'type')
2689
+ side = self.safe_string(rawOrder, 'side')
2690
+ amount = self.safe_number(rawOrder, 'amount')
2691
+ price = self.safe_number(rawOrder, 'price')
2692
+ orderParams = self.safe_dict(rawOrder, 'params', {})
2693
+ orderRequest = self.create_order_request(symbol, type, side, amount, price, orderParams)
2694
+ clientOrderId = self.safe_string(orderRequest, 'clientOrderId')
2695
+ if clientOrderId is None:
2696
+ orderRequest['clientOrderId'] = self.uuid() # both spot and swap endpoints require clientOrderId
2697
+ ordersRequests.append(orderRequest)
2698
+ firstOrder = ordersRequests[0]
2699
+ firstSymbol = self.safe_string(firstOrder, 'symbol')
2700
+ market = self.market(firstSymbol)
2701
+ request: dict = {
2702
+ 'orders': ordersRequests,
2703
+ }
2704
+ response = None
2705
+ if market['spot']:
2706
+ response = await self.privatePostApiV1SpotBatchOrders(self.extend(request, params))
2707
+ #
2708
+ # {
2709
+ # "code": 0,
2710
+ # "result": [
2711
+ # {
2712
+ # "code": "0000",
2713
+ # "order": {
2714
+ # "accountId": "1732885739589466112",
2715
+ # "symbol": "ETHUSDT",
2716
+ # "symbolName": "ETHUSDT",
2717
+ # "clientOrderId": "1722701490163000",
2718
+ # "orderId": "1744540984757258752",
2719
+ # "transactTime": "1722701491385",
2720
+ # "price": "1500",
2721
+ # "origQty": "0.001",
2722
+ # "executedQty": "0",
2723
+ # "status": "NEW",
2724
+ # "timeInForce": "GTC",
2725
+ # "type": "LIMIT",
2726
+ # "side": "BUY",
2727
+ # "reqAmount": "0"
2728
+ # }
2729
+ # }
2730
+ # ],
2731
+ # "concentration": ""
2732
+ # }
2733
+ #
2734
+ elif market['swap']:
2735
+ response = await self.privatePostApiV1FuturesBatchOrders(self.extend(request, params))
2736
+ #
2737
+ # {
2738
+ # "code": "0000",
2739
+ # "result": [
2740
+ # {
2741
+ # "code": "0000",
2742
+ # "order": {
2743
+ # "time": "1722704251911",
2744
+ # "updateTime": "1722704251918",
2745
+ # "orderId": "1744564141727808768",
2746
+ # "clientOrderId": "1722704250648000",
2747
+ # "symbol": "ETHUSDT-PERPETUAL",
2748
+ # "price": "1500",
2749
+ # "leverage": "4",
2750
+ # "origQty": "1",
2751
+ # "executedQty": "0",
2752
+ # "avgPrice": "0",
2753
+ # "marginLocked": "0.375",
2754
+ # "type": "LIMIT",
2755
+ # "side": "BUY_OPEN",
2756
+ # "timeInForce": "GTC",
2757
+ # "status": "NEW",
2758
+ # "priceType": "INPUT",
2759
+ # "isLiquidationOrder": False,
2760
+ # "indexPrice": "0",
2761
+ # "liquidationType": ""
2762
+ # }
2763
+ # },
2764
+ # {
2765
+ # "code": "0207",
2766
+ # "msg": "Create limit order sell price too low"
2767
+ # }
2768
+ # ]
2769
+ # }
2770
+ #
2771
+ else:
2772
+ raise NotSupported(self.id + ' ' + 'createOrderRequest() is not supported for ' + market['type'] + ' type of markets')
2773
+ result = self.safe_list(response, 'result', [])
2774
+ responseOrders = []
2775
+ for i in range(0, len(result)):
2776
+ responseEntry = self.safe_dict(result, i, {})
2777
+ responseOrder = self.safe_dict(responseEntry, 'order', {})
2778
+ responseOrders.append(responseOrder)
2779
+ return self.parse_orders(responseOrders)
2780
+
2781
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
2782
+ """
2783
+ cancels an open order
2784
+
2785
+ https://hashkeyglobal-apidoc.readme.io/reference/cancel-order
2786
+ https://hashkeyglobal-apidoc.readme.io/reference/cancel-futures-order
2787
+
2788
+ :param str id: order id
2789
+ :param str symbol: unified symbol of the market the order was made in
2790
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2791
+ :param str [params.type]: 'spot' or 'swap' - the type of the market to fetch entry for(default 'spot')
2792
+ :param str [params.clientOrderId]: a unique id for the order that can be used alternative for the id
2793
+ :param bool [params.trigger]: *swap markets only* True for canceling a trigger order(default False)
2794
+ :param bool [params.stop]: *swap markets only* an alternative for trigger param
2795
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2796
+ """
2797
+ methodName = 'cancelOrder'
2798
+ self.check_type_param(methodName, params)
2799
+ await self.load_markets()
2800
+ request: dict = {}
2801
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2802
+ if clientOrderId is None:
2803
+ request['orderId'] = id
2804
+ market: Market = None
2805
+ if symbol is not None:
2806
+ market = self.market(symbol)
2807
+ marketType = 'spot'
2808
+ marketType, params = self.handle_market_type_and_params(methodName, market, params, marketType)
2809
+ response = None
2810
+ if marketType == 'spot':
2811
+ response = await self.privateDeleteApiV1SpotOrder(self.extend(request, params))
2812
+ #
2813
+ # {
2814
+ # "accountId": "1732885739589466112",
2815
+ # "symbol": "ETHUSDT",
2816
+ # "clientOrderId": "1722006209978370",
2817
+ # "orderId": "1738708541676585728",
2818
+ # "transactTime": "1722006209989",
2819
+ # "price": "5000",
2820
+ # "origQty": "0.005",
2821
+ # "executedQty": "0",
2822
+ # "status": "NEW",
2823
+ # "timeInForce": "GTC",
2824
+ # "type": "LIMIT_MAKER",
2825
+ # "side": "SELL"
2826
+ # }
2827
+ #
2828
+ elif marketType == 'swap':
2829
+ isTrigger = False
2830
+ isTrigger, params = self.handle_trigger_option_and_params(params, methodName, isTrigger)
2831
+ if isTrigger:
2832
+ request['type'] = 'STOP'
2833
+ else:
2834
+ request['type'] = 'LIMIT'
2835
+ if market is not None:
2836
+ request['symbol'] = market['id']
2837
+ response = await self.privateDeleteApiV1FuturesOrder(self.extend(request, params))
2838
+ #
2839
+ # {
2840
+ # "time": "1722432302919",
2841
+ # "updateTime": "1722432302925",
2842
+ # "orderId": "1742282868229463040",
2843
+ # "clientOrderId": "1722432301670",
2844
+ # "symbol": "ETHUSDT-PERPETUAL",
2845
+ # "price": "4000",
2846
+ # "leverage": "5",
2847
+ # "origQty": "10",
2848
+ # "executedQty": "0",
2849
+ # "avgPrice": "0",
2850
+ # "marginLocked": "0",
2851
+ # "type": "LIMIT_MAKER",
2852
+ # "side": "SELL_CLOSE",
2853
+ # "timeInForce": "GTC",
2854
+ # "status": "NEW",
2855
+ # "priceType": "INPUT",
2856
+ # "isLiquidationOrder": False,
2857
+ # "indexPrice": "0",
2858
+ # "liquidationType": ""
2859
+ # }
2860
+ #
2861
+ else:
2862
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets')
2863
+ return self.parse_order(response)
2864
+
2865
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
2866
+ """
2867
+ cancel all open orders
2868
+
2869
+ https://hashkeyglobal-apidoc.readme.io/reference/cancel-all-open-orders
2870
+ https://hashkeyglobal-apidoc.readme.io/reference/batch-cancel-futures-order
2871
+
2872
+ :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
2873
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2874
+ :param str [params.side]: 'buy' or 'sell'
2875
+ :returns dict: response from exchange
2876
+ """
2877
+ # Does not cancel trigger orders. For canceling trigger order use cancelOrder() or cancelOrders()
2878
+ methodName = 'cancelAllOrders'
2879
+ if symbol is None:
2880
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a symbol argument')
2881
+ await self.load_markets()
2882
+ market = self.market(symbol)
2883
+ request: dict = {
2884
+ 'symbol': market['id'],
2885
+ }
2886
+ side = self.safe_string(params, 'side')
2887
+ if side is not None:
2888
+ request['side'] = side
2889
+ response = None
2890
+ if market['spot']:
2891
+ response = await self.privateDeleteApiV1SpotOpenOrders(self.extend(request, params))
2892
+ #
2893
+ # {"success": True}
2894
+ #
2895
+ elif market['swap']:
2896
+ response = await self.privateDeleteApiV1FuturesBatchOrders(self.extend(request, params))
2897
+ #
2898
+ # {"message": "success", "timestamp": "1723127222198", "code": "0000"}
2899
+ #
2900
+ else:
2901
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + market['type'] + ' type of markets')
2902
+ order = self.safe_order(response)
2903
+ order['info'] = response
2904
+ return [order]
2905
+
2906
+ async def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
2907
+ """
2908
+ cancel multiple orders
2909
+
2910
+ https://hashkeyglobal-apidoc.readme.io/reference/cancel-multiple-orders
2911
+ https://hashkeyglobal-apidoc.readme.io/reference/batch-cancel-futures-order-by-order-id
2912
+
2913
+ :param str[] ids: order ids
2914
+ :param str [symbol]: unified market symbol(not used by hashkey)
2915
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2916
+ :param str [params.type]: 'spot' or 'swap' - the type of the market to fetch entry for(default 'spot')
2917
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2918
+ """
2919
+ methodName = 'cancelOrders'
2920
+ await self.load_markets()
2921
+ request = {}
2922
+ orderIds = ','.join(ids)
2923
+ request['ids'] = orderIds
2924
+ market: Market = None
2925
+ if symbol is not None:
2926
+ market = self.market(symbol)
2927
+ marketType = 'spot'
2928
+ marketType, params = self.handle_market_type_and_params(methodName, market, params, marketType)
2929
+ response = None
2930
+ if marketType == 'spot':
2931
+ response = await self.privateDeleteApiV1SpotCancelOrderByIds(self.extend(request))
2932
+ #
2933
+ # {
2934
+ # "code": "0000",
2935
+ # "result": []
2936
+ # }
2937
+ #
2938
+ elif marketType == 'swap':
2939
+ response = self.privateDeleteApiV1FuturesCancelOrderByIds(self.extend(request))
2940
+ else:
2941
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets')
2942
+ order = self.safe_order(response)
2943
+ order['info'] = response
2944
+ return [order]
2945
+
2946
+ async def fetch_order(self, id: str, symbol: Str = None, params={}) -> Order:
2947
+ """
2948
+ fetches information on an order made by the user
2949
+
2950
+ https://hashkeyglobal-apidoc.readme.io/reference/query-order
2951
+ https://hashkeyglobal-apidoc.readme.io/reference/get-futures-order
2952
+
2953
+ :param str id: the order id
2954
+ :param str symbol: unified symbol of the market the order was made in
2955
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2956
+ :param str [params.type]: 'spot' or 'swap' - the type of the market to fetch entry for(default 'spot')
2957
+ :param str [params.clientOrderId]: a unique id for the order that can be used alternative for the id
2958
+ :param str [params.accountId]: *spot markets only* account id to fetch the order from
2959
+ :param bool [params.trigger]: *swap markets only* True for fetching a trigger order(default False)
2960
+ :param bool [params.stop]: *swap markets only* an alternative for trigger param
2961
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2962
+ """
2963
+ methodName = 'fetchOrder'
2964
+ self.check_type_param(methodName, params)
2965
+ await self.load_markets()
2966
+ request: dict = {}
2967
+ clientOrderId: Str = None
2968
+ clientOrderId, params = self.handle_param_string(params, 'clientOrderId')
2969
+ if clientOrderId is None:
2970
+ request['orderId'] = id
2971
+ market: Market = None
2972
+ if symbol is not None:
2973
+ market = self.market(symbol)
2974
+ marketType = 'spot'
2975
+ marketType, params = self.handle_market_type_and_params(methodName, market, params, marketType)
2976
+ response = None
2977
+ if marketType == 'spot':
2978
+ if clientOrderId is not None:
2979
+ request['origClientOrderId'] = clientOrderId
2980
+ response = await self.privateGetApiV1SpotOrder(self.extend(request, params))
2981
+ #
2982
+ # {
2983
+ # "accountId": "1732885739589466112",
2984
+ # "exchangeId": "301",
2985
+ # "symbol": "ETHUSDT",
2986
+ # "symbolName": "ETHUSDT",
2987
+ # "clientOrderId": "1722004623170558",
2988
+ # "orderId": "1738695230608169984",
2989
+ # "price": "0",
2990
+ # "origQty": "0",
2991
+ # "executedQty": "0.0061",
2992
+ # "cummulativeQuoteQty": "19.736489",
2993
+ # "cumulativeQuoteQty": "19.736489",
2994
+ # "avgPrice": "3235.49",
2995
+ # "status": "FILLED",
2996
+ # "timeInForce": "IOC",
2997
+ # "type": "MARKET",
2998
+ # "side": "BUY",
2999
+ # "stopPrice": "0.0",
3000
+ # "icebergQty": "0.0",
3001
+ # "time": "1722004623186",
3002
+ # "updateTime": "1722004623406",
3003
+ # "isWorking": True,
3004
+ # "reqAmount": "20",
3005
+ # "feeCoin": "",
3006
+ # "feeAmount": "0",
3007
+ # "sumFeeAmount": "0"
3008
+ # }
3009
+ #
3010
+ elif marketType == 'swap':
3011
+ isTrigger = False
3012
+ isTrigger, params = self.handle_trigger_option_and_params(params, methodName, isTrigger)
3013
+ if isTrigger:
3014
+ request['type'] = 'STOP'
3015
+ response = await self.privateGetApiV1FuturesOrder(self.extend(request, params))
3016
+ #
3017
+ # {
3018
+ # "time": "1722429951611",
3019
+ # "updateTime": "1722429951700",
3020
+ # "orderId": "1742263144028363776",
3021
+ # "clientOrderId": "1722429950315",
3022
+ # "symbol": "ETHUSDT-PERPETUAL",
3023
+ # "price": "3460.62",
3024
+ # "leverage": "5",
3025
+ # "origQty": "10",
3026
+ # "executedQty": "10",
3027
+ # "avgPrice": "3327.52",
3028
+ # "marginLocked": "0",
3029
+ # "type": "LIMIT",
3030
+ # "side": "BUY_OPEN",
3031
+ # "timeInForce": "IOC",
3032
+ # "status": "FILLED",
3033
+ # "priceType": "MARKET",
3034
+ # "isLiquidationOrder": False,
3035
+ # "indexPrice": "0",
3036
+ # "liquidationType": ""
3037
+ # }
3038
+ #
3039
+ else:
3040
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets')
3041
+ return self.parse_order(response)
3042
+
3043
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
3044
+ """
3045
+ fetch all unfilled currently open orders
3046
+
3047
+ https://hashkeyglobal-apidoc.readme.io/reference/get-current-open-orders
3048
+ https://hashkeyglobal-apidoc.readme.io/reference/get-sub-account-open-orders
3049
+ https://hashkeyglobal-apidoc.readme.io/reference/sub
3050
+ https://hashkeyglobal-apidoc.readme.io/reference/query-open-futures-orders
3051
+
3052
+ :param str [symbol]: unified market symbol of the market orders were made in - is mandatory for swap markets
3053
+ :param int [since]: the earliest time in ms to fetch orders for
3054
+ :param int [limit]: the maximum number of order structures to retrieve - default 500, maximum 1000
3055
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3056
+ :param str [params.type]: 'spot' or 'swap' - the type of the market to fetch entries for(default 'spot')
3057
+ :param str [params.orderId]: *spot markets only* the id of the order to fetch
3058
+ :param str [params.side]: *spot markets only* 'buy' or 'sell' - the side of the orders to fetch
3059
+ :param str [params.fromOrderId]: *swap markets only* the id of the order to start from
3060
+ :param bool [params.trigger]: *swap markets only* True for fetching trigger orders(default False)
3061
+ :param bool [params.stop]: *swap markets only* an alternative for trigger param
3062
+ :param str [params.accountId]: account id to fetch the orders from
3063
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3064
+ """
3065
+ methodName = 'fetchOpenOrders'
3066
+ self.check_type_param(methodName, params)
3067
+ await self.load_markets()
3068
+ market: Market = None
3069
+ if symbol is not None:
3070
+ market = self.market(symbol)
3071
+ marketType = 'spot'
3072
+ marketType, params = self.handle_market_type_and_params(methodName, market, params, marketType)
3073
+ params = self.extend({'methodName': methodName}, params)
3074
+ if marketType == 'spot':
3075
+ return await self.fetch_open_spot_orders(symbol, since, limit, params)
3076
+ elif marketType == 'swap':
3077
+ return await self.fetch_open_swap_orders(symbol, since, limit, params)
3078
+ else:
3079
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets')
3080
+
3081
+ async def fetch_open_spot_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
3082
+ """
3083
+ @ignore
3084
+ fetch all unfilled currently open orders for spot markets
3085
+
3086
+ https://hashkeyglobal-apidoc.readme.io/reference/get-current-open-orders
3087
+ https://hashkeyglobal-apidoc.readme.io/reference/sub
3088
+
3089
+ :param str [symbol]: unified market symbol of the market orders were made in
3090
+ :param int [since]: the earliest time in ms to fetch orders for
3091
+ :param int [limit]: the maximum number of order structures to retrieve - default 500, maximum 1000
3092
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3093
+ :param str [params.orderId]: the id of the order to fetch
3094
+ :param str [params.side]: 'buy' or 'sell' - the side of the orders to fetch
3095
+ :param str [params.accountId]: account id to fetch the orders from
3096
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3097
+ """
3098
+ await self.load_markets()
3099
+ methodName = 'fetchOpenSpotOrders'
3100
+ methodName, params = self.handle_param_string(params, 'methodName', methodName)
3101
+ market: Market = None
3102
+ request: dict = {}
3103
+ response = None
3104
+ accountId: Str = None
3105
+ accountId, params = self.handle_option_and_params(params, methodName, 'accountId')
3106
+ if accountId is not None:
3107
+ request['subAccountId'] = accountId
3108
+ response = await self.privateGetApiV1SpotSubAccountOpenOrders(self.extend(request, params))
3109
+ else:
3110
+ if symbol is not None:
3111
+ market = self.market(symbol)
3112
+ request['symbol'] = market['id']
3113
+ if limit is not None:
3114
+ request['limit'] = limit
3115
+ response = await self.privateGetApiV1SpotOpenOrders(self.extend(request, params))
3116
+ #
3117
+ # [
3118
+ # {
3119
+ # "accountId": "1732885739589466112",
3120
+ # "exchangeId": "301",
3121
+ # "symbol": "ETHUSDT",
3122
+ # "symbolName": "ETHUSDT",
3123
+ # "clientOrderId": "1",
3124
+ # "orderId": "1739491435386897152",
3125
+ # "price": "2000",
3126
+ # "origQty": "0.001",
3127
+ # "executedQty": "0",
3128
+ # "cummulativeQuoteQty": "0",
3129
+ # "cumulativeQuoteQty": "0",
3130
+ # "avgPrice": "0",
3131
+ # "status": "NEW",
3132
+ # "timeInForce": "GTC",
3133
+ # "type": "LIMIT",
3134
+ # "side": "BUY",
3135
+ # "stopPrice": "0.0",
3136
+ # "icebergQty": "0.0",
3137
+ # "time": "1722099538193",
3138
+ # "updateTime": "1722099538197",
3139
+ # "isWorking": True,
3140
+ # "reqAmount": "0"
3141
+ # }
3142
+ # ]
3143
+ #
3144
+ return self.parse_orders(response, market, since, limit)
3145
+
3146
+ async def fetch_open_swap_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
3147
+ """
3148
+ @ignore
3149
+ fetch all unfilled currently open orders for swap markets
3150
+
3151
+ https://hashkeyglobal-apidoc.readme.io/reference/query-open-futures-orders
3152
+ https://hashkeyglobal-apidoc.readme.io/reference/get-sub-account-open-orders
3153
+
3154
+ :param str symbol: *is mandatory* unified market symbol of the market orders were made in
3155
+ :param int [since]: the earliest time in ms to fetch orders for
3156
+ :param int [limit]: the maximum number of order structures to retrieve - maximum 500
3157
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3158
+ :param str [params.fromOrderId]: the id of the order to start from
3159
+ :param bool [params.trigger]: True for fetching trigger orders(default False)
3160
+ :param bool [params.stop]: an alternative for trigger param
3161
+ :param str [params.accountId]: account id to fetch the orders from
3162
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3163
+ """
3164
+ methodName = 'fetchOpenSwapOrders'
3165
+ methodName, params = self.handle_param_string(params, 'methodName', methodName)
3166
+ if symbol is None:
3167
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a symbol argument for swap market orders')
3168
+ market = self.market(symbol)
3169
+ request: dict = {
3170
+ 'symbol': market['id'],
3171
+ }
3172
+ isTrigger = False
3173
+ isTrigger, params = self.handle_trigger_option_and_params(params, methodName, isTrigger)
3174
+ if isTrigger:
3175
+ request['type'] = 'STOP'
3176
+ else:
3177
+ request['type'] = 'LIMIT'
3178
+ if limit is not None:
3179
+ request['limit'] = limit
3180
+ response = None
3181
+ accountId: Str = None
3182
+ accountId, params = self.handle_option_and_params(params, methodName, 'accountId')
3183
+ if accountId is not None:
3184
+ request['subAccountId'] = accountId
3185
+ response = await self.privateGetApiV1FuturesSubAccountOpenOrders(self.extend(request, params))
3186
+ else:
3187
+ response = await self.privateGetApiV1FuturesOpenOrders(self.extend(request, params))
3188
+ # 'LIMIT'
3189
+ # [
3190
+ # {
3191
+ # "time": "1722432302919",
3192
+ # "updateTime": "1722432302925",
3193
+ # "orderId": "1742282868229463040",
3194
+ # "clientOrderId": "1722432301670",
3195
+ # "symbol": "ETHUSDT-PERPETUAL",
3196
+ # "price": "4000",
3197
+ # "leverage": "5",
3198
+ # "origQty": "10",
3199
+ # "executedQty": "0",
3200
+ # "avgPrice": "0",
3201
+ # "marginLocked": "0",
3202
+ # "type": "LIMIT_MAKER",
3203
+ # "side": "SELL_CLOSE",
3204
+ # "timeInForce": "GTC",
3205
+ # "status": "NEW",
3206
+ # "priceType": "INPUT",
3207
+ # "isLiquidationOrder": False,
3208
+ # "indexPrice": "0",
3209
+ # "liquidationType": ""
3210
+ # }
3211
+ # ]
3212
+ #
3213
+ # 'STOP'
3214
+ # [
3215
+ # {
3216
+ # "time": "1722433095688",
3217
+ # "updateTime": "1722433095688",
3218
+ # "orderId": "1742289518466225664",
3219
+ # "accountId": "1735619524953226496",
3220
+ # "clientOrderId": "1722433094438",
3221
+ # "symbol": "ETHUSDT-PERPETUAL",
3222
+ # "price": "3700",
3223
+ # "leverage": "0",
3224
+ # "origQty": "10",
3225
+ # "type": "STOP",
3226
+ # "side": "SELL_CLOSE",
3227
+ # "status": "ORDER_NEW",
3228
+ # "stopPrice": "3600"
3229
+ # }
3230
+ # ]
3231
+ return self.parse_orders(response, market, since, limit)
3232
+
3233
+ async def fetch_canceled_and_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
3234
+ """
3235
+ fetches information on multiple canceled and closed orders made by the user
3236
+
3237
+ https://hashkeyglobal-apidoc.readme.io/reference/get-all-orders
3238
+ https://hashkeyglobal-apidoc.readme.io/reference/query-futures-history-orders
3239
+ https://hashkeyglobal-apidoc.readme.io/reference/get-sub-account-history-orders
3240
+
3241
+ :param str symbol: *is mandatory for swap markets* unified market symbol of the market orders were made in
3242
+ :param int [since]: the earliest time in ms to fetch orders for
3243
+ :param int [limit]: the maximum number of order structures to retrieve - default 500, maximum 1000
3244
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3245
+ :param int [params.until]: the latest time in ms to fetch entries for - only supports the last 90 days timeframe
3246
+ :param str [params.type]: 'spot' or 'swap' - the type of the market to fetch entries for(default 'spot')
3247
+ :param str [params.orderId]: *spot markets only* the id of the order to fetch
3248
+ :param str [params.side]: *spot markets only* 'buy' or 'sell' - the side of the orders to fetch
3249
+ :param str [params.fromOrderId]: *swap markets only* the id of the order to start from
3250
+ :param bool [params.trigger]: *swap markets only* the id of the order to start from True for fetching trigger orders(default False)
3251
+ :param bool [params.stop]: *swap markets only* the id of the order to start from an alternative for trigger param
3252
+ :param str [params.accountId]: account id to fetch the orders from
3253
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
3254
+ """
3255
+ methodName = 'fetchCanceledAndClosedOrders'
3256
+ self.check_type_param(methodName, params)
3257
+ await self.load_markets()
3258
+ request: dict = {}
3259
+ if limit is not None:
3260
+ request['limit'] = limit
3261
+ if since is not None:
3262
+ request['startTime'] = since
3263
+ until: Int = None
3264
+ until, params = self.handle_option_and_params(params, methodName, 'until')
3265
+ if until is not None:
3266
+ request['endTime'] = until
3267
+ accountId: Str = None
3268
+ accountId, params = self.handle_option_and_params(params, methodName, 'accountId')
3269
+ market: Market = None
3270
+ if symbol is not None:
3271
+ market = self.market(symbol)
3272
+ marketType = 'spot'
3273
+ marketType, params = self.handle_market_type_and_params(methodName, market, params, marketType)
3274
+ response = None
3275
+ if marketType == 'spot':
3276
+ if market is not None:
3277
+ request['symbol'] = market['id']
3278
+ if accountId is not None:
3279
+ request['accountId'] = accountId
3280
+ response = await self.privateGetApiV1SpotTradeOrders(self.extend(request, params))
3281
+ #
3282
+ # [
3283
+ # {
3284
+ # "accountId": "1732885739589466112",
3285
+ # "exchangeId": "301",
3286
+ # "symbol": "ETHUSDT",
3287
+ # "symbolName": "ETHUSDT",
3288
+ # "clientOrderId": "1722082982086472",
3289
+ # "orderId": "1739352552762301440",
3290
+ # "price": "0",
3291
+ # "origQty": "0.001",
3292
+ # "executedQty": "0.001",
3293
+ # "cummulativeQuoteQty": "3.28996",
3294
+ # "cumulativeQuoteQty": "3.28996",
3295
+ # "avgPrice": "3289.96",
3296
+ # "status": "FILLED",
3297
+ # "timeInForce": "IOC",
3298
+ # "type": "MARKET",
3299
+ # "side": "BUY",
3300
+ # "stopPrice": "0.0",
3301
+ # "icebergQty": "0.0",
3302
+ # "time": "1722082982093",
3303
+ # "updateTime": "1722082982097",
3304
+ # "isWorking": True,
3305
+ # "reqAmount": "0"
3306
+ # },
3307
+ # ...
3308
+ # ]
3309
+ #
3310
+ elif marketType == 'swap':
3311
+ if symbol is None:
3312
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a symbol argument for swap markets')
3313
+ request['symbol'] = market['id']
3314
+ isTrigger = False
3315
+ isTrigger, params = self.handle_trigger_option_and_params(params, methodName, isTrigger)
3316
+ if isTrigger:
3317
+ request['type'] = 'STOP'
3318
+ else:
3319
+ request['type'] = 'LIMIT'
3320
+ if accountId is not None:
3321
+ request['subAccountId'] = accountId
3322
+ response = await self.privateGetApiV1FuturesSubAccountHistoryOrders(self.extend(request, params))
3323
+ else:
3324
+ response = await self.privateGetApiV1FuturesHistoryOrders(self.extend(request, params))
3325
+ #
3326
+ # [
3327
+ # {
3328
+ # "time": "1722429951611",
3329
+ # "updateTime": "1722429951700",
3330
+ # "orderId": "1742263144028363776",
3331
+ # "clientOrderId": "1722429950315",
3332
+ # "symbol": "ETHUSDT-PERPETUAL",
3333
+ # "price": "3460.62",
3334
+ # "leverage": "5",
3335
+ # "origQty": "10",
3336
+ # "executedQty": "10",
3337
+ # "avgPrice": "3327.52",
3338
+ # "marginLocked": "0",
3339
+ # "type": "LIMIT",
3340
+ # "side": "BUY_OPEN",
3341
+ # "timeInForce": "IOC",
3342
+ # "status": "FILLED",
3343
+ # "priceType": "MARKET",
3344
+ # "isLiquidationOrder": False,
3345
+ # "indexPrice": "0",
3346
+ # "liquidationType": ""
3347
+ # }
3348
+ # ]
3349
+ #
3350
+ else:
3351
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + marketType + ' type of markets')
3352
+ return self.parse_orders(response, market, since, limit)
3353
+
3354
+ def check_type_param(self, methodName, params):
3355
+ # some hashkey endpoints have a type param for swap markets that defines the type of an order
3356
+ # type param is reserved in ccxt for defining the type of the market
3357
+ # current method warns user if he provides the exchange specific value in type parameter
3358
+ paramsType = self.safe_string(params, 'type')
3359
+ if (paramsType is not None) and (paramsType != 'spot') and (paramsType != 'swap'):
3360
+ raise BadRequest(self.id + ' ' + methodName + '() type parameter can not be "' + paramsType + '". It should define the type of the market("spot" or "swap"). To define the type of an order use the trigger parameter(True for trigger orders)')
3361
+
3362
+ def handle_trigger_option_and_params(self, params: object, methodName: str, defaultValue=None):
3363
+ isTrigger = defaultValue
3364
+ isTrigger, params = self.handle_option_and_params_2(params, methodName, 'stop', 'trigger', isTrigger)
3365
+ return [isTrigger, params]
3366
+
3367
+ def parse_order(self, order: dict, market: Market = None) -> Order:
3368
+ #
3369
+ # createOrder spot
3370
+ # {
3371
+ # "accountId": "1732885739589466112",
3372
+ # "symbol": "ETHUSDT",
3373
+ # "symbolName": "ETHUSDT",
3374
+ # "clientOrderId": "1722004623170558",
3375
+ # "orderId": "1738695230608169984",
3376
+ # "transactTime": "1722004623186",
3377
+ # "price": "0",
3378
+ # "origQty": "0",
3379
+ # "executedQty": "0.0061",
3380
+ # "status": "FILLED",
3381
+ # "timeInForce": "IOC",
3382
+ # "type": "MARKET",
3383
+ # "side": "BUY",
3384
+ # "reqAmount": "20",
3385
+ # "concentration": ""
3386
+ # }
3387
+ #
3388
+ # fetchOrder spot
3389
+ # {
3390
+ # "accountId": "1732885739589466112",
3391
+ # "exchangeId": "301",
3392
+ # "symbol": "ETHUSDT",
3393
+ # "symbolName": "ETHUSDT",
3394
+ # "clientOrderId": "1722004623170558",
3395
+ # "orderId": "1738695230608169984",
3396
+ # "price": "0",
3397
+ # "origQty": "0",
3398
+ # "executedQty": "0.0061",
3399
+ # "cummulativeQuoteQty": "19.736489",
3400
+ # "cumulativeQuoteQty": "19.736489",
3401
+ # "avgPrice": "3235.49",
3402
+ # "status": "FILLED",
3403
+ # "timeInForce": "IOC",
3404
+ # "type": "MARKET",
3405
+ # "side": "BUY",
3406
+ # "stopPrice": "0.0",
3407
+ # "icebergQty": "0.0",
3408
+ # "time": "1722004623186",
3409
+ # "updateTime": "1722004623406",
3410
+ # "isWorking": True,
3411
+ # "reqAmount": "20",
3412
+ # "feeCoin": "",
3413
+ # "feeAmount": "0",
3414
+ # "sumFeeAmount": "0"
3415
+ # }
3416
+ #
3417
+ # cancelOrder
3418
+ # {
3419
+ # "accountId": "1732885739589466112",
3420
+ # "symbol": "ETHUSDT",
3421
+ # "clientOrderId": "1722006209978370",
3422
+ # "orderId": "1738708541676585728",
3423
+ # "transactTime": "1722006209989",
3424
+ # "price": "5000",
3425
+ # "origQty": "0.005",
3426
+ # "executedQty": "0",
3427
+ # "status": "NEW",
3428
+ # "timeInForce": "GTC",
3429
+ # "type": "LIMIT_MAKER",
3430
+ # "side": "SELL"
3431
+ # }
3432
+ #
3433
+ # createOrder swap
3434
+ # {
3435
+ # "time": "1722429951611",
3436
+ # "updateTime": "1722429951648",
3437
+ # "orderId": "1742263144028363776",
3438
+ # "clientOrderId": "1722429950315",
3439
+ # "symbol": "ETHUSDT-PERPETUAL",
3440
+ # "price": "3460.62",
3441
+ # "leverage": "5",
3442
+ # "origQty": "10",
3443
+ # "executedQty": "10",
3444
+ # "avgPrice": "0",
3445
+ # "marginLocked": "6.9212",
3446
+ # "type": "LIMIT",
3447
+ # "side": "BUY_OPEN",
3448
+ # "timeInForce": "IOC",
3449
+ # "status": "FILLED",
3450
+ # "priceType": "MARKET",
3451
+ # "contractMultiplier": "0.00100000"
3452
+ # }
3453
+ #
3454
+ # fetchOrder swap
3455
+ # {
3456
+ # "time": "1722429951611",
3457
+ # "updateTime": "1722429951700",
3458
+ # "orderId": "1742263144028363776",
3459
+ # "clientOrderId": "1722429950315",
3460
+ # "symbol": "ETHUSDT-PERPETUAL",
3461
+ # "price": "3460.62",
3462
+ # "leverage": "5",
3463
+ # "origQty": "10",
3464
+ # "executedQty": "10",
3465
+ # "avgPrice": "3327.52",
3466
+ # "marginLocked": "0",
3467
+ # "type": "LIMIT",
3468
+ # "side": "BUY_OPEN",
3469
+ # "timeInForce": "IOC",
3470
+ # "status": "FILLED",
3471
+ # "priceType": "MARKET",
3472
+ # "isLiquidationOrder": False,
3473
+ # "indexPrice": "0",
3474
+ # "liquidationType": ""
3475
+ # }
3476
+ #
3477
+ marketId = self.safe_string(order, 'symbol')
3478
+ market = self.safe_market(marketId, market)
3479
+ timestamp = self.safe_integer_2(order, 'transactTime', 'time')
3480
+ status = self.safe_string(order, 'status')
3481
+ type = self.safe_string(order, 'type')
3482
+ priceType = self.safe_string(order, 'priceType')
3483
+ if priceType == 'MARKET':
3484
+ type = 'market'
3485
+ price = self.omit_zero(self.safe_string(order, 'price'))
3486
+ if type == 'STOP':
3487
+ if price is None:
3488
+ type = 'market'
3489
+ else:
3490
+ type = 'limit'
3491
+ timeInForce = self.safe_string(order, 'timeInForce')
3492
+ postOnly: Bool = None
3493
+ type, timeInForce, postOnly = self.parse_order_type_time_in_force_and_post_only(type, timeInForce)
3494
+ average = self.omit_zero(self.safe_string(order, 'avgPrice'))
3495
+ if price is None:
3496
+ price = average
3497
+ side = self.safe_string_lower(order, 'side')
3498
+ reduceOnly: Bool = None
3499
+ side, reduceOnly = self.parse_order_side_and_reduce_only(side)
3500
+ feeCurrncyId = self.safe_string(order, 'feeCoin')
3501
+ if feeCurrncyId == '':
3502
+ feeCurrncyId = None
3503
+ return self.safe_order({
3504
+ 'id': self.safe_string(order, 'orderId'),
3505
+ 'clientOrderId': self.safe_string(order, 'clientOrderId'),
3506
+ 'datetime': self.iso8601(timestamp),
3507
+ 'timestamp': timestamp,
3508
+ 'lastTradeTimestamp': None,
3509
+ 'lastUpdateTimestamp': self.safe_integer(order, 'updateTime'),
3510
+ 'status': self.parse_order_status(status),
3511
+ 'symbol': market['symbol'],
3512
+ 'type': type,
3513
+ 'timeInForce': timeInForce,
3514
+ 'side': side,
3515
+ 'price': price,
3516
+ 'average': average,
3517
+ 'amount': self.omit_zero(self.safe_string(order, 'origQty')),
3518
+ 'filled': self.safe_string(order, 'executedQty'),
3519
+ 'remaining': None,
3520
+ 'triggerPrice': self.omit_zero(self.safe_string(order, 'stopPrice')),
3521
+ 'takeProfitPrice': None,
3522
+ 'stopLossPrice': None,
3523
+ 'cost': self.omit_zero(self.safe_string_2(order, 'cumulativeQuoteQty', 'cummulativeQuoteQty')),
3524
+ 'trades': None,
3525
+ 'fee': {
3526
+ 'currency': self.safe_currency_code(feeCurrncyId),
3527
+ 'amount': self.omit_zero(self.safe_string(order, 'feeAmount')),
3528
+ },
3529
+ 'reduceOnly': reduceOnly,
3530
+ 'postOnly': postOnly,
3531
+ 'info': order,
3532
+ }, market)
3533
+
3534
+ def parse_order_side_and_reduce_only(self, unparsed):
3535
+ parts = unparsed.split('_')
3536
+ side = parts[0]
3537
+ reduceOnly: Bool = None
3538
+ secondPart = self.safe_string(parts, 1)
3539
+ if secondPart is not None:
3540
+ if secondPart == 'open':
3541
+ reduceOnly = False
3542
+ elif (secondPart == 'close'):
3543
+ reduceOnly = True
3544
+ return [side, reduceOnly]
3545
+
3546
+ def parse_order_status(self, status):
3547
+ statuses = {
3548
+ 'NEW': 'open',
3549
+ 'PARTIALLY_FILLED': 'open',
3550
+ 'PARTIALLY_CANCELED': 'canceled',
3551
+ 'FILLED': 'closed',
3552
+ 'CANCELED': 'canceled',
3553
+ 'ORDER_CANCELED': 'canceled',
3554
+ 'PENDING_CANCEL': 'canceled',
3555
+ 'REJECTED': 'rejected',
3556
+ 'ORDER_NEW': 'open',
3557
+ }
3558
+ return self.safe_string(statuses, status, status)
3559
+
3560
+ def parse_order_type_time_in_force_and_post_only(self, type, timeInForce):
3561
+ postOnly: Bool = None
3562
+ if type == 'LIMIT_MAKER':
3563
+ postOnly = True
3564
+ elif (timeInForce == 'LIMIT_MAKER') or (timeInForce == 'MAKER'):
3565
+ postOnly = True
3566
+ timeInForce = 'PO'
3567
+ type = self.parse_order_type(type)
3568
+ return [type, timeInForce, postOnly]
3569
+
3570
+ def parse_order_type(self, type):
3571
+ types = {
3572
+ 'MARKET': 'market',
3573
+ 'LIMIT': 'limit',
3574
+ 'LIMIT_MAKER': 'limit',
3575
+ 'MARKET_OF_BASE': 'market',
3576
+ }
3577
+ return self.safe_string(types, type, type)
3578
+
3579
+ async def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
3580
+ """
3581
+ fetch the current funding rate
3582
+
3583
+ https://hashkeyglobal-apidoc.readme.io/reference/get-futures-funding-rate
3584
+
3585
+ :param str symbol: unified market symbol
3586
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3587
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
3588
+ """
3589
+ await self.load_markets()
3590
+ market = self.market(symbol)
3591
+ request: dict = {
3592
+ 'symbol': market['id'],
3593
+ 'timestamp': self.milliseconds(),
3594
+ }
3595
+ response = await self.publicGetApiV1FuturesFundingRate(self.extend(request, params))
3596
+ #
3597
+ # [
3598
+ # {"symbol": "ETHUSDT-PERPETUAL", "rate": "0.0001", "nextSettleTime": "1722297600000"}
3599
+ # ]
3600
+ #
3601
+ rate = self.safe_dict(response, 0, {})
3602
+ return self.parse_funding_rate(rate, market)
3603
+
3604
+ async def fetch_funding_rates(self, symbols: Strings = None, params={}) -> FundingRates:
3605
+ """
3606
+ fetch the funding rate for multiple markets
3607
+
3608
+ https://hashkeyglobal-apidoc.readme.io/reference/get-futures-funding-rate
3609
+
3610
+ :param str[]|None symbols: list of unified market symbols
3611
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3612
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexed by market symbols
3613
+ """
3614
+ await self.load_markets()
3615
+ symbols = self.market_symbols(symbols)
3616
+ request: dict = {
3617
+ 'timestamp': self.milliseconds(),
3618
+ }
3619
+ response = await self.publicGetApiV1FuturesFundingRate(self.extend(request, params))
3620
+ #
3621
+ # [
3622
+ # {"symbol": "BTCUSDT-PERPETUAL", "rate": "0.0001", "nextSettleTime": "1722297600000"},
3623
+ # {"symbol": "ETHUSDT-PERPETUAL", "rate": "0.0001", "nextSettleTime": "1722297600000"}
3624
+ # ]
3625
+ #
3626
+ return self.parse_funding_rates(response, symbols)
3627
+
3628
+ def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
3629
+ #
3630
+ # {
3631
+ # "symbol": "ETHUSDT-PERPETUAL",
3632
+ # "rate": "0.0001",
3633
+ # "nextSettleTime": "1722297600000"
3634
+ # }
3635
+ #
3636
+ marketId = self.safe_string(contract, 'symbol')
3637
+ market = self.safe_market(marketId, market, None, 'swap')
3638
+ fundingRate = self.safe_number(contract, 'rate')
3639
+ fundingTimestamp = self.safe_integer(contract, 'nextSettleTime')
3640
+ return {
3641
+ 'info': contract,
3642
+ 'symbol': market['symbol'],
3643
+ 'markPrice': None,
3644
+ 'indexPrice': None,
3645
+ 'interestRate': None,
3646
+ 'estimatedSettlePrice': None,
3647
+ 'timestamp': None,
3648
+ 'datetime': None,
3649
+ 'fundingRate': fundingRate,
3650
+ 'fundingTimestamp': None,
3651
+ 'fundingDatetime': None,
3652
+ 'nextFundingRate': None,
3653
+ 'nextFundingTimestamp': fundingTimestamp,
3654
+ 'nextFundingDatetime': self.iso8601(fundingTimestamp),
3655
+ 'previousFundingRate': None,
3656
+ 'previousFundingTimestamp': None,
3657
+ 'previousFundingDatetime': None,
3658
+ 'interval': None,
3659
+ }
3660
+
3661
+ async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3662
+ """
3663
+ fetches historical funding rate prices
3664
+
3665
+ https://hashkeyglobal-apidoc.readme.io/reference/get-futures-history-funding-rate
3666
+
3667
+ :param str symbol: unified symbol of the market to fetch the funding rate history for
3668
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
3669
+ :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
3670
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3671
+ :param int [params.fromId]: the id of the entry to start from
3672
+ :param int [params.endId]: the id of the entry to end with
3673
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
3674
+ """
3675
+ await self.load_markets()
3676
+ if symbol is None:
3677
+ raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
3678
+ market = self.market(symbol)
3679
+ request: dict = {
3680
+ 'symbol': market['id'],
3681
+ }
3682
+ if limit is not None:
3683
+ request['limit'] = limit
3684
+ response = await self.publicGetApiV1FuturesHistoryFundingRate(self.extend(request, params))
3685
+ #
3686
+ # [
3687
+ # {
3688
+ # "id": "10698",
3689
+ # "symbol": "ETHUSDT-PERPETUAL",
3690
+ # "settleTime": "1722268800000",
3691
+ # "settleRate": "0.0001"
3692
+ # },
3693
+ # ...
3694
+ # ]
3695
+ #
3696
+ rates = []
3697
+ for i in range(0, len(response)):
3698
+ entry = response[i]
3699
+ timestamp = self.safe_integer(entry, 'settleTime')
3700
+ rates.append({
3701
+ 'info': entry,
3702
+ 'symbol': self.safe_symbol(self.safe_string(entry, 'symbol'), market, None, 'swap'),
3703
+ 'fundingRate': self.safe_number(entry, 'settleRate'),
3704
+ 'timestamp': timestamp,
3705
+ 'datetime': self.iso8601(timestamp),
3706
+ })
3707
+ sorted = self.sort_by(rates, 'timestamp')
3708
+ return self.filter_by_since_limit(sorted, since, limit)
3709
+
3710
+ async def fetch_positions(self, symbols: Strings = None, params={}) -> List[Position]:
3711
+ """
3712
+ fetch open positions for a market
3713
+
3714
+ https://hashkeyglobal-apidoc.readme.io/reference/get-futures-positions
3715
+
3716
+ fetch all open positions
3717
+ :param str[]|None symbols: list of unified market symbols
3718
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3719
+ :param str [params.side]: 'LONG' or 'SHORT' - the direction of the position(if not provided, positions for both sides will be returned)
3720
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
3721
+ """
3722
+ methodName = 'fetchPositions'
3723
+ if (symbols is None):
3724
+ raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a symbol argument with one single market symbol')
3725
+ else:
3726
+ symbolsLength = len(symbols)
3727
+ if symbolsLength != 1:
3728
+ raise NotSupported(self.id + ' ' + methodName + '() is supported for a symbol argument with one single market symbol only')
3729
+ await self.load_markets()
3730
+ return await self.fetch_positions_for_symbol(symbols[0], self.extend({'methodName': 'fetchPositions'}, params))
3731
+
3732
+ async def fetch_positions_for_symbol(self, symbol: str, params={}) -> List[Position]:
3733
+ """
3734
+ fetch open positions for a single market
3735
+
3736
+ https://hashkeyglobal-apidoc.readme.io/reference/get-futures-positions
3737
+
3738
+ fetch all open positions for specific symbol
3739
+ :param str symbol: unified market symbol
3740
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3741
+ :param str [params.side]: 'LONG' or 'SHORT' - the direction of the position(if not provided, positions for both sides will be returned)
3742
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
3743
+ """
3744
+ await self.load_markets()
3745
+ market = self.market(symbol)
3746
+ methodName = 'fetchPosition'
3747
+ methodName, params = self.handle_param_string(params, 'methodName', methodName)
3748
+ if not market['swap']:
3749
+ raise NotSupported(self.id + ' ' + methodName + '() supports swap markets only')
3750
+ request: dict = {
3751
+ 'symbol': market['id'],
3752
+ }
3753
+ response = await self.privateGetApiV1FuturesPositions(self.extend(request, params))
3754
+ #
3755
+ # [
3756
+ # {
3757
+ # "symbol": "ETHUSDT-PERPETUAL",
3758
+ # "side": "LONG",
3759
+ # "avgPrice": "3327.52",
3760
+ # "position": "10",
3761
+ # "available": "0",
3762
+ # "leverage": "5",
3763
+ # "lastPrice": "3324.44",
3764
+ # "positionValue": "33.2752",
3765
+ # "liquidationPrice": "-953.83",
3766
+ # "margin": "6.9012",
3767
+ # "marginRate": "",
3768
+ # "unrealizedPnL": "-0.0288",
3769
+ # "profitRate": "-0.0041",
3770
+ # "realizedPnL": "-0.0199",
3771
+ # "minMargin": "0.2173"
3772
+ # }
3773
+ # ]
3774
+ #
3775
+ return self.parse_positions(response, [symbol])
3776
+
3777
+ def parse_position(self, position: dict, market: Market = None):
3778
+ marketId = self.safe_string(position, 'symbol')
3779
+ market = self.safe_market(marketId, market)
3780
+ symbol = market['symbol']
3781
+ return self.safe_position({
3782
+ 'symbol': symbol,
3783
+ 'id': None,
3784
+ 'timestamp': None,
3785
+ 'datetime': None,
3786
+ 'contracts': self.safe_number(position, 'position'),
3787
+ 'contractSize': None,
3788
+ 'side': self.safe_string_lower(position, 'side'),
3789
+ 'notional': self.safe_number(position, 'positionValue'),
3790
+ 'leverage': self.safe_integer(position, 'leverage'),
3791
+ 'unrealizedPnl': self.safe_number(position, 'unrealizedPnL'),
3792
+ 'realizedPnl': self.safe_number(position, 'realizedPnL'),
3793
+ 'collateral': None,
3794
+ 'entryPrice': self.safe_number(position, 'avgPrice'),
3795
+ 'markPrice': None,
3796
+ 'liquidationPrice': self.safe_number(position, 'liquidationPrice'),
3797
+ 'marginMode': 'cross',
3798
+ 'hedged': True,
3799
+ 'maintenanceMargin': self.safe_number(position, 'minMargin'),
3800
+ 'maintenanceMarginPercentage': None,
3801
+ 'initialMargin': self.safe_number(position, 'margin'),
3802
+ 'initialMarginPercentage': None,
3803
+ 'marginRatio': None,
3804
+ 'lastUpdateTimestamp': None,
3805
+ 'lastPrice': self.safe_number(position, 'lastPrice'),
3806
+ 'stopLossPrice': None,
3807
+ 'takeProfitPrice': None,
3808
+ 'percentage': None,
3809
+ 'info': position,
3810
+ })
3811
+
3812
+ async def fetch_leverage(self, symbol: str, params={}) -> Leverage:
3813
+ """
3814
+ fetch the set leverage for a market
3815
+
3816
+ https://hashkeyglobal-apidoc.readme.io/reference/query-futures-leverage-trade
3817
+
3818
+ :param str symbol: unified market symbol
3819
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3820
+ :returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
3821
+ """
3822
+ await self.load_markets()
3823
+ market = self.market(symbol)
3824
+ request: dict = {
3825
+ 'symbol': market['id'],
3826
+ }
3827
+ response = await self.privateGetApiV1FuturesLeverage(self.extend(request, params))
3828
+ #
3829
+ # [
3830
+ # {
3831
+ # "symbolId": "ETHUSDT-PERPETUAL",
3832
+ # "leverage": "5",
3833
+ # "marginType": "CROSS"
3834
+ # }
3835
+ # ]
3836
+ #
3837
+ leverage = self.safe_dict(response, 0, {})
3838
+ return self.parse_leverage(leverage, market)
3839
+
3840
+ def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
3841
+ marginMode = self.safe_string_lower(leverage, 'marginType')
3842
+ leverageValue = self.safe_number(leverage, 'leverage')
3843
+ return {
3844
+ 'info': leverage,
3845
+ 'symbol': market['symbol'],
3846
+ 'marginMode': marginMode,
3847
+ 'longLeverage': leverageValue,
3848
+ 'shortLeverage': leverageValue,
3849
+ }
3850
+
3851
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
3852
+ """
3853
+ set the level of leverage for a market
3854
+
3855
+ https://hashkeyglobal-apidoc.readme.io/reference/change-futures-leverage-trade
3856
+
3857
+ :param float leverage: the rate of leverage
3858
+ :param str symbol: unified market symbol
3859
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3860
+ :returns dict: response from the exchange
3861
+ """
3862
+ if symbol is None:
3863
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
3864
+ await self.load_markets()
3865
+ request: dict = {
3866
+ 'leverage': leverage,
3867
+ }
3868
+ market = self.market(symbol)
3869
+ request['symbol'] = market['id']
3870
+ response = await self.privatePostApiV1FuturesLeverage(self.extend(request, params))
3871
+ #
3872
+ # {
3873
+ # "code": "0000",
3874
+ # "symbolId": "ETHUSDT-PERPETUAL",
3875
+ # "leverage": "3"
3876
+ # }
3877
+ #
3878
+ return self.parse_leverage(response, market)
3879
+
3880
+ async def fetch_leverage_tiers(self, symbols: Strings = None, params={}) -> LeverageTiers:
3881
+ """
3882
+ retrieve information on the maximum leverage, and maintenance margin for trades of varying trade sizes
3883
+
3884
+ https://hashkeyglobal-apidoc.readme.io/reference/exchangeinfo
3885
+
3886
+ :param str[]|None symbols: list of unified market symbols
3887
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3888
+ :returns dict: a dictionary of `leverage tiers structures <https://docs.ccxt.com/#/?id=leverage-tiers-structure>`, indexed by market symbols
3889
+ """
3890
+ await self.load_markets()
3891
+ response = await self.publicGetApiV1ExchangeInfo(params)
3892
+ # response is the same fetchMarkets()
3893
+ data = self.safe_list(response, 'contracts', [])
3894
+ symbols = self.market_symbols(symbols)
3895
+ return self.parse_leverage_tiers(data, symbols, 'symbol')
3896
+
3897
+ def parse_market_leverage_tiers(self, info, market: Market = None) -> List[LeverageTier]:
3898
+ #
3899
+ # {
3900
+ # "filters": [
3901
+ # {
3902
+ # "minPrice": "0.1",
3903
+ # "maxPrice": "100000.00000000",
3904
+ # "tickSize": "0.1",
3905
+ # "filterType": "PRICE_FILTER"
3906
+ # },
3907
+ # {
3908
+ # "minQty": "0.001",
3909
+ # "maxQty": "10",
3910
+ # "stepSize": "0.001",
3911
+ # "marketOrderMinQty": "0",
3912
+ # "marketOrderMaxQty": "0",
3913
+ # "filterType": "LOT_SIZE"
3914
+ # },
3915
+ # {
3916
+ # "minNotional": "0",
3917
+ # "filterType": "MIN_NOTIONAL"
3918
+ # },
3919
+ # {
3920
+ # "maxSellPrice": "999999",
3921
+ # "buyPriceUpRate": "0.05",
3922
+ # "sellPriceDownRate": "0.05",
3923
+ # "maxEntrustNum": 200,
3924
+ # "maxConditionNum": 200,
3925
+ # "filterType": "LIMIT_TRADING"
3926
+ # },
3927
+ # {
3928
+ # "buyPriceUpRate": "0.05",
3929
+ # "sellPriceDownRate": "0.05",
3930
+ # "filterType": "MARKET_TRADING"
3931
+ # },
3932
+ # {
3933
+ # "noAllowMarketStartTime": "0",
3934
+ # "noAllowMarketEndTime": "0",
3935
+ # "limitOrderStartTime": "0",
3936
+ # "limitOrderEndTime": "0",
3937
+ # "limitMinPrice": "0",
3938
+ # "limitMaxPrice": "0",
3939
+ # "filterType": "OPEN_QUOTE"
3940
+ # }
3941
+ # ],
3942
+ # "exchangeId": "301",
3943
+ # "symbol": "BTCUSDT-PERPETUAL",
3944
+ # "symbolName": "BTCUSDT-PERPETUAL",
3945
+ # "status": "TRADING",
3946
+ # "baseAsset": "BTCUSDT-PERPETUAL",
3947
+ # "baseAssetPrecision": "0.001",
3948
+ # "quoteAsset": "USDT",
3949
+ # "quoteAssetPrecision": "0.1",
3950
+ # "icebergAllowed": False,
3951
+ # "inverse": False,
3952
+ # "index": "USDT",
3953
+ # "marginToken": "USDT",
3954
+ # "marginPrecision": "0.0001",
3955
+ # "contractMultiplier": "0.001",
3956
+ # "underlying": "BTC",
3957
+ # "riskLimits": [
3958
+ # {
3959
+ # "riskLimitId": "200000722",
3960
+ # "quantity": "1000.00",
3961
+ # "initialMargin": "0.10",
3962
+ # "maintMargin": "0.005",
3963
+ # "isWhite": False
3964
+ # },
3965
+ # {
3966
+ # "riskLimitId": "200000723",
3967
+ # "quantity": "2000.00",
3968
+ # "initialMargin": "0.10",
3969
+ # "maintMargin": "0.01",
3970
+ # "isWhite": False
3971
+ # }
3972
+ # ]
3973
+ # }
3974
+ #
3975
+ riskLimits = self.safe_list(info, 'riskLimits', [])
3976
+ marketId = self.safe_string(info, 'symbol')
3977
+ market = self.safe_market(marketId, market)
3978
+ tiers = []
3979
+ for i in range(0, len(riskLimits)):
3980
+ tier = riskLimits[i]
3981
+ initialMarginRate = self.safe_string(tier, 'initialMargin')
3982
+ tiers.append({
3983
+ 'tier': self.sum(i, 1),
3984
+ 'symbol': self.safe_symbol(marketId, market),
3985
+ 'currency': market['settle'],
3986
+ 'minNotional': None,
3987
+ 'maxNotional': self.safe_number(tier, 'quantity'),
3988
+ 'maintenanceMarginRate': self.safe_number(tier, 'maintMargin'),
3989
+ 'maxLeverage': self.parse_number(Precise.string_div('1', initialMarginRate)),
3990
+ 'info': tier,
3991
+ })
3992
+ return tiers
3993
+
3994
+ async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
3995
+ """
3996
+ fetch the trading fees for a market
3997
+
3998
+ https://developers.binance.com/docs/wallet/asset/trade-fee # spot
3999
+ https://hashkeyglobal-apidoc.readme.io/reference/get-futures-commission-rate-request-weight # swap
4000
+
4001
+ :param str symbol: unified market symbol
4002
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4003
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
4004
+ """
4005
+ await self.load_markets()
4006
+ market = self.market(symbol)
4007
+ methodName = 'fetchTradingFee'
4008
+ response = None
4009
+ if market['spot']:
4010
+ response = await self.fetch_trading_fees(params)
4011
+ return self.safe_dict(response, symbol)
4012
+ elif market['swap']:
4013
+ response = await self.privateGetApiV1FuturesCommissionRate(self.extend({'symbol': market['id']}, params))
4014
+ return self.parse_trading_fee(response, market)
4015
+ #
4016
+ # {
4017
+ # "openMakerFee": "0.00025",
4018
+ # "openTakerFee": "0.0006",
4019
+ # "closeMakerFee": "0.00025",
4020
+ # "closeTakerFee": "0.0006"
4021
+ # }
4022
+ #
4023
+ else:
4024
+ raise NotSupported(self.id + ' ' + methodName + '() is not supported for ' + market['type'] + ' type of markets')
4025
+
4026
+ async def fetch_trading_fees(self, params={}) -> TradingFees:
4027
+ """
4028
+ *for spot markets only* fetch the trading fees for multiple markets
4029
+
4030
+ https://developers.binance.com/docs/wallet/asset/trade-fee
4031
+
4032
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4033
+ :returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
4034
+ """
4035
+ await self.load_markets()
4036
+ response = await self.privateGetApiV1AccountVipInfo(params)
4037
+ #
4038
+ # {
4039
+ # "code": 0,
4040
+ # "vipLevel": "0",
4041
+ # "tradeVol30Day": "67",
4042
+ # "totalAssetBal": "0",
4043
+ # "data": [
4044
+ # {
4045
+ # "symbol": "UXLINKUSDT",
4046
+ # "productType": "Token-Token",
4047
+ # "buyMakerFeeCurrency": "UXLINK",
4048
+ # "buyTakerFeeCurrency": "UXLINK",
4049
+ # "sellMakerFeeCurrency": "USDT",
4050
+ # "sellTakerFeeCurrency": "USDT",
4051
+ # "actualMakerRate": "0.0012",
4052
+ # "actualTakerRate": "0.0012"
4053
+ # },
4054
+ # ...
4055
+ # ],
4056
+ # "updateTimestamp": "1722320137809"
4057
+ # }
4058
+ #
4059
+ data = self.safe_list(response, 'data', [])
4060
+ result: dict = {}
4061
+ for i in range(0, len(data)):
4062
+ fee = self.safe_dict(data, i, {})
4063
+ parsedFee = self.parse_trading_fee(fee)
4064
+ result[parsedFee['symbol']] = parsedFee
4065
+ return result
4066
+
4067
+ def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
4068
+ #
4069
+ # spot
4070
+ # {
4071
+ # "symbol": "UXLINKUSDT",
4072
+ # "productType": "Token-Token",
4073
+ # "buyMakerFeeCurrency": "UXLINK",
4074
+ # "buyTakerFeeCurrency": "UXLINK",
4075
+ # "sellMakerFeeCurrency": "USDT",
4076
+ # "sellTakerFeeCurrency": "USDT",
4077
+ # "actualMakerRate": "0.0012",
4078
+ # "actualTakerRate": "0.0012"
4079
+ # }
4080
+ #
4081
+ # swap
4082
+ # {
4083
+ # "openMakerFee": "0.00025",
4084
+ # "openTakerFee": "0.0006",
4085
+ # "closeMakerFee": "0.00025",
4086
+ # "closeTakerFee": "0.0006"
4087
+ # }
4088
+ #
4089
+ marketId = self.safe_string(fee, 'symbol')
4090
+ market = self.safe_market(marketId, market)
4091
+ return {
4092
+ 'info': fee,
4093
+ 'symbol': market['symbol'],
4094
+ 'maker': self.safe_number_2(fee, 'openMakerFee', 'actualMakerRate'),
4095
+ 'taker': self.safe_number_2(fee, 'openTakerFee', 'actualTakerRate'),
4096
+ 'percentage': True,
4097
+ 'tierBased': True,
4098
+ }
4099
+
4100
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
4101
+ url = self.urls['api'][api] + '/' + path
4102
+ query: Str = None
4103
+ if api == 'private':
4104
+ self.check_required_credentials()
4105
+ timestamp = self.milliseconds()
4106
+ additionalParams = {
4107
+ 'timestamp': timestamp,
4108
+ }
4109
+ recvWindow = self.safe_integer(self.options, 'recvWindow')
4110
+ if recvWindow is not None:
4111
+ additionalParams['recvWindow'] = recvWindow
4112
+ headers = {
4113
+ 'X-HK-APIKEY': self.apiKey,
4114
+ 'Content-Type': 'application/x-www-form-urlencoded',
4115
+ }
4116
+ signature: Str = None
4117
+ if (method == 'POST') and ((path == 'api/v1/spot/batchOrders') or (path == 'api/v1/futures/batchOrders')):
4118
+ headers['Content-Type'] = 'application/json'
4119
+ body = self.json(self.safe_list(params, 'orders'))
4120
+ signature = self.hmac(self.encode(self.custom_urlencode(additionalParams)), self.encode(self.secret), hashlib.sha256)
4121
+ query = self.custom_urlencode(self.extend(additionalParams, {'signature': signature}))
4122
+ url += '?' + query
4123
+ else:
4124
+ totalParams = self.extend(additionalParams, params)
4125
+ signature = self.hmac(self.encode(self.custom_urlencode(totalParams)), self.encode(self.secret), hashlib.sha256)
4126
+ totalParams['signature'] = signature
4127
+ query = self.custom_urlencode(totalParams)
4128
+ if method == 'GET':
4129
+ url += '?' + query
4130
+ else:
4131
+ body = query
4132
+ headers['INPUT-SOURCE'] = self.safe_string(self.options, 'broker', '10000700011')
4133
+ headers['broker_sign'] = signature
4134
+ else:
4135
+ query = self.urlencode(params)
4136
+ if len(query) != 0:
4137
+ url += '?' + query
4138
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
4139
+
4140
+ def custom_urlencode(self, params: dict = {}) -> Str:
4141
+ result = self.urlencode(params)
4142
+ result = result.replace('%2C', ',')
4143
+ return result
4144
+
4145
+ def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
4146
+ if response is None:
4147
+ return None
4148
+ errorInArray = False
4149
+ responseCodeString = self.safe_string(response, 'code', None)
4150
+ responseCodeInteger = self.safe_integer(response, 'code', None) # some codes in response are returned as '0000' others
4151
+ if responseCodeInteger == 0:
4152
+ result = self.safe_list(response, 'result', []) # for batch methods
4153
+ for i in range(0, len(result)):
4154
+ entry = self.safe_dict(result, i)
4155
+ entryCodeInteger = self.safe_integer(entry, 'code')
4156
+ if entryCodeInteger != 0:
4157
+ errorInArray = True
4158
+ responseCodeString = self.safe_string(entry, 'code')
4159
+ if (code != 200) or errorInArray:
4160
+ feedback = self.id + ' ' + body
4161
+ self.throw_broadly_matched_exception(self.exceptions['broad'], responseCodeString, feedback)
4162
+ self.throw_exactly_matched_exception(self.exceptions['exact'], responseCodeString, feedback)
4163
+ raise ExchangeError(feedback)
4164
+ return None