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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (546) hide show
  1. ccxt/__init__.py +36 -14
  2. ccxt/abstract/alpaca.py +4 -0
  3. ccxt/abstract/bigone.py +1 -1
  4. ccxt/abstract/binance.py +112 -48
  5. ccxt/abstract/binancecoinm.py +112 -48
  6. ccxt/abstract/binanceus.py +147 -83
  7. ccxt/abstract/binanceusdm.py +112 -48
  8. ccxt/abstract/bingx.py +133 -78
  9. ccxt/abstract/bitbank.py +5 -0
  10. ccxt/abstract/bitfinex.py +136 -65
  11. ccxt/abstract/bitfinex1.py +69 -0
  12. ccxt/abstract/bitflyer.py +1 -0
  13. ccxt/abstract/bitget.py +8 -1
  14. ccxt/abstract/bitmart.py +13 -1
  15. ccxt/abstract/bitopro.py +1 -0
  16. ccxt/abstract/bitpanda.py +0 -12
  17. ccxt/abstract/bitrue.py +3 -3
  18. ccxt/abstract/bitstamp.py +26 -3
  19. ccxt/abstract/blofin.py +24 -0
  20. ccxt/abstract/btcbox.py +1 -0
  21. ccxt/abstract/bybit.py +29 -14
  22. ccxt/abstract/cex.py +28 -29
  23. ccxt/abstract/coinbase.py +6 -0
  24. ccxt/abstract/coinbaseadvanced.py +94 -0
  25. ccxt/abstract/{coinbasepro.py → coinbaseexchange.py} +1 -0
  26. ccxt/abstract/coinbaseinternational.py +1 -1
  27. ccxt/abstract/coincatch.py +94 -0
  28. ccxt/abstract/coinex.py +233 -123
  29. ccxt/abstract/coinmetro.py +1 -0
  30. ccxt/abstract/cryptocom.py +14 -0
  31. ccxt/abstract/defx.py +69 -0
  32. ccxt/abstract/deribit.py +1 -0
  33. ccxt/abstract/digifinex.py +1 -0
  34. ccxt/abstract/ellipx.py +25 -0
  35. ccxt/abstract/gate.py +20 -0
  36. ccxt/abstract/gateio.py +20 -0
  37. ccxt/abstract/gemini.py +1 -0
  38. ccxt/abstract/hashkey.py +67 -0
  39. ccxt/abstract/hyperliquid.py +1 -1
  40. ccxt/abstract/independentreserve.py +6 -0
  41. ccxt/abstract/kraken.py +4 -3
  42. ccxt/abstract/krakenfutures.py +4 -0
  43. ccxt/abstract/kucoin.py +25 -0
  44. ccxt/abstract/kucoinfutures.py +35 -0
  45. ccxt/abstract/luno.py +2 -0
  46. ccxt/abstract/mexc.py +4 -0
  47. ccxt/abstract/myokx.py +340 -0
  48. ccxt/abstract/oceanex.py +5 -0
  49. ccxt/abstract/okx.py +30 -0
  50. ccxt/abstract/onetrading.py +0 -12
  51. ccxt/abstract/oxfun.py +34 -0
  52. ccxt/abstract/paradex.py +40 -0
  53. ccxt/abstract/phemex.py +1 -0
  54. ccxt/abstract/upbit.py +4 -0
  55. ccxt/abstract/vertex.py +19 -0
  56. ccxt/abstract/whitebit.py +31 -1
  57. ccxt/abstract/woo.py +6 -2
  58. ccxt/abstract/woofipro.py +119 -0
  59. ccxt/abstract/xt.py +153 -0
  60. ccxt/abstract/zonda.py +6 -0
  61. ccxt/ace.py +164 -60
  62. ccxt/alpaca.py +727 -63
  63. ccxt/ascendex.py +395 -249
  64. ccxt/async_support/__init__.py +36 -14
  65. ccxt/async_support/ace.py +164 -60
  66. ccxt/async_support/alpaca.py +727 -63
  67. ccxt/async_support/ascendex.py +396 -249
  68. ccxt/async_support/base/exchange.py +531 -155
  69. ccxt/async_support/base/ws/aiohttp_client.py +28 -5
  70. ccxt/async_support/base/ws/cache.py +3 -2
  71. ccxt/async_support/base/ws/client.py +26 -5
  72. ccxt/async_support/base/ws/fast_client.py +4 -3
  73. ccxt/async_support/base/ws/functions.py +1 -1
  74. ccxt/async_support/base/ws/future.py +40 -31
  75. ccxt/async_support/base/ws/order_book_side.py +3 -0
  76. ccxt/async_support/bequant.py +1 -1
  77. ccxt/async_support/bigone.py +329 -202
  78. ccxt/async_support/binance.py +3513 -1511
  79. ccxt/async_support/binancecoinm.py +2 -1
  80. ccxt/async_support/binanceus.py +12 -1
  81. ccxt/async_support/binanceusdm.py +3 -1
  82. ccxt/async_support/bingx.py +3105 -881
  83. ccxt/async_support/bit2c.py +119 -38
  84. ccxt/async_support/bitbank.py +215 -76
  85. ccxt/async_support/bitbns.py +124 -53
  86. ccxt/async_support/bitfinex.py +3236 -1078
  87. ccxt/async_support/bitfinex1.py +1711 -0
  88. ccxt/async_support/bitflyer.py +239 -50
  89. ccxt/async_support/bitget.py +1513 -563
  90. ccxt/async_support/bithumb.py +201 -67
  91. ccxt/async_support/bitmart.py +1320 -435
  92. ccxt/async_support/bitmex.py +308 -111
  93. ccxt/async_support/bitopro.py +256 -96
  94. ccxt/async_support/bitrue.py +365 -233
  95. ccxt/async_support/bitso.py +201 -89
  96. ccxt/async_support/bitstamp.py +438 -269
  97. ccxt/async_support/bitteam.py +179 -73
  98. ccxt/async_support/bitvavo.py +180 -70
  99. ccxt/async_support/bl3p.py +92 -25
  100. ccxt/async_support/blockchaincom.py +193 -79
  101. ccxt/async_support/blofin.py +403 -150
  102. ccxt/async_support/btcalpha.py +161 -55
  103. ccxt/async_support/btcbox.py +250 -34
  104. ccxt/async_support/btcmarkets.py +232 -85
  105. ccxt/async_support/btcturk.py +159 -60
  106. ccxt/async_support/bybit.py +2326 -1255
  107. ccxt/async_support/cex.py +1409 -1329
  108. ccxt/async_support/coinbase.py +1455 -288
  109. ccxt/async_support/coinbaseadvanced.py +17 -0
  110. ccxt/async_support/{coinbasepro.py → coinbaseexchange.py} +233 -99
  111. ccxt/async_support/coinbaseinternational.py +428 -88
  112. ccxt/async_support/coincatch.py +5152 -0
  113. ccxt/async_support/coincheck.py +121 -38
  114. ccxt/async_support/coinex.py +4020 -3339
  115. ccxt/async_support/coinlist.py +273 -116
  116. ccxt/async_support/coinmate.py +204 -97
  117. ccxt/async_support/coinmetro.py +203 -110
  118. ccxt/async_support/coinone.py +142 -68
  119. ccxt/async_support/coinsph.py +206 -89
  120. ccxt/async_support/coinspot.py +137 -62
  121. ccxt/async_support/cryptocom.py +515 -185
  122. ccxt/async_support/currencycom.py +203 -85
  123. ccxt/async_support/defx.py +2066 -0
  124. ccxt/async_support/delta.py +467 -158
  125. ccxt/async_support/deribit.py +558 -324
  126. ccxt/async_support/digifinex.py +340 -223
  127. ccxt/async_support/ellipx.py +1826 -0
  128. ccxt/async_support/exmo.py +259 -128
  129. ccxt/async_support/gate.py +1473 -464
  130. ccxt/async_support/gemini.py +206 -84
  131. ccxt/async_support/hashkey.py +4164 -0
  132. ccxt/async_support/hitbtc.py +334 -178
  133. ccxt/async_support/hollaex.py +134 -83
  134. ccxt/async_support/htx.py +1095 -563
  135. ccxt/async_support/huobijp.py +105 -56
  136. ccxt/async_support/hyperliquid.py +1634 -269
  137. ccxt/async_support/idex.py +148 -95
  138. ccxt/async_support/independentreserve.py +236 -31
  139. ccxt/async_support/indodax.py +165 -62
  140. ccxt/async_support/kraken.py +871 -354
  141. ccxt/async_support/krakenfutures.py +324 -100
  142. ccxt/async_support/kucoin.py +1050 -355
  143. ccxt/async_support/kucoinfutures.py +1004 -149
  144. ccxt/async_support/kuna.py +138 -106
  145. ccxt/async_support/latoken.py +135 -79
  146. ccxt/async_support/lbank.py +290 -113
  147. ccxt/async_support/luno.py +112 -62
  148. ccxt/async_support/lykke.py +104 -55
  149. ccxt/async_support/mercado.py +36 -29
  150. ccxt/async_support/mexc.py +995 -429
  151. ccxt/async_support/myokx.py +43 -0
  152. ccxt/async_support/ndax.py +163 -82
  153. ccxt/async_support/novadax.py +121 -75
  154. ccxt/async_support/oceanex.py +175 -59
  155. ccxt/async_support/okcoin.py +222 -163
  156. ccxt/async_support/okx.py +1777 -455
  157. ccxt/async_support/onetrading.py +132 -414
  158. ccxt/async_support/oxfun.py +2832 -0
  159. ccxt/async_support/p2b.py +79 -51
  160. ccxt/async_support/paradex.py +2017 -0
  161. ccxt/async_support/paymium.py +56 -32
  162. ccxt/async_support/phemex.py +572 -196
  163. ccxt/async_support/poloniex.py +218 -95
  164. ccxt/async_support/poloniexfutures.py +260 -92
  165. ccxt/async_support/probit.py +143 -110
  166. ccxt/async_support/timex.py +123 -70
  167. ccxt/async_support/tokocrypto.py +129 -93
  168. ccxt/async_support/tradeogre.py +39 -25
  169. ccxt/async_support/upbit.py +322 -113
  170. ccxt/async_support/vertex.py +2983 -0
  171. ccxt/async_support/wavesexchange.py +227 -173
  172. ccxt/async_support/wazirx.py +145 -65
  173. ccxt/async_support/whitebit.py +533 -138
  174. ccxt/async_support/woo.py +1155 -295
  175. ccxt/async_support/woofipro.py +2716 -0
  176. ccxt/async_support/xt.py +4628 -0
  177. ccxt/async_support/yobit.py +160 -92
  178. ccxt/async_support/zaif.py +80 -33
  179. ccxt/async_support/zonda.py +140 -69
  180. ccxt/base/errors.py +51 -20
  181. ccxt/base/exchange.py +1729 -482
  182. ccxt/base/precise.py +10 -0
  183. ccxt/base/types.py +223 -4
  184. ccxt/bequant.py +1 -1
  185. ccxt/bigone.py +329 -202
  186. ccxt/binance.py +3513 -1511
  187. ccxt/binancecoinm.py +2 -1
  188. ccxt/binanceus.py +12 -1
  189. ccxt/binanceusdm.py +3 -1
  190. ccxt/bingx.py +3105 -881
  191. ccxt/bit2c.py +119 -38
  192. ccxt/bitbank.py +215 -76
  193. ccxt/bitbns.py +124 -53
  194. ccxt/bitfinex.py +3235 -1078
  195. ccxt/bitfinex1.py +1710 -0
  196. ccxt/bitflyer.py +239 -50
  197. ccxt/bitget.py +1513 -563
  198. ccxt/bithumb.py +200 -67
  199. ccxt/bitmart.py +1320 -435
  200. ccxt/bitmex.py +308 -111
  201. ccxt/bitopro.py +256 -96
  202. ccxt/bitrue.py +365 -233
  203. ccxt/bitso.py +201 -89
  204. ccxt/bitstamp.py +438 -269
  205. ccxt/bitteam.py +179 -73
  206. ccxt/bitvavo.py +180 -70
  207. ccxt/bl3p.py +92 -25
  208. ccxt/blockchaincom.py +193 -79
  209. ccxt/blofin.py +403 -150
  210. ccxt/btcalpha.py +161 -55
  211. ccxt/btcbox.py +250 -34
  212. ccxt/btcmarkets.py +232 -85
  213. ccxt/btcturk.py +159 -60
  214. ccxt/bybit.py +2326 -1255
  215. ccxt/cex.py +1408 -1329
  216. ccxt/coinbase.py +1455 -288
  217. ccxt/coinbaseadvanced.py +17 -0
  218. ccxt/{coinbasepro.py → coinbaseexchange.py} +233 -99
  219. ccxt/coinbaseinternational.py +428 -88
  220. ccxt/coincatch.py +5152 -0
  221. ccxt/coincheck.py +121 -38
  222. ccxt/coinex.py +4020 -3339
  223. ccxt/coinlist.py +273 -116
  224. ccxt/coinmate.py +204 -97
  225. ccxt/coinmetro.py +203 -110
  226. ccxt/coinone.py +142 -68
  227. ccxt/coinsph.py +206 -89
  228. ccxt/coinspot.py +137 -62
  229. ccxt/cryptocom.py +515 -185
  230. ccxt/currencycom.py +203 -85
  231. ccxt/defx.py +2065 -0
  232. ccxt/delta.py +467 -158
  233. ccxt/deribit.py +558 -324
  234. ccxt/digifinex.py +340 -223
  235. ccxt/ellipx.py +1826 -0
  236. ccxt/exmo.py +259 -128
  237. ccxt/gate.py +1473 -464
  238. ccxt/gemini.py +206 -84
  239. ccxt/hashkey.py +4164 -0
  240. ccxt/hitbtc.py +334 -178
  241. ccxt/hollaex.py +134 -83
  242. ccxt/htx.py +1095 -563
  243. ccxt/huobijp.py +105 -56
  244. ccxt/hyperliquid.py +1633 -269
  245. ccxt/idex.py +148 -95
  246. ccxt/independentreserve.py +235 -31
  247. ccxt/indodax.py +165 -62
  248. ccxt/kraken.py +871 -354
  249. ccxt/krakenfutures.py +324 -100
  250. ccxt/kucoin.py +1050 -355
  251. ccxt/kucoinfutures.py +1004 -149
  252. ccxt/kuna.py +138 -106
  253. ccxt/latoken.py +135 -79
  254. ccxt/lbank.py +290 -113
  255. ccxt/luno.py +112 -62
  256. ccxt/lykke.py +104 -55
  257. ccxt/mercado.py +36 -29
  258. ccxt/mexc.py +994 -429
  259. ccxt/myokx.py +43 -0
  260. ccxt/ndax.py +163 -82
  261. ccxt/novadax.py +121 -75
  262. ccxt/oceanex.py +175 -59
  263. ccxt/okcoin.py +222 -163
  264. ccxt/okx.py +1777 -455
  265. ccxt/onetrading.py +132 -414
  266. ccxt/oxfun.py +2831 -0
  267. ccxt/p2b.py +79 -51
  268. ccxt/paradex.py +2017 -0
  269. ccxt/paymium.py +56 -32
  270. ccxt/phemex.py +572 -196
  271. ccxt/poloniex.py +218 -95
  272. ccxt/poloniexfutures.py +260 -92
  273. ccxt/pro/__init__.py +29 -5
  274. ccxt/pro/alpaca.py +32 -17
  275. ccxt/pro/ascendex.py +63 -15
  276. ccxt/pro/bequant.py +4 -0
  277. ccxt/pro/binance.py +1596 -329
  278. ccxt/pro/binancecoinm.py +1 -0
  279. ccxt/pro/binanceus.py +2 -9
  280. ccxt/pro/binanceusdm.py +2 -0
  281. ccxt/pro/bingx.py +527 -134
  282. ccxt/pro/bitcoincom.py +4 -1
  283. ccxt/pro/bitfinex.py +731 -266
  284. ccxt/pro/bitfinex1.py +635 -0
  285. ccxt/pro/bitget.py +726 -357
  286. ccxt/pro/bithumb.py +380 -0
  287. ccxt/pro/bitmart.py +138 -39
  288. ccxt/pro/bitmex.py +199 -40
  289. ccxt/pro/bitopro.py +25 -13
  290. ccxt/pro/bitrue.py +31 -32
  291. ccxt/pro/bitstamp.py +7 -6
  292. ccxt/pro/bitvavo.py +204 -82
  293. ccxt/pro/blockchaincom.py +30 -17
  294. ccxt/pro/blofin.py +692 -0
  295. ccxt/pro/bybit.py +791 -82
  296. ccxt/pro/cex.py +99 -51
  297. ccxt/pro/coinbase.py +220 -30
  298. ccxt/{async_support/hitbtc3.py → pro/coinbaseadvanced.py} +5 -5
  299. ccxt/pro/{coinbasepro.py → coinbaseexchange.py} +19 -19
  300. ccxt/pro/coinbaseinternational.py +193 -30
  301. ccxt/pro/coincatch.py +1464 -0
  302. ccxt/pro/coincheck.py +11 -6
  303. ccxt/pro/coinex.py +967 -661
  304. ccxt/pro/coinone.py +17 -10
  305. ccxt/pro/cryptocom.py +446 -66
  306. ccxt/pro/currencycom.py +11 -10
  307. ccxt/pro/defx.py +832 -0
  308. ccxt/pro/deribit.py +168 -32
  309. ccxt/pro/exmo.py +253 -21
  310. ccxt/pro/gate.py +729 -64
  311. ccxt/pro/gemini.py +44 -26
  312. ccxt/pro/hashkey.py +802 -0
  313. ccxt/pro/hitbtc.py +208 -103
  314. ccxt/pro/hollaex.py +25 -9
  315. ccxt/pro/htx.py +83 -39
  316. ccxt/pro/huobijp.py +17 -16
  317. ccxt/pro/hyperliquid.py +502 -31
  318. ccxt/pro/idex.py +28 -13
  319. ccxt/pro/independentreserve.py +21 -16
  320. ccxt/pro/kraken.py +298 -51
  321. ccxt/pro/krakenfutures.py +166 -75
  322. ccxt/pro/kucoin.py +395 -77
  323. ccxt/pro/kucoinfutures.py +400 -99
  324. ccxt/pro/lbank.py +52 -31
  325. ccxt/pro/luno.py +12 -10
  326. ccxt/pro/mexc.py +400 -50
  327. ccxt/pro/myokx.py +28 -0
  328. ccxt/pro/ndax.py +25 -12
  329. ccxt/pro/okcoin.py +28 -9
  330. ccxt/pro/okx.py +935 -124
  331. ccxt/pro/onetrading.py +41 -24
  332. ccxt/pro/oxfun.py +1054 -0
  333. ccxt/pro/p2b.py +100 -24
  334. ccxt/pro/paradex.py +352 -0
  335. ccxt/pro/phemex.py +93 -34
  336. ccxt/pro/poloniex.py +129 -50
  337. ccxt/pro/poloniexfutures.py +53 -32
  338. ccxt/pro/probit.py +93 -86
  339. ccxt/pro/upbit.py +401 -8
  340. ccxt/pro/vertex.py +943 -0
  341. ccxt/pro/wazirx.py +46 -28
  342. ccxt/pro/whitebit.py +65 -12
  343. ccxt/pro/woo.py +486 -70
  344. ccxt/pro/woofipro.py +1271 -0
  345. ccxt/pro/xt.py +1067 -0
  346. ccxt/probit.py +143 -110
  347. ccxt/static_dependencies/__init__.py +1 -1
  348. ccxt/static_dependencies/lark/__init__.py +38 -0
  349. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  350. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  351. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  352. ccxt/static_dependencies/lark/common.py +86 -0
  353. ccxt/static_dependencies/lark/exceptions.py +292 -0
  354. ccxt/static_dependencies/lark/grammar.py +130 -0
  355. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  356. ccxt/static_dependencies/lark/indenter.py +143 -0
  357. ccxt/static_dependencies/lark/lark.py +658 -0
  358. ccxt/static_dependencies/lark/lexer.py +678 -0
  359. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  360. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  361. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  362. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  363. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  364. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  365. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  366. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  367. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  368. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  369. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  370. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  371. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  372. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  373. ccxt/static_dependencies/lark/py.typed +0 -0
  374. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  375. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  376. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  377. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  378. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  379. ccxt/static_dependencies/lark/tree.py +267 -0
  380. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  381. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  382. ccxt/static_dependencies/lark/utils.py +343 -0
  383. ccxt/static_dependencies/lark/visitors.py +596 -0
  384. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  385. ccxt/static_dependencies/marshmallow/base.py +65 -0
  386. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  387. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  388. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  389. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  390. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  391. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  392. ccxt/static_dependencies/marshmallow/py.typed +0 -0
  393. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  394. ccxt/static_dependencies/marshmallow/types.py +12 -0
  395. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  396. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  397. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  398. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  399. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  400. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  401. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  402. ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
  403. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  404. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  405. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  406. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  407. ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
  408. ccxt/static_dependencies/starknet/__init__.py +0 -0
  409. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  410. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  411. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  412. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  413. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  414. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  415. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  416. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  417. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  418. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  419. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  420. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  421. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  422. ccxt/static_dependencies/starknet/common.py +15 -0
  423. ccxt/static_dependencies/starknet/constants.py +39 -0
  424. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  425. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  426. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  427. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  428. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  429. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  430. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  431. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  432. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  433. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  434. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  435. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  436. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  437. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  438. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  439. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  440. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  441. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  442. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  443. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  444. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  445. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  446. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  447. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  448. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  449. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  450. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  451. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  452. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  453. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  454. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  455. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  456. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  457. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  458. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  459. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  460. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  461. ccxt/static_dependencies/starkware/__init__.py +0 -0
  462. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  463. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  464. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  465. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  466. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  467. ccxt/static_dependencies/sympy/__init__.py +0 -0
  468. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  469. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  470. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  471. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  472. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  473. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  474. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  475. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  476. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  477. ccxt/test/{test_async.py → tests_async.py} +465 -407
  478. ccxt/test/tests_helpers.py +285 -0
  479. ccxt/test/tests_init.py +39 -0
  480. ccxt/test/{test_sync.py → tests_sync.py} +465 -409
  481. ccxt/timex.py +123 -70
  482. ccxt/tokocrypto.py +129 -93
  483. ccxt/tradeogre.py +39 -25
  484. ccxt/upbit.py +322 -113
  485. ccxt/vertex.py +2983 -0
  486. ccxt/wavesexchange.py +227 -173
  487. ccxt/wazirx.py +145 -65
  488. ccxt/whitebit.py +533 -138
  489. ccxt/woo.py +1155 -295
  490. ccxt/woofipro.py +2716 -0
  491. ccxt/xt.py +4627 -0
  492. ccxt/yobit.py +159 -92
  493. ccxt/zaif.py +80 -33
  494. ccxt/zonda.py +140 -69
  495. ccxt-4.4.48.dist-info/LICENSE.txt +21 -0
  496. ccxt-4.4.48.dist-info/METADATA +646 -0
  497. ccxt-4.4.48.dist-info/RECORD +669 -0
  498. {ccxt-4.2.76.dist-info → ccxt-4.4.48.dist-info}/WHEEL +1 -1
  499. ccxt/abstract/bitbay.py +0 -47
  500. ccxt/abstract/bitfinex2.py +0 -139
  501. ccxt/abstract/hitbtc3.py +0 -115
  502. ccxt/async_support/bitbay.py +0 -17
  503. ccxt/async_support/bitfinex2.py +0 -3496
  504. ccxt/async_support/flowbtc.py +0 -34
  505. ccxt/bitbay.py +0 -17
  506. ccxt/bitfinex2.py +0 -3496
  507. ccxt/flowbtc.py +0 -34
  508. ccxt/hitbtc3.py +0 -16
  509. ccxt/pro/bitfinex2.py +0 -1081
  510. ccxt/test/base/__init__.py +0 -28
  511. ccxt/test/base/test_account.py +0 -26
  512. ccxt/test/base/test_balance.py +0 -56
  513. ccxt/test/base/test_borrow_interest.py +0 -35
  514. ccxt/test/base/test_borrow_rate.py +0 -32
  515. ccxt/test/base/test_calculate_fee.py +0 -51
  516. ccxt/test/base/test_crypto.py +0 -127
  517. ccxt/test/base/test_currency.py +0 -76
  518. ccxt/test/base/test_datetime.py +0 -103
  519. ccxt/test/base/test_decimal_to_precision.py +0 -392
  520. ccxt/test/base/test_deep_extend.py +0 -68
  521. ccxt/test/base/test_deposit_withdrawal.py +0 -50
  522. ccxt/test/base/test_exchange_datetime_functions.py +0 -76
  523. ccxt/test/base/test_funding_rate_history.py +0 -29
  524. ccxt/test/base/test_last_price.py +0 -32
  525. ccxt/test/base/test_ledger_entry.py +0 -45
  526. ccxt/test/base/test_ledger_item.py +0 -48
  527. ccxt/test/base/test_leverage_tier.py +0 -33
  528. ccxt/test/base/test_margin_mode.py +0 -24
  529. ccxt/test/base/test_margin_modification.py +0 -35
  530. ccxt/test/base/test_market.py +0 -190
  531. ccxt/test/base/test_number.py +0 -411
  532. ccxt/test/base/test_ohlcv.py +0 -32
  533. ccxt/test/base/test_open_interest.py +0 -32
  534. ccxt/test/base/test_order.py +0 -64
  535. ccxt/test/base/test_order_book.py +0 -63
  536. ccxt/test/base/test_position.py +0 -60
  537. ccxt/test/base/test_shared_methods.py +0 -345
  538. ccxt/test/base/test_status.py +0 -24
  539. ccxt/test/base/test_throttle.py +0 -126
  540. ccxt/test/base/test_ticker.py +0 -86
  541. ccxt/test/base/test_trade.py +0 -47
  542. ccxt/test/base/test_trading_fee.py +0 -26
  543. ccxt/test/base/test_transaction.py +0 -39
  544. ccxt-4.2.76.dist-info/METADATA +0 -626
  545. ccxt-4.2.76.dist-info/RECORD +0 -534
  546. {ccxt-4.2.76.dist-info → ccxt-4.4.48.dist-info}/top_level.txt +0 -0
ccxt/kucoin.py CHANGED
@@ -8,9 +8,10 @@ from ccxt.abstract.kucoin import ImplicitAPI
8
8
  import hashlib
9
9
  import math
10
10
  import json
11
- from ccxt.base.types import Account, Balances, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry
11
+ from ccxt.base.types import Account, Balances, BorrowInterest, Bool, Currencies, Currency, DepositAddress, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
12
12
  from typing import List
13
13
  from ccxt.base.errors import ExchangeError
14
+ from ccxt.base.errors import AuthenticationError
14
15
  from ccxt.base.errors import PermissionDenied
15
16
  from ccxt.base.errors import AccountSuspended
16
17
  from ccxt.base.errors import ArgumentsRequired
@@ -24,7 +25,7 @@ from ccxt.base.errors import NotSupported
24
25
  from ccxt.base.errors import RateLimitExceeded
25
26
  from ccxt.base.errors import ExchangeNotAvailable
26
27
  from ccxt.base.errors import InvalidNonce
27
- from ccxt.base.errors import AuthenticationError
28
+ from ccxt.base.decimal_to_precision import TRUNCATE
28
29
  from ccxt.base.decimal_to_precision import TICK_SIZE
29
30
  from ccxt.base.precise import Precise
30
31
 
@@ -70,13 +71,14 @@ class kucoin(Exchange, ImplicitAPI):
70
71
  'fetchAccounts': True,
71
72
  'fetchBalance': True,
72
73
  'fetchBorrowInterest': True,
73
- 'fetchBorrowRateHistories': False,
74
- 'fetchBorrowRateHistory': False,
74
+ 'fetchBorrowRateHistories': True,
75
+ 'fetchBorrowRateHistory': True,
75
76
  'fetchClosedOrders': True,
76
77
  'fetchCrossBorrowRate': False,
77
78
  'fetchCrossBorrowRates': False,
78
79
  'fetchCurrencies': True,
79
80
  'fetchDepositAddress': True,
81
+ 'fetchDepositAddresses': False,
80
82
  'fetchDepositAddressesByNetwork': True,
81
83
  'fetchDeposits': True,
82
84
  'fetchDepositWithdrawFee': True,
@@ -91,10 +93,13 @@ class kucoin(Exchange, ImplicitAPI):
91
93
  'fetchL3OrderBook': True,
92
94
  'fetchLedger': True,
93
95
  'fetchLeverageTiers': False,
96
+ 'fetchMarginAdjustmentHistory': False,
94
97
  'fetchMarginMode': False,
95
98
  'fetchMarketLeverageTiers': False,
96
99
  'fetchMarkets': True,
97
100
  'fetchMarkOHLCV': False,
101
+ 'fetchMarkPrice': True,
102
+ 'fetchMarkPrices': True,
98
103
  'fetchMyTrades': True,
99
104
  'fetchOHLCV': True,
100
105
  'fetchOpenInterest': False,
@@ -105,7 +110,9 @@ class kucoin(Exchange, ImplicitAPI):
105
110
  'fetchOrderBooks': False,
106
111
  'fetchOrdersByStatus': True,
107
112
  'fetchOrderTrades': True,
113
+ 'fetchPositionHistory': False,
108
114
  'fetchPositionMode': False,
115
+ 'fetchPositionsHistory': False,
109
116
  'fetchPremiumIndexOHLCV': False,
110
117
  'fetchStatus': True,
111
118
  'fetchTicker': True,
@@ -119,7 +126,7 @@ class kucoin(Exchange, ImplicitAPI):
119
126
  'fetchWithdrawals': True,
120
127
  'repayCrossMargin': True,
121
128
  'repayIsolatedMargin': True,
122
- 'setLeverage': False,
129
+ 'setLeverage': True,
123
130
  'setMarginMode': False,
124
131
  'setPositionMode': False,
125
132
  'signIn': False,
@@ -136,6 +143,7 @@ class kucoin(Exchange, ImplicitAPI):
136
143
  'futuresPublic': 'https://api-futures.kucoin.com',
137
144
  'webExchange': 'https://kucoin.com/_api',
138
145
  'broker': 'https://api-broker.kucoin.com',
146
+ 'earn': 'https://api.kucoin.com',
139
147
  },
140
148
  'www': 'https://www.kucoin.com',
141
149
  'doc': [
@@ -173,7 +181,9 @@ class kucoin(Exchange, ImplicitAPI):
173
181
  'status': 4.5, # 3PW
174
182
  # margin trading
175
183
  'mark-price/{symbol}/current': 3, # 2PW
184
+ 'mark-price/all-symbols': 3,
176
185
  'margin/config': 25, # 25SW
186
+ 'announcements': 20, # 20W
177
187
  },
178
188
  'post': {
179
189
  # ws
@@ -212,8 +222,10 @@ class kucoin(Exchange, ImplicitAPI):
212
222
  'market/orderbook/level{level}': 3, # 3SW
213
223
  'market/orderbook/level2': 3, # 3SW
214
224
  'market/orderbook/level3': 3, # 3SW
225
+ 'hf/accounts/opened': 2, #
215
226
  'hf/orders/active': 2, # 2SW
216
227
  'hf/orders/active/symbols': 2, # 2SW
228
+ 'hf/margin/order/active/symbols': 2, # 2SW
217
229
  'hf/orders/done': 2, # 2SW
218
230
  'hf/orders/{orderId}': 2, # 2SW
219
231
  'hf/orders/client-order/{clientOid}': 2, # 2SW
@@ -242,15 +254,20 @@ class kucoin(Exchange, ImplicitAPI):
242
254
  'margin/currencies': 20, # 20SW
243
255
  'risk/limit/strategy': 20, # 20SW(Deprecate)
244
256
  'isolated/symbols': 20, # 20SW
257
+ 'margin/symbols': 5,
245
258
  'isolated/account/{symbol}': 50, # 50SW
246
259
  'margin/borrow': 15, # 15SW
247
260
  'margin/repay': 15, # 15SW
261
+ 'margin/interest': 20, # 20SW
248
262
  'project/list': 10, # 10SW
249
263
  'project/marketInterestRate': 7.5, # 5PW
250
264
  'redeem/orders': 10, # 10SW
251
265
  'purchase/orders': 10, # 10SW
252
266
  # broker
253
267
  'broker/api/rebase/download': 3,
268
+ 'migrate/user/account/status': 3,
269
+ # affiliate
270
+ 'affiliate/inviter/statistics': 30,
254
271
  },
255
272
  'post': {
256
273
  # account
@@ -290,6 +307,8 @@ class kucoin(Exchange, ImplicitAPI):
290
307
  'lend/purchase/update': 10, # 10SW
291
308
  # ws
292
309
  'bullet-private': 10, # 10SW
310
+ 'position/update-user-leverage': 5,
311
+ 'deposit-address/create': 20,
293
312
  },
294
313
  'delete': {
295
314
  # account
@@ -402,6 +421,10 @@ class kucoin(Exchange, ImplicitAPI):
402
421
  'broker/nd/account': 2,
403
422
  'broker/nd/account/apikey': 2,
404
423
  'broker/nd/rebase/download': 3,
424
+ 'asset/ndbroker/deposit/list': 1,
425
+ 'broker/nd/transfer/detail': 1,
426
+ 'broker/nd/deposit/detail': 1,
427
+ 'broker/nd/withdraw/detail': 1,
405
428
  },
406
429
  'post': {
407
430
  'broker/nd/transfer': 1,
@@ -413,6 +436,25 @@ class kucoin(Exchange, ImplicitAPI):
413
436
  'broker/nd/account/apikey': 3,
414
437
  },
415
438
  },
439
+ 'earn': {
440
+ 'get': {
441
+ 'otc-loan/loan': 1,
442
+ 'otc-loan/accounts': 1,
443
+ 'earn/redeem-preview': 7.5, # 5EW
444
+ 'earn/saving/products': 7.5, # 5EW
445
+ 'earn/hold-assets': 7.5, # 5EW
446
+ 'earn/promotion/products': 7.5, # 5EW
447
+ 'earn/kcs-staking/products': 7.5, # 5EW
448
+ 'earn/staking/products': 7.5, # 5EW
449
+ 'earn/eth-staking/products': 7.5, # 5EW
450
+ },
451
+ 'post': {
452
+ 'earn/orders': 7.5, # 5EW
453
+ },
454
+ 'delete': {
455
+ 'earn/orders': 7.5, # 5EW
456
+ },
457
+ },
416
458
  },
417
459
  'timeframes': {
418
460
  '1m': '1min',
@@ -433,6 +475,7 @@ class kucoin(Exchange, ImplicitAPI):
433
475
  'precisionMode': TICK_SIZE,
434
476
  'exceptions': {
435
477
  'exact': {
478
+ 'The order does not exist.': OrderNotFound,
436
479
  'order not exist': OrderNotFound,
437
480
  'order not exist.': OrderNotFound, # duplicated error temporarily
438
481
  'order_not_exist': OrderNotFound, # {"code":"order_not_exist","msg":"order_not_exist"} ¯\_(ツ)_/¯
@@ -440,6 +483,8 @@ class kucoin(Exchange, ImplicitAPI):
440
483
  'Order size below the minimum requirement.': InvalidOrder, # {"code":"400100","msg":"Order size below the minimum requirement."}
441
484
  'The withdrawal amount is below the minimum requirement.': ExchangeError, # {"code":"400100","msg":"The withdrawal amount is below the minimum requirement."}
442
485
  'Unsuccessful! Exceeded the max. funds out-transfer limit': InsufficientFunds, # {"code":"200000","msg":"Unsuccessful! Exceeded the max. funds out-transfer limit"}
486
+ 'The amount increment is invalid.': BadRequest,
487
+ 'The quantity is below the minimum requirement.': InvalidOrder, # {"msg":"The quantity is below the minimum requirement.","code":"400100"}
443
488
  '400': BadRequest,
444
489
  '401': AuthenticationError,
445
490
  '403': NotSupported,
@@ -463,6 +508,56 @@ class kucoin(Exchange, ImplicitAPI):
463
508
  '130202': ExchangeError, # The system is renewing the loan automatically. Please try again later
464
509
  '130203': InsufficientFunds, # Insufficient account balance
465
510
  '130204': BadRequest, # As the total lending amount for platform leverage reaches the platform's maximum position limit, the system suspends the borrowing function of leverage
511
+ '130301': InsufficientFunds, # Insufficient account balance
512
+ '130302': PermissionDenied, # Your relevant permission rights have been restricted, you can contact customer service for processing
513
+ '130303': NotSupported, # The current trading pair does not support isolated positions
514
+ '130304': NotSupported, # The trading function of the current trading pair is not enabled
515
+ '130305': NotSupported, # The current trading pair does not support cross position
516
+ '130306': NotSupported, # The account has not opened leveraged trading
517
+ '130307': NotSupported, # Please reopen the leverage agreement
518
+ '130308': InvalidOrder, # Position renewal freeze
519
+ '130309': InvalidOrder, # Position forced liquidation freeze
520
+ '130310': ExchangeError, # Abnormal leverage account status
521
+ '130311': InvalidOrder, # Failed to place an order, triggering buy limit
522
+ '130312': InvalidOrder, # Trigger global position limit, suspend buying
523
+ '130313': InvalidOrder, # Trigger global position limit, suspend selling
524
+ '130314': InvalidOrder, # Trigger the global position limit and prompt the remaining quantity available for purchase
525
+ '130315': NotSupported, # This feature has been suspended due to country restrictions
526
+ '126000': ExchangeError, # Abnormal margin trading
527
+ '126001': NotSupported, # Users currently do not support high frequency
528
+ '126002': ExchangeError, # There is a risk problem in your account and transactions are temporarily not allowed!
529
+ '126003': InvalidOrder, # The commission amount is less than the minimum transaction amount for a single commission
530
+ '126004': ExchangeError, # Trading pair does not exist or is prohibited
531
+ '126005': PermissionDenied, # This trading pair requires advanced KYC certification before trading
532
+ '126006': ExchangeError, # Trading pair is not available
533
+ '126007': ExchangeError, # Trading pair suspended
534
+ '126009': ExchangeError, # Trading pair is suspended from creating orders
535
+ '126010': ExchangeError, # Trading pair suspended order cancellation
536
+ '126011': ExchangeError, # There are too many orders in the order
537
+ '126013': InsufficientFunds, # Insufficient account balance
538
+ '126015': ExchangeError, # It is prohibited to place orders on self trading pair
539
+ '126021': NotSupported, # This digital asset does not support user participation in your region, thank you for your understanding!
540
+ '126022': InvalidOrder, # The final transaction price of your order will trigger the price protection strategy. To protect the price from deviating too much, please place an order again.
541
+ '126027': InvalidOrder, # Only limit orders are supported
542
+ '126028': InvalidOrder, # Only limit orders are supported before the specified time
543
+ '126029': InvalidOrder, # The maximum order price is: xxx
544
+ '126030': InvalidOrder, # The minimum order price is: xxx
545
+ '126033': InvalidOrder, # Duplicate order
546
+ '126034': InvalidOrder, # Failed to create take profit and stop loss order
547
+ '126036': InvalidOrder, # Failed to create margin order
548
+ '126037': ExchangeError, # Due to country and region restrictions, self function has been suspended!
549
+ '126038': ExchangeError, # Third-party service call failed(internal exception)
550
+ '126039': ExchangeError, # Third-party service call failed, reason: xxx
551
+ '126041': ExchangeError, # clientTimestamp parameter error
552
+ '126042': ExchangeError, # Exceeded maximum position limit
553
+ '126043': OrderNotFound, # Order does not exist
554
+ '126044': InvalidOrder, # clientOid duplicate
555
+ '126045': NotSupported, # This digital asset does not support user participation in your region, thank you for your understanding!
556
+ '126046': NotSupported, # This digital asset does not support your IP region, thank you for your understanding!
557
+ '126047': PermissionDenied, # Please complete identity verification
558
+ '126048': PermissionDenied, # Please complete authentication for the master account
559
+ '135005': ExchangeError, # Margin order query business abnormality
560
+ '135018': ExchangeError, # Margin order query service abnormality
466
561
  '200004': InsufficientFunds,
467
562
  '210014': InvalidOrder, # {"code":"210014","msg":"Exceeds the max. borrowing amount, the remaining amount you can borrow: 0USDT"}
468
563
  '210021': InsufficientFunds, # {"code":"210021","msg":"Balance not enough"}
@@ -479,20 +574,25 @@ class kucoin(Exchange, ImplicitAPI):
479
574
  '400006': AuthenticationError,
480
575
  '400007': AuthenticationError,
481
576
  '400008': NotSupported,
482
- '400100': InsufficientFunds, # {"msg":"account.available.amount","code":"400100"}
577
+ '400100': InsufficientFunds, # {"msg":"account.available.amount","code":"400100"} or {"msg":"Withdrawal amount is below the minimum requirement.","code":"400100"}
483
578
  '400200': InvalidOrder, # {"code":"400200","msg":"Forbidden to place an order"}
579
+ '400330': InvalidOrder, # {"msg":"Order price can't deviate from NAV by 50%","code":"400330"}
484
580
  '400350': InvalidOrder, # {"code":"400350","msg":"Upper limit for holding: 10,000USDT, you can still buy 10,000USDT worth of coin."}
485
581
  '400370': InvalidOrder, # {"code":"400370","msg":"Max. price: 0.02500000000000000000"}
486
582
  '400400': BadRequest, # Parameter error
583
+ '400401': AuthenticationError, # User is not logged in
487
584
  '400500': InvalidOrder, # {"code":"400500","msg":"Your located country/region is currently not supported for the trading of self token"}
488
585
  '400600': BadSymbol, # {"code":"400600","msg":"validation.createOrder.symbolNotAvailable"}
489
586
  '400760': InvalidOrder, # {"code":"400760","msg":"order price should be more than XX"}
490
587
  '401000': BadRequest, # {"code":"401000","msg":"The interface has been deprecated"}
588
+ '408000': BadRequest, # Network timeout, please try again later
491
589
  '411100': AccountSuspended,
492
590
  '415000': BadRequest, # {"code":"415000","msg":"Unsupported Media Type"}
493
591
  '400303': PermissionDenied, # {"msg":"To enjoy the full range of our products and services, we kindly request you complete the identity verification process.","code":"400303"}
494
592
  '500000': ExchangeNotAvailable, # {"code":"500000","msg":"Internal Server Error"}
495
593
  '260220': InvalidAddress, # {"code": "260220", "msg": "deposit.address.not.exists"}
594
+ '600100': InsufficientFunds, # {"msg":"Funds below the minimum requirement.","code":"600100"}
595
+ '600101': InvalidOrder, # {"msg":"The order funds should more then 0.1 USDT.","code":"600101"}
496
596
  '900014': BadRequest, # {"code":"900014","msg":"Invalid chainId"}
497
597
  },
498
598
  'broad': {
@@ -550,11 +650,17 @@ class kucoin(Exchange, ImplicitAPI):
550
650
  'BIFI': 'BIFIF',
551
651
  'VAI': 'VAIOT',
552
652
  'WAX': 'WAXP',
653
+ 'ALT': 'APTOSLAUNCHTOKEN',
654
+ 'KALT': 'ALT', # ALTLAYER
655
+ 'FUD': 'FTX Users\' Debt',
553
656
  },
554
657
  'options': {
658
+ 'hf': None, # would be auto set to `true/false` after first load
555
659
  'version': 'v1',
556
660
  'symbolSeparator': '-',
557
661
  'fetchMyTradesMethod': 'private_get_fills',
662
+ 'timeDifference': 0, # the difference between system clock and Binance clock
663
+ 'adjustForTimeDifference': False, # controls the adjustment logic upon instantiation
558
664
  'fetchCurrencies': {
559
665
  'webApiEnable': True, # fetches from WEB
560
666
  'webApiRetries': 1,
@@ -574,6 +680,8 @@ class kucoin(Exchange, ImplicitAPI):
574
680
  'currencies': 'v3',
575
681
  'currencies/{currency}': 'v3',
576
682
  'symbols': 'v2',
683
+ 'mark-price/all-symbols': 'v3',
684
+ 'announcements': 'v3',
577
685
  },
578
686
  },
579
687
  'private': {
@@ -598,6 +706,7 @@ class kucoin(Exchange, ImplicitAPI):
598
706
  'oco/orders': 'v3',
599
707
  # margin trading
600
708
  'hf/margin/orders/active': 'v3',
709
+ 'hf/margin/order/active/symbols': 'v3',
601
710
  'hf/margin/orders/done': 'v3',
602
711
  'hf/margin/orders/{orderId}': 'v3',
603
712
  'hf/margin/orders/client-order/{clientOid}': 'v3',
@@ -606,10 +715,15 @@ class kucoin(Exchange, ImplicitAPI):
606
715
  'margin/currencies': 'v3',
607
716
  'margin/borrow': 'v3',
608
717
  'margin/repay': 'v3',
718
+ 'margin/interest': 'v3',
609
719
  'project/list': 'v3',
610
720
  'project/marketInterestRate': 'v3',
611
721
  'redeem/orders': 'v3',
612
722
  'purchase/orders': 'v3',
723
+ 'migrate/user/account/status': 'v3',
724
+ 'margin/symbols': 'v3',
725
+ 'affiliate/inviter/statistics': 'v2',
726
+ 'asset/ndbroker/deposit/list': 'v1',
613
727
  },
614
728
  'POST': {
615
729
  # account
@@ -619,6 +733,7 @@ class kucoin(Exchange, ImplicitAPI):
619
733
  'accounts/sub-transfer': 'v2',
620
734
  'accounts/inner-transfer': 'v2',
621
735
  'transfer-out': 'v3',
736
+ 'deposit-address/create': 'v3',
622
737
  # spot trading
623
738
  'oco/order': 'v3',
624
739
  # margin trading
@@ -629,6 +744,8 @@ class kucoin(Exchange, ImplicitAPI):
629
744
  'purchase': 'v3',
630
745
  'redeem': 'v3',
631
746
  'lend/purchase/update': 'v3',
747
+ 'position/update-user-leverage': 'v3',
748
+ 'withdrawals': 'v3',
632
749
  },
633
750
  'DELETE': {
634
751
  # account
@@ -676,7 +793,7 @@ class kucoin(Exchange, ImplicitAPI):
676
793
  'hf': 'trade_hf',
677
794
  },
678
795
  'networks': {
679
- 'BTC': 'btc',
796
+ 'BRC20': 'btc',
680
797
  'BTCNATIVESEGWIT': 'bech32',
681
798
  'ERC20': 'eth',
682
799
  'TRC20': 'trx',
@@ -694,7 +811,7 @@ class kucoin(Exchange, ImplicitAPI):
694
811
  'TLOS': 'tlos', # tlosevm is different
695
812
  'CFX': 'cfx',
696
813
  'ACA': 'aca',
697
- 'OPTIMISM': 'optimism',
814
+ 'OP': 'optimism',
698
815
  'ONT': 'ont',
699
816
  'GLMR': 'glmr',
700
817
  'CSPR': 'cspr',
@@ -813,6 +930,7 @@ class kucoin(Exchange, ImplicitAPI):
813
930
  'TRUE': 'true',
814
931
  'CS': 'cs',
815
932
  'ORAI': 'orai',
933
+ 'BASE': 'base',
816
934
  # below will be uncommented after consensus
817
935
  # 'BITCOINDIAMON': 'bcd',
818
936
  # 'BITCOINGOLD': 'btg',
@@ -888,15 +1006,85 @@ class kucoin(Exchange, ImplicitAPI):
888
1006
  'spot': 'TRADE',
889
1007
  },
890
1008
  },
1009
+ 'features': {
1010
+ 'spot': {
1011
+ 'sandbox': False,
1012
+ 'createOrder': {
1013
+ 'marginMode': True,
1014
+ 'triggerPrice': True,
1015
+ 'triggerPriceType': None,
1016
+ 'triggerDirection': False,
1017
+ 'stopLossPrice': True,
1018
+ 'takeProfitPrice': True,
1019
+ 'attachedStopLossTakeProfit': None, # not supported
1020
+ 'timeInForce': {
1021
+ 'IOC': True,
1022
+ 'FOK': True,
1023
+ 'PO': True,
1024
+ 'GTD': True,
1025
+ },
1026
+ 'hedged': False,
1027
+ 'trailing': False,
1028
+ 'leverage': False,
1029
+ 'marketBuyByCost': True,
1030
+ 'marketBuyRequiresPrice': False,
1031
+ 'selfTradePrevention': True, # todo implement
1032
+ 'iceberg': True, # todo implement
1033
+ },
1034
+ 'createOrders': {
1035
+ 'max': 5,
1036
+ },
1037
+ 'fetchMyTrades': {
1038
+ 'marginMode': True,
1039
+ 'limit': None,
1040
+ 'daysBack': None,
1041
+ 'untilDays': 7, # per implementation comments
1042
+ },
1043
+ 'fetchOrder': {
1044
+ 'marginMode': False,
1045
+ 'trigger': True,
1046
+ 'trailing': False,
1047
+ },
1048
+ 'fetchOpenOrders': {
1049
+ 'marginMode': True,
1050
+ 'limit': 500,
1051
+ 'trigger': True,
1052
+ 'trailing': False,
1053
+ },
1054
+ 'fetchOrders': None,
1055
+ 'fetchClosedOrders': {
1056
+ 'marginMode': True,
1057
+ 'limit': 500,
1058
+ 'daysBack': None,
1059
+ 'daysBackCanceled': None,
1060
+ 'untilDays': 7,
1061
+ 'trigger': True,
1062
+ 'trailing': False,
1063
+ },
1064
+ 'fetchOHLCV': {
1065
+ 'limit': 1500,
1066
+ },
1067
+ },
1068
+ 'swap': {
1069
+ 'linear': None,
1070
+ 'inverse': None,
1071
+ },
1072
+ 'future': {
1073
+ 'linear': None,
1074
+ 'inverse': None,
1075
+ },
1076
+ },
891
1077
  })
892
1078
 
893
1079
  def nonce(self):
894
- return self.milliseconds()
1080
+ return self.milliseconds() - self.options['timeDifference']
895
1081
 
896
1082
  def fetch_time(self, params={}):
897
1083
  """
898
1084
  fetches the current integer timestamp in milliseconds from the exchange server
899
- :see: https://docs.kucoin.com/#server-time
1085
+
1086
+ https://docs.kucoin.com/#server-time
1087
+
900
1088
  :param dict [params]: extra parameters specific to the exchange API endpoint
901
1089
  :returns int: the current integer timestamp in milliseconds from the exchange server
902
1090
  """
@@ -913,7 +1101,9 @@ class kucoin(Exchange, ImplicitAPI):
913
1101
  def fetch_status(self, params={}):
914
1102
  """
915
1103
  the latest known information on the availability of the exchange API
916
- :see: https://docs.kucoin.com/#service-status
1104
+
1105
+ https://docs.kucoin.com/#service-status
1106
+
917
1107
  :param dict [params]: extra parameters specific to the exchange API endpoint
918
1108
  :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
919
1109
  """
@@ -937,15 +1127,20 @@ class kucoin(Exchange, ImplicitAPI):
937
1127
  'info': response,
938
1128
  }
939
1129
 
940
- def fetch_markets(self, params={}):
1130
+ def fetch_markets(self, params={}) -> List[Market]:
941
1131
  """
942
1132
  retrieves data on all markets for kucoin
943
- :see: https://docs.kucoin.com/#get-symbols-list-deprecated
944
- :see: https://docs.kucoin.com/#get-all-tickers
1133
+
1134
+ https://docs.kucoin.com/#get-symbols-list-deprecated
1135
+ https://docs.kucoin.com/#get-all-tickers
1136
+
945
1137
  :param dict [params]: extra parameters specific to the exchange API endpoint
946
1138
  :returns dict[]: an array of objects representing market data
947
1139
  """
948
- response = self.publicGetSymbols(params)
1140
+ fetchTickersFees = None
1141
+ fetchTickersFees, params = self.handle_option_and_params(params, 'fetchMarkets', 'fetchTickersFees', True)
1142
+ promises = []
1143
+ promises.append(self.publicGetSymbols(params))
949
1144
  #
950
1145
  # {
951
1146
  # "code": "200000",
@@ -968,59 +1163,102 @@ class kucoin(Exchange, ImplicitAPI):
968
1163
  # "isMarginEnabled": True,
969
1164
  # "enableTrading": True
970
1165
  # },
971
- # ]
972
- # }
973
1166
  #
974
- data = self.safe_list(response, 'data')
975
- options = self.safe_dict(self.options, 'fetchMarkets', {})
976
- fetchTickersFees = self.safe_bool(options, 'fetchTickersFees', True)
977
- tickersResponse = {}
1167
+ credentialsSet = self.check_required_credentials(False)
1168
+ requestMarginables = credentialsSet and self.safe_bool(params, 'marginables', True)
1169
+ if requestMarginables:
1170
+ promises.append(self.privateGetMarginSymbols(params)) # cross margin symbols
1171
+ #
1172
+ # {
1173
+ # "code": "200000",
1174
+ # "data": {
1175
+ # "timestamp": 1719393213421,
1176
+ # "items": [
1177
+ # {
1178
+ # # same object market, with one additional field:
1179
+ # "minFunds": "0.1"
1180
+ # },
1181
+ #
1182
+ promises.append(self.privateGetIsolatedSymbols(params)) # isolated margin symbols
1183
+ #
1184
+ # {
1185
+ # "code": "200000",
1186
+ # "data": [
1187
+ # {
1188
+ # "symbol": "NKN-USDT",
1189
+ # "symbolName": "NKN-USDT",
1190
+ # "baseCurrency": "NKN",
1191
+ # "quoteCurrency": "USDT",
1192
+ # "maxLeverage": 5,
1193
+ # "flDebtRatio": "0.97",
1194
+ # "tradeEnable": True,
1195
+ # "autoRenewMaxDebtRatio": "0.96",
1196
+ # "baseBorrowEnable": True,
1197
+ # "quoteBorrowEnable": True,
1198
+ # "baseTransferInEnable": True,
1199
+ # "quoteTransferInEnable": True,
1200
+ # "baseBorrowCoefficient": "1",
1201
+ # "quoteBorrowCoefficient": "1"
1202
+ # },
1203
+ #
978
1204
  if fetchTickersFees:
979
- tickersResponse = self.publicGetMarketAllTickers(params)
980
- #
981
- # {
982
- # "code": "200000",
983
- # "data": {
984
- # "time":1602832092060,
985
- # "ticker":[
986
- # {
987
- # "symbol": "BTC-USDT", # symbol
988
- # "symbolName":"BTC-USDT", # Name of trading pairs, it would change after renaming
989
- # "buy": "11328.9", # bestAsk
990
- # "sell": "11329", # bestBid
991
- # "changeRate": "-0.0055", # 24h change rate
992
- # "changePrice": "-63.6", # 24h change price
993
- # "high": "11610", # 24h highest price
994
- # "low": "11200", # 24h lowest price
995
- # "vol": "2282.70993217", # 24h volume,the aggregated trading volume in BTC
996
- # "volValue": "25984946.157790431", # 24h total, the trading volume in quote currency of last 24 hours
997
- # "last": "11328.9", # last price
998
- # "averagePrice": "11360.66065903", # 24h average transaction price yesterday
999
- # "takerFeeRate": "0.001", # Basic Taker Fee
1000
- # "makerFeeRate": "0.001", # Basic Maker Fee
1001
- # "takerCoefficient": "1", # Taker Fee Coefficient
1002
- # "makerCoefficient": "1" # Maker Fee Coefficient
1003
- # }
1004
- # ]
1005
- # }
1006
- # }
1007
- #
1008
- tickersData = self.safe_dict(tickersResponse, 'data', {})
1009
- tickers = self.safe_list(tickersData, 'ticker', [])
1010
- tickersByMarketId = self.index_by(tickers, 'symbol')
1205
+ promises.append(self.publicGetMarketAllTickers(params))
1206
+ #
1207
+ # {
1208
+ # "code": "200000",
1209
+ # "data": {
1210
+ # "time":1602832092060,
1211
+ # "ticker":[
1212
+ # {
1213
+ # "symbol": "BTC-USDT", # symbol
1214
+ # "symbolName":"BTC-USDT", # Name of trading pairs, it would change after renaming
1215
+ # "buy": "11328.9", # bestAsk
1216
+ # "sell": "11329", # bestBid
1217
+ # "changeRate": "-0.0055", # 24h change rate
1218
+ # "changePrice": "-63.6", # 24h change price
1219
+ # "high": "11610", # 24h highest price
1220
+ # "low": "11200", # 24h lowest price
1221
+ # "vol": "2282.70993217", # 24h volume,the aggregated trading volume in BTC
1222
+ # "volValue": "25984946.157790431", # 24h total, the trading volume in quote currency of last 24 hours
1223
+ # "last": "11328.9", # last price
1224
+ # "averagePrice": "11360.66065903", # 24h average transaction price yesterday
1225
+ # "takerFeeRate": "0.001", # Basic Taker Fee
1226
+ # "makerFeeRate": "0.001", # Basic Maker Fee
1227
+ # "takerCoefficient": "1", # Taker Fee Coefficient
1228
+ # "makerCoefficient": "1" # Maker Fee Coefficient
1229
+ # }
1230
+ #
1231
+ if credentialsSet:
1232
+ # load migration status for account
1233
+ promises.append(self.load_migration_status())
1234
+ responses = promises
1235
+ symbolsData = self.safe_list(responses[0], 'data')
1236
+ crossData = self.safe_dict(responses[1], 'data', {}) if requestMarginables else {}
1237
+ crossItems = self.safe_list(crossData, 'items', [])
1238
+ crossById = self.index_by(crossItems, 'symbol')
1239
+ isolatedData = responses[2] if requestMarginables else {}
1240
+ isolatedItems = self.safe_list(isolatedData, 'data', [])
1241
+ isolatedById = self.index_by(isolatedItems, 'symbol')
1242
+ tickersIdx = 3 if requestMarginables else 1
1243
+ tickersResponse = self.safe_dict(responses, tickersIdx, {})
1244
+ tickerItems = self.safe_list(self.safe_dict(tickersResponse, 'data', {}), 'ticker', [])
1245
+ tickersById = self.index_by(tickerItems, 'symbol')
1011
1246
  result = []
1012
- for i in range(0, len(data)):
1013
- market = data[i]
1247
+ for i in range(0, len(symbolsData)):
1248
+ market = symbolsData[i]
1014
1249
  id = self.safe_string(market, 'symbol')
1015
1250
  baseId, quoteId = id.split('-')
1016
1251
  base = self.safe_currency_code(baseId)
1017
1252
  quote = self.safe_currency_code(quoteId)
1018
1253
  # quoteIncrement = self.safe_number(market, 'quoteIncrement')
1019
- ticker = self.safe_dict(tickersByMarketId, id, {})
1254
+ ticker = self.safe_dict(tickersById, id, {})
1020
1255
  makerFeeRate = self.safe_string(ticker, 'makerFeeRate')
1021
1256
  takerFeeRate = self.safe_string(ticker, 'takerFeeRate')
1022
1257
  makerCoefficient = self.safe_string(ticker, 'makerCoefficient')
1023
1258
  takerCoefficient = self.safe_string(ticker, 'takerCoefficient')
1259
+ hasCrossMargin = (id in crossById)
1260
+ hasIsolatedMargin = (id in isolatedById)
1261
+ isMarginable = self.safe_bool(market, 'isMarginEnabled', False) or hasCrossMargin or hasIsolatedMargin
1024
1262
  result.append({
1025
1263
  'id': id,
1026
1264
  'symbol': base + '/' + quote,
@@ -1032,7 +1270,11 @@ class kucoin(Exchange, ImplicitAPI):
1032
1270
  'settleId': None,
1033
1271
  'type': 'spot',
1034
1272
  'spot': True,
1035
- 'margin': self.safe_bool(market, 'isMarginEnabled'),
1273
+ 'margin': isMarginable,
1274
+ 'marginModes': {
1275
+ 'cross': hasCrossMargin,
1276
+ 'isolated': hasIsolatedMargin,
1277
+ },
1036
1278
  'swap': False,
1037
1279
  'future': False,
1038
1280
  'option': False,
@@ -1072,12 +1314,40 @@ class kucoin(Exchange, ImplicitAPI):
1072
1314
  'created': None,
1073
1315
  'info': market,
1074
1316
  })
1317
+ if self.options['adjustForTimeDifference']:
1318
+ self.load_time_difference()
1075
1319
  return result
1076
1320
 
1077
- def fetch_currencies(self, params={}):
1321
+ def load_migration_status(self, force: bool = False):
1322
+ """
1323
+ :param boolean force: load account state for non hf
1324
+ loads the migration status for the account(hf or not)
1325
+
1326
+ https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/get-user-type
1327
+
1328
+ """
1329
+ if not ('hf' in self.options) or (self.options['hf'] is None) or force:
1330
+ result: dict = self.privateGetHfAccountsOpened()
1331
+ self.options['hf'] = self.safe_bool(result, 'data')
1332
+
1333
+ def handle_hf_and_params(self, params={}):
1334
+ migrated: Bool = self.safe_bool(self.options, 'hf', False)
1335
+ loadedHf: Bool = None
1336
+ if migrated is not None:
1337
+ if migrated:
1338
+ loadedHf = True
1339
+ else:
1340
+ loadedHf = False
1341
+ hf: Bool = self.safe_bool(params, 'hf', loadedHf)
1342
+ params = self.omit(params, 'hf')
1343
+ return [hf, params]
1344
+
1345
+ def fetch_currencies(self, params={}) -> Currencies:
1078
1346
  """
1079
1347
  fetches all available currencies on an exchange
1080
- :see: https://docs.kucoin.com/#get-currencies
1348
+
1349
+ https://docs.kucoin.com/#get-currencies
1350
+
1081
1351
  :param dict params: extra parameters specific to the exchange API endpoint
1082
1352
  :returns dict: an associative dictionary of currencies
1083
1353
  """
@@ -1099,8 +1369,10 @@ class kucoin(Exchange, ImplicitAPI):
1099
1369
  # "chains":[
1100
1370
  # {
1101
1371
  # "chainName":"ERC20",
1102
- # "chain":"eth",
1372
+ # "chainId": "eth"
1103
1373
  # "withdrawalMinSize":"2999",
1374
+ # "depositMinSize":null,
1375
+ # "withdrawFeeRate":"0",
1104
1376
  # "withdrawalMinFee":"2999",
1105
1377
  # "isWithdrawEnabled":false,
1106
1378
  # "isDepositEnabled":false,
@@ -1149,12 +1421,12 @@ class kucoin(Exchange, ImplicitAPI):
1149
1421
  # }
1150
1422
  #
1151
1423
  responses = promises
1152
- currenciesResponse = self.safe_value(responses, 0, {})
1153
- currenciesData = self.safe_value(currenciesResponse, 'data', [])
1154
- additionalResponse = self.safe_value(responses, 1, {})
1155
- additionalData = self.safe_value(additionalResponse, 'data', [])
1424
+ currenciesResponse = self.safe_dict(responses, 0, {})
1425
+ currenciesData = self.safe_list(currenciesResponse, 'data', [])
1426
+ additionalResponse = self.safe_dict(responses, 1, {})
1427
+ additionalData = self.safe_list(additionalResponse, 'data', [])
1156
1428
  additionalDataGrouped = self.group_by(additionalData, 'currency')
1157
- result = {}
1429
+ result: dict = {}
1158
1430
  for i in range(0, len(currenciesData)):
1159
1431
  entry = currenciesData[i]
1160
1432
  id = self.safe_string(entry, 'currency')
@@ -1162,9 +1434,9 @@ class kucoin(Exchange, ImplicitAPI):
1162
1434
  code = self.safe_currency_code(id)
1163
1435
  isWithdrawEnabled = None
1164
1436
  isDepositEnabled = None
1165
- networks = {}
1437
+ networks: dict = {}
1166
1438
  chains = self.safe_list(entry, 'chains', [])
1167
- extraChainsData = self.index_by(self.safe_value(additionalDataGrouped, id, []), 'chain')
1439
+ extraChainsData = self.index_by(self.safe_list(additionalDataGrouped, id, []), 'chain')
1168
1440
  rawPrecision = self.safe_string(entry, 'precision')
1169
1441
  precision = self.parse_number(self.parse_precision(rawPrecision))
1170
1442
  chainsLength = len(chains)
@@ -1175,7 +1447,7 @@ class kucoin(Exchange, ImplicitAPI):
1175
1447
  for j in range(0, chainsLength):
1176
1448
  chain = chains[j]
1177
1449
  chainId = self.safe_string(chain, 'chainId')
1178
- networkCode = self.network_id_to_code(chainId)
1450
+ networkCode = self.network_id_to_code(chainId, code)
1179
1451
  chainWithdrawEnabled = self.safe_bool(chain, 'isWithdrawEnabled', False)
1180
1452
  if isWithdrawEnabled is None:
1181
1453
  isWithdrawEnabled = chainWithdrawEnabled
@@ -1203,7 +1475,7 @@ class kucoin(Exchange, ImplicitAPI):
1203
1475
  'max': None,
1204
1476
  },
1205
1477
  'deposit': {
1206
- 'min': self.safe_number(chainExtraData, 'depositMinSize'),
1478
+ 'min': self.safe_number(chain, 'depositMinSize'),
1207
1479
  'max': None,
1208
1480
  },
1209
1481
  },
@@ -1229,7 +1501,9 @@ class kucoin(Exchange, ImplicitAPI):
1229
1501
  def fetch_accounts(self, params={}) -> List[Account]:
1230
1502
  """
1231
1503
  fetch all the accounts associated with a profile
1232
- :see: https://docs.kucoin.com/#list-accounts
1504
+
1505
+ https://docs.kucoin.com/#list-accounts
1506
+
1233
1507
  :param dict [params]: extra parameters specific to the exchange API endpoint
1234
1508
  :returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
1235
1509
  """
@@ -1277,14 +1551,16 @@ class kucoin(Exchange, ImplicitAPI):
1277
1551
  def fetch_transaction_fee(self, code: str, params={}):
1278
1552
  """
1279
1553
  *DEPRECATED* please use fetchDepositWithdrawFee instead
1280
- :see: https://docs.kucoin.com/#get-withdrawal-quotas
1554
+
1555
+ https://docs.kucoin.com/#get-withdrawal-quotas
1556
+
1281
1557
  :param str code: unified currency code
1282
1558
  :param dict params: extra parameters specific to the exchange API endpoint
1283
1559
  :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
1284
1560
  """
1285
1561
  self.load_markets()
1286
1562
  currency = self.currency(code)
1287
- request = {
1563
+ request: dict = {
1288
1564
  'currency': currency['id'],
1289
1565
  }
1290
1566
  networkCode = None
@@ -1292,8 +1568,8 @@ class kucoin(Exchange, ImplicitAPI):
1292
1568
  if networkCode is not None:
1293
1569
  request['chain'] = self.network_code_to_id(networkCode).lower()
1294
1570
  response = self.privateGetWithdrawalsQuotas(self.extend(request, params))
1295
- data = self.safe_value(response, 'data')
1296
- withdrawFees = {}
1571
+ data = self.safe_dict(response, 'data', {})
1572
+ withdrawFees: dict = {}
1297
1573
  withdrawFees[code] = self.safe_number(data, 'withdrawMinFee')
1298
1574
  return {
1299
1575
  'info': response,
@@ -1304,7 +1580,9 @@ class kucoin(Exchange, ImplicitAPI):
1304
1580
  def fetch_deposit_withdraw_fee(self, code: str, params={}):
1305
1581
  """
1306
1582
  fetch the fee for deposits and withdrawals
1307
- :see: https://docs.kucoin.com/#get-withdrawal-quotas
1583
+
1584
+ https://docs.kucoin.com/#get-withdrawal-quotas
1585
+
1308
1586
  :param str code: unified currency code
1309
1587
  :param dict [params]: extra parameters specific to the exchange API endpoint
1310
1588
  :param str [params.network]: The chain of currency. This only apply for multi-chain currency, and there is no need for single chain currency; you can query the chain through the response of the GET /api/v2/currencies/{currency} interface
@@ -1312,7 +1590,7 @@ class kucoin(Exchange, ImplicitAPI):
1312
1590
  """
1313
1591
  self.load_markets()
1314
1592
  currency = self.currency(code)
1315
- request = {
1593
+ request: dict = {
1316
1594
  'currency': currency['id'],
1317
1595
  }
1318
1596
  networkCode = None
@@ -1357,32 +1635,28 @@ class kucoin(Exchange, ImplicitAPI):
1357
1635
  # "chain": "ERC20"
1358
1636
  # }
1359
1637
  #
1360
- result = {
1638
+ minWithdrawFee = self.safe_number(fee, 'withdrawMinFee')
1639
+ result: dict = {
1361
1640
  'info': fee,
1362
1641
  'withdraw': {
1642
+ 'fee': minWithdrawFee,
1643
+ 'percentage': False,
1644
+ },
1645
+ 'deposit': {
1363
1646
  'fee': None,
1364
1647
  'percentage': None,
1365
1648
  },
1649
+ 'networks': {},
1650
+ }
1651
+ networkId = self.safe_string(fee, 'chain')
1652
+ networkCode = self.network_id_to_code(networkId, self.safe_string(currency, 'code'))
1653
+ result['networks'][networkCode] = {
1654
+ 'withdraw': minWithdrawFee,
1366
1655
  'deposit': {
1367
1656
  'fee': None,
1368
1657
  'percentage': None,
1369
1658
  },
1370
- 'networks': {},
1371
1659
  }
1372
- isWithdrawEnabled = self.safe_bool(fee, 'isWithdrawEnabled')
1373
- if isWithdrawEnabled:
1374
- result['withdraw']['fee'] = self.safe_number_2(fee, 'withdrawalMinFee', 'withdrawMinFee')
1375
- result['withdraw']['percentage'] = False
1376
- networkId = self.safe_string(fee, 'chain')
1377
- if networkId:
1378
- networkCode = self.network_id_to_code(networkId, self.safe_string(currency, 'code'))
1379
- result['networks'][networkCode] = {
1380
- 'withdraw': result['withdraw'],
1381
- 'deposit': {
1382
- 'fee': None,
1383
- 'percentage': None,
1384
- },
1385
- }
1386
1660
  return result
1387
1661
 
1388
1662
  def is_futures_method(self, methodName, params):
@@ -1402,7 +1676,7 @@ class kucoin(Exchange, ImplicitAPI):
1402
1676
  params = self.omit(params, 'type')
1403
1677
  return(type == 'contract') or (type == 'future') or (type == 'futures') # * (type == 'futures') deprecated, use(type == 'future')
1404
1678
 
1405
- def parse_ticker(self, ticker, market: Market = None) -> Ticker:
1679
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1406
1680
  #
1407
1681
  # {
1408
1682
  # "symbol": "BTC-USDT", # symbol
@@ -1468,7 +1742,7 @@ class kucoin(Exchange, ImplicitAPI):
1468
1742
  symbol = market['symbol']
1469
1743
  baseVolume = self.safe_string(ticker, 'vol')
1470
1744
  quoteVolume = self.safe_string(ticker, 'volValue')
1471
- timestamp = self.safe_integer_2(ticker, 'time', 'datetime')
1745
+ timestamp = self.safe_integer_n(ticker, ['time', 'datetime', 'timePoint'])
1472
1746
  return self.safe_ticker({
1473
1747
  'symbol': symbol,
1474
1748
  'timestamp': timestamp,
@@ -1489,13 +1763,16 @@ class kucoin(Exchange, ImplicitAPI):
1489
1763
  'average': self.safe_string(ticker, 'averagePrice'),
1490
1764
  'baseVolume': baseVolume,
1491
1765
  'quoteVolume': quoteVolume,
1766
+ 'markPrice': self.safe_string(ticker, 'value'),
1492
1767
  'info': ticker,
1493
1768
  }, market)
1494
1769
 
1495
1770
  def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1496
1771
  """
1497
1772
  fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1498
- :see: https://docs.kucoin.com/#get-all-tickers
1773
+
1774
+ https://docs.kucoin.com/#get-all-tickers
1775
+
1499
1776
  :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1500
1777
  :param dict [params]: extra parameters specific to the exchange API endpoint
1501
1778
  :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
@@ -1534,7 +1811,7 @@ class kucoin(Exchange, ImplicitAPI):
1534
1811
  data = self.safe_dict(response, 'data', {})
1535
1812
  tickers = self.safe_list(data, 'ticker', [])
1536
1813
  time = self.safe_integer(data, 'time')
1537
- result = {}
1814
+ result: dict = {}
1538
1815
  for i in range(0, len(tickers)):
1539
1816
  tickers[i]['time'] = time
1540
1817
  ticker = self.parse_ticker(tickers[i])
@@ -1543,17 +1820,35 @@ class kucoin(Exchange, ImplicitAPI):
1543
1820
  result[symbol] = ticker
1544
1821
  return self.filter_by_array_tickers(result, 'symbol', symbols)
1545
1822
 
1823
+ def fetch_mark_prices(self, symbols: Strings = None, params={}) -> Tickers:
1824
+ """
1825
+ fetches the mark price for multiple markets
1826
+
1827
+ https://www.kucoin.com/docs/rest/margin-trading/margin-info/get-all-margin-trading-pairs-mark-prices
1828
+
1829
+ :param str[] [symbols]: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1830
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1831
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1832
+ """
1833
+ self.load_markets()
1834
+ symbols = self.market_symbols(symbols)
1835
+ response = self.publicGetMarkPriceAllSymbols(params)
1836
+ data = self.safe_list(response, 'data', [])
1837
+ return self.parse_tickers(data)
1838
+
1546
1839
  def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1547
1840
  """
1548
1841
  fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1549
- :see: https://docs.kucoin.com/#get-24hr-stats
1842
+
1843
+ https://docs.kucoin.com/#get-24hr-stats
1844
+
1550
1845
  :param str symbol: unified symbol of the market to fetch the ticker for
1551
1846
  :param dict [params]: extra parameters specific to the exchange API endpoint
1552
1847
  :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1553
1848
  """
1554
1849
  self.load_markets()
1555
1850
  market = self.market(symbol)
1556
- request = {
1851
+ request: dict = {
1557
1852
  'symbol': market['id'],
1558
1853
  }
1559
1854
  response = self.publicGetMarketStats(self.extend(request, params))
@@ -1580,7 +1875,28 @@ class kucoin(Exchange, ImplicitAPI):
1580
1875
  # }
1581
1876
  # }
1582
1877
  #
1583
- return self.parse_ticker(response['data'], market)
1878
+ data = self.safe_dict(response, 'data', {})
1879
+ return self.parse_ticker(data, market)
1880
+
1881
+ def fetch_mark_price(self, symbol: str, params={}) -> Ticker:
1882
+ """
1883
+ fetches the mark price for a specific market
1884
+
1885
+ https://www.kucoin.com/docs/rest/margin-trading/margin-info/get-mark-price
1886
+
1887
+ :param str symbol: unified symbol of the market to fetch the ticker for
1888
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1889
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1890
+ """
1891
+ self.load_markets()
1892
+ market = self.market(symbol)
1893
+ request: dict = {
1894
+ 'symbol': market['id'],
1895
+ }
1896
+ response = self.publicGetMarkPriceSymbolCurrent(self.extend(request, params))
1897
+ #
1898
+ data = self.safe_dict(response, 'data', {})
1899
+ return self.parse_ticker(data, market)
1584
1900
 
1585
1901
  def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1586
1902
  #
@@ -1606,7 +1922,9 @@ class kucoin(Exchange, ImplicitAPI):
1606
1922
  def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1607
1923
  """
1608
1924
  fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1609
- :see: https://docs.kucoin.com/#get-klines
1925
+
1926
+ https://docs.kucoin.com/#get-klines
1927
+
1610
1928
  :param str symbol: unified symbol of the market to fetch OHLCV data for
1611
1929
  :param str timeframe: the length of time each candle represents
1612
1930
  :param int [since]: timestamp in ms of the earliest candle to fetch
@@ -1622,7 +1940,7 @@ class kucoin(Exchange, ImplicitAPI):
1622
1940
  return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1500)
1623
1941
  market = self.market(symbol)
1624
1942
  marketId = market['id']
1625
- request = {
1943
+ request: dict = {
1626
1944
  'symbol': marketId,
1627
1945
  'type': self.safe_string(self.timeframes, timeframe, timeframe),
1628
1946
  }
@@ -1657,7 +1975,9 @@ class kucoin(Exchange, ImplicitAPI):
1657
1975
 
1658
1976
  def create_deposit_address(self, code: str, params={}):
1659
1977
  """
1660
- :see: https://docs.kucoin.com/#create-deposit-address
1978
+
1979
+ https://www.kucoin.com/docs/rest/funding/deposit/create-deposit-address-v3-
1980
+
1661
1981
  create a currency deposit address
1662
1982
  :param str code: unified currency code of the currency for the deposit address
1663
1983
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1666,24 +1986,38 @@ class kucoin(Exchange, ImplicitAPI):
1666
1986
  """
1667
1987
  self.load_markets()
1668
1988
  currency = self.currency(code)
1669
- request = {
1989
+ request: dict = {
1670
1990
  'currency': currency['id'],
1671
1991
  }
1672
1992
  networkCode = None
1673
1993
  networkCode, params = self.handle_network_code_and_params(params)
1674
1994
  if networkCode is not None:
1675
- request['chain'] = self.network_code_to_id(networkCode).lower()
1676
- response = self.privatePostDepositAddresses(self.extend(request, params))
1995
+ request['chain'] = self.network_code_to_id(networkCode) # docs mention "chain-name", but seems "chain-id" is used, like in "fetchDepositAddress"
1996
+ response = self.privatePostDepositAddressCreate(self.extend(request, params))
1677
1997
  # {"code":"260000","msg":"Deposit address already exists."}
1678
- # BCH {"code":"200000","data":{"address":"bitcoincash:qza3m4nj9rx7l9r0cdadfqxts6f92shvhvr5ls4q7z","memo":""}}
1679
- # BTC {"code":"200000","data":{"address":"36SjucKqQpQSvsak9A7h6qzFjrVXpRNZhE","memo":""}}
1998
+ #
1999
+ # {
2000
+ # "code": "200000",
2001
+ # "data": {
2002
+ # "address": "0x2336d1834faab10b2dac44e468f2627138417431",
2003
+ # "memo": null,
2004
+ # "chainId": "bsc",
2005
+ # "to": "MAIN",
2006
+ # "expirationDate": 0,
2007
+ # "currency": "BNB",
2008
+ # "chainName": "BEP20"
2009
+ # }
2010
+ # }
2011
+ #
1680
2012
  data = self.safe_dict(response, 'data', {})
1681
2013
  return self.parse_deposit_address(data, currency)
1682
2014
 
1683
- def fetch_deposit_address(self, code: str, params={}):
2015
+ def fetch_deposit_address(self, code: str, params={}) -> DepositAddress:
1684
2016
  """
1685
2017
  fetch the deposit address for a currency associated with self account
1686
- :see: https://docs.kucoin.com/#get-deposit-addresses-v2
2018
+
2019
+ https://docs.kucoin.com/#get-deposit-addresses-v2
2020
+
1687
2021
  :param str code: unified currency code
1688
2022
  :param dict [params]: extra parameters specific to the exchange API endpoint
1689
2023
  :param str [params.network]: the blockchain network name
@@ -1691,7 +2025,7 @@ class kucoin(Exchange, ImplicitAPI):
1691
2025
  """
1692
2026
  self.load_markets()
1693
2027
  currency = self.currency(code)
1694
- request = {
2028
+ request: dict = {
1695
2029
  'currency': currency['id'],
1696
2030
  # for USDT - OMNI, ERC20, TRC20, default is ERC20
1697
2031
  # for BTC - Native, Segwit, TRC20, the parameters are bech32, btc, trx, default is Native
@@ -1712,28 +2046,30 @@ class kucoin(Exchange, ImplicitAPI):
1712
2046
  raise ExchangeError(self.id + ' fetchDepositAddress() returned an empty response, you might try to run createDepositAddress() first and try again')
1713
2047
  return self.parse_deposit_address(data, currency)
1714
2048
 
1715
- def parse_deposit_address(self, depositAddress, currency: Currency = None):
2049
+ def parse_deposit_address(self, depositAddress, currency: Currency = None) -> DepositAddress:
1716
2050
  address = self.safe_string(depositAddress, 'address')
1717
2051
  # BCH/BSV is returned with a "bitcoincash:" prefix, which we cut off here and only keep the address
1718
2052
  if address is not None:
1719
2053
  address = address.replace('bitcoincash:', '')
1720
2054
  code = None
1721
2055
  if currency is not None:
1722
- code = currency['id']
2056
+ code = self.safe_currency_code(currency['id'])
1723
2057
  if code != 'NIM':
1724
2058
  # contains spaces
1725
2059
  self.check_address(address)
1726
2060
  return {
1727
2061
  'info': depositAddress,
1728
2062
  'currency': code,
2063
+ 'network': self.network_id_to_code(self.safe_string(depositAddress, 'chainId')),
1729
2064
  'address': address,
1730
2065
  'tag': self.safe_string(depositAddress, 'memo'),
1731
- 'network': self.network_id_to_code(self.safe_string(depositAddress, 'chain')),
1732
2066
  }
1733
2067
 
1734
- def fetch_deposit_addresses_by_network(self, code: str, params={}):
2068
+ def fetch_deposit_addresses_by_network(self, code: str, params={}) -> List[DepositAddress]:
1735
2069
  """
1736
- :see: https://docs.kucoin.com/#get-deposit-addresses-v2
2070
+
2071
+ https://docs.kucoin.com/#get-deposit-addresses-v2
2072
+
1737
2073
  fetch the deposit address for a currency associated with self account
1738
2074
  :param str code: unified currency code
1739
2075
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1741,7 +2077,7 @@ class kucoin(Exchange, ImplicitAPI):
1741
2077
  """
1742
2078
  self.load_markets()
1743
2079
  currency = self.currency(code)
1744
- request = {
2080
+ request: dict = {
1745
2081
  'currency': currency['id'],
1746
2082
  }
1747
2083
  version = self.options['versions']['private']['GET']['deposit-addresses']
@@ -1765,15 +2101,17 @@ class kucoin(Exchange, ImplicitAPI):
1765
2101
  self.options['versions']['private']['GET']['deposit-addresses'] = version
1766
2102
  chains = self.safe_list(response, 'data', [])
1767
2103
  parsed = self.parse_deposit_addresses(chains, [currency['code']], False, {
1768
- 'currency': currency['id'],
2104
+ 'currency': currency['code'],
1769
2105
  })
1770
2106
  return self.index_by(parsed, 'network')
1771
2107
 
1772
2108
  def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1773
2109
  """
1774
2110
  fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1775
- :see: https://www.kucoin.com/docs/rest/spot-trading/market-data/get-part-order-book-aggregated-
1776
- :see: https://www.kucoin.com/docs/rest/spot-trading/market-data/get-full-order-book-aggregated-
2111
+
2112
+ https://www.kucoin.com/docs/rest/spot-trading/market-data/get-part-order-book-aggregated-
2113
+ https://www.kucoin.com/docs/rest/spot-trading/market-data/get-full-order-book-aggregated-
2114
+
1777
2115
  :param str symbol: unified symbol of the market to fetch the order book for
1778
2116
  :param int [limit]: the maximum amount of order book entries to return
1779
2117
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1782,7 +2120,7 @@ class kucoin(Exchange, ImplicitAPI):
1782
2120
  self.load_markets()
1783
2121
  market = self.market(symbol)
1784
2122
  level = self.safe_integer(params, 'level', 2)
1785
- request = {'symbol': market['id']}
2123
+ request: dict = {'symbol': market['id']}
1786
2124
  isAuthenticated = self.check_required_credentials(False)
1787
2125
  response = None
1788
2126
  if not isAuthenticated or limit is not None:
@@ -1847,49 +2185,56 @@ class kucoin(Exchange, ImplicitAPI):
1847
2185
  def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1848
2186
  """
1849
2187
  Create an order on the exchange
1850
- :see: https://docs.kucoin.com/spot#place-a-new-order
1851
- :see: https://docs.kucoin.com/spot#place-a-new-order-2
1852
- :see: https://docs.kucoin.com/spot#place-a-margin-order
1853
- :see: https://docs.kucoin.com/spot-hf/#place-hf-order
1854
- :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-order-test
1855
- :see: https://www.kucoin.com/docs/rest/margin-trading/orders/place-margin-order-test
2188
+
2189
+ https://docs.kucoin.com/spot#place-a-new-order
2190
+ https://docs.kucoin.com/spot#place-a-new-order-2
2191
+ https://docs.kucoin.com/spot#place-a-margin-order
2192
+ https://docs.kucoin.com/spot-hf/#place-hf-order
2193
+ https://www.kucoin.com/docs/rest/spot-trading/orders/place-order-test
2194
+ https://www.kucoin.com/docs/rest/margin-trading/orders/place-margin-order-test
2195
+ https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/sync-place-hf-order
2196
+
1856
2197
  :param str symbol: Unified CCXT market symbol
1857
2198
  :param str type: 'limit' or 'market'
1858
2199
  :param str side: 'buy' or 'sell'
1859
2200
  :param float amount: the amount of currency to trade
1860
- :param float [price]: *ignored in "market" orders* the price at which the order is to be fullfilled at in units of the quote currency
2201
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
1861
2202
  :param dict [params]: extra parameters specific to the exchange API endpoint
1862
2203
  :param float [params.triggerPrice]: The price at which a trigger order is triggered at
1863
2204
  :param str [params.marginMode]: 'cross', # cross(cross mode) and isolated(isolated mode), set to cross by default, the isolated mode will be released soon, stay tuned
1864
2205
  :param str [params.timeInForce]: GTC, GTT, IOC, or FOK, default is GTC, limit orders only
1865
2206
  :param str [params.postOnly]: Post only flag, invalid when timeInForce is IOC or FOK
1866
- *
1867
- * EXCHANGE SPECIFIC PARAMETERS
2207
+
2208
+ EXCHANGE SPECIFIC PARAMETERS
1868
2209
  :param str [params.clientOid]: client order id, defaults to uuid if not passed
1869
2210
  :param str [params.remark]: remark for the order, length cannot exceed 100 utf8 characters
1870
2211
  :param str [params.tradeType]: 'TRADE', # TRADE, MARGIN_TRADE # not used with margin orders
1871
- * limit orders ---------------------------------------------------
2212
+ limit orders ---------------------------------------------------
1872
2213
  :param float [params.cancelAfter]: long, # cancel after n seconds, requires timeInForce to be GTT
1873
2214
  :param bool [params.hidden]: False, # Order will not be displayed in the order book
1874
2215
  :param bool [params.iceberg]: False, # Only a portion of the order is displayed in the order book
1875
2216
  :param str [params.visibleSize]: self.amount_to_precision(symbol, visibleSize), # The maximum visible size of an iceberg order
1876
- * market orders --------------------------------------------------
2217
+ market orders --------------------------------------------------
1877
2218
  :param str [params.funds]: # Amount of quote currency to use
1878
- * stop orders ----------------------------------------------------
1879
- :param str [params.stop]: Either loss or entry, the default is loss. Requires stopPrice to be defined
1880
- * margin orders --------------------------------------------------
2219
+ stop orders ----------------------------------------------------
2220
+ :param str [params.stop]: Either loss or entry, the default is loss. Requires triggerPrice to be defined
2221
+ margin orders --------------------------------------------------
1881
2222
  :param float [params.leverage]: Leverage size of the order
1882
2223
  :param str [params.stp]: '', # self trade prevention, CN, CO, CB or DC
1883
2224
  :param bool [params.autoBorrow]: False, # The system will first borrow you funds at the optimal interest rate and then place an order for you
1884
2225
  :param bool [params.hf]: False, # True for hf order
1885
2226
  :param bool [params.test]: set to True to test an order, no order will be created but the request will be validated
2227
+ :param bool [params.sync]: set to True to use the hf sync call
1886
2228
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1887
2229
  """
1888
2230
  self.load_markets()
1889
2231
  market = self.market(symbol)
1890
2232
  testOrder = self.safe_bool(params, 'test', False)
1891
2233
  params = self.omit(params, 'test')
1892
- isHf = self.safe_bool(params, 'hf', False)
2234
+ hf = None
2235
+ hf, params = self.handle_hf_and_params(params)
2236
+ useSync = False
2237
+ useSync, params = self.handle_option_and_params(params, 'createOrder', 'sync', False)
1893
2238
  triggerPrice, stopLossPrice, takeProfitPrice = self.handle_trigger_prices(params)
1894
2239
  tradeType = self.safe_string(params, 'tradeType') # keep it for backward compatibility
1895
2240
  isTriggerOrder = (triggerPrice or stopLossPrice or takeProfitPrice)
@@ -1902,14 +2247,18 @@ class kucoin(Exchange, ImplicitAPI):
1902
2247
  if testOrder:
1903
2248
  if isMarginOrder:
1904
2249
  response = self.privatePostMarginOrderTest(orderRequest)
2250
+ elif hf:
2251
+ response = self.privatePostHfOrdersTest(orderRequest)
1905
2252
  else:
1906
2253
  response = self.privatePostOrdersTest(orderRequest)
1907
- elif isHf:
1908
- response = self.privatePostHfOrders(orderRequest)
1909
2254
  elif isTriggerOrder:
1910
2255
  response = self.privatePostStopOrder(orderRequest)
1911
2256
  elif isMarginOrder:
1912
2257
  response = self.privatePostMarginOrder(orderRequest)
2258
+ elif useSync:
2259
+ response = self.privatePostHfOrdersSync(orderRequest)
2260
+ elif hf:
2261
+ response = self.privatePostHfOrders(orderRequest)
1913
2262
  else:
1914
2263
  response = self.privatePostOrders(orderRequest)
1915
2264
  #
@@ -1926,7 +2275,9 @@ class kucoin(Exchange, ImplicitAPI):
1926
2275
  def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
1927
2276
  """
1928
2277
  create a market order by providing the symbol, side and cost
1929
- :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2278
+
2279
+ https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2280
+
1930
2281
  :param str symbol: unified symbol of the market to create an order in
1931
2282
  :param str side: 'buy' or 'sell'
1932
2283
  :param float cost: how much you want to trade in units of the quote currency
@@ -1934,13 +2285,17 @@ class kucoin(Exchange, ImplicitAPI):
1934
2285
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1935
2286
  """
1936
2287
  self.load_markets()
1937
- params['cost'] = cost
1938
- return self.create_order(symbol, 'market', side, cost, None, params)
2288
+ req = {
2289
+ 'cost': cost,
2290
+ }
2291
+ return self.create_order(symbol, 'market', side, 0, None, self.extend(req, params))
1939
2292
 
1940
2293
  def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1941
2294
  """
1942
2295
  create a market buy order by providing the symbol and cost
1943
- :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2296
+
2297
+ https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2298
+
1944
2299
  :param str symbol: unified symbol of the market to create an order in
1945
2300
  :param float cost: how much you want to trade in units of the quote currency
1946
2301
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1952,7 +2307,9 @@ class kucoin(Exchange, ImplicitAPI):
1952
2307
  def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}):
1953
2308
  """
1954
2309
  create a market sell order by providing the symbol and cost
1955
- :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2310
+
2311
+ https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2312
+
1956
2313
  :param str symbol: unified symbol of the market to create an order in
1957
2314
  :param float cost: how much you want to trade in units of the quote currency
1958
2315
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1964,11 +2321,15 @@ class kucoin(Exchange, ImplicitAPI):
1964
2321
  def create_orders(self, orders: List[OrderRequest], params={}):
1965
2322
  """
1966
2323
  create a list of trade orders
1967
- :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-multiple-orders
1968
- :see: https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/place-multiple-hf-orders
2324
+
2325
+ https://www.kucoin.com/docs/rest/spot-trading/orders/place-multiple-orders
2326
+ https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/place-multiple-hf-orders
2327
+ https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/sync-place-multiple-hf-orders
2328
+
1969
2329
  :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
1970
2330
  :param dict [params]: extra parameters specific to the exchange API endpoint
1971
2331
  :param bool [params.hf]: False, # True for hf orders
2332
+ :param bool [params.sync]: False, # True to use the hf sync call
1972
2333
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1973
2334
  """
1974
2335
  self.load_markets()
@@ -1992,14 +2353,18 @@ class kucoin(Exchange, ImplicitAPI):
1992
2353
  orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
1993
2354
  ordersRequests.append(orderRequest)
1994
2355
  market = self.market(symbol)
1995
- request = {
2356
+ request: dict = {
1996
2357
  'symbol': market['id'],
1997
2358
  'orderList': ordersRequests,
1998
2359
  }
1999
- hf = self.safe_bool(params, 'hf', False)
2000
- params = self.omit(params, 'hf')
2360
+ hf = None
2361
+ hf, params = self.handle_hf_and_params(params)
2362
+ useSync = False
2363
+ useSync, params = self.handle_option_and_params(params, 'createOrders', 'sync', False)
2001
2364
  response = None
2002
- if hf:
2365
+ if useSync:
2366
+ response = self.privatePostHfOrdersMultiSync(self.extend(request, params))
2367
+ elif hf:
2003
2368
  response = self.privatePostHfOrdersMulti(self.extend(request, params))
2004
2369
  else:
2005
2370
  response = self.privatePostOrdersMulti(self.extend(request, params))
@@ -2037,12 +2402,19 @@ class kucoin(Exchange, ImplicitAPI):
2037
2402
  data = self.safe_list(data, 'data', [])
2038
2403
  return self.parse_orders(data)
2039
2404
 
2405
+ def market_order_amount_to_precision(self, symbol: str, amount):
2406
+ market = self.market(symbol)
2407
+ result = self.decimal_to_precision(amount, TRUNCATE, market['info']['quoteIncrement'], self.precisionMode, self.paddingMode)
2408
+ if result == '0':
2409
+ raise InvalidOrder(self.id + ' amount of ' + market['symbol'] + ' must be greater than minimum amount precision of ' + self.number_to_string(market['precision']['amount']))
2410
+ return result
2411
+
2040
2412
  def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2041
2413
  market = self.market(symbol)
2042
2414
  # required param, cannot be used twice
2043
2415
  clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId', self.uuid())
2044
2416
  params = self.omit(params, ['clientOid', 'clientOrderId'])
2045
- request = {
2417
+ request: dict = {
2046
2418
  'clientOid': clientOrderId,
2047
2419
  'side': side,
2048
2420
  'symbol': market['id'],
@@ -2057,7 +2429,7 @@ class kucoin(Exchange, ImplicitAPI):
2057
2429
  if quoteAmount is not None:
2058
2430
  params = self.omit(params, ['cost', 'funds'])
2059
2431
  # kucoin uses base precision even for quote values
2060
- costString = self.amount_to_precision(symbol, quoteAmount)
2432
+ costString = self.market_order_amount_to_precision(symbol, quoteAmount)
2061
2433
  request['funds'] = costString
2062
2434
  else:
2063
2435
  amountString = self.amount_to_precision(symbol, amount)
@@ -2097,20 +2469,22 @@ class kucoin(Exchange, ImplicitAPI):
2097
2469
  def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
2098
2470
  """
2099
2471
  edit an order, kucoin currently only supports the modification of HF orders
2100
- :see: https://docs.kucoin.com/spot-hf/#modify-order
2472
+
2473
+ https://docs.kucoin.com/spot-hf/#modify-order
2474
+
2101
2475
  :param str id: order id
2102
2476
  :param str symbol: unified symbol of the market to create an order in
2103
2477
  :param str type: not used
2104
2478
  :param str side: not used
2105
2479
  :param float amount: how much of the currency you want to trade in units of the base currency
2106
- :param float [price]: the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
2480
+ :param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
2107
2481
  :param dict [params]: extra parameters specific to the exchange API endpoint
2108
2482
  :param str [params.clientOrderId]: client order id, defaults to id if not passed
2109
2483
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2110
2484
  """
2111
2485
  self.load_markets()
2112
2486
  market = self.market(symbol)
2113
- request = {
2487
+ request: dict = {
2114
2488
  'symbol': market['id'],
2115
2489
  }
2116
2490
  clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId')
@@ -2137,78 +2511,149 @@ class kucoin(Exchange, ImplicitAPI):
2137
2511
  def cancel_order(self, id: str, symbol: Str = None, params={}):
2138
2512
  """
2139
2513
  cancels an open order
2140
- :see: https://docs.kucoin.com/spot#cancel-an-order
2141
- :see: https://docs.kucoin.com/spot#cancel-an-order-2
2142
- :see: https://docs.kucoin.com/spot#cancel-single-order-by-clientoid
2143
- :see: https://docs.kucoin.com/spot#cancel-single-order-by-clientoid-2
2144
- :see: https://docs.kucoin.com/spot-hf/#cancel-orders-by-orderid
2145
- :see: https://docs.kucoin.com/spot-hf/#cancel-order-by-clientoid
2514
+
2515
+ https://docs.kucoin.com/spot#cancel-an-order
2516
+ https://docs.kucoin.com/spot#cancel-an-order-2
2517
+ https://docs.kucoin.com/spot#cancel-single-order-by-clientoid
2518
+ https://docs.kucoin.com/spot#cancel-single-order-by-clientoid-2
2519
+ https://docs.kucoin.com/spot-hf/#cancel-orders-by-orderid
2520
+ https://docs.kucoin.com/spot-hf/#cancel-order-by-clientoid
2521
+ https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/sync-cancel-hf-order-by-orderid
2522
+ https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/sync-cancel-hf-order-by-clientoid
2523
+
2146
2524
  :param str id: order id
2147
2525
  :param str symbol: unified symbol of the market the order was made in
2148
2526
  :param dict [params]: extra parameters specific to the exchange API endpoint
2149
- :param bool [params.stop]: True if cancelling a stop order
2527
+ :param bool [params.trigger]: True if cancelling a stop order
2150
2528
  :param bool [params.hf]: False, # True for hf order
2529
+ :param bool [params.sync]: False, # True to use the hf sync call
2151
2530
  :returns: Response from the exchange
2152
2531
  """
2153
2532
  self.load_markets()
2154
- request = {}
2533
+ request: dict = {}
2155
2534
  clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId')
2156
- stop = self.safe_bool_2(params, 'stop', 'trigger', False)
2157
- hf = self.safe_bool(params, 'hf', False)
2158
- if hf:
2535
+ trigger = self.safe_bool_2(params, 'stop', 'trigger', False)
2536
+ hf = None
2537
+ hf, params = self.handle_hf_and_params(params)
2538
+ useSync = False
2539
+ useSync, params = self.handle_option_and_params(params, 'cancelOrder', 'sync', False)
2540
+ if hf or useSync:
2159
2541
  if symbol is None:
2160
2542
  raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol parameter for hf orders')
2161
2543
  market = self.market(symbol)
2162
2544
  request['symbol'] = market['id']
2163
2545
  response = None
2164
- params = self.omit(params, ['clientOid', 'clientOrderId', 'stop', 'hf', 'trigger'])
2546
+ params = self.omit(params, ['clientOid', 'clientOrderId', 'stop', 'trigger'])
2165
2547
  if clientOrderId is not None:
2166
2548
  request['clientOid'] = clientOrderId
2167
- if stop:
2549
+ if trigger:
2168
2550
  response = self.privateDeleteStopOrderCancelOrderByClientOid(self.extend(request, params))
2551
+ #
2552
+ # {
2553
+ # code: '200000',
2554
+ # data: {
2555
+ # cancelledOrderId: 'vs8lgpiuao41iaft003khbbk',
2556
+ # clientOid: '123456'
2557
+ # }
2558
+ # }
2559
+ #
2560
+ elif useSync:
2561
+ response = self.privateDeleteHfOrdersSyncClientOrderClientOid(self.extend(request, params))
2169
2562
  elif hf:
2170
2563
  response = self.privateDeleteHfOrdersClientOrderClientOid(self.extend(request, params))
2564
+ #
2565
+ # {
2566
+ # "code": "200000",
2567
+ # "data": {
2568
+ # "clientOid": "6d539dc614db3"
2569
+ # }
2570
+ # }
2571
+ #
2171
2572
  else:
2172
2573
  response = self.privateDeleteOrderClientOrderClientOid(self.extend(request, params))
2574
+ #
2575
+ # {
2576
+ # code: '200000',
2577
+ # data: {
2578
+ # cancelledOrderId: '665e580f6660500007aba341',
2579
+ # clientOid: '1234567',
2580
+ # cancelledOcoOrderIds: null
2581
+ # }
2582
+ # }
2583
+ #
2584
+ response = self.safe_dict(response, 'data')
2585
+ return self.parse_order(response)
2173
2586
  else:
2174
2587
  request['orderId'] = id
2175
- if stop:
2588
+ if trigger:
2176
2589
  response = self.privateDeleteStopOrderOrderId(self.extend(request, params))
2590
+ #
2591
+ # {
2592
+ # code: '200000',
2593
+ # data: {cancelledOrderIds: ['vs8lgpiuaco91qk8003vebu9']}
2594
+ # }
2595
+ #
2596
+ elif useSync:
2597
+ response = self.privateDeleteHfOrdersSyncOrderId(self.extend(request, params))
2177
2598
  elif hf:
2178
2599
  response = self.privateDeleteHfOrdersOrderId(self.extend(request, params))
2600
+ #
2601
+ # {
2602
+ # "code": "200000",
2603
+ # "data": {
2604
+ # "orderId": "630625dbd9180300014c8d52"
2605
+ # }
2606
+ # }
2607
+ #
2608
+ response = self.safe_dict(response, 'data')
2609
+ return self.parse_order(response)
2179
2610
  else:
2180
2611
  response = self.privateDeleteOrdersOrderId(self.extend(request, params))
2181
- return response
2612
+ #
2613
+ # {
2614
+ # code: '200000',
2615
+ # data: {cancelledOrderIds: ['665e4fbe28051a0007245c41']}
2616
+ # }
2617
+ #
2618
+ data = self.safe_dict(response, 'data')
2619
+ orderIds = self.safe_list(data, 'cancelledOrderIds', [])
2620
+ orderId = self.safe_string(orderIds, 0)
2621
+ return self.safe_order({
2622
+ 'info': data,
2623
+ 'id': orderId,
2624
+ })
2182
2625
 
2183
2626
  def cancel_all_orders(self, symbol: Str = None, params={}):
2184
2627
  """
2185
2628
  cancel all open orders
2186
- :see: https://docs.kucoin.com/spot#cancel-all-orders
2187
- :see: https://docs.kucoin.com/spot#cancel-orders
2188
- :see: https://docs.kucoin.com/spot-hf/#cancel-all-hf-orders-by-symbol
2629
+
2630
+ https://docs.kucoin.com/spot#cancel-all-orders
2631
+ https://docs.kucoin.com/spot#cancel-orders
2632
+ https://docs.kucoin.com/spot-hf/#cancel-all-hf-orders-by-symbol
2633
+
2189
2634
  :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
2190
2635
  :param dict [params]: extra parameters specific to the exchange API endpoint
2191
- :param bool [params.stop]: *invalid for isolated margin* True if cancelling all stop orders
2636
+ :param bool [params.trigger]: *invalid for isolated margin* True if cancelling all stop orders
2192
2637
  :param str [params.marginMode]: 'cross' or 'isolated'
2193
2638
  :param str [params.orderIds]: *stop orders only* Comma seperated order IDs
2194
- :param bool [params.stop]: True if cancelling a stop order
2195
2639
  :param bool [params.hf]: False, # True for hf order
2196
2640
  :returns: Response from the exchange
2197
2641
  """
2198
2642
  self.load_markets()
2199
- request = {}
2200
- stop = self.safe_bool(params, 'stop', False)
2201
- hf = self.safe_bool(params, 'hf', False)
2202
- params = self.omit(params, ['stop', 'hf'])
2643
+ request: dict = {}
2644
+ trigger = self.safe_bool(params, 'stop', False)
2645
+ hf = None
2646
+ hf, params = self.handle_hf_and_params(params)
2647
+ params = self.omit(params, 'stop')
2203
2648
  marginMode, query = self.handle_margin_mode_and_params('cancelAllOrders', params)
2204
2649
  if symbol is not None:
2205
2650
  request['symbol'] = self.market_id(symbol)
2206
2651
  if marginMode is not None:
2207
2652
  request['tradeType'] = self.options['marginModes'][marginMode]
2208
- if marginMode == 'isolated' and stop:
2653
+ if marginMode == 'isolated' and trigger:
2209
2654
  raise BadRequest(self.id + ' cancelAllOrders does not support isolated margin for stop orders')
2210
2655
  response = None
2211
- if stop:
2656
+ if trigger:
2212
2657
  response = self.privateDeleteStopOrderCancel(self.extend(request, query))
2213
2658
  elif hf:
2214
2659
  if symbol is None:
@@ -2222,38 +2667,42 @@ class kucoin(Exchange, ImplicitAPI):
2222
2667
  def fetch_orders_by_status(self, status, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2223
2668
  """
2224
2669
  fetch a list of orders
2225
- :see: https://docs.kucoin.com/spot#list-orders
2226
- :see: https://docs.kucoin.com/spot#list-stop-orders
2227
- :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2228
- :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2670
+
2671
+ https://docs.kucoin.com/spot#list-orders
2672
+ https://docs.kucoin.com/spot#list-stop-orders
2673
+ https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2674
+ https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2675
+
2229
2676
  :param str status: *not used for stop orders* 'open' or 'closed'
2230
2677
  :param str symbol: unified market symbol
2231
2678
  :param int [since]: timestamp in ms of the earliest order
2232
2679
  :param int [limit]: max number of orders to return
2233
2680
  :param dict [params]: exchange specific params
2234
2681
  :param int [params.until]: end time in ms
2235
- :param bool [params.stop]: True if fetching stop orders
2236
2682
  :param str [params.side]: buy or sell
2237
2683
  :param str [params.type]: limit, market, limit_stop or market_stop
2238
2684
  :param str [params.tradeType]: TRADE for spot trading, MARGIN_TRADE for Margin Trading
2239
- :param int [params.currentPage]: *stop orders only* current page
2240
- :param str [params.orderIds]: *stop orders only* comma seperated order ID list
2241
- :param bool [params.stop]: True if fetching a stop order
2685
+ :param int [params.currentPage]: *trigger orders only* current page
2686
+ :param str [params.orderIds]: *trigger orders only* comma seperated order ID list
2687
+ :param bool [params.trigger]: True if fetching a trigger order
2242
2688
  :param bool [params.hf]: False, # True for hf order
2243
2689
  :returns: An `array of order structures <https://docs.ccxt.com/#/?id=order-structure>`
2244
2690
  """
2245
2691
  self.load_markets()
2246
2692
  lowercaseStatus = status.lower()
2247
- until = self.safe_integer_2(params, 'until', 'till')
2248
- stop = self.safe_bool(params, 'stop', False)
2249
- hf = self.safe_bool(params, 'hf', False)
2250
- params = self.omit(params, ['stop', 'hf', 'till', 'until'])
2693
+ until = self.safe_integer(params, 'until')
2694
+ trigger = self.safe_bool_2(params, 'stop', 'trigger', False)
2695
+ hf = None
2696
+ hf, params = self.handle_hf_and_params(params)
2697
+ if hf and (symbol is None):
2698
+ raise ArgumentsRequired(self.id + ' fetchOrdersByStatus() requires a symbol parameter for hf orders')
2699
+ params = self.omit(params, ['stop', 'trigger', 'till', 'until'])
2251
2700
  marginMode, query = self.handle_margin_mode_and_params('fetchOrdersByStatus', params)
2252
2701
  if lowercaseStatus == 'open':
2253
2702
  lowercaseStatus = 'active'
2254
2703
  elif lowercaseStatus == 'closed':
2255
2704
  lowercaseStatus = 'done'
2256
- request = {
2705
+ request: dict = {
2257
2706
  'status': lowercaseStatus,
2258
2707
  }
2259
2708
  market = None
@@ -2268,7 +2717,7 @@ class kucoin(Exchange, ImplicitAPI):
2268
2717
  request['endAt'] = until
2269
2718
  request['tradeType'] = self.safe_string(self.options['marginModes'], marginMode, 'TRADE')
2270
2719
  response = None
2271
- if stop:
2720
+ if trigger:
2272
2721
  response = self.privateGetStopOrder(self.extend(request, query))
2273
2722
  elif hf:
2274
2723
  if lowercaseStatus == 'active':
@@ -2320,26 +2769,31 @@ class kucoin(Exchange, ImplicitAPI):
2320
2769
  # ]
2321
2770
  # }
2322
2771
  # }
2772
+ listData = self.safe_list(response, 'data')
2773
+ if listData is not None:
2774
+ return self.parse_orders(listData, market, since, limit)
2323
2775
  responseData = self.safe_dict(response, 'data', {})
2324
- orders = self.safe_value(responseData, 'items', responseData)
2776
+ orders = self.safe_list(responseData, 'items', [])
2325
2777
  return self.parse_orders(orders, market, since, limit)
2326
2778
 
2327
2779
  def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2328
2780
  """
2329
2781
  fetches information on multiple closed orders made by the user
2330
- :see: https://docs.kucoin.com/spot#list-orders
2331
- :see: https://docs.kucoin.com/spot#list-stop-orders
2332
- :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2333
- :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2782
+
2783
+ https://docs.kucoin.com/spot#list-orders
2784
+ https://docs.kucoin.com/spot#list-stop-orders
2785
+ https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2786
+ https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2787
+
2334
2788
  :param str symbol: unified market symbol of the market orders were made in
2335
2789
  :param int [since]: the earliest time in ms to fetch orders for
2336
2790
  :param int [limit]: the maximum number of order structures to retrieve
2337
2791
  :param dict [params]: extra parameters specific to the exchange API endpoint
2338
- :param int [params.till]: end time in ms
2792
+ :param int [params.until]: end time in ms
2339
2793
  :param str [params.side]: buy or sell
2340
2794
  :param str [params.type]: limit, market, limit_stop or market_stop
2341
2795
  :param str [params.tradeType]: TRADE for spot trading, MARGIN_TRADE for Margin Trading
2342
- :param bool [params.stop]: True if fetching a stop order
2796
+ :param bool [params.trigger]: True if fetching a trigger order
2343
2797
  :param bool [params.hf]: False, # True for hf order
2344
2798
  :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)
2345
2799
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
@@ -2354,22 +2808,23 @@ class kucoin(Exchange, ImplicitAPI):
2354
2808
  def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2355
2809
  """
2356
2810
  fetch all unfilled currently open orders
2357
- :see: https://docs.kucoin.com/spot#list-orders
2358
- :see: https://docs.kucoin.com/spot#list-stop-orders
2359
- :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2360
- :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2811
+
2812
+ https://docs.kucoin.com/spot#list-orders
2813
+ https://docs.kucoin.com/spot#list-stop-orders
2814
+ https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2815
+ https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2816
+
2361
2817
  :param str symbol: unified market symbol
2362
2818
  :param int [since]: the earliest time in ms to fetch open orders for
2363
2819
  :param int [limit]: the maximum number of open orders structures to retrieve
2364
2820
  :param dict [params]: extra parameters specific to the exchange API endpoint
2365
- :param int [params.till]: end time in ms
2366
- :param bool [params.stop]: True if fetching stop orders
2821
+ :param int [params.until]: end time in ms
2822
+ :param bool [params.trigger]: True if fetching trigger orders
2367
2823
  :param str [params.side]: buy or sell
2368
2824
  :param str [params.type]: limit, market, limit_stop or market_stop
2369
2825
  :param str [params.tradeType]: TRADE for spot trading, MARGIN_TRADE for Margin Trading
2370
- :param int [params.currentPage]: *stop orders only* current page
2371
- :param str [params.orderIds]: *stop orders only* comma seperated order ID list
2372
- :param bool [params.stop]: True if fetching a stop order
2826
+ :param int [params.currentPage]: *trigger orders only* current page
2827
+ :param str [params.orderIds]: *trigger orders only* comma seperated order ID list
2373
2828
  :param bool [params.hf]: False, # True for hf order
2374
2829
  :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)
2375
2830
  :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
@@ -2384,25 +2839,28 @@ class kucoin(Exchange, ImplicitAPI):
2384
2839
  def fetch_order(self, id: str, symbol: Str = None, params={}):
2385
2840
  """
2386
2841
  fetch an order
2387
- :see: https://docs.kucoin.com/spot#get-an-order
2388
- :see: https://docs.kucoin.com/spot#get-single-active-order-by-clientoid
2389
- :see: https://docs.kucoin.com/spot#get-single-order-info
2390
- :see: https://docs.kucoin.com/spot#get-single-order-by-clientoid
2391
- :see: https://docs.kucoin.com/spot-hf/#details-of-a-single-hf-order
2392
- :see: https://docs.kucoin.com/spot-hf/#obtain-details-of-a-single-hf-order-using-clientoid
2842
+
2843
+ https://docs.kucoin.com/spot#get-an-order
2844
+ https://docs.kucoin.com/spot#get-single-active-order-by-clientoid
2845
+ https://docs.kucoin.com/spot#get-single-order-info
2846
+ https://docs.kucoin.com/spot#get-single-order-by-clientoid
2847
+ https://docs.kucoin.com/spot-hf/#details-of-a-single-hf-order
2848
+ https://docs.kucoin.com/spot-hf/#obtain-details-of-a-single-hf-order-using-clientoid
2849
+
2393
2850
  :param str id: Order id
2394
- :param str symbol: not sent to exchange except for stop orders with clientOid, but used internally by CCXT to filter
2851
+ :param str symbol: not sent to exchange except for trigger orders with clientOid, but used internally by CCXT to filter
2395
2852
  :param dict [params]: exchange specific parameters
2396
- :param bool [params.stop]: True if fetching a stop order
2853
+ :param bool [params.trigger]: True if fetching a trigger order
2397
2854
  :param bool [params.hf]: False, # True for hf order
2398
2855
  :param bool [params.clientOid]: unique order id created by users to identify their orders
2399
2856
  :returns: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2400
2857
  """
2401
2858
  self.load_markets()
2402
- request = {}
2859
+ request: dict = {}
2403
2860
  clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId')
2404
- stop = self.safe_bool(params, 'stop', False)
2405
- hf = self.safe_bool(params, 'hf', False)
2861
+ trigger = self.safe_bool_2(params, 'stop', 'trigger', False)
2862
+ hf = None
2863
+ hf, params = self.handle_hf_and_params(params)
2406
2864
  market = None
2407
2865
  if symbol is not None:
2408
2866
  market = self.market(symbol)
@@ -2410,11 +2868,11 @@ class kucoin(Exchange, ImplicitAPI):
2410
2868
  if symbol is None:
2411
2869
  raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol parameter for hf orders')
2412
2870
  request['symbol'] = market['id']
2413
- params = self.omit(params, ['stop', 'hf', 'clientOid', 'clientOrderId'])
2871
+ params = self.omit(params, ['stop', 'clientOid', 'clientOrderId', 'trigger'])
2414
2872
  response = None
2415
2873
  if clientOrderId is not None:
2416
2874
  request['clientOid'] = clientOrderId
2417
- if stop:
2875
+ if trigger:
2418
2876
  if symbol is not None:
2419
2877
  request['symbol'] = market['id']
2420
2878
  response = self.privateGetStopOrderQueryOrderByClientOid(self.extend(request, params))
@@ -2429,7 +2887,7 @@ class kucoin(Exchange, ImplicitAPI):
2429
2887
  if id is None:
2430
2888
  raise InvalidOrder(self.id + ' fetchOrder() requires an order id')
2431
2889
  request['orderId'] = id
2432
- if stop:
2890
+ if trigger:
2433
2891
  response = self.privateGetStopOrderOrderId(self.extend(request, params))
2434
2892
  elif hf:
2435
2893
  response = self.privateGetHfOrdersOrderId(self.extend(request, params))
@@ -2440,7 +2898,7 @@ class kucoin(Exchange, ImplicitAPI):
2440
2898
  responseData = self.safe_value(responseData, 0)
2441
2899
  return self.parse_order(responseData, market)
2442
2900
 
2443
- def parse_order(self, order, market: Market = None) -> Order:
2901
+ def parse_order(self, order: dict, market: Market = None) -> Order:
2444
2902
  #
2445
2903
  # createOrder
2446
2904
  #
@@ -2567,7 +3025,7 @@ class kucoin(Exchange, ImplicitAPI):
2567
3025
  feeCurrencyId = self.safe_string(order, 'feeCurrency')
2568
3026
  cancelExist = self.safe_bool(order, 'cancelExist', False)
2569
3027
  responseStop = self.safe_string(order, 'stop')
2570
- stop = responseStop is not None
3028
+ trigger = responseStop is not None
2571
3029
  stopTriggered = self.safe_bool(order, 'stopTriggered', False)
2572
3030
  isActive = self.safe_bool_2(order, 'isActive', 'active')
2573
3031
  responseStatus = self.safe_string(order, 'status')
@@ -2577,7 +3035,7 @@ class kucoin(Exchange, ImplicitAPI):
2577
3035
  status = 'open'
2578
3036
  else:
2579
3037
  status = 'closed'
2580
- if stop:
3038
+ if trigger:
2581
3039
  if responseStatus == 'NEW':
2582
3040
  status = 'open'
2583
3041
  elif not isActive and not stopTriggered:
@@ -2586,10 +3044,9 @@ class kucoin(Exchange, ImplicitAPI):
2586
3044
  status = 'canceled'
2587
3045
  if responseStatus == 'fail':
2588
3046
  status = 'rejected'
2589
- stopPrice = self.safe_number(order, 'stopPrice')
2590
3047
  return self.safe_order({
2591
3048
  'info': order,
2592
- 'id': self.safe_string_n(order, ['id', 'orderId', 'newOrderId']),
3049
+ 'id': self.safe_string_n(order, ['id', 'orderId', 'newOrderId', 'cancelledOrderId']),
2593
3050
  'clientOrderId': self.safe_string(order, 'clientOid'),
2594
3051
  'symbol': self.safe_symbol(marketId, market, '-'),
2595
3052
  'type': self.safe_string(order, 'type'),
@@ -2598,8 +3055,7 @@ class kucoin(Exchange, ImplicitAPI):
2598
3055
  'side': self.safe_string(order, 'side'),
2599
3056
  'amount': self.safe_string(order, 'size'),
2600
3057
  'price': self.safe_string(order, 'price'), # price is zero for market order, omitZero is called in safeOrder2
2601
- 'stopPrice': stopPrice,
2602
- 'triggerPrice': stopPrice,
3058
+ 'triggerPrice': self.safe_number(order, 'stopPrice'),
2603
3059
  'cost': self.safe_string(order, 'dealFunds'),
2604
3060
  'filled': self.safe_string(order, 'dealSize'),
2605
3061
  'remaining': None,
@@ -2611,15 +3067,17 @@ class kucoin(Exchange, ImplicitAPI):
2611
3067
  },
2612
3068
  'status': status,
2613
3069
  'lastTradeTimestamp': None,
2614
- 'average': None,
3070
+ 'average': self.safe_string(order, 'avgDealPrice'),
2615
3071
  'trades': None,
2616
3072
  }, market)
2617
3073
 
2618
3074
  def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2619
3075
  """
2620
3076
  fetch all the trades made from a single order
2621
- :see: https://docs.kucoin.com/#list-fills
2622
- :see: https://docs.kucoin.com/spot-hf/#transaction-details
3077
+
3078
+ https://docs.kucoin.com/#list-fills
3079
+ https://docs.kucoin.com/spot-hf/#transaction-details
3080
+
2623
3081
  :param str id: order id
2624
3082
  :param str symbol: unified market symbol
2625
3083
  :param int [since]: the earliest time in ms to fetch trades for
@@ -2627,15 +3085,17 @@ class kucoin(Exchange, ImplicitAPI):
2627
3085
  :param dict [params]: extra parameters specific to the exchange API endpoint
2628
3086
  :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2629
3087
  """
2630
- request = {
3088
+ request: dict = {
2631
3089
  'orderId': id,
2632
3090
  }
2633
3091
  return self.fetch_my_trades(symbol, since, limit, self.extend(request, params))
2634
3092
 
2635
3093
  def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2636
3094
  """
2637
- :see: https://docs.kucoin.com/#list-fills
2638
- :see: https://docs.kucoin.com/spot-hf/#transaction-details
3095
+
3096
+ https://docs.kucoin.com/#list-fills
3097
+ https://docs.kucoin.com/spot-hf/#transaction-details
3098
+
2639
3099
  fetch all trades made by the user
2640
3100
  :param str symbol: unified market symbol
2641
3101
  :param int [since]: the earliest time in ms to fetch trades for
@@ -2651,8 +3111,9 @@ class kucoin(Exchange, ImplicitAPI):
2651
3111
  paginate, params = self.handle_option_and_params(params, 'fetchMyTrades', 'paginate')
2652
3112
  if paginate:
2653
3113
  return self.fetch_paginated_call_dynamic('fetchMyTrades', symbol, since, limit, params)
2654
- request = {}
2655
- hf = self.safe_bool(params, 'hf', False)
3114
+ request: dict = {}
3115
+ hf = None
3116
+ hf, params = self.handle_hf_and_params(params)
2656
3117
  if hf and symbol is None:
2657
3118
  raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol parameter for hf orders')
2658
3119
  market = None
@@ -2666,6 +3127,10 @@ class kucoin(Exchange, ImplicitAPI):
2666
3127
  response = None
2667
3128
  request, params = self.handle_until_option('endAt', request, params)
2668
3129
  if hf:
3130
+ # does not return trades earlier than 2019-02-18T00:00:00Z
3131
+ if since is not None:
3132
+ # only returns trades up to one week after the since param
3133
+ request['startAt'] = since
2669
3134
  response = self.privateGetHfFills(self.extend(request, params))
2670
3135
  elif method == 'private_get_fills':
2671
3136
  # does not return trades earlier than 2019-02-18T00:00:00Z
@@ -2732,7 +3197,9 @@ class kucoin(Exchange, ImplicitAPI):
2732
3197
  def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
2733
3198
  """
2734
3199
  get the list of most recent trades for a particular symbol
2735
- :see: https://docs.kucoin.com/#get-trade-histories
3200
+
3201
+ https://www.kucoin.com/docs/rest/spot-trading/market-data/get-trade-histories
3202
+
2736
3203
  :param str symbol: unified symbol of the market to fetch trades for
2737
3204
  :param int [since]: timestamp in ms of the earliest trade to fetch
2738
3205
  :param int [limit]: the maximum amount of trades to fetch
@@ -2741,7 +3208,7 @@ class kucoin(Exchange, ImplicitAPI):
2741
3208
  """
2742
3209
  self.load_markets()
2743
3210
  market = self.market(symbol)
2744
- request = {
3211
+ request: dict = {
2745
3212
  'symbol': market['id'],
2746
3213
  }
2747
3214
  # pagination is not supported on the exchange side anymore
@@ -2769,7 +3236,7 @@ class kucoin(Exchange, ImplicitAPI):
2769
3236
  trades = self.safe_list(response, 'data', [])
2770
3237
  return self.parse_trades(trades, market, since, limit)
2771
3238
 
2772
- def parse_trade(self, trade, market: Market = None) -> Trade:
3239
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
2773
3240
  #
2774
3241
  # fetchTrades(public)
2775
3242
  #
@@ -2894,17 +3361,19 @@ class kucoin(Exchange, ImplicitAPI):
2894
3361
  'fee': fee,
2895
3362
  }, market)
2896
3363
 
2897
- def fetch_trading_fee(self, symbol: str, params={}):
3364
+ def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
2898
3365
  """
2899
3366
  fetch the trading fees for a market
2900
- :see: https://docs.kucoin.com/#actual-fee-rate-of-the-trading-pair
3367
+
3368
+ https://www.kucoin.com/docs/rest/funding/trade-fee/trading-pair-actual-fee-spot-margin-trade_hf
3369
+
2901
3370
  :param str symbol: unified market symbol
2902
3371
  :param dict [params]: extra parameters specific to the exchange API endpoint
2903
3372
  :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
2904
3373
  """
2905
3374
  self.load_markets()
2906
3375
  market = self.market(symbol)
2907
- request = {
3376
+ request: dict = {
2908
3377
  'symbols': market['id'],
2909
3378
  }
2910
3379
  response = self.privateGetTradeFees(self.extend(request, params))
@@ -2932,10 +3401,12 @@ class kucoin(Exchange, ImplicitAPI):
2932
3401
  'tierBased': True,
2933
3402
  }
2934
3403
 
2935
- def withdraw(self, code: str, amount: float, address, tag=None, params={}):
3404
+ def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction:
2936
3405
  """
2937
3406
  make a withdrawal
2938
- :see: https://docs.kucoin.com/#apply-withdraw-2
3407
+
3408
+ https://www.kucoin.com/docs/rest/funding/withdrawals/apply-withdraw-v3-
3409
+
2939
3410
  :param str code: unified currency code
2940
3411
  :param float amount: the amount to withdraw
2941
3412
  :param str address: the address to withdraw to
@@ -2947,10 +3418,10 @@ class kucoin(Exchange, ImplicitAPI):
2947
3418
  self.load_markets()
2948
3419
  self.check_address(address)
2949
3420
  currency = self.currency(code)
2950
- request = {
3421
+ request: dict = {
2951
3422
  'currency': currency['id'],
2952
- 'address': address,
2953
- 'amount': amount,
3423
+ 'toAddress': address,
3424
+ 'withdrawType': 'ADDRESS',
2954
3425
  # 'memo': tag,
2955
3426
  # 'isInner': False, # internal transfer or external withdrawal
2956
3427
  # 'remark': 'optional',
@@ -2962,13 +3433,14 @@ class kucoin(Exchange, ImplicitAPI):
2962
3433
  networkCode, params = self.handle_network_code_and_params(params)
2963
3434
  if networkCode is not None:
2964
3435
  request['chain'] = self.network_code_to_id(networkCode).lower()
3436
+ request['amount'] = float(self.currency_to_precision(code, amount, networkCode))
2965
3437
  includeFee = None
2966
3438
  includeFee, params = self.handle_option_and_params(params, 'withdraw', 'includeFee', False)
2967
3439
  if includeFee:
2968
3440
  request['feeDeductType'] = 'INTERNAL'
2969
3441
  response = self.privatePostWithdrawals(self.extend(request, params))
2970
3442
  #
2971
- # https://github.com/ccxt/ccxt/issues/5558
3443
+ # the id is inside "data"
2972
3444
  #
2973
3445
  # {
2974
3446
  # "code": 200000,
@@ -2980,8 +3452,8 @@ class kucoin(Exchange, ImplicitAPI):
2980
3452
  data = self.safe_dict(response, 'data', {})
2981
3453
  return self.parse_transaction(data, currency)
2982
3454
 
2983
- def parse_transaction_status(self, status):
2984
- statuses = {
3455
+ def parse_transaction_status(self, status: Str):
3456
+ statuses: dict = {
2985
3457
  'SUCCESS': 'ok',
2986
3458
  'PROCESSING': 'pending',
2987
3459
  'WALLET_PROCESSING': 'pending',
@@ -2989,7 +3461,7 @@ class kucoin(Exchange, ImplicitAPI):
2989
3461
  }
2990
3462
  return self.safe_string(statuses, status, status)
2991
3463
 
2992
- def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
3464
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
2993
3465
  #
2994
3466
  # fetchDeposits
2995
3467
  #
@@ -3096,8 +3568,10 @@ class kucoin(Exchange, ImplicitAPI):
3096
3568
  def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3097
3569
  """
3098
3570
  fetch all deposits made to an account
3099
- :see: https://docs.kucoin.com/#get-deposit-list
3100
- :see: https://docs.kucoin.com/#get-v1-historical-deposits-list
3571
+
3572
+ https://www.kucoin.com/docs/rest/funding/deposit/get-deposit-list
3573
+ https://www.kucoin.com/docs/rest/funding/deposit/get-v1-historical-deposits-list
3574
+
3101
3575
  :param str code: unified currency code
3102
3576
  :param int [since]: the earliest time in ms to fetch deposits for
3103
3577
  :param int [limit]: the maximum number of deposits structures to retrieve
@@ -3111,7 +3585,7 @@ class kucoin(Exchange, ImplicitAPI):
3111
3585
  paginate, params = self.handle_option_and_params(params, 'fetchDeposits', 'paginate')
3112
3586
  if paginate:
3113
3587
  return self.fetch_paginated_call_dynamic('fetchDeposits', code, since, limit, params)
3114
- request = {}
3588
+ request: dict = {}
3115
3589
  currency = None
3116
3590
  if code is not None:
3117
3591
  currency = self.currency(code)
@@ -3166,14 +3640,17 @@ class kucoin(Exchange, ImplicitAPI):
3166
3640
  # }
3167
3641
  # }
3168
3642
  #
3169
- responseData = response['data']['items']
3170
- return self.parse_transactions(responseData, currency, since, limit, {'type': 'deposit'})
3643
+ data = self.safe_dict(response, 'data', {})
3644
+ items = self.safe_list(data, 'items', [])
3645
+ return self.parse_transactions(items, currency, since, limit, {'type': 'deposit'})
3171
3646
 
3172
3647
  def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3173
3648
  """
3174
3649
  fetch all withdrawals made from an account
3175
- :see: https://docs.kucoin.com/#get-withdrawals-list
3176
- :see: https://docs.kucoin.com/#get-v1-historical-withdrawals-list
3650
+
3651
+ https://www.kucoin.com/docs/rest/funding/withdrawals/get-withdrawals-list
3652
+ https://www.kucoin.com/docs/rest/funding/withdrawals/get-v1-historical-withdrawals-list
3653
+
3177
3654
  :param str code: unified currency code
3178
3655
  :param int [since]: the earliest time in ms to fetch withdrawals for
3179
3656
  :param int [limit]: the maximum number of withdrawals structures to retrieve
@@ -3187,7 +3664,7 @@ class kucoin(Exchange, ImplicitAPI):
3187
3664
  paginate, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'paginate')
3188
3665
  if paginate:
3189
3666
  return self.fetch_paginated_call_dynamic('fetchWithdrawals', code, since, limit, params)
3190
- request = {}
3667
+ request: dict = {}
3191
3668
  currency = None
3192
3669
  if code is not None:
3193
3670
  currency = self.currency(code)
@@ -3243,14 +3720,15 @@ class kucoin(Exchange, ImplicitAPI):
3243
3720
  # }
3244
3721
  # }
3245
3722
  #
3246
- responseData = response['data']['items']
3247
- return self.parse_transactions(responseData, currency, since, limit, {'type': 'withdrawal'})
3723
+ data = self.safe_dict(response, 'data', {})
3724
+ items = self.safe_list(data, 'items', [])
3725
+ return self.parse_transactions(items, currency, since, limit, {'type': 'withdrawal'})
3248
3726
 
3249
3727
  def parse_balance_helper(self, entry):
3250
3728
  account = self.account()
3251
- account['used'] = self.safe_string(entry, 'holdBalance')
3252
- account['free'] = self.safe_string(entry, 'availableBalance')
3253
- account['total'] = self.safe_string(entry, 'totalBalance')
3729
+ account['used'] = self.safe_string_2(entry, 'holdBalance', 'hold')
3730
+ account['free'] = self.safe_string_2(entry, 'availableBalance', 'available')
3731
+ account['total'] = self.safe_string_2(entry, 'totalBalance', 'total')
3254
3732
  debt = self.safe_string(entry, 'liability')
3255
3733
  interest = self.safe_string(entry, 'interest')
3256
3734
  account['debt'] = Precise.string_add(debt, interest)
@@ -3259,9 +3737,11 @@ class kucoin(Exchange, ImplicitAPI):
3259
3737
  def fetch_balance(self, params={}) -> Balances:
3260
3738
  """
3261
3739
  query for balance and get the amount of funds available for trading or funds locked in orders
3262
- :see: https://docs.kucoin.com/#list-accounts
3263
- :see: https://www.kucoin.com/docs/rest/account/basic-info/get-account-list-spot-margin-trade_hf
3264
- :see: https://docs.kucoin.com/#query-isolated-margin-account-info
3740
+
3741
+ https://www.kucoin.com/docs/rest/account/basic-info/get-account-list-spot-margin-trade_hf
3742
+ https://www.kucoin.com/docs/rest/funding/funding-overview/get-account-detail-margin
3743
+ https://www.kucoin.com/docs/rest/funding/funding-overview/get-account-detail-isolated-margin
3744
+
3265
3745
  :param dict [params]: extra parameters specific to the exchange API endpoint
3266
3746
  :param dict [params.marginMode]: 'cross' or 'isolated', margin type for fetching margin balance
3267
3747
  :param dict [params.type]: extra parameters specific to the exchange API endpoint
@@ -3278,15 +3758,15 @@ class kucoin(Exchange, ImplicitAPI):
3278
3758
  accountsByType = self.safe_dict(self.options, 'accountsByType')
3279
3759
  type = self.safe_string(accountsByType, requestedType, requestedType)
3280
3760
  params = self.omit(params, 'type')
3281
- isHf = self.safe_bool(params, 'hf', False)
3282
- if isHf:
3761
+ hf = None
3762
+ hf, params = self.handle_hf_and_params(params)
3763
+ if hf and (type != 'main'):
3283
3764
  type = 'trade_hf'
3284
- params = self.omit(params, 'hf')
3285
3765
  marginMode, query = self.handle_margin_mode_and_params('fetchBalance', params)
3286
3766
  response = None
3287
- request = {}
3767
+ request: dict = {}
3288
3768
  isolated = (marginMode == 'isolated') or (type == 'isolated')
3289
- cross = (marginMode == 'cross') or (type == 'cross')
3769
+ cross = (marginMode == 'cross') or (type == 'margin')
3290
3770
  if isolated:
3291
3771
  if currency is not None:
3292
3772
  request['balanceCurrency'] = currency['id']
@@ -3299,7 +3779,7 @@ class kucoin(Exchange, ImplicitAPI):
3299
3779
  request['type'] = type
3300
3780
  response = self.privateGetAccounts(self.extend(request, query))
3301
3781
  #
3302
- # Spot and Cross
3782
+ # Spot
3303
3783
  #
3304
3784
  # {
3305
3785
  # "code": "200000",
@@ -3315,35 +3795,59 @@ class kucoin(Exchange, ImplicitAPI):
3315
3795
  # ]
3316
3796
  # }
3317
3797
  #
3798
+ # Cross
3799
+ #
3800
+ # {
3801
+ # "code": "200000",
3802
+ # "data": {
3803
+ # "debtRatio": "0",
3804
+ # "accounts": [
3805
+ # {
3806
+ # "currency": "USDT",
3807
+ # "totalBalance": "5",
3808
+ # "availableBalance": "5",
3809
+ # "holdBalance": "0",
3810
+ # "liability": "0",
3811
+ # "maxBorrowSize": "20"
3812
+ # },
3813
+ # ]
3814
+ # }
3815
+ # }
3816
+ #
3318
3817
  # Isolated
3319
3818
  #
3320
3819
  # {
3321
3820
  # "code": "200000",
3322
3821
  # "data": {
3323
- # "totalConversionBalance": "0",
3324
- # "liabilityConversionBalance": "0",
3822
+ # "totalAssetOfQuoteCurrency": "0",
3823
+ # "totalLiabilityOfQuoteCurrency": "0",
3824
+ # "timestamp": 1712085661155,
3325
3825
  # "assets": [
3326
3826
  # {
3327
3827
  # "symbol": "MANA-USDT",
3328
- # "status": "CLEAR",
3828
+ # "status": "EFFECTIVE",
3329
3829
  # "debtRatio": "0",
3330
3830
  # "baseAsset": {
3331
3831
  # "currency": "MANA",
3332
- # "totalBalance": "0",
3333
- # "holdBalance": "0",
3334
- # "availableBalance": "0",
3832
+ # "borrowEnabled": True,
3833
+ # "transferInEnabled": True,
3834
+ # "total": "0",
3835
+ # "hold": "0",
3836
+ # "available": "0",
3335
3837
  # "liability": "0",
3336
3838
  # "interest": "0",
3337
- # "borrowableAmount": "0"
3839
+ # "maxBorrowSize": "0"
3338
3840
  # },
3339
3841
  # "quoteAsset": {
3340
3842
  # "currency": "USDT",
3341
- # "totalBalance": "0",
3342
- # "holdBalance": "0",
3343
- # "availableBalance": "0",
3843
+ # "borrowEnabled": True,
3844
+ # "transferInEnabled": True,
3845
+ # "total": "0",
3846
+ # "hold": "0",
3847
+ # "available": "0",
3344
3848
  # "liability": "0",
3345
3849
  # "interest": "0",
3346
- # "borrowableAmount": "0"
3850
+ # "maxBorrowSize": "0"
3347
3851
  # }
3348
3852
  # },
3349
3853
  # ...
@@ -3351,13 +3855,14 @@ class kucoin(Exchange, ImplicitAPI):
3351
3855
  # }
3352
3856
  # }
3353
3857
  #
3354
- data = self.safe_list(response, 'data', [])
3355
- result = {
3858
+ data = None
3859
+ result: dict = {
3356
3860
  'info': response,
3357
3861
  'timestamp': None,
3358
3862
  'datetime': None,
3359
3863
  }
3360
3864
  if isolated:
3865
+ data = self.safe_dict(response, 'data', {})
3361
3866
  assets = self.safe_value(data, 'assets', data)
3362
3867
  for i in range(0, len(assets)):
3363
3868
  entry = assets[i]
@@ -3367,11 +3872,12 @@ class kucoin(Exchange, ImplicitAPI):
3367
3872
  quote = self.safe_dict(entry, 'quoteAsset', {})
3368
3873
  baseCode = self.safe_currency_code(self.safe_string(base, 'currency'))
3369
3874
  quoteCode = self.safe_currency_code(self.safe_string(quote, 'currency'))
3370
- subResult = {}
3875
+ subResult: dict = {}
3371
3876
  subResult[baseCode] = self.parse_balance_helper(base)
3372
3877
  subResult[quoteCode] = self.parse_balance_helper(quote)
3373
3878
  result[symbol] = self.safe_balance(subResult)
3374
3879
  elif cross:
3880
+ data = self.safe_dict(response, 'data', {})
3375
3881
  accounts = self.safe_list(data, 'accounts', [])
3376
3882
  for i in range(0, len(accounts)):
3377
3883
  balance = accounts[i]
@@ -3379,6 +3885,7 @@ class kucoin(Exchange, ImplicitAPI):
3379
3885
  codeInner = self.safe_currency_code(currencyId)
3380
3886
  result[codeInner] = self.parse_balance_helper(balance)
3381
3887
  else:
3888
+ data = self.safe_list(response, 'data', [])
3382
3889
  for i in range(0, len(data)):
3383
3890
  balance = data[i]
3384
3891
  balanceType = self.safe_string(balance, 'type')
@@ -3396,9 +3903,11 @@ class kucoin(Exchange, ImplicitAPI):
3396
3903
  def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
3397
3904
  """
3398
3905
  transfer currency internally between wallets on the same account
3399
- :see: https://docs.kucoin.com/#inner-transfer
3400
- :see: https://docs.kucoin.com/futures/#transfer-funds-to-kucoin-main-account-2
3401
- :see: https://docs.kucoin.com/spot-hf/#internal-funds-transfers-in-high-frequency-trading-accounts
3906
+
3907
+ https://www.kucoin.com/docs/rest/funding/transfer/inner-transfer
3908
+ https://docs.kucoin.com/futures/#transfer-funds-to-kucoin-main-account-2
3909
+ https://docs.kucoin.com/spot-hf/#internal-funds-transfers-in-high-frequency-trading-accounts
3910
+
3402
3911
  :param str code: unified currency code
3403
3912
  :param float amount: amount to transfer
3404
3913
  :param str fromAccount: account to transfer from
@@ -3416,7 +3925,7 @@ class kucoin(Exchange, ImplicitAPI):
3416
3925
  if fromId == 'contract':
3417
3926
  if toId != 'main':
3418
3927
  raise ExchangeError(self.id + ' transfer() only supports transferring from futures account to main account')
3419
- request = {
3928
+ request: dict = {
3420
3929
  'currency': currency['id'],
3421
3930
  'amount': requestedAmount,
3422
3931
  }
@@ -3451,7 +3960,7 @@ class kucoin(Exchange, ImplicitAPI):
3451
3960
  data = self.safe_dict(response, 'data')
3452
3961
  return self.parse_transfer(data, currency)
3453
3962
  else:
3454
- request = {
3963
+ request: dict = {
3455
3964
  'currency': currency['id'],
3456
3965
  'amount': requestedAmount,
3457
3966
  }
@@ -3478,7 +3987,7 @@ class kucoin(Exchange, ImplicitAPI):
3478
3987
  data = self.safe_dict(response, 'data')
3479
3988
  return self.parse_transfer(data, currency)
3480
3989
 
3481
- def parse_transfer(self, transfer, currency: Currency = None):
3990
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
3482
3991
  #
3483
3992
  # transfer(spot)
3484
3993
  #
@@ -3533,14 +4042,14 @@ class kucoin(Exchange, ImplicitAPI):
3533
4042
  'info': transfer,
3534
4043
  }
3535
4044
 
3536
- def parse_transfer_status(self, status):
3537
- statuses = {
4045
+ def parse_transfer_status(self, status: Str) -> Str:
4046
+ statuses: dict = {
3538
4047
  'PROCESSING': 'pending',
3539
4048
  }
3540
4049
  return self.safe_string(statuses, status, status)
3541
4050
 
3542
4051
  def parse_ledger_entry_type(self, type):
3543
- types = {
4052
+ types: dict = {
3544
4053
  'Assets Transferred in After Upgrading': 'transfer', # Assets Transferred in After V1 to V2 Upgrading
3545
4054
  'Deposit': 'transaction', # Deposit
3546
4055
  'Withdrawal': 'transaction', # Withdrawal
@@ -3583,7 +4092,7 @@ class kucoin(Exchange, ImplicitAPI):
3583
4092
  }
3584
4093
  return self.safe_string(types, type, type)
3585
4094
 
3586
- def parse_ledger_entry(self, item, currency: Currency = None):
4095
+ def parse_ledger_entry(self, item: dict, currency: Currency = None) -> LedgerEntry:
3587
4096
  #
3588
4097
  # {
3589
4098
  # "id": "611a1e7c6a053300067a88d9", #unique key for each ledger entry
@@ -3601,6 +4110,7 @@ class kucoin(Exchange, ImplicitAPI):
3601
4110
  id = self.safe_string(item, 'id')
3602
4111
  currencyId = self.safe_string(item, 'currency')
3603
4112
  code = self.safe_currency_code(currencyId, currency)
4113
+ currency = self.safe_currency(currencyId, currency)
3604
4114
  amount = self.safe_number(item, 'amount')
3605
4115
  balanceAfter = None
3606
4116
  # balanceAfter = self.safe_number(item, 'balance'); only returns zero string
@@ -3643,7 +4153,8 @@ class kucoin(Exchange, ImplicitAPI):
3643
4153
  if feeCost != '0':
3644
4154
  feeCurrency = code
3645
4155
  fee = {'cost': self.parse_number(feeCost), 'currency': feeCurrency}
3646
- return {
4156
+ return self.safe_ledger_entry({
4157
+ 'info': item,
3647
4158
  'id': id,
3648
4159
  'direction': direction,
3649
4160
  'account': account,
@@ -3658,33 +4169,34 @@ class kucoin(Exchange, ImplicitAPI):
3658
4169
  'after': balanceAfter, # None
3659
4170
  'status': None,
3660
4171
  'fee': fee,
3661
- 'info': item,
3662
- }
4172
+ }, currency)
3663
4173
 
3664
- def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
4174
+ def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LedgerEntry]:
3665
4175
  """
3666
- :see: https://docs.kucoin.com/#get-account-ledgers
3667
- :see: https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-trade_hf
3668
- :see: https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-margin_hf
3669
- fetch the history of changes, actions done by the user or operations that altered balance of the user
3670
- :param str code: unified currency code, default is None
4176
+ fetch the history of changes, actions done by the user or operations that altered the balance of the user
4177
+
4178
+ https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-spot-margin
4179
+ https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-trade_hf
4180
+ https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-margin_hf
4181
+
4182
+ :param str [code]: unified currency code, default is None
3671
4183
  :param int [since]: timestamp in ms of the earliest ledger entry, default is None
3672
- :param int [limit]: max number of ledger entrys to return, default is None
4184
+ :param int [limit]: max number of ledger entries to return, default is None
3673
4185
  :param dict [params]: extra parameters specific to the exchange API endpoint
3674
4186
  :param boolean [params.hf]: default False, when True will fetch ledger entries for the high frequency trading account
3675
4187
  :param int [params.until]: the latest time in ms to fetch entries for
3676
- :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)
3677
- :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
4188
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [available parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
4189
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger>`
3678
4190
  """
3679
4191
  self.load_markets()
3680
4192
  self.load_accounts()
3681
4193
  paginate = False
3682
4194
  paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
3683
- isHf = self.safe_bool(params, 'hf')
3684
- params = self.omit(params, 'hf')
4195
+ hf = None
4196
+ hf, params = self.handle_hf_and_params(params)
3685
4197
  if paginate:
3686
4198
  return self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params)
3687
- request = {
4199
+ request: dict = {
3688
4200
  # 'currency': currency['id'], # can choose up to 10, if not provided returns for all currencies by default
3689
4201
  # 'direction': 'in', # 'out'
3690
4202
  # 'bizType': 'DEPOSIT', # DEPOSIT, WITHDRAW, TRANSFER, SUB_TRANSFER,TRADE_EXCHANGE, MARGIN_EXCHANGE, KUCOIN_BONUS(optional)
@@ -3702,7 +4214,7 @@ class kucoin(Exchange, ImplicitAPI):
3702
4214
  marginMode = None
3703
4215
  marginMode, params = self.handle_margin_mode_and_params('fetchLedger', params)
3704
4216
  response = None
3705
- if isHf:
4217
+ if hf:
3706
4218
  if marginMode is not None:
3707
4219
  response = self.privateGetHfMarginAccountLedgers(self.extend(request, params))
3708
4220
  else:
@@ -3767,15 +4279,6 @@ class kucoin(Exchange, ImplicitAPI):
3767
4279
  return config['v1']
3768
4280
  return self.safe_value(config, 'cost', 1)
3769
4281
 
3770
- def parse_borrow_rate_history(self, response, code, since, limit):
3771
- result = []
3772
- for i in range(0, len(response)):
3773
- item = response[i]
3774
- borrowRate = self.parse_borrow_rate(item)
3775
- result.append(borrowRate)
3776
- sorted = self.sort_by(result, 'timestamp')
3777
- return self.filter_by_currency_since_limit(sorted, code, since, limit)
3778
-
3779
4282
  def parse_borrow_rate(self, info, currency: Currency = None):
3780
4283
  #
3781
4284
  # {
@@ -3787,25 +4290,34 @@ class kucoin(Exchange, ImplicitAPI):
3787
4290
  # "timestamp": 1658531274508488480
3788
4291
  # },
3789
4292
  #
3790
- timestampId = self.safe_string(info, 'timestamp')
3791
- timestamp = Precise.string_mul(timestampId, '0.000001')
4293
+ # {
4294
+ # "createdAt": 1697783812257,
4295
+ # "currency": "XMR",
4296
+ # "interestAmount": "0.1",
4297
+ # "dayRatio": "0.001"
4298
+ # }
4299
+ #
4300
+ timestampId = self.safe_string_2(info, 'createdAt', 'timestamp')
4301
+ timestamp = self.parse_to_int(timestampId[0:13])
3792
4302
  currencyId = self.safe_string(info, 'currency')
3793
4303
  return {
3794
4304
  'currency': self.safe_currency_code(currencyId, currency),
3795
- 'rate': self.safe_number(info, 'dailyIntRate'),
4305
+ 'rate': self.safe_number_2(info, 'dailyIntRate', 'dayRatio'),
3796
4306
  'period': 86400000,
3797
4307
  'timestamp': timestamp,
3798
4308
  'datetime': self.iso8601(timestamp),
3799
4309
  'info': info,
3800
4310
  }
3801
4311
 
3802
- def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4312
+ def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[BorrowInterest]:
3803
4313
  """
3804
4314
  fetch the interest owed by the user for borrowing currency for margin trading
3805
- :see: https://docs.kucoin.com/#get-repay-record
3806
- :see: https://docs.kucoin.com/#query-isolated-margin-account-info
3807
- :param str code: unified currency code
3808
- :param str symbol: unified market symbol, required for isolated margin
4315
+
4316
+ https://docs.kucoin.com/#get-repay-record
4317
+ https://docs.kucoin.com/#query-isolated-margin-account-info
4318
+
4319
+ :param str [code]: unified currency code
4320
+ :param str [symbol]: unified market symbol, required for isolated margin
3809
4321
  :param int [since]: the earliest time in ms to fetch borrrow interest for
3810
4322
  :param int [limit]: the maximum number of structures to retrieve
3811
4323
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -3814,14 +4326,19 @@ class kucoin(Exchange, ImplicitAPI):
3814
4326
  """
3815
4327
  self.load_markets()
3816
4328
  marginMode = None
3817
- marginMode, params = self.handle_margin_mode_and_params('fetchBorrowInterest', params)
3818
- if marginMode is None:
3819
- marginMode = 'cross' # cross marginMode
3820
- request = {}
3821
- response = None
4329
+ marginMode, params = self.handle_margin_mode_and_params('fetchBorrowInterest', params, 'cross')
4330
+ request: dict = {}
4331
+ currency = None
3822
4332
  if code is not None:
3823
4333
  currency = self.currency(code)
3824
- request['quoteCurrency'] = currency['id']
4334
+ if marginMode == 'isolated':
4335
+ request['balanceCurrency'] = currency['id']
4336
+ else:
4337
+ request['quoteCurrency'] = currency['id']
4338
+ market = None
4339
+ if symbol is not None:
4340
+ market = self.market(symbol)
4341
+ response = None
3825
4342
  if marginMode == 'isolated':
3826
4343
  response = self.privateGetIsolatedAccounts(self.extend(request, params))
3827
4344
  else:
@@ -3892,9 +4409,11 @@ class kucoin(Exchange, ImplicitAPI):
3892
4409
  #
3893
4410
  data = self.safe_dict(response, 'data', {})
3894
4411
  assets = self.safe_list(data, 'assets', []) if (marginMode == 'isolated') else self.safe_list(data, 'accounts', [])
3895
- return self.parse_borrow_interests(assets, None)
4412
+ interest = self.parse_borrow_interests(assets, market)
4413
+ filteredByCurrency = self.filter_by_currency_since_limit(interest, code, since, limit)
4414
+ return self.filter_by_symbol_since_limit(filteredByCurrency, symbol, since, limit)
3896
4415
 
3897
- def parse_borrow_interest(self, info, market: Market = None):
4416
+ def parse_borrow_interest(self, info: dict, market: Market = None) -> BorrowInterest:
3898
4417
  #
3899
4418
  # Cross
3900
4419
  #
@@ -3957,21 +4476,153 @@ class kucoin(Exchange, ImplicitAPI):
3957
4476
  interest = self.safe_number(info, 'accruedInterest')
3958
4477
  currencyId = self.safe_string(info, 'currency')
3959
4478
  return {
4479
+ 'info': info,
3960
4480
  'symbol': symbol,
3961
- 'marginMode': marginMode,
3962
4481
  'currency': self.safe_currency_code(currencyId),
3963
4482
  'interest': interest,
3964
4483
  'interestRate': self.safe_number(info, 'dailyIntRate'),
3965
4484
  'amountBorrowed': amountBorrowed,
4485
+ 'marginMode': marginMode,
3966
4486
  'timestamp': timestamp, # create time
3967
4487
  'datetime': self.iso8601(timestamp),
3968
- 'info': info,
3969
4488
  }
3970
4489
 
4490
+ def fetch_borrow_rate_histories(self, codes=None, since: Int = None, limit: Int = None, params={}):
4491
+ """
4492
+ retrieves a history of a multiple currencies borrow interest rate at specific time slots, returns all currencies if no symbols passed, default is None
4493
+
4494
+ https://www.kucoin.com/docs/rest/margin-trading/margin-trading-v3-/get-cross-isolated-margin-interest-records
4495
+
4496
+ :param str[]|None codes: list of unified currency codes, default is None
4497
+ :param int [since]: timestamp in ms of the earliest borrowRate, default is None
4498
+ :param int [limit]: max number of borrow rate prices to return, default is None
4499
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4500
+ :param str [params.marginMode]: 'cross' or 'isolated' default is 'cross'
4501
+ :param int [params.until]: the latest time in ms to fetch entries for
4502
+ :returns dict: a dictionary of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>` indexed by the market symbol
4503
+ """
4504
+ self.load_markets()
4505
+ marginResult = self.handle_margin_mode_and_params('fetchBorrowRateHistories', params)
4506
+ marginMode = self.safe_string(marginResult, 0, 'cross')
4507
+ isIsolated = (marginMode == 'isolated') # True-isolated, False-cross
4508
+ request: dict = {
4509
+ 'isIsolated': isIsolated,
4510
+ }
4511
+ if since is not None:
4512
+ request['startTime'] = since
4513
+ request, params = self.handle_until_option('endTime', request, params)
4514
+ if limit is not None:
4515
+ request['pageSize'] = limit # default:50, min:10, max:500
4516
+ response = self.privateGetMarginInterest(self.extend(request, params))
4517
+ #
4518
+ # {
4519
+ # "code": "200000",
4520
+ # "data": {
4521
+ # "timestamp": 1710829939673,
4522
+ # "currentPage": 1,
4523
+ # "pageSize": 50,
4524
+ # "totalNum": 0,
4525
+ # "totalPage": 0,
4526
+ # "items": [
4527
+ # {
4528
+ # "createdAt": 1697783812257,
4529
+ # "currency": "XMR",
4530
+ # "interestAmount": "0.1",
4531
+ # "dayRatio": "0.001"
4532
+ # }
4533
+ # ]
4534
+ # }
4535
+ # }
4536
+ #
4537
+ data = self.safe_dict(response, 'data')
4538
+ rows = self.safe_list(data, 'items', [])
4539
+ return self.parse_borrow_rate_histories(rows, codes, since, limit)
4540
+
4541
+ def fetch_borrow_rate_history(self, code: str, since: Int = None, limit: Int = None, params={}):
4542
+ """
4543
+ retrieves a history of a currencies borrow interest rate at specific time slots
4544
+
4545
+ https://www.kucoin.com/docs/rest/margin-trading/margin-trading-v3-/get-cross-isolated-margin-interest-records
4546
+
4547
+ :param str code: unified currency code
4548
+ :param int [since]: timestamp for the earliest borrow rate
4549
+ :param int [limit]: the maximum number of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>` to retrieve
4550
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4551
+ :param str [params.marginMode]: 'cross' or 'isolated' default is 'cross'
4552
+ :param int [params.until]: the latest time in ms to fetch entries for
4553
+ :returns dict[]: an array of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>`
4554
+ """
4555
+ self.load_markets()
4556
+ marginResult = self.handle_margin_mode_and_params('fetchBorrowRateHistories', params)
4557
+ marginMode = self.safe_string(marginResult, 0, 'cross')
4558
+ isIsolated = (marginMode == 'isolated') # True-isolated, False-cross
4559
+ currency = self.currency(code)
4560
+ request: dict = {
4561
+ 'isIsolated': isIsolated,
4562
+ 'currency': currency['id'],
4563
+ }
4564
+ if since is not None:
4565
+ request['startTime'] = since
4566
+ request, params = self.handle_until_option('endTime', request, params)
4567
+ if limit is not None:
4568
+ request['pageSize'] = limit # default:50, min:10, max:500
4569
+ response = self.privateGetMarginInterest(self.extend(request, params))
4570
+ #
4571
+ # {
4572
+ # "code": "200000",
4573
+ # "data": {
4574
+ # "timestamp": 1710829939673,
4575
+ # "currentPage": 1,
4576
+ # "pageSize": 50,
4577
+ # "totalNum": 0,
4578
+ # "totalPage": 0,
4579
+ # "items": [
4580
+ # {
4581
+ # "createdAt": 1697783812257,
4582
+ # "currency": "XMR",
4583
+ # "interestAmount": "0.1",
4584
+ # "dayRatio": "0.001"
4585
+ # }
4586
+ # ]
4587
+ # }
4588
+ # }
4589
+ #
4590
+ data = self.safe_dict(response, 'data')
4591
+ rows = self.safe_list(data, 'items', [])
4592
+ return self.parse_borrow_rate_history(rows, code, since, limit)
4593
+
4594
+ def parse_borrow_rate_histories(self, response, codes, since, limit):
4595
+ #
4596
+ # [
4597
+ # {
4598
+ # "createdAt": 1697783812257,
4599
+ # "currency": "XMR",
4600
+ # "interestAmount": "0.1",
4601
+ # "dayRatio": "0.001"
4602
+ # }
4603
+ # ]
4604
+ #
4605
+ borrowRateHistories: dict = {}
4606
+ for i in range(0, len(response)):
4607
+ item = response[i]
4608
+ code = self.safe_currency_code(self.safe_string(item, 'currency'))
4609
+ if codes is None or self.in_array(code, codes):
4610
+ if not (code in borrowRateHistories):
4611
+ borrowRateHistories[code] = []
4612
+ borrowRateStructure = self.parse_borrow_rate(item)
4613
+ borrowRateHistories[code].append(borrowRateStructure)
4614
+ keys = list(borrowRateHistories.keys())
4615
+ for i in range(0, len(keys)):
4616
+ code = keys[i]
4617
+ borrowRateHistories[code] = self.filter_by_currency_since_limit(borrowRateHistories[code], code, since, limit)
4618
+ return borrowRateHistories
4619
+
3971
4620
  def borrow_cross_margin(self, code: str, amount: float, params={}):
3972
4621
  """
3973
4622
  create a loan to borrow margin
3974
- :see: https://docs.kucoin.com/#1-margin-borrowing
4623
+
4624
+ https://docs.kucoin.com/#1-margin-borrowing
4625
+
3975
4626
  :param str code: unified currency code of the currency to borrow
3976
4627
  :param float amount: the amount to borrow
3977
4628
  :param dict [params]: extra parameters specific to the exchange API endpoints
@@ -3980,7 +4631,7 @@ class kucoin(Exchange, ImplicitAPI):
3980
4631
  """
3981
4632
  self.load_markets()
3982
4633
  currency = self.currency(code)
3983
- request = {
4634
+ request: dict = {
3984
4635
  'currency': currency['id'],
3985
4636
  'size': self.currency_to_precision(code, amount),
3986
4637
  'timeInForce': 'FOK',
@@ -4004,7 +4655,9 @@ class kucoin(Exchange, ImplicitAPI):
4004
4655
  def borrow_isolated_margin(self, symbol: str, code: str, amount: float, params={}):
4005
4656
  """
4006
4657
  create a loan to borrow margin
4007
- :see: https://docs.kucoin.com/#1-margin-borrowing
4658
+
4659
+ https://docs.kucoin.com/#1-margin-borrowing
4660
+
4008
4661
  :param str symbol: unified market symbol, required for isolated margin
4009
4662
  :param str code: unified currency code of the currency to borrow
4010
4663
  :param float amount: the amount to borrow
@@ -4015,7 +4668,7 @@ class kucoin(Exchange, ImplicitAPI):
4015
4668
  self.load_markets()
4016
4669
  market = self.market(symbol)
4017
4670
  currency = self.currency(code)
4018
- request = {
4671
+ request: dict = {
4019
4672
  'currency': currency['id'],
4020
4673
  'size': self.currency_to_precision(code, amount),
4021
4674
  'symbol': market['id'],
@@ -4041,7 +4694,9 @@ class kucoin(Exchange, ImplicitAPI):
4041
4694
  def repay_cross_margin(self, code: str, amount, params={}):
4042
4695
  """
4043
4696
  repay borrowed margin and interest
4044
- :see: https://docs.kucoin.com/#2-repayment
4697
+
4698
+ https://docs.kucoin.com/#2-repayment
4699
+
4045
4700
  :param str code: unified currency code of the currency to repay
4046
4701
  :param float amount: the amount to repay
4047
4702
  :param dict [params]: extra parameters specific to the exchange API endpoints
@@ -4049,7 +4704,7 @@ class kucoin(Exchange, ImplicitAPI):
4049
4704
  """
4050
4705
  self.load_markets()
4051
4706
  currency = self.currency(code)
4052
- request = {
4707
+ request: dict = {
4053
4708
  'currency': currency['id'],
4054
4709
  'size': self.currency_to_precision(code, amount),
4055
4710
  }
@@ -4072,7 +4727,9 @@ class kucoin(Exchange, ImplicitAPI):
4072
4727
  def repay_isolated_margin(self, symbol: str, code: str, amount, params={}):
4073
4728
  """
4074
4729
  repay borrowed margin and interest
4075
- :see: https://docs.kucoin.com/#2-repayment
4730
+
4731
+ https://docs.kucoin.com/#2-repayment
4732
+
4076
4733
  :param str symbol: unified market symbol
4077
4734
  :param str code: unified currency code of the currency to repay
4078
4735
  :param float amount: the amount to repay
@@ -4082,7 +4739,7 @@ class kucoin(Exchange, ImplicitAPI):
4082
4739
  self.load_markets()
4083
4740
  market = self.market(symbol)
4084
4741
  currency = self.currency(code)
4085
- request = {
4742
+ request: dict = {
4086
4743
  'currency': currency['id'],
4087
4744
  'size': self.currency_to_precision(code, amount),
4088
4745
  'symbol': market['id'],
@@ -4126,7 +4783,9 @@ class kucoin(Exchange, ImplicitAPI):
4126
4783
  def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
4127
4784
  """
4128
4785
  fetch deposit and withdraw fees - *IMPORTANT* use fetchDepositWithdrawFee to get more in-depth info
4129
- :see: https://docs.kucoin.com/#get-currencies
4786
+
4787
+ https://docs.kucoin.com/#get-currencies
4788
+
4130
4789
  :param str[]|None codes: list of unified currency codes
4131
4790
  :param dict [params]: extra parameters specific to the exchange API endpoint
4132
4791
  :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
@@ -4154,6 +4813,38 @@ class kucoin(Exchange, ImplicitAPI):
4154
4813
  data = self.safe_list(response, 'data', [])
4155
4814
  return self.parse_deposit_withdraw_fees(data, codes, 'currency')
4156
4815
 
4816
+ def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
4817
+ """
4818
+ set the level of leverage for a market
4819
+
4820
+ https://www.kucoin.com/docs/rest/margin-trading/margin-trading-v3-/modify-leverage-multiplier
4821
+
4822
+ :param int [leverage]: New leverage multiplier. Must be greater than 1 and up to two decimal places, and cannot be less than the user's current debt leverage or greater than the system's maximum leverage
4823
+ :param str [symbol]: unified market symbol
4824
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4825
+ :returns dict: response from the exchange
4826
+ """
4827
+ self.load_markets()
4828
+ market = None
4829
+ marketType: Str = None
4830
+ marketType, params = self.handle_market_type_and_params('setLeverage', None, params)
4831
+ if (symbol is not None) or marketType != 'spot':
4832
+ market = self.market(symbol)
4833
+ if market['contract']:
4834
+ raise NotSupported(self.id + ' setLeverage currently supports only spot margin')
4835
+ marginMode: Str = None
4836
+ marginMode, params = self.handle_margin_mode_and_params('setLeverage', params)
4837
+ if marginMode is None:
4838
+ raise ArgumentsRequired(self.id + ' setLeverage requires a marginMode parameter')
4839
+ request: dict = {}
4840
+ if marginMode == 'isolated' and symbol is None:
4841
+ raise ArgumentsRequired(self.id + ' setLeverage requires a symbol parameter for isolated margin')
4842
+ if symbol is not None:
4843
+ request['symbol'] = market['id']
4844
+ request['leverage'] = str(leverage)
4845
+ request['isIsolated'] = (marginMode == 'isolated')
4846
+ return self.privatePostPositionUpdateUserLeverage(self.extend(request, params))
4847
+
4157
4848
  def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
4158
4849
  #
4159
4850
  # the v2 URL is https://openapi-v2.kucoin.com/api/v1/endpoint
@@ -4169,12 +4860,14 @@ class kucoin(Exchange, ImplicitAPI):
4169
4860
  endpoint = '/api/' + version + '/' + self.implode_params(path, params)
4170
4861
  if api == 'webExchange':
4171
4862
  endpoint = '/' + self.implode_params(path, params)
4863
+ if api == 'earn':
4864
+ endpoint = '/api/v1/' + self.implode_params(path, params)
4172
4865
  query = self.omit(params, self.extract_params(path))
4173
4866
  endpart = ''
4174
4867
  headers = headers if (headers is not None) else {}
4175
4868
  url = self.urls['api'][api]
4176
4869
  if not self.is_empty(query):
4177
- if (method == 'GET') or (method == 'DELETE'):
4870
+ if ((method == 'GET') or (method == 'DELETE')) and (path != 'orders/multi-cancel'):
4178
4871
  endpoint += '?' + self.rawencode(query)
4179
4872
  else:
4180
4873
  body = self.json(query)
@@ -4184,7 +4877,8 @@ class kucoin(Exchange, ImplicitAPI):
4184
4877
  isFuturePrivate = (api == 'futuresPrivate')
4185
4878
  isPrivate = (api == 'private')
4186
4879
  isBroker = (api == 'broker')
4187
- if isPrivate or isFuturePrivate or isBroker:
4880
+ isEarn = (api == 'earn')
4881
+ if isPrivate or isFuturePrivate or isBroker or isEarn:
4188
4882
  self.check_required_credentials()
4189
4883
  timestamp = str(self.nonce())
4190
4884
  headers = self.extend({
@@ -4210,13 +4904,14 @@ class kucoin(Exchange, ImplicitAPI):
4210
4904
  partnerSignature = self.hmac(self.encode(partnerPayload), self.encode(partnerSecret), hashlib.sha256, 'base64')
4211
4905
  headers['KC-API-PARTNER-SIGN'] = partnerSignature
4212
4906
  headers['KC-API-PARTNER'] = partnerId
4907
+ headers['KC-API-PARTNER-VERIFY'] = 'true'
4213
4908
  if isBroker:
4214
4909
  brokerName = self.safe_string(partner, 'name')
4215
4910
  if brokerName is not None:
4216
4911
  headers['KC-BROKER-NAME'] = brokerName
4217
4912
  return {'url': url, 'method': method, 'body': body, 'headers': headers}
4218
4913
 
4219
- def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
4914
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
4220
4915
  if not response:
4221
4916
  self.throw_broadly_matched_exception(self.exceptions['broad'], body, body)
4222
4917
  return None
@@ -4228,7 +4923,7 @@ class kucoin(Exchange, ImplicitAPI):
4228
4923
  #
4229
4924
  errorCode = self.safe_string(response, 'code')
4230
4925
  message = self.safe_string_2(response, 'msg', 'data', '')
4231
- feedback = self.id + ' ' + message
4926
+ feedback = self.id + ' ' + body
4232
4927
  self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
4233
4928
  self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
4234
4929
  self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)