ccxt-ir 4.3.46.0.1__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 (772) hide show
  1. ccxt/__init__.py +358 -0
  2. ccxt/abantether.py +316 -0
  3. ccxt/abstract/__init__.py +0 -0
  4. ccxt/abstract/abantether.py +5 -0
  5. ccxt/abstract/ace.py +15 -0
  6. ccxt/abstract/afratether.py +6 -0
  7. ccxt/abstract/alpaca.py +70 -0
  8. ccxt/abstract/arzinja.py +5 -0
  9. ccxt/abstract/arzplus.py +7 -0
  10. ccxt/abstract/ascendex.py +77 -0
  11. ccxt/abstract/bequant.py +115 -0
  12. ccxt/abstract/bigone.py +45 -0
  13. ccxt/abstract/binance.py +712 -0
  14. ccxt/abstract/binancecoinm.py +712 -0
  15. ccxt/abstract/binanceus.py +764 -0
  16. ccxt/abstract/binanceusdm.py +712 -0
  17. ccxt/abstract/bingx.py +113 -0
  18. ccxt/abstract/bit2c.py +27 -0
  19. ccxt/abstract/bitbank.py +27 -0
  20. ccxt/abstract/bitbay.py +53 -0
  21. ccxt/abstract/bitbns.py +40 -0
  22. ccxt/abstract/bitcoincom.py +115 -0
  23. ccxt/abstract/bitfinex.py +69 -0
  24. ccxt/abstract/bitfinex2.py +139 -0
  25. ccxt/abstract/bitflyer.py +38 -0
  26. ccxt/abstract/bitget.py +508 -0
  27. ccxt/abstract/bithumb.py +32 -0
  28. ccxt/abstract/bitimen.py +7 -0
  29. ccxt/abstract/bitir.py +7 -0
  30. ccxt/abstract/bitmart.py +99 -0
  31. ccxt/abstract/bitmex.py +97 -0
  32. ccxt/abstract/bitopro.py +29 -0
  33. ccxt/abstract/bitpanda.py +35 -0
  34. ccxt/abstract/bitpin.py +7 -0
  35. ccxt/abstract/bitrue.py +72 -0
  36. ccxt/abstract/bitso.py +43 -0
  37. ccxt/abstract/bitstamp.py +258 -0
  38. ccxt/abstract/bitteam.py +29 -0
  39. ccxt/abstract/bitvavo.py +27 -0
  40. ccxt/abstract/bl3p.py +19 -0
  41. ccxt/abstract/blockchaincom.py +28 -0
  42. ccxt/abstract/blofin.py +37 -0
  43. ccxt/abstract/btcalpha.py +18 -0
  44. ccxt/abstract/btcbox.py +13 -0
  45. ccxt/abstract/btcmarkets.py +39 -0
  46. ccxt/abstract/btcturk.py +20 -0
  47. ccxt/abstract/bybit.py +298 -0
  48. ccxt/abstract/cex.py +33 -0
  49. ccxt/abstract/coinbase.py +94 -0
  50. ccxt/abstract/coinbaseadvanced.py +94 -0
  51. ccxt/abstract/coinbaseexchange.py +67 -0
  52. ccxt/abstract/coinbaseinternational.py +39 -0
  53. ccxt/abstract/coincatch.py +94 -0
  54. ccxt/abstract/coincheck.py +33 -0
  55. ccxt/abstract/coinex.py +237 -0
  56. ccxt/abstract/coinlist.py +54 -0
  57. ccxt/abstract/coinmate.py +62 -0
  58. ccxt/abstract/coinmetro.py +34 -0
  59. ccxt/abstract/coinone.py +67 -0
  60. ccxt/abstract/coinsph.py +54 -0
  61. ccxt/abstract/coinspot.py +28 -0
  62. ccxt/abstract/cryptocom.py +107 -0
  63. ccxt/abstract/currencycom.py +68 -0
  64. ccxt/abstract/delta.py +50 -0
  65. ccxt/abstract/deribit.py +125 -0
  66. ccxt/abstract/digifinex.py +91 -0
  67. ccxt/abstract/eterex.py +5 -0
  68. ccxt/abstract/excoino.py +7 -0
  69. ccxt/abstract/exir.py +8 -0
  70. ccxt/abstract/exmo.py +55 -0
  71. ccxt/abstract/exnovin.py +6 -0
  72. ccxt/abstract/farhadexchange.py +5 -0
  73. ccxt/abstract/fmfwio.py +115 -0
  74. ccxt/abstract/gate.py +265 -0
  75. ccxt/abstract/gateio.py +265 -0
  76. ccxt/abstract/gemini.py +58 -0
  77. ccxt/abstract/hashkey.py +67 -0
  78. ccxt/abstract/hitbtc.py +115 -0
  79. ccxt/abstract/hitbtc3.py +115 -0
  80. ccxt/abstract/hitobit.py +8 -0
  81. ccxt/abstract/hollaex.py +33 -0
  82. ccxt/abstract/htx.py +548 -0
  83. ccxt/abstract/huobi.py +548 -0
  84. ccxt/abstract/huobijp.py +114 -0
  85. ccxt/abstract/hyperliquid.py +6 -0
  86. ccxt/abstract/idex.py +26 -0
  87. ccxt/abstract/independentreserve.py +37 -0
  88. ccxt/abstract/indodax.py +26 -0
  89. ccxt/abstract/jibitex.py +7 -0
  90. ccxt/abstract/kraken.py +57 -0
  91. ccxt/abstract/krakenfutures.py +38 -0
  92. ccxt/abstract/kucoin.py +214 -0
  93. ccxt/abstract/kucoinfutures.py +233 -0
  94. ccxt/abstract/kuna.py +182 -0
  95. ccxt/abstract/latoken.py +56 -0
  96. ccxt/abstract/lbank.py +61 -0
  97. ccxt/abstract/luno.py +37 -0
  98. ccxt/abstract/lykke.py +29 -0
  99. ccxt/abstract/mercado.py +25 -0
  100. ccxt/abstract/mexc.py +178 -0
  101. ccxt/abstract/ndax.py +97 -0
  102. ccxt/abstract/nobitex.py +7 -0
  103. ccxt/abstract/novadax.py +29 -0
  104. ccxt/abstract/oceanex.py +22 -0
  105. ccxt/abstract/okcoin.py +74 -0
  106. ccxt/abstract/okexchange.py +8 -0
  107. ccxt/abstract/okx.py +324 -0
  108. ccxt/abstract/ompfinex.py +7 -0
  109. ccxt/abstract/onetrading.py +35 -0
  110. ccxt/abstract/oxfun.py +34 -0
  111. ccxt/abstract/p2b.py +22 -0
  112. ccxt/abstract/paradex.py +40 -0
  113. ccxt/abstract/paymium.py +28 -0
  114. ccxt/abstract/phemex.py +115 -0
  115. ccxt/abstract/poloniex.py +69 -0
  116. ccxt/abstract/poloniexfutures.py +48 -0
  117. ccxt/abstract/probit.py +23 -0
  118. ccxt/abstract/ramzinex.py +7 -0
  119. ccxt/abstract/sarmayex.py +5 -0
  120. ccxt/abstract/sarrafex.py +7 -0
  121. ccxt/abstract/tabdeal.py +7 -0
  122. ccxt/abstract/tetherland.py +5 -0
  123. ccxt/abstract/timex.py +62 -0
  124. ccxt/abstract/tokocrypto.py +37 -0
  125. ccxt/abstract/tradeogre.py +16 -0
  126. ccxt/abstract/twox.py +5 -0
  127. ccxt/abstract/ubitex.py +7 -0
  128. ccxt/abstract/upbit.py +38 -0
  129. ccxt/abstract/vertex.py +19 -0
  130. ccxt/abstract/wallex.py +8 -0
  131. ccxt/abstract/wavesexchange.py +154 -0
  132. ccxt/abstract/wazirx.py +30 -0
  133. ccxt/abstract/whitebit.py +98 -0
  134. ccxt/abstract/woo.py +83 -0
  135. ccxt/abstract/woofipro.py +119 -0
  136. ccxt/abstract/xt.py +152 -0
  137. ccxt/abstract/yobit.py +16 -0
  138. ccxt/abstract/zaif.py +38 -0
  139. ccxt/abstract/zonda.py +53 -0
  140. ccxt/ace.py +1012 -0
  141. ccxt/afratether.py +293 -0
  142. ccxt/alpaca.py +1083 -0
  143. ccxt/arzinja.py +285 -0
  144. ccxt/arzplus.py +412 -0
  145. ccxt/ascendex.py +3330 -0
  146. ccxt/async_support/__init__.py +337 -0
  147. ccxt/async_support/abantether.py +316 -0
  148. ccxt/async_support/ace.py +1012 -0
  149. ccxt/async_support/afratether.py +293 -0
  150. ccxt/async_support/alpaca.py +1083 -0
  151. ccxt/async_support/arzinja.py +285 -0
  152. ccxt/async_support/arzplus.py +412 -0
  153. ccxt/async_support/ascendex.py +3330 -0
  154. ccxt/async_support/base/__init__.py +1 -0
  155. ccxt/async_support/base/exchange.py +1966 -0
  156. ccxt/async_support/base/throttler.py +50 -0
  157. ccxt/async_support/base/ws/__init__.py +38 -0
  158. ccxt/async_support/base/ws/aiohttp_client.py +125 -0
  159. ccxt/async_support/base/ws/cache.py +212 -0
  160. ccxt/async_support/base/ws/client.py +193 -0
  161. ccxt/async_support/base/ws/fast_client.py +96 -0
  162. ccxt/async_support/base/ws/functions.py +59 -0
  163. ccxt/async_support/base/ws/future.py +58 -0
  164. ccxt/async_support/base/ws/order_book.py +78 -0
  165. ccxt/async_support/base/ws/order_book_side.py +174 -0
  166. ccxt/async_support/bequant.py +33 -0
  167. ccxt/async_support/bigone.py +2113 -0
  168. ccxt/async_support/binance.py +12234 -0
  169. ccxt/async_support/binancecoinm.py +45 -0
  170. ccxt/async_support/binanceus.py +211 -0
  171. ccxt/async_support/binanceusdm.py +58 -0
  172. ccxt/async_support/bingx.py +4325 -0
  173. ccxt/async_support/bit2c.py +866 -0
  174. ccxt/async_support/bitbank.py +1001 -0
  175. ccxt/async_support/bitbay.py +17 -0
  176. ccxt/async_support/bitbns.py +1154 -0
  177. ccxt/async_support/bitcoincom.py +17 -0
  178. ccxt/async_support/bitfinex.py +1617 -0
  179. ccxt/async_support/bitfinex2.py +3552 -0
  180. ccxt/async_support/bitflyer.py +995 -0
  181. ccxt/async_support/bitget.py +8273 -0
  182. ccxt/async_support/bithumb.py +1061 -0
  183. ccxt/async_support/bitimen.py +401 -0
  184. ccxt/async_support/bitir.py +490 -0
  185. ccxt/async_support/bitmart.py +4415 -0
  186. ccxt/async_support/bitmex.py +2756 -0
  187. ccxt/async_support/bitopro.py +1630 -0
  188. ccxt/async_support/bitpanda.py +16 -0
  189. ccxt/async_support/bitpin.py +454 -0
  190. ccxt/async_support/bitrue.py +3027 -0
  191. ccxt/async_support/bitso.py +1670 -0
  192. ccxt/async_support/bitstamp.py +2203 -0
  193. ccxt/async_support/bitteam.py +2239 -0
  194. ccxt/async_support/bitvavo.py +1968 -0
  195. ccxt/async_support/bl3p.py +485 -0
  196. ccxt/async_support/blockchaincom.py +1104 -0
  197. ccxt/async_support/blofin.py +2066 -0
  198. ccxt/async_support/btcalpha.py +891 -0
  199. ccxt/async_support/btcbox.py +544 -0
  200. ccxt/async_support/btcmarkets.py +1221 -0
  201. ccxt/async_support/btcturk.py +911 -0
  202. ccxt/async_support/bybit.py +8159 -0
  203. ccxt/async_support/cex.py +1605 -0
  204. ccxt/async_support/coinbase.py +4475 -0
  205. ccxt/async_support/coinbaseadvanced.py +17 -0
  206. ccxt/async_support/coinbaseexchange.py +1734 -0
  207. ccxt/async_support/coinbaseinternational.py +1899 -0
  208. ccxt/async_support/coincatch.py +5069 -0
  209. ccxt/async_support/coincheck.py +815 -0
  210. ccxt/async_support/coinex.py +5526 -0
  211. ccxt/async_support/coinlist.py +2243 -0
  212. ccxt/async_support/coinmate.py +1067 -0
  213. ccxt/async_support/coinmetro.py +1797 -0
  214. ccxt/async_support/coinone.py +1127 -0
  215. ccxt/async_support/coinsph.py +1850 -0
  216. ccxt/async_support/coinspot.py +534 -0
  217. ccxt/async_support/cryptocom.py +2822 -0
  218. ccxt/async_support/currencycom.py +1950 -0
  219. ccxt/async_support/delta.py +3376 -0
  220. ccxt/async_support/deribit.py +3437 -0
  221. ccxt/async_support/digifinex.py +3960 -0
  222. ccxt/async_support/eterex.py +286 -0
  223. ccxt/async_support/excoino.py +399 -0
  224. ccxt/async_support/exir.py +375 -0
  225. ccxt/async_support/exmo.py +2462 -0
  226. ccxt/async_support/exnovin.py +360 -0
  227. ccxt/async_support/farhadexchange.py +266 -0
  228. ccxt/async_support/fmfwio.py +34 -0
  229. ccxt/async_support/gate.py +6976 -0
  230. ccxt/async_support/gateio.py +16 -0
  231. ccxt/async_support/gemini.py +1825 -0
  232. ccxt/async_support/hashkey.py +4150 -0
  233. ccxt/async_support/hitbtc.py +3423 -0
  234. ccxt/async_support/hitbtc3.py +16 -0
  235. ccxt/async_support/hitobit.py +391 -0
  236. ccxt/async_support/hollaex.py +1813 -0
  237. ccxt/async_support/htx.py +8506 -0
  238. ccxt/async_support/huobi.py +16 -0
  239. ccxt/async_support/huobijp.py +1801 -0
  240. ccxt/async_support/hyperliquid.py +2431 -0
  241. ccxt/async_support/idex.py +1766 -0
  242. ccxt/async_support/independentreserve.py +784 -0
  243. ccxt/async_support/indodax.py +1247 -0
  244. ccxt/async_support/jibitex.py +395 -0
  245. ccxt/async_support/kraken.py +2894 -0
  246. ccxt/async_support/krakenfutures.py +2601 -0
  247. ccxt/async_support/kucoin.py +4602 -0
  248. ccxt/async_support/kucoinfutures.py +2698 -0
  249. ccxt/async_support/kuna.py +1841 -0
  250. ccxt/async_support/latoken.py +1664 -0
  251. ccxt/async_support/lbank.py +2683 -0
  252. ccxt/async_support/luno.py +1067 -0
  253. ccxt/async_support/lykke.py +1270 -0
  254. ccxt/async_support/mercado.py +842 -0
  255. ccxt/async_support/mexc.py +5369 -0
  256. ccxt/async_support/ndax.py +2354 -0
  257. ccxt/async_support/nobitex.py +419 -0
  258. ccxt/async_support/novadax.py +1484 -0
  259. ccxt/async_support/oceanex.py +903 -0
  260. ccxt/async_support/okcoin.py +2936 -0
  261. ccxt/async_support/okexchange.py +349 -0
  262. ccxt/async_support/okx.py +7827 -0
  263. ccxt/async_support/ompfinex.py +472 -0
  264. ccxt/async_support/onetrading.py +1911 -0
  265. ccxt/async_support/oxfun.py +2773 -0
  266. ccxt/async_support/p2b.py +1194 -0
  267. ccxt/async_support/paradex.py +2015 -0
  268. ccxt/async_support/paymium.py +564 -0
  269. ccxt/async_support/phemex.py +4473 -0
  270. ccxt/async_support/poloniex.py +2232 -0
  271. ccxt/async_support/poloniexfutures.py +1717 -0
  272. ccxt/async_support/probit.py +1734 -0
  273. ccxt/async_support/ramzinex.py +476 -0
  274. ccxt/async_support/sarmayex.py +357 -0
  275. ccxt/async_support/sarrafex.py +478 -0
  276. ccxt/async_support/tabdeal.py +364 -0
  277. ccxt/async_support/tetherland.py +349 -0
  278. ccxt/async_support/timex.py +1593 -0
  279. ccxt/async_support/tokocrypto.py +2405 -0
  280. ccxt/async_support/tradeogre.py +608 -0
  281. ccxt/async_support/twox.py +326 -0
  282. ccxt/async_support/ubitex.py +409 -0
  283. ccxt/async_support/upbit.py +1833 -0
  284. ccxt/async_support/vertex.py +2922 -0
  285. ccxt/async_support/wallex.py +445 -0
  286. ccxt/async_support/wavesexchange.py +2473 -0
  287. ccxt/async_support/wazirx.py +1224 -0
  288. ccxt/async_support/whitebit.py +2469 -0
  289. ccxt/async_support/woo.py +3114 -0
  290. ccxt/async_support/woofipro.py +2533 -0
  291. ccxt/async_support/xt.py +4454 -0
  292. ccxt/async_support/yobit.py +1283 -0
  293. ccxt/async_support/zaif.py +725 -0
  294. ccxt/async_support/zonda.py +1828 -0
  295. ccxt/base/__init__.py +27 -0
  296. ccxt/base/decimal_to_precision.py +174 -0
  297. ccxt/base/errors.py +242 -0
  298. ccxt/base/exchange.py +5941 -0
  299. ccxt/base/precise.py +287 -0
  300. ccxt/base/types.py +502 -0
  301. ccxt/bequant.py +33 -0
  302. ccxt/bigone.py +2112 -0
  303. ccxt/binance.py +12233 -0
  304. ccxt/binancecoinm.py +45 -0
  305. ccxt/binanceus.py +211 -0
  306. ccxt/binanceusdm.py +58 -0
  307. ccxt/bingx.py +4324 -0
  308. ccxt/bit2c.py +866 -0
  309. ccxt/bitbank.py +1001 -0
  310. ccxt/bitbay.py +17 -0
  311. ccxt/bitbns.py +1154 -0
  312. ccxt/bitcoincom.py +17 -0
  313. ccxt/bitfinex.py +1617 -0
  314. ccxt/bitfinex2.py +3552 -0
  315. ccxt/bitflyer.py +995 -0
  316. ccxt/bitget.py +8272 -0
  317. ccxt/bithumb.py +1061 -0
  318. ccxt/bitimen.py +401 -0
  319. ccxt/bitir.py +490 -0
  320. ccxt/bitmart.py +4415 -0
  321. ccxt/bitmex.py +2756 -0
  322. ccxt/bitopro.py +1630 -0
  323. ccxt/bitpanda.py +16 -0
  324. ccxt/bitpin.py +454 -0
  325. ccxt/bitrue.py +3026 -0
  326. ccxt/bitso.py +1670 -0
  327. ccxt/bitstamp.py +2203 -0
  328. ccxt/bitteam.py +2239 -0
  329. ccxt/bitvavo.py +1968 -0
  330. ccxt/bl3p.py +485 -0
  331. ccxt/blockchaincom.py +1104 -0
  332. ccxt/blofin.py +2066 -0
  333. ccxt/btcalpha.py +891 -0
  334. ccxt/btcbox.py +544 -0
  335. ccxt/btcmarkets.py +1221 -0
  336. ccxt/btcturk.py +911 -0
  337. ccxt/bybit.py +8158 -0
  338. ccxt/cex.py +1605 -0
  339. ccxt/coinbase.py +4474 -0
  340. ccxt/coinbaseadvanced.py +17 -0
  341. ccxt/coinbaseexchange.py +1734 -0
  342. ccxt/coinbaseinternational.py +1899 -0
  343. ccxt/coincatch.py +5069 -0
  344. ccxt/coincheck.py +815 -0
  345. ccxt/coinex.py +5525 -0
  346. ccxt/coinlist.py +2243 -0
  347. ccxt/coinmate.py +1067 -0
  348. ccxt/coinmetro.py +1797 -0
  349. ccxt/coinone.py +1127 -0
  350. ccxt/coinsph.py +1850 -0
  351. ccxt/coinspot.py +534 -0
  352. ccxt/cryptocom.py +2822 -0
  353. ccxt/currencycom.py +1950 -0
  354. ccxt/delta.py +3376 -0
  355. ccxt/deribit.py +3437 -0
  356. ccxt/digifinex.py +3959 -0
  357. ccxt/eterex.py +286 -0
  358. ccxt/excoino.py +399 -0
  359. ccxt/exir.py +375 -0
  360. ccxt/exmo.py +2462 -0
  361. ccxt/exnovin.py +360 -0
  362. ccxt/farhadexchange.py +266 -0
  363. ccxt/fmfwio.py +34 -0
  364. ccxt/gate.py +6975 -0
  365. ccxt/gateio.py +16 -0
  366. ccxt/gemini.py +1824 -0
  367. ccxt/hashkey.py +4150 -0
  368. ccxt/hitbtc.py +3423 -0
  369. ccxt/hitbtc3.py +16 -0
  370. ccxt/hitobit.py +391 -0
  371. ccxt/hollaex.py +1813 -0
  372. ccxt/htx.py +8505 -0
  373. ccxt/huobi.py +16 -0
  374. ccxt/huobijp.py +1801 -0
  375. ccxt/hyperliquid.py +2430 -0
  376. ccxt/idex.py +1766 -0
  377. ccxt/independentreserve.py +784 -0
  378. ccxt/indodax.py +1247 -0
  379. ccxt/jibitex.py +395 -0
  380. ccxt/kraken.py +2894 -0
  381. ccxt/krakenfutures.py +2601 -0
  382. ccxt/kucoin.py +4601 -0
  383. ccxt/kucoinfutures.py +2698 -0
  384. ccxt/kuna.py +1841 -0
  385. ccxt/latoken.py +1664 -0
  386. ccxt/lbank.py +2682 -0
  387. ccxt/luno.py +1067 -0
  388. ccxt/lykke.py +1270 -0
  389. ccxt/mercado.py +842 -0
  390. ccxt/mexc.py +5369 -0
  391. ccxt/ndax.py +2354 -0
  392. ccxt/nobitex.py +419 -0
  393. ccxt/novadax.py +1484 -0
  394. ccxt/oceanex.py +903 -0
  395. ccxt/okcoin.py +2936 -0
  396. ccxt/okexchange.py +349 -0
  397. ccxt/okx.py +7826 -0
  398. ccxt/ompfinex.py +472 -0
  399. ccxt/onetrading.py +1911 -0
  400. ccxt/oxfun.py +2772 -0
  401. ccxt/p2b.py +1194 -0
  402. ccxt/paradex.py +2015 -0
  403. ccxt/paymium.py +564 -0
  404. ccxt/phemex.py +4473 -0
  405. ccxt/poloniex.py +2232 -0
  406. ccxt/poloniexfutures.py +1717 -0
  407. ccxt/pro/__init__.py +149 -0
  408. ccxt/pro/alpaca.py +685 -0
  409. ccxt/pro/ascendex.py +916 -0
  410. ccxt/pro/bequant.py +38 -0
  411. ccxt/pro/binance.py +3488 -0
  412. ccxt/pro/binancecoinm.py +28 -0
  413. ccxt/pro/binanceus.py +48 -0
  414. ccxt/pro/binanceusdm.py +31 -0
  415. ccxt/pro/bingx.py +1264 -0
  416. ccxt/pro/bitcoincom.py +34 -0
  417. ccxt/pro/bitfinex.py +621 -0
  418. ccxt/pro/bitfinex2.py +1083 -0
  419. ccxt/pro/bitget.py +1692 -0
  420. ccxt/pro/bithumb.py +368 -0
  421. ccxt/pro/bitmart.py +1449 -0
  422. ccxt/pro/bitmex.py +1656 -0
  423. ccxt/pro/bitopro.py +445 -0
  424. ccxt/pro/bitpanda.py +15 -0
  425. ccxt/pro/bitrue.py +447 -0
  426. ccxt/pro/bitstamp.py +522 -0
  427. ccxt/pro/bitvavo.py +1270 -0
  428. ccxt/pro/blockchaincom.py +738 -0
  429. ccxt/pro/blofin.py +692 -0
  430. ccxt/pro/bybit.py +2000 -0
  431. ccxt/pro/cex.py +1440 -0
  432. ccxt/pro/coinbase.py +678 -0
  433. ccxt/pro/coinbaseadvanced.py +16 -0
  434. ccxt/pro/coinbaseexchange.py +895 -0
  435. ccxt/pro/coinbaseinternational.py +620 -0
  436. ccxt/pro/coincatch.py +1464 -0
  437. ccxt/pro/coincheck.py +199 -0
  438. ccxt/pro/coinex.py +1061 -0
  439. ccxt/pro/coinone.py +395 -0
  440. ccxt/pro/cryptocom.py +947 -0
  441. ccxt/pro/currencycom.py +536 -0
  442. ccxt/pro/deribit.py +892 -0
  443. ccxt/pro/exmo.py +629 -0
  444. ccxt/pro/gate.py +1416 -0
  445. ccxt/pro/gateio.py +15 -0
  446. ccxt/pro/gemini.py +865 -0
  447. ccxt/pro/hashkey.py +802 -0
  448. ccxt/pro/hitbtc.py +1216 -0
  449. ccxt/pro/hollaex.py +563 -0
  450. ccxt/pro/htx.py +2215 -0
  451. ccxt/pro/huobi.py +15 -0
  452. ccxt/pro/huobijp.py +570 -0
  453. ccxt/pro/hyperliquid.py +525 -0
  454. ccxt/pro/idex.py +672 -0
  455. ccxt/pro/independentreserve.py +270 -0
  456. ccxt/pro/kraken.py +1356 -0
  457. ccxt/pro/krakenfutures.py +1492 -0
  458. ccxt/pro/kucoin.py +1133 -0
  459. ccxt/pro/kucoinfutures.py +1081 -0
  460. ccxt/pro/lbank.py +843 -0
  461. ccxt/pro/luno.py +303 -0
  462. ccxt/pro/mexc.py +1122 -0
  463. ccxt/pro/ndax.py +506 -0
  464. ccxt/pro/okcoin.py +698 -0
  465. ccxt/pro/okx.py +1851 -0
  466. ccxt/pro/onetrading.py +1275 -0
  467. ccxt/pro/oxfun.py +950 -0
  468. ccxt/pro/p2b.py +419 -0
  469. ccxt/pro/paradex.py +352 -0
  470. ccxt/pro/phemex.py +1441 -0
  471. ccxt/pro/poloniex.py +1166 -0
  472. ccxt/pro/poloniexfutures.py +990 -0
  473. ccxt/pro/probit.py +551 -0
  474. ccxt/pro/upbit.py +520 -0
  475. ccxt/pro/vertex.py +943 -0
  476. ccxt/pro/wazirx.py +749 -0
  477. ccxt/pro/whitebit.py +864 -0
  478. ccxt/pro/woo.py +1078 -0
  479. ccxt/pro/woofipro.py +1183 -0
  480. ccxt/pro/xt.py +1067 -0
  481. ccxt/probit.py +1734 -0
  482. ccxt/ramzinex.py +476 -0
  483. ccxt/sarmayex.py +357 -0
  484. ccxt/sarrafex.py +478 -0
  485. ccxt/static_dependencies/__init__.py +1 -0
  486. ccxt/static_dependencies/ecdsa/__init__.py +14 -0
  487. ccxt/static_dependencies/ecdsa/_version.py +520 -0
  488. ccxt/static_dependencies/ecdsa/curves.py +56 -0
  489. ccxt/static_dependencies/ecdsa/der.py +221 -0
  490. ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
  491. ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
  492. ccxt/static_dependencies/ecdsa/keys.py +332 -0
  493. ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
  494. ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
  495. ccxt/static_dependencies/ecdsa/util.py +266 -0
  496. ccxt/static_dependencies/ethereum/__init__.py +7 -0
  497. ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
  498. ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
  499. ccxt/static_dependencies/ethereum/abi/base.py +152 -0
  500. ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
  501. ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
  502. ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
  503. ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
  504. ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
  505. ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
  506. ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
  507. ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
  508. ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
  509. ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
  510. ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
  511. ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
  512. ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
  513. ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
  514. ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
  515. ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
  516. ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
  517. ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
  518. ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
  519. ccxt/static_dependencies/ethereum/account/messages.py +263 -0
  520. ccxt/static_dependencies/ethereum/account/py.typed +0 -0
  521. ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
  522. ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
  523. ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
  524. ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
  525. ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
  526. ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
  527. ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
  528. ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
  529. ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
  530. ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
  531. ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
  532. ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
  533. ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
  534. ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
  535. ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
  536. ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
  537. ccxt/static_dependencies/ethereum/utils/address.py +171 -0
  538. ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
  539. ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
  540. ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
  541. ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
  542. ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
  543. ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
  544. ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
  545. ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
  546. ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
  547. ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
  548. ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
  549. ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
  550. ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
  551. ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
  552. ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
  553. ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
  554. ccxt/static_dependencies/ethereum/utils/types.py +54 -0
  555. ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
  556. ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
  557. ccxt/static_dependencies/ethereum/utils/units.py +31 -0
  558. ccxt/static_dependencies/keccak/__init__.py +3 -0
  559. ccxt/static_dependencies/keccak/keccak.py +197 -0
  560. ccxt/static_dependencies/lark/__init__.py +38 -0
  561. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  562. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  563. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  564. ccxt/static_dependencies/lark/common.py +86 -0
  565. ccxt/static_dependencies/lark/exceptions.py +292 -0
  566. ccxt/static_dependencies/lark/grammar.py +130 -0
  567. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  568. ccxt/static_dependencies/lark/indenter.py +143 -0
  569. ccxt/static_dependencies/lark/lark.py +658 -0
  570. ccxt/static_dependencies/lark/lexer.py +678 -0
  571. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  572. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  573. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  574. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  575. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  576. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  577. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  578. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  579. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  580. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  581. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  582. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  583. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  584. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  585. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  586. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  587. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  588. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  589. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  590. ccxt/static_dependencies/lark/tree.py +267 -0
  591. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  592. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  593. ccxt/static_dependencies/lark/utils.py +343 -0
  594. ccxt/static_dependencies/lark/visitors.py +596 -0
  595. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  596. ccxt/static_dependencies/marshmallow/base.py +65 -0
  597. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  598. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  599. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  600. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  601. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  602. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  603. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  604. ccxt/static_dependencies/marshmallow/types.py +12 -0
  605. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  606. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  607. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  608. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  609. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  610. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  611. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  612. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  613. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  614. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  615. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  616. ccxt/static_dependencies/msgpack/__init__.py +55 -0
  617. ccxt/static_dependencies/msgpack/exceptions.py +48 -0
  618. ccxt/static_dependencies/msgpack/ext.py +168 -0
  619. ccxt/static_dependencies/msgpack/fallback.py +951 -0
  620. ccxt/static_dependencies/parsimonious/__init__.py +10 -0
  621. ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
  622. ccxt/static_dependencies/parsimonious/expressions.py +479 -0
  623. ccxt/static_dependencies/parsimonious/grammar.py +487 -0
  624. ccxt/static_dependencies/parsimonious/nodes.py +325 -0
  625. ccxt/static_dependencies/parsimonious/utils.py +40 -0
  626. ccxt/static_dependencies/starknet/__init__.py +0 -0
  627. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  628. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  629. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  630. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  631. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  632. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  633. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  634. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  635. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  636. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  637. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  638. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  639. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  640. ccxt/static_dependencies/starknet/common.py +15 -0
  641. ccxt/static_dependencies/starknet/constants.py +39 -0
  642. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  643. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  644. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  645. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  646. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  647. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  648. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  649. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  650. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  651. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  652. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  653. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  654. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  655. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  656. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  657. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  658. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  659. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  660. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  661. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  662. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  663. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  664. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  665. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  666. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  667. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  668. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  669. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  670. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  671. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  672. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  673. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  674. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  675. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  676. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  677. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  678. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  679. ccxt/static_dependencies/starkware/__init__.py +0 -0
  680. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  681. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  682. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  683. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  684. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  685. ccxt/static_dependencies/sympy/__init__.py +0 -0
  686. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  687. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  688. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  689. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  690. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  691. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  692. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  693. ccxt/static_dependencies/toolz/__init__.py +26 -0
  694. ccxt/static_dependencies/toolz/_signatures.py +784 -0
  695. ccxt/static_dependencies/toolz/_version.py +520 -0
  696. ccxt/static_dependencies/toolz/compatibility.py +30 -0
  697. ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
  698. ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
  699. ccxt/static_dependencies/toolz/curried/operator.py +22 -0
  700. ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
  701. ccxt/static_dependencies/toolz/functoolz.py +1049 -0
  702. ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
  703. ccxt/static_dependencies/toolz/recipes.py +46 -0
  704. ccxt/static_dependencies/toolz/utils.py +9 -0
  705. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  706. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  707. ccxt/tabdeal.py +364 -0
  708. ccxt/test/__init__.py +3 -0
  709. ccxt/test/base/__init__.py +29 -0
  710. ccxt/test/base/test_account.py +26 -0
  711. ccxt/test/base/test_balance.py +56 -0
  712. ccxt/test/base/test_borrow_interest.py +35 -0
  713. ccxt/test/base/test_borrow_rate.py +32 -0
  714. ccxt/test/base/test_calculate_fee.py +51 -0
  715. ccxt/test/base/test_crypto.py +127 -0
  716. ccxt/test/base/test_currency.py +76 -0
  717. ccxt/test/base/test_datetime.py +109 -0
  718. ccxt/test/base/test_decimal_to_precision.py +392 -0
  719. ccxt/test/base/test_deep_extend.py +68 -0
  720. ccxt/test/base/test_deposit_withdrawal.py +50 -0
  721. ccxt/test/base/test_exchange_datetime_functions.py +76 -0
  722. ccxt/test/base/test_funding_rate_history.py +29 -0
  723. ccxt/test/base/test_last_price.py +31 -0
  724. ccxt/test/base/test_ledger_entry.py +45 -0
  725. ccxt/test/base/test_ledger_item.py +48 -0
  726. ccxt/test/base/test_leverage_tier.py +33 -0
  727. ccxt/test/base/test_liquidation.py +50 -0
  728. ccxt/test/base/test_margin_mode.py +24 -0
  729. ccxt/test/base/test_margin_modification.py +35 -0
  730. ccxt/test/base/test_market.py +193 -0
  731. ccxt/test/base/test_number.py +411 -0
  732. ccxt/test/base/test_ohlcv.py +33 -0
  733. ccxt/test/base/test_open_interest.py +32 -0
  734. ccxt/test/base/test_order.py +64 -0
  735. ccxt/test/base/test_order_book.py +69 -0
  736. ccxt/test/base/test_position.py +60 -0
  737. ccxt/test/base/test_shared_methods.py +353 -0
  738. ccxt/test/base/test_status.py +24 -0
  739. ccxt/test/base/test_throttle.py +126 -0
  740. ccxt/test/base/test_ticker.py +92 -0
  741. ccxt/test/base/test_trade.py +47 -0
  742. ccxt/test/base/test_trading_fee.py +26 -0
  743. ccxt/test/base/test_transaction.py +39 -0
  744. ccxt/test/test_async.py +1649 -0
  745. ccxt/test/test_sync.py +1648 -0
  746. ccxt/test/tests_async.py +1558 -0
  747. ccxt/test/tests_helpers.py +287 -0
  748. ccxt/test/tests_init.py +39 -0
  749. ccxt/test/tests_sync.py +1555 -0
  750. ccxt/tetherland.py +349 -0
  751. ccxt/timex.py +1593 -0
  752. ccxt/tokocrypto.py +2405 -0
  753. ccxt/tradeogre.py +608 -0
  754. ccxt/twox.py +326 -0
  755. ccxt/ubitex.py +409 -0
  756. ccxt/upbit.py +1833 -0
  757. ccxt/vertex.py +2922 -0
  758. ccxt/wallex.py +445 -0
  759. ccxt/wavesexchange.py +2472 -0
  760. ccxt/wazirx.py +1224 -0
  761. ccxt/whitebit.py +2469 -0
  762. ccxt/woo.py +3114 -0
  763. ccxt/woofipro.py +2533 -0
  764. ccxt/xt.py +4453 -0
  765. ccxt/yobit.py +1283 -0
  766. ccxt/zaif.py +725 -0
  767. ccxt/zonda.py +1828 -0
  768. ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
  769. ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
  770. ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
  771. ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
  772. ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,4602 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.kucoin import ImplicitAPI
8
+ import asyncio
9
+ import hashlib
10
+ import math
11
+ import json
12
+ from ccxt.base.types import Account, Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry
13
+ from typing import List
14
+ from ccxt.base.errors import ExchangeError
15
+ from ccxt.base.errors import AuthenticationError
16
+ from ccxt.base.errors import PermissionDenied
17
+ from ccxt.base.errors import AccountSuspended
18
+ from ccxt.base.errors import ArgumentsRequired
19
+ from ccxt.base.errors import BadRequest
20
+ from ccxt.base.errors import BadSymbol
21
+ from ccxt.base.errors import InsufficientFunds
22
+ from ccxt.base.errors import InvalidAddress
23
+ from ccxt.base.errors import InvalidOrder
24
+ from ccxt.base.errors import OrderNotFound
25
+ from ccxt.base.errors import NotSupported
26
+ from ccxt.base.errors import RateLimitExceeded
27
+ from ccxt.base.errors import ExchangeNotAvailable
28
+ from ccxt.base.errors import InvalidNonce
29
+ from ccxt.base.decimal_to_precision import TRUNCATE
30
+ from ccxt.base.decimal_to_precision import TICK_SIZE
31
+ from ccxt.base.precise import Precise
32
+
33
+
34
+ class kucoin(Exchange, ImplicitAPI):
35
+
36
+ def describe(self):
37
+ return self.deep_extend(super(kucoin, self).describe(), {
38
+ 'id': 'kucoin',
39
+ 'name': 'KuCoin',
40
+ 'countries': ['SC'],
41
+ 'rateLimit': 10, # 100 requests per second =>( 1000ms / 100 ) = 10 ms between requests on average
42
+ 'version': 'v2',
43
+ 'certified': True,
44
+ 'pro': True,
45
+ 'comment': 'Platform 2.0',
46
+ 'quoteJsonNumbers': False,
47
+ 'has': {
48
+ 'CORS': None,
49
+ 'spot': True,
50
+ 'margin': True,
51
+ 'swap': False,
52
+ 'future': False,
53
+ 'option': False,
54
+ 'borrowCrossMargin': True,
55
+ 'borrowIsolatedMargin': True,
56
+ 'cancelAllOrders': True,
57
+ 'cancelOrder': True,
58
+ 'closeAllPositions': False,
59
+ 'closePosition': False,
60
+ 'createDepositAddress': True,
61
+ 'createMarketBuyOrderWithCost': True,
62
+ 'createMarketOrderWithCost': True,
63
+ 'createMarketSellOrderWithCost': True,
64
+ 'createOrder': True,
65
+ 'createOrders': True,
66
+ 'createPostOnlyOrder': True,
67
+ 'createStopLimitOrder': True,
68
+ 'createStopMarketOrder': True,
69
+ 'createStopOrder': True,
70
+ 'createTriggerOrder': True,
71
+ 'editOrder': True,
72
+ 'fetchAccounts': True,
73
+ 'fetchBalance': True,
74
+ 'fetchBorrowInterest': True,
75
+ 'fetchBorrowRateHistories': True,
76
+ 'fetchBorrowRateHistory': True,
77
+ 'fetchClosedOrders': True,
78
+ 'fetchCrossBorrowRate': False,
79
+ 'fetchCrossBorrowRates': False,
80
+ 'fetchCurrencies': True,
81
+ 'fetchDepositAddress': True,
82
+ 'fetchDepositAddressesByNetwork': True,
83
+ 'fetchDeposits': True,
84
+ 'fetchDepositWithdrawFee': True,
85
+ 'fetchDepositWithdrawFees': True,
86
+ 'fetchFundingHistory': False,
87
+ 'fetchFundingRate': False,
88
+ 'fetchFundingRateHistory': False,
89
+ 'fetchFundingRates': False,
90
+ 'fetchIndexOHLCV': False,
91
+ 'fetchIsolatedBorrowRate': False,
92
+ 'fetchIsolatedBorrowRates': False,
93
+ 'fetchL3OrderBook': True,
94
+ 'fetchLedger': True,
95
+ 'fetchLeverageTiers': False,
96
+ 'fetchMarginAdjustmentHistory': False,
97
+ 'fetchMarginMode': False,
98
+ 'fetchMarketLeverageTiers': False,
99
+ 'fetchMarkets': True,
100
+ 'fetchMarkOHLCV': False,
101
+ 'fetchMyTrades': True,
102
+ 'fetchOHLCV': True,
103
+ 'fetchOpenInterest': False,
104
+ 'fetchOpenInterestHistory': False,
105
+ 'fetchOpenOrders': True,
106
+ 'fetchOrder': True,
107
+ 'fetchOrderBook': True,
108
+ 'fetchOrderBooks': False,
109
+ 'fetchOrdersByStatus': True,
110
+ 'fetchOrderTrades': True,
111
+ 'fetchPositionHistory': False,
112
+ 'fetchPositionMode': False,
113
+ 'fetchPositionsHistory': False,
114
+ 'fetchPremiumIndexOHLCV': False,
115
+ 'fetchStatus': True,
116
+ 'fetchTicker': True,
117
+ 'fetchTickers': True,
118
+ 'fetchTime': True,
119
+ 'fetchTrades': True,
120
+ 'fetchTradingFee': True,
121
+ 'fetchTradingFees': False,
122
+ 'fetchTransactionFee': True,
123
+ 'fetchTransfers': False,
124
+ 'fetchWithdrawals': True,
125
+ 'repayCrossMargin': True,
126
+ 'repayIsolatedMargin': True,
127
+ 'setLeverage': False,
128
+ 'setMarginMode': False,
129
+ 'setPositionMode': False,
130
+ 'signIn': False,
131
+ 'transfer': True,
132
+ 'withdraw': True,
133
+ },
134
+ 'urls': {
135
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295558-132aaf80-c50e-11ea-9801-a2fb0c57c799.jpg',
136
+ 'referral': 'https://www.kucoin.com/ucenter/signup?rcode=E5wkqe',
137
+ 'api': {
138
+ 'public': 'https://api.kucoin.com',
139
+ 'private': 'https://api.kucoin.com',
140
+ 'futuresPrivate': 'https://api-futures.kucoin.com',
141
+ 'futuresPublic': 'https://api-futures.kucoin.com',
142
+ 'webExchange': 'https://kucoin.com/_api',
143
+ 'broker': 'https://api-broker.kucoin.com',
144
+ 'earn': 'https://api.kucoin.com',
145
+ },
146
+ 'www': 'https://www.kucoin.com',
147
+ 'doc': [
148
+ 'https://docs.kucoin.com',
149
+ ],
150
+ },
151
+ 'requiredCredentials': {
152
+ 'apiKey': True,
153
+ 'secret': True,
154
+ 'password': True,
155
+ },
156
+ 'api': {
157
+ # level VIP0
158
+ # Spot => 3000/30s => 100/s
159
+ # Weight = x => 100/(100/x) = x
160
+ # Futures Management Public => 2000/30s => 200/3/s
161
+ # Weight = x => 100/(200/3/x) = x*1.5
162
+ 'public': {
163
+ 'get': {
164
+ # spot trading
165
+ 'currencies': 4.5, # 3PW
166
+ 'currencies/{currency}': 4.5, # 3PW
167
+ 'symbols': 6, # 4PW
168
+ 'market/orderbook/level1': 3, # 2PW
169
+ 'market/allTickers': 22.5, # 15PW
170
+ 'market/stats': 22.5, # 15PW
171
+ 'markets': 4.5, # 3PW
172
+ 'market/orderbook/level{level}_{limit}': 6, # 4PW
173
+ 'market/orderbook/level2_20': 3, # 2PW
174
+ 'market/orderbook/level2_100': 6, # 4PW
175
+ 'market/histories': 4.5, # 3PW
176
+ 'market/candles': 4.5, # 3PW
177
+ 'prices': 4.5, # 3PW
178
+ 'timestamp': 4.5, # 3PW
179
+ 'status': 4.5, # 3PW
180
+ # margin trading
181
+ 'mark-price/{symbol}/current': 3, # 2PW
182
+ 'margin/config': 25, # 25SW
183
+ },
184
+ 'post': {
185
+ # ws
186
+ 'bullet-public': 15, # 10PW
187
+ },
188
+ },
189
+ 'private': {
190
+ 'get': {
191
+ # account
192
+ 'user-info': 30, # 20MW
193
+ 'accounts': 7.5, # 5MW
194
+ 'accounts/{accountId}': 7.5, # 5MW
195
+ 'accounts/ledgers': 3, # 2MW
196
+ 'hf/accounts/ledgers': 2, # 2SW
197
+ 'hf/margin/account/ledgers': 2, # 2SW
198
+ 'transaction-history': 3, # 2MW
199
+ 'sub/user': 30, # 20MW
200
+ 'sub-accounts/{subUserId}': 22.5, # 15MW
201
+ 'sub-accounts': 30, # 20MW
202
+ 'sub/api-key': 30, # 20MW
203
+ # funding
204
+ 'margin/account': 40, # 40SW
205
+ 'margin/accounts': 15, # 15SW
206
+ 'isolated/accounts': 15, # 15SW
207
+ 'deposit-addresses': 7.5, # 5MW
208
+ 'deposits': 7.5, # 5MW
209
+ 'hist-deposits': 7.5, # 5MW
210
+ 'withdrawals': 30, # 20MW
211
+ 'hist-withdrawals': 30, # 20MW
212
+ 'withdrawals/quotas': 30, # 20MW
213
+ 'accounts/transferable': 30, # 20MW
214
+ 'transfer-list': 30, # 20MW
215
+ 'base-fee': 3, # 3SW
216
+ 'trade-fees': 3, # 3SW
217
+ # spot trading
218
+ 'market/orderbook/level{level}': 3, # 3SW
219
+ 'market/orderbook/level2': 3, # 3SW
220
+ 'market/orderbook/level3': 3, # 3SW
221
+ 'hf/orders/active': 2, # 2SW
222
+ 'hf/orders/active/symbols': 2, # 2SW
223
+ 'hf/orders/done': 2, # 2SW
224
+ 'hf/orders/{orderId}': 2, # 2SW
225
+ 'hf/orders/client-order/{clientOid}': 2, # 2SW
226
+ 'hf/orders/dead-cancel-all/query': 2, # 2SW
227
+ 'hf/fills': 2, # 2SW
228
+ 'orders': 2, # 2SW
229
+ 'limit/orders': 3, # 3SW
230
+ 'orders/{orderId}': 2, # 2SW
231
+ 'order/client-order/{clientOid}': 3, # 3SW
232
+ 'fills': 10, # 10SW
233
+ 'limit/fills': 20, # 20SW
234
+ 'stop-order': 8, # 8SW
235
+ 'stop-order/{orderId}': 3, # 3SW
236
+ 'stop-order/queryOrderByClientOid': 3, # 3SW
237
+ 'oco/order/{orderId}': 2, # 2SW
238
+ 'oco/order/details/{orderId}': 2, # 2SW
239
+ 'oco/client-order/{clientOid}': 2, # 2SW
240
+ 'oco/orders': 2, # 2SW
241
+ # margin trading
242
+ 'hf/margin/orders/active': 4, # 4SW
243
+ 'hf/margin/orders/done': 10, # 10SW
244
+ 'hf/margin/orders/{orderId}': 4, # 4SW
245
+ 'hf/margin/orders/client-order/{clientOid}': 5, # 5SW
246
+ 'hf/margin/fills': 5, # 5SW
247
+ 'etf/info': 25, # 25SW
248
+ 'margin/currencies': 20, # 20SW
249
+ 'risk/limit/strategy': 20, # 20SW(Deprecate)
250
+ 'isolated/symbols': 20, # 20SW
251
+ 'isolated/account/{symbol}': 50, # 50SW
252
+ 'margin/borrow': 15, # 15SW
253
+ 'margin/repay': 15, # 15SW
254
+ 'margin/interest': 20, # 20SW
255
+ 'project/list': 10, # 10SW
256
+ 'project/marketInterestRate': 7.5, # 5PW
257
+ 'redeem/orders': 10, # 10SW
258
+ 'purchase/orders': 10, # 10SW
259
+ # broker
260
+ 'broker/api/rebase/download': 3,
261
+ },
262
+ 'post': {
263
+ # account
264
+ 'sub/user/created': 22.5, # 15MW
265
+ 'sub/api-key': 30, # 20MW
266
+ 'sub/api-key/update': 45, # 30MW
267
+ # funding
268
+ 'deposit-addresses': 30, # 20MW
269
+ 'withdrawals': 7.5, # 5MW
270
+ 'accounts/universal-transfer': 6, # 4MW
271
+ 'accounts/sub-transfer': 45, # 30MW
272
+ 'accounts/inner-transfer': 15, # 10MW
273
+ 'transfer-out': 30, # 20MW
274
+ 'transfer-in': 30, # 20MW
275
+ # spot trading
276
+ 'hf/orders': 1, # 1SW
277
+ 'hf/orders/test': 1, # 1SW
278
+ 'hf/orders/sync': 1, # 1SW
279
+ 'hf/orders/multi': 1, # 1SW
280
+ 'hf/orders/multi/sync': 1, # 1SW
281
+ 'hf/orders/alter': 3, # 3SW
282
+ 'hf/orders/dead-cancel-all': 2, # 2SW
283
+ 'orders': 2, # 2SW
284
+ 'orders/test': 2, # 2SW
285
+ 'orders/multi': 3, # 3SW
286
+ 'stop-order': 2, # 2SW
287
+ 'oco/order': 2, # 2SW
288
+ # margin trading
289
+ 'hf/margin/order': 5, # 5SW
290
+ 'hf/margin/order/test': 5, # 5SW
291
+ 'margin/order': 5, # 5SW
292
+ 'margin/order/test': 5, # 5SW
293
+ 'margin/borrow': 15, # 15SW
294
+ 'margin/repay': 10, # 10SW
295
+ 'purchase': 15, # 15SW
296
+ 'redeem': 15, # 15SW
297
+ 'lend/purchase/update': 10, # 10SW
298
+ # ws
299
+ 'bullet-private': 10, # 10SW
300
+ },
301
+ 'delete': {
302
+ # account
303
+ 'sub/api-key': 45, # 30MW
304
+ # funding
305
+ 'withdrawals/{withdrawalId}': 30, # 20MW
306
+ # spot trading
307
+ 'hf/orders/{orderId}': 1, # 1SW
308
+ 'hf/orders/sync/{orderId}': 1, # 1SW
309
+ 'hf/orders/client-order/{clientOid}': 1, # 1SW
310
+ 'hf/orders/sync/client-order/{clientOid}': 1, # 1SW
311
+ 'hf/orders/cancel/{orderId}': 2, # 2SW
312
+ 'hf/orders': 2, # 2SW
313
+ 'hf/orders/cancelAll': 30, # 30SW
314
+ 'orders/{orderId}': 3, # 3SW
315
+ 'order/client-order/{clientOid}': 5, # 5SW
316
+ 'orders': 20, # 20SW
317
+ 'stop-order/{orderId}': 3, # 3SW
318
+ 'stop-order/cancelOrderByClientOid': 5, # 5SW
319
+ 'stop-order/cancel': 3, # 3SW
320
+ 'oco/order/{orderId}': 3, # 3SW
321
+ 'oco/client-order/{clientOid}': 3, # 3SW
322
+ 'oco/orders': 3, # 3SW
323
+ # margin trading
324
+ 'hf/margin/orders/{orderId}': 5, # 5SW
325
+ 'hf/margin/orders/client-order/{clientOid}': 5, # 5SW
326
+ 'hf/margin/orders': 10, # 10SW
327
+ },
328
+ },
329
+ 'futuresPublic': {
330
+ 'get': {
331
+ 'contracts/active': 4.5, # 3PW
332
+ 'contracts/{symbol}': 4.5, # 3PW
333
+ 'ticker': 3, # 2PW
334
+ 'level2/snapshot': 4.5, # 3PW
335
+ 'level2/depth20': 7.5, # 5PW
336
+ 'level2/depth100': 15, # 10PW
337
+ 'trade/history': 7.5, # 5PW
338
+ 'kline/query': 4.5, # 3PW
339
+ 'interest/query': 7.5, # 5PW
340
+ 'index/query': 3, # 2PW
341
+ 'mark-price/{symbol}/current': 4.5, # 3PW
342
+ 'premium/query': 4.5, # 3PW
343
+ 'trade-statistics': 4.5, # 3PW
344
+ 'funding-rate/{symbol}/current': 3, # 2PW
345
+ 'contract/funding-rates': 7.5, # 5PW
346
+ 'timestamp': 3, # 2PW
347
+ 'status': 6, # 4PW
348
+ # ?
349
+ 'level2/message/query': 1.3953,
350
+ },
351
+ 'post': {
352
+ # ws
353
+ 'bullet-public': 15, # 10PW
354
+ },
355
+ },
356
+ 'futuresPrivate': {
357
+ 'get': {
358
+ # account
359
+ 'transaction-history': 3, # 2MW
360
+ # funding
361
+ 'account-overview': 7.5, # 5FW
362
+ 'account-overview-all': 9, # 6FW
363
+ 'transfer-list': 30, # 20MW
364
+ # futures
365
+ 'orders': 3, # 2FW
366
+ 'stopOrders': 9, # 6FW
367
+ 'recentDoneOrders': 7.5, # 5FW
368
+ 'orders/{orderId}': 7.5, # 5FW
369
+ 'orders/byClientOid': 7.5, # 5FW
370
+ 'fills': 7.5, # 5FW
371
+ 'recentFills': 4.5, # 3FW
372
+ 'openOrderStatistics': 15, # 10FW
373
+ 'position': 3, # 2FW
374
+ 'positions': 3, # 2FW
375
+ 'margin/maxWithdrawMargin': 15, # 10FW
376
+ 'contracts/risk-limit/{symbol}': 7.5, # 5FW
377
+ 'funding-history': 7.5, # 5FW
378
+ },
379
+ 'post': {
380
+ # funding
381
+ 'transfer-out': 30, # 20MW
382
+ 'transfer-in': 30, # 20MW
383
+ # futures
384
+ 'orders': 3, # 2FW
385
+ 'orders/test': 3, # 2FW
386
+ 'orders/multi': 4.5, # 3FW
387
+ 'position/margin/auto-deposit-status': 6, # 4FW
388
+ 'margin/withdrawMargin': 15, # 10FW
389
+ 'position/margin/deposit-margin': 6, # 4FW
390
+ 'position/risk-limit-level/change': 6, # 4FW
391
+ # ws
392
+ 'bullet-private': 15, # 10FW
393
+ },
394
+ 'delete': {
395
+ 'orders/{orderId}': 1.5, # 1FW
396
+ 'orders/client-order/{clientOid}': 1.5, # 1FW
397
+ 'orders': 45, # 30FW
398
+ 'stopOrders': 22.5, # 15FW
399
+ },
400
+ },
401
+ 'webExchange': {
402
+ 'get': {
403
+ 'currency/currency/chain-info': 1, # self is temporary from webApi
404
+ },
405
+ },
406
+ 'broker': {
407
+ 'get': {
408
+ 'broker/nd/info': 2,
409
+ 'broker/nd/account': 2,
410
+ 'broker/nd/account/apikey': 2,
411
+ 'broker/nd/rebase/download': 3,
412
+ 'broker/nd/transfer/detail': 1,
413
+ 'broker/nd/deposit/detail': 1,
414
+ 'broker/nd/withdraw/detail': 1,
415
+ },
416
+ 'post': {
417
+ 'broker/nd/transfer': 1,
418
+ 'broker/nd/account': 3,
419
+ 'broker/nd/account/apikey': 3,
420
+ 'broker/nd/account/update-apikey': 3,
421
+ },
422
+ 'delete': {
423
+ 'broker/nd/account/apikey': 3,
424
+ },
425
+ },
426
+ 'earn': {
427
+ 'get': {
428
+ 'otc-loan/loan': 1,
429
+ 'otc-loan/accounts': 1,
430
+ 'earn/redeem-preview': 7.5, # 5EW
431
+ 'earn/saving/products': 7.5, # 5EW
432
+ 'earn/hold-assets': 7.5, # 5EW
433
+ 'earn/promotion/products': 7.5, # 5EW
434
+ 'earn/kcs-staking/products': 7.5, # 5EW
435
+ 'earn/staking/products': 7.5, # 5EW
436
+ 'earn/eth-staking/products': 7.5, # 5EW
437
+ },
438
+ 'post': {
439
+ 'earn/orders': 7.5, # 5EW
440
+ },
441
+ 'delete': {
442
+ 'earn/orders': 7.5, # 5EW
443
+ },
444
+ },
445
+ },
446
+ 'timeframes': {
447
+ '1m': '1min',
448
+ '3m': '3min',
449
+ '5m': '5min',
450
+ '15m': '15min',
451
+ '30m': '30min',
452
+ '1h': '1hour',
453
+ '2h': '2hour',
454
+ '4h': '4hour',
455
+ '6h': '6hour',
456
+ '8h': '8hour',
457
+ '12h': '12hour',
458
+ '1d': '1day',
459
+ '1w': '1week',
460
+ '1M': '1month',
461
+ },
462
+ 'precisionMode': TICK_SIZE,
463
+ 'exceptions': {
464
+ 'exact': {
465
+ 'order not exist': OrderNotFound,
466
+ 'order not exist.': OrderNotFound, # duplicated error temporarily
467
+ 'order_not_exist': OrderNotFound, # {"code":"order_not_exist","msg":"order_not_exist"} ¯\_(ツ)_/¯
468
+ 'order_not_exist_or_not_allow_to_cancel': InvalidOrder, # {"code":"400100","msg":"order_not_exist_or_not_allow_to_cancel"}
469
+ 'Order size below the minimum requirement.': InvalidOrder, # {"code":"400100","msg":"Order size below the minimum requirement."}
470
+ 'The withdrawal amount is below the minimum requirement.': ExchangeError, # {"code":"400100","msg":"The withdrawal amount is below the minimum requirement."}
471
+ 'Unsuccessful! Exceeded the max. funds out-transfer limit': InsufficientFunds, # {"code":"200000","msg":"Unsuccessful! Exceeded the max. funds out-transfer limit"}
472
+ 'The amount increment is invalid.': BadRequest,
473
+ 'The quantity is below the minimum requirement.': InvalidOrder, # {"msg":"The quantity is below the minimum requirement.","code":"400100"}
474
+ '400': BadRequest,
475
+ '401': AuthenticationError,
476
+ '403': NotSupported,
477
+ '404': NotSupported,
478
+ '405': NotSupported,
479
+ '415': NotSupported,
480
+ '429': RateLimitExceeded,
481
+ '500': ExchangeNotAvailable, # Internal Server Error -- We had a problem with our server. Try again later.
482
+ '503': ExchangeNotAvailable,
483
+ '101030': PermissionDenied, # {"code":"101030","msg":"You haven't yet enabled the margin trading"}
484
+ '103000': InvalidOrder, # {"code":"103000","msg":"Exceed the borrowing limit, the remaining borrowable amount is: 0USDT"}
485
+ '130101': BadRequest, # Parameter error
486
+ '130102': ExchangeError, # Maximum subscription amount has been exceeded.
487
+ '130103': OrderNotFound, # Subscription order does not exist.
488
+ '130104': ExchangeError, # Maximum number of subscription orders has been exceeded.
489
+ '130105': InsufficientFunds, # Insufficient balance.
490
+ '130106': NotSupported, # The currency does not support redemption.
491
+ '130107': ExchangeError, # Redemption amount exceeds subscription amount.
492
+ '130108': OrderNotFound, # Redemption order does not exist.
493
+ '130201': PermissionDenied, # Your account has restricted access to certain features. Please contact customer service for further assistance
494
+ '130202': ExchangeError, # The system is renewing the loan automatically. Please try again later
495
+ '130203': InsufficientFunds, # Insufficient account balance
496
+ '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
497
+ '130301': InsufficientFunds, # Insufficient account balance
498
+ '130302': PermissionDenied, # Your relevant permission rights have been restricted, you can contact customer service for processing
499
+ '130303': NotSupported, # The current trading pair does not support isolated positions
500
+ '130304': NotSupported, # The trading function of the current trading pair is not enabled
501
+ '130305': NotSupported, # The current trading pair does not support cross position
502
+ '130306': NotSupported, # The account has not opened leveraged trading
503
+ '130307': NotSupported, # Please reopen the leverage agreement
504
+ '130308': InvalidOrder, # Position renewal freeze
505
+ '130309': InvalidOrder, # Position forced liquidation freeze
506
+ '130310': ExchangeError, # Abnormal leverage account status
507
+ '130311': InvalidOrder, # Failed to place an order, triggering buy limit
508
+ '130312': InvalidOrder, # Trigger global position limit, suspend buying
509
+ '130313': InvalidOrder, # Trigger global position limit, suspend selling
510
+ '130314': InvalidOrder, # Trigger the global position limit and prompt the remaining quantity available for purchase
511
+ '130315': NotSupported, # This feature has been suspended due to country restrictions
512
+ '126000': ExchangeError, # Abnormal margin trading
513
+ '126001': NotSupported, # Users currently do not support high frequency
514
+ '126002': ExchangeError, # There is a risk problem in your account and transactions are temporarily not allowed!
515
+ '126003': InvalidOrder, # The commission amount is less than the minimum transaction amount for a single commission
516
+ '126004': ExchangeError, # Trading pair does not exist or is prohibited
517
+ '126005': PermissionDenied, # This trading pair requires advanced KYC certification before trading
518
+ '126006': ExchangeError, # Trading pair is not available
519
+ '126007': ExchangeError, # Trading pair suspended
520
+ '126009': ExchangeError, # Trading pair is suspended from creating orders
521
+ '126010': ExchangeError, # Trading pair suspended order cancellation
522
+ '126011': ExchangeError, # There are too many orders in the order
523
+ '126013': InsufficientFunds, # Insufficient account balance
524
+ '126015': ExchangeError, # It is prohibited to place orders on self trading pair
525
+ '126021': NotSupported, # This digital asset does not support user participation in your region, thank you for your understanding!
526
+ '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.
527
+ '126027': InvalidOrder, # Only limit orders are supported
528
+ '126028': InvalidOrder, # Only limit orders are supported before the specified time
529
+ '126029': InvalidOrder, # The maximum order price is: xxx
530
+ '126030': InvalidOrder, # The minimum order price is: xxx
531
+ '126033': InvalidOrder, # Duplicate order
532
+ '126034': InvalidOrder, # Failed to create take profit and stop loss order
533
+ '126036': InvalidOrder, # Failed to create margin order
534
+ '126037': ExchangeError, # Due to country and region restrictions, self function has been suspended!
535
+ '126038': ExchangeError, # Third-party service call failed(internal exception)
536
+ '126039': ExchangeError, # Third-party service call failed, reason: xxx
537
+ '126041': ExchangeError, # clientTimestamp parameter error
538
+ '126042': ExchangeError, # Exceeded maximum position limit
539
+ '126043': OrderNotFound, # Order does not exist
540
+ '126044': InvalidOrder, # clientOid duplicate
541
+ '126045': NotSupported, # This digital asset does not support user participation in your region, thank you for your understanding!
542
+ '126046': NotSupported, # This digital asset does not support your IP region, thank you for your understanding!
543
+ '126047': PermissionDenied, # Please complete identity verification
544
+ '126048': PermissionDenied, # Please complete authentication for the master account
545
+ '135005': ExchangeError, # Margin order query business abnormality
546
+ '135018': ExchangeError, # Margin order query service abnormality
547
+ '200004': InsufficientFunds,
548
+ '210014': InvalidOrder, # {"code":"210014","msg":"Exceeds the max. borrowing amount, the remaining amount you can borrow: 0USDT"}
549
+ '210021': InsufficientFunds, # {"code":"210021","msg":"Balance not enough"}
550
+ '230003': InsufficientFunds, # {"code":"230003","msg":"Balance insufficient!"}
551
+ '260000': InvalidAddress, # {"code":"260000","msg":"Deposit address already exists."}
552
+ '260100': InsufficientFunds, # {"code":"260100","msg":"account.noBalance"}
553
+ '300000': InvalidOrder,
554
+ '400000': BadSymbol,
555
+ '400001': AuthenticationError,
556
+ '400002': InvalidNonce,
557
+ '400003': AuthenticationError,
558
+ '400004': AuthenticationError,
559
+ '400005': AuthenticationError,
560
+ '400006': AuthenticationError,
561
+ '400007': AuthenticationError,
562
+ '400008': NotSupported,
563
+ '400100': InsufficientFunds, # {"msg":"account.available.amount","code":"400100"} or {"msg":"Withdrawal amount is below the minimum requirement.","code":"400100"}
564
+ '400200': InvalidOrder, # {"code":"400200","msg":"Forbidden to place an order"}
565
+ '400350': InvalidOrder, # {"code":"400350","msg":"Upper limit for holding: 10,000USDT, you can still buy 10,000USDT worth of coin."}
566
+ '400370': InvalidOrder, # {"code":"400370","msg":"Max. price: 0.02500000000000000000"}
567
+ '400400': BadRequest, # Parameter error
568
+ '400401': AuthenticationError, # User is not logged in
569
+ '400500': InvalidOrder, # {"code":"400500","msg":"Your located country/region is currently not supported for the trading of self token"}
570
+ '400600': BadSymbol, # {"code":"400600","msg":"validation.createOrder.symbolNotAvailable"}
571
+ '400760': InvalidOrder, # {"code":"400760","msg":"order price should be more than XX"}
572
+ '401000': BadRequest, # {"code":"401000","msg":"The interface has been deprecated"}
573
+ '408000': BadRequest, # Network timeout, please try again later
574
+ '411100': AccountSuspended,
575
+ '415000': BadRequest, # {"code":"415000","msg":"Unsupported Media Type"}
576
+ '400303': PermissionDenied, # {"msg":"To enjoy the full range of our products and services, we kindly request you complete the identity verification process.","code":"400303"}
577
+ '500000': ExchangeNotAvailable, # {"code":"500000","msg":"Internal Server Error"}
578
+ '260220': InvalidAddress, # {"code": "260220", "msg": "deposit.address.not.exists"}
579
+ '900014': BadRequest, # {"code":"900014","msg":"Invalid chainId"}
580
+ },
581
+ 'broad': {
582
+ 'Exceeded the access frequency': RateLimitExceeded,
583
+ 'require more permission': PermissionDenied,
584
+ },
585
+ },
586
+ 'fees': {
587
+ 'trading': {
588
+ 'tierBased': True,
589
+ 'percentage': True,
590
+ 'taker': self.parse_number('0.001'),
591
+ 'maker': self.parse_number('0.001'),
592
+ 'tiers': {
593
+ 'taker': [
594
+ [self.parse_number('0'), self.parse_number('0.001')],
595
+ [self.parse_number('50'), self.parse_number('0.001')],
596
+ [self.parse_number('200'), self.parse_number('0.0009')],
597
+ [self.parse_number('500'), self.parse_number('0.0008')],
598
+ [self.parse_number('1000'), self.parse_number('0.0007')],
599
+ [self.parse_number('2000'), self.parse_number('0.0007')],
600
+ [self.parse_number('4000'), self.parse_number('0.0006')],
601
+ [self.parse_number('8000'), self.parse_number('0.0005')],
602
+ [self.parse_number('15000'), self.parse_number('0.00045')],
603
+ [self.parse_number('25000'), self.parse_number('0.0004')],
604
+ [self.parse_number('40000'), self.parse_number('0.00035')],
605
+ [self.parse_number('60000'), self.parse_number('0.0003')],
606
+ [self.parse_number('80000'), self.parse_number('0.00025')],
607
+ ],
608
+ 'maker': [
609
+ [self.parse_number('0'), self.parse_number('0.001')],
610
+ [self.parse_number('50'), self.parse_number('0.0009')],
611
+ [self.parse_number('200'), self.parse_number('0.0007')],
612
+ [self.parse_number('500'), self.parse_number('0.0005')],
613
+ [self.parse_number('1000'), self.parse_number('0.0003')],
614
+ [self.parse_number('2000'), self.parse_number('0')],
615
+ [self.parse_number('4000'), self.parse_number('0')],
616
+ [self.parse_number('8000'), self.parse_number('0')],
617
+ [self.parse_number('15000'), self.parse_number('-0.00005')],
618
+ [self.parse_number('25000'), self.parse_number('-0.00005')],
619
+ [self.parse_number('40000'), self.parse_number('-0.00005')],
620
+ [self.parse_number('60000'), self.parse_number('-0.00005')],
621
+ [self.parse_number('80000'), self.parse_number('-0.00005')],
622
+ ],
623
+ },
624
+ },
625
+ 'funding': {
626
+ 'tierBased': False,
627
+ 'percentage': False,
628
+ 'withdraw': {},
629
+ 'deposit': {},
630
+ },
631
+ },
632
+ 'commonCurrencies': {
633
+ 'BIFI': 'BIFIF',
634
+ 'VAI': 'VAIOT',
635
+ 'WAX': 'WAXP',
636
+ 'ALT': 'APTOSLAUNCHTOKEN',
637
+ 'KALT': 'ALT', # ALTLAYER
638
+ },
639
+ 'options': {
640
+ 'version': 'v1',
641
+ 'symbolSeparator': '-',
642
+ 'fetchMyTradesMethod': 'private_get_fills',
643
+ 'fetchCurrencies': {
644
+ 'webApiEnable': True, # fetches from WEB
645
+ 'webApiRetries': 1,
646
+ 'webApiMuteFailure': True,
647
+ },
648
+ 'fetchMarkets': {
649
+ 'fetchTickersFees': True,
650
+ },
651
+ 'withdraw': {
652
+ 'includeFee': False,
653
+ },
654
+ # endpoint versions
655
+ 'versions': {
656
+ 'public': {
657
+ 'GET': {
658
+ # spot trading
659
+ 'currencies': 'v3',
660
+ 'currencies/{currency}': 'v3',
661
+ 'symbols': 'v2',
662
+ },
663
+ },
664
+ 'private': {
665
+ 'GET': {
666
+ # account
667
+ 'user-info': 'v2',
668
+ 'hf/margin/account/ledgers': 'v3',
669
+ 'sub/user': 'v2',
670
+ 'sub-accounts': 'v2',
671
+ # funding
672
+ 'margin/accounts': 'v3',
673
+ 'isolated/accounts': 'v3',
674
+ # 'deposit-addresses': 'v2',
675
+ 'deposit-addresses': 'v1', # 'v1' for fetchDepositAddress, 'v2' for fetchDepositAddressesByNetwork
676
+ # spot trading
677
+ 'market/orderbook/level2': 'v3',
678
+ 'market/orderbook/level3': 'v3',
679
+ 'market/orderbook/level{level}': 'v3',
680
+ 'oco/order/{orderId}': 'v3',
681
+ 'oco/order/details/{orderId}': 'v3',
682
+ 'oco/client-order/{clientOid}': 'v3',
683
+ 'oco/orders': 'v3',
684
+ # margin trading
685
+ 'hf/margin/orders/active': 'v3',
686
+ 'hf/margin/orders/done': 'v3',
687
+ 'hf/margin/orders/{orderId}': 'v3',
688
+ 'hf/margin/orders/client-order/{clientOid}': 'v3',
689
+ 'hf/margin/fills': 'v3',
690
+ 'etf/info': 'v3',
691
+ 'margin/currencies': 'v3',
692
+ 'margin/borrow': 'v3',
693
+ 'margin/repay': 'v3',
694
+ 'margin/interest': 'v3',
695
+ 'project/list': 'v3',
696
+ 'project/marketInterestRate': 'v3',
697
+ 'redeem/orders': 'v3',
698
+ 'purchase/orders': 'v3',
699
+ },
700
+ 'POST': {
701
+ # account
702
+ 'sub/user/created': 'v2',
703
+ # funding
704
+ 'accounts/universal-transfer': 'v3',
705
+ 'accounts/sub-transfer': 'v2',
706
+ 'accounts/inner-transfer': 'v2',
707
+ 'transfer-out': 'v3',
708
+ # spot trading
709
+ 'oco/order': 'v3',
710
+ # margin trading
711
+ 'hf/margin/order': 'v3',
712
+ 'hf/margin/order/test': 'v3',
713
+ 'margin/borrow': 'v3',
714
+ 'margin/repay': 'v3',
715
+ 'purchase': 'v3',
716
+ 'redeem': 'v3',
717
+ 'lend/purchase/update': 'v3',
718
+ },
719
+ 'DELETE': {
720
+ # account
721
+ # funding
722
+ # spot trading
723
+ 'hf/margin/orders/{orderId}': 'v3',
724
+ 'hf/margin/orders/client-order/{clientOid}': 'v3',
725
+ 'hf/margin/orders': 'v3',
726
+ 'oco/order/{orderId}': 'v3',
727
+ 'oco/client-order/{clientOid}': 'v3',
728
+ 'oco/orders': 'v3',
729
+ # margin trading
730
+ },
731
+ },
732
+ 'futuresPrivate': {
733
+ 'POST': {
734
+ 'transfer-out': 'v3',
735
+ },
736
+ },
737
+ },
738
+ 'partner': {
739
+ # the support for spot and future exchanges settings
740
+ 'spot': {
741
+ 'id': 'ccxt',
742
+ 'key': '9e58cc35-5b5e-4133-92ec-166e3f077cb8',
743
+ },
744
+ 'future': {
745
+ 'id': 'ccxtfutures',
746
+ 'key': '1b327198-f30c-4f14-a0ac-918871282f15',
747
+ },
748
+ # exchange-wide settings are also supported
749
+ # 'id': 'ccxt'
750
+ # 'key': '9e58cc35-5b5e-4133-92ec-166e3f077cb8',
751
+ },
752
+ 'accountsByType': {
753
+ 'spot': 'trade',
754
+ 'margin': 'margin',
755
+ 'cross': 'margin',
756
+ 'isolated': 'isolated',
757
+ 'main': 'main',
758
+ 'funding': 'main',
759
+ 'future': 'contract',
760
+ 'swap': 'contract',
761
+ 'mining': 'pool',
762
+ 'hf': 'trade_hf',
763
+ },
764
+ 'networks': {
765
+ 'BTC': 'btc',
766
+ 'BTCNATIVESEGWIT': 'bech32',
767
+ 'ERC20': 'eth',
768
+ 'TRC20': 'trx',
769
+ 'HRC20': 'heco',
770
+ 'MATIC': 'matic',
771
+ 'KCC': 'kcc', # kucoin community chain
772
+ 'SOL': 'sol',
773
+ 'ALGO': 'algo',
774
+ 'EOS': 'eos',
775
+ 'BEP20': 'bsc',
776
+ 'BEP2': 'bnb',
777
+ 'ARBONE': 'arbitrum',
778
+ 'AVAXX': 'avax',
779
+ 'AVAXC': 'avaxc',
780
+ 'TLOS': 'tlos', # tlosevm is different
781
+ 'CFX': 'cfx',
782
+ 'ACA': 'aca',
783
+ 'OPTIMISM': 'optimism',
784
+ 'ONT': 'ont',
785
+ 'GLMR': 'glmr',
786
+ 'CSPR': 'cspr',
787
+ 'KLAY': 'klay',
788
+ 'XRD': 'xrd',
789
+ 'RVN': 'rvn',
790
+ 'NEAR': 'near',
791
+ 'APT': 'aptos',
792
+ 'ETHW': 'ethw',
793
+ 'TON': 'ton',
794
+ 'BCH': 'bch',
795
+ 'BSV': 'bchsv',
796
+ 'BCHA': 'bchabc',
797
+ 'OSMO': 'osmo',
798
+ 'NANO': 'nano',
799
+ 'XLM': 'xlm',
800
+ 'VET': 'vet',
801
+ 'IOST': 'iost',
802
+ 'ZIL': 'zil',
803
+ 'XRP': 'xrp',
804
+ 'TOMO': 'tomo',
805
+ 'XMR': 'xmr',
806
+ 'COTI': 'coti',
807
+ 'XTZ': 'xtz',
808
+ 'ADA': 'ada',
809
+ 'WAX': 'waxp',
810
+ 'THETA': 'theta',
811
+ 'ONE': 'one',
812
+ 'IOTEX': 'iotx',
813
+ 'NULS': 'nuls',
814
+ 'KSM': 'ksm',
815
+ 'LTC': 'ltc',
816
+ 'WAVES': 'waves',
817
+ 'DOT': 'dot',
818
+ 'STEEM': 'steem',
819
+ 'QTUM': 'qtum',
820
+ 'DOGE': 'doge',
821
+ 'FIL': 'fil',
822
+ 'XYM': 'xym',
823
+ 'FLUX': 'flux',
824
+ 'ATOM': 'atom',
825
+ 'XDC': 'xdc',
826
+ 'KDA': 'kda',
827
+ 'ICP': 'icp',
828
+ 'CELO': 'celo',
829
+ 'LSK': 'lsk',
830
+ 'VSYS': 'vsys',
831
+ 'KAR': 'kar',
832
+ 'XCH': 'xch',
833
+ 'FLOW': 'flow',
834
+ 'BAND': 'band',
835
+ 'EGLD': 'egld',
836
+ 'HBAR': 'hbar',
837
+ 'XPR': 'xpr',
838
+ 'AR': 'ar',
839
+ 'FTM': 'ftm',
840
+ 'KAVA': 'kava',
841
+ 'KMA': 'kma',
842
+ 'XEC': 'xec',
843
+ 'IOTA': 'iota',
844
+ 'HNT': 'hnt',
845
+ 'ASTR': 'astr',
846
+ 'PDEX': 'pdex',
847
+ 'METIS': 'metis',
848
+ 'ZEC': 'zec',
849
+ 'POKT': 'pokt',
850
+ 'OASYS': 'oas',
851
+ 'OASIS': 'oasis', # a.k.a. ROSE
852
+ 'ETC': 'etc',
853
+ 'AKT': 'akt',
854
+ 'FSN': 'fsn',
855
+ 'SCRT': 'scrt',
856
+ 'CFG': 'cfg',
857
+ 'ICX': 'icx',
858
+ 'KMD': 'kmd',
859
+ 'NEM': 'NEM',
860
+ 'STX': 'stx',
861
+ 'DGB': 'dgb',
862
+ 'DCR': 'dcr',
863
+ 'CKB': 'ckb', # ckb2 is just odd entry
864
+ 'ELA': 'ela', # esc might be another chain elastos smart chain
865
+ 'HYDRA': 'hydra',
866
+ 'BTM': 'btm',
867
+ 'KARDIA': 'kai',
868
+ 'SXP': 'sxp', # a.k.a. solar swipe
869
+ 'NEBL': 'nebl',
870
+ 'ZEN': 'zen',
871
+ 'SDN': 'sdn',
872
+ 'LTO': 'lto',
873
+ 'WEMIX': 'wemix',
874
+ # 'BOBA': 'boba', # tbd
875
+ 'EVER': 'ever',
876
+ 'BNC': 'bnc',
877
+ 'BNCDOT': 'bncdot',
878
+ # 'CMP': 'cmp', # todo: after consensus
879
+ 'AION': 'aion',
880
+ 'GRIN': 'grin',
881
+ 'LOKI': 'loki',
882
+ 'QKC': 'qkc',
883
+ 'TT': 'TT',
884
+ 'PIVX': 'pivx',
885
+ 'SERO': 'sero',
886
+ 'METER': 'meter',
887
+ 'STATEMINE': 'statemine', # a.k.a. RMRK
888
+ 'DVPN': 'dvpn',
889
+ 'XPRT': 'xprt',
890
+ 'MOVR': 'movr',
891
+ 'ERGO': 'ergo',
892
+ 'ABBC': 'abbc',
893
+ 'DIVI': 'divi',
894
+ 'PURA': 'pura',
895
+ 'DFI': 'dfi',
896
+ # 'NEO': 'neo', # tbd neo legacy
897
+ 'NEON3': 'neon3',
898
+ 'DOCK': 'dock',
899
+ 'TRUE': 'true',
900
+ 'CS': 'cs',
901
+ 'ORAI': 'orai',
902
+ # below will be uncommented after consensus
903
+ # 'BITCOINDIAMON': 'bcd',
904
+ # 'BITCOINGOLD': 'btg',
905
+ # 'HTR': 'htr',
906
+ # 'DEROHE': 'derohe',
907
+ # 'NDAU': 'ndau',
908
+ # 'HPB': 'hpb',
909
+ # 'AXE': 'axe',
910
+ # 'BITCOINPRIVATE': 'btcp',
911
+ # 'EDGEWARE': 'edg',
912
+ # 'JUPITER': 'jup',
913
+ # 'VELAS': 'vlx', # vlxevm is different
914
+ # # 'terra' luna lunc TBD
915
+ # 'DIGITALBITS': 'xdb',
916
+ # # fra is fra-emv on kucoin
917
+ # 'PASTEL': 'psl',
918
+ # # sysevm
919
+ # 'CONCORDIUM': 'ccd',
920
+ # 'AURORA': 'aurora',
921
+ # 'PHA': 'pha', # a.k.a. khala
922
+ # 'PAL': 'pal',
923
+ # 'RSK': 'rbtc',
924
+ # 'NIX': 'nix',
925
+ # 'NIM': 'nim',
926
+ # 'NRG': 'nrg',
927
+ # 'RFOX': 'rfox',
928
+ # 'PIONEER': 'neer',
929
+ # 'PIXIE': 'pix',
930
+ # 'ALEPHZERO': 'azero',
931
+ # 'ACHAIN': 'act', # actevm is different
932
+ # 'BOSCOIN': 'bos',
933
+ # 'ELECTRONEUM': 'etn',
934
+ # 'GOCHAIN': 'go',
935
+ # 'SOPHIATX': 'sphtx',
936
+ # 'WANCHAIN': 'wan',
937
+ # 'ZEEPIN': 'zpt',
938
+ # 'MATRIXAI': 'man',
939
+ # 'METADIUM': 'meta',
940
+ # 'METAHASH': 'mhc',
941
+ # # eosc --"eosforce" tbd
942
+ # 'IOTCHAIN': 'itc',
943
+ # 'CONTENTOS': 'cos',
944
+ # 'CPCHAIN': 'cpc',
945
+ # 'INTCHAIN': 'int',
946
+ # # 'DASH': 'dash', tbd digita-cash
947
+ # 'WALTONCHAIN': 'wtc',
948
+ # 'CONSTELLATION': 'dag',
949
+ # 'ONELEDGER': 'olt',
950
+ # 'AIRDAO': 'amb', # a.k.a. AMBROSUS
951
+ # 'ENERGYWEB': 'ewt',
952
+ # 'WAVESENTERPRISE': 'west',
953
+ # 'HYPERCASH': 'hc',
954
+ # 'ENECUUM': 'enq',
955
+ # 'HAVEN': 'xhv',
956
+ # 'CHAINX': 'pcx',
957
+ # # 'FLUXOLD': 'zel', # zel seems old chain(with uppercase FLUX in kucoin UI and with id 'zel')
958
+ # 'BUMO': 'bu',
959
+ # 'DEEPONION': 'onion',
960
+ # 'ULORD': 'ut',
961
+ # 'ASCH': 'xas',
962
+ # 'SOLARIS': 'xlr',
963
+ # 'APOLLO': 'apl',
964
+ # 'PIRATECHAIN': 'arrr',
965
+ # 'ULTRA': 'uos',
966
+ # 'EMONEY': 'ngm',
967
+ # 'AURORACHAIN': 'aoa',
968
+ # 'KLEVER': 'klv',
969
+ # undetermined: xns(insolar), rhoc, luk(luniverse), kts(klimatas), bchn(bitcoin cash node), god(shallow entry), lit(litmus),
970
+ },
971
+ 'marginModes': {
972
+ 'cross': 'MARGIN_TRADE',
973
+ 'isolated': 'MARGIN_ISOLATED_TRADE',
974
+ 'spot': 'TRADE',
975
+ },
976
+ },
977
+ })
978
+
979
+ def nonce(self):
980
+ return self.milliseconds()
981
+
982
+ async def fetch_time(self, params={}):
983
+ """
984
+ fetches the current integer timestamp in milliseconds from the exchange server
985
+ :see: https://docs.kucoin.com/#server-time
986
+ :param dict [params]: extra parameters specific to the exchange API endpoint
987
+ :returns int: the current integer timestamp in milliseconds from the exchange server
988
+ """
989
+ response = await self.publicGetTimestamp(params)
990
+ #
991
+ # {
992
+ # "code":"200000",
993
+ # "msg":"success",
994
+ # "data":1546837113087
995
+ # }
996
+ #
997
+ return self.safe_integer(response, 'data')
998
+
999
+ async def fetch_status(self, params={}):
1000
+ """
1001
+ the latest known information on the availability of the exchange API
1002
+ :see: https://docs.kucoin.com/#service-status
1003
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1004
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
1005
+ """
1006
+ response = await self.publicGetStatus(params)
1007
+ #
1008
+ # {
1009
+ # "code":"200000",
1010
+ # "data":{
1011
+ # "status":"open", #open, close, cancelonly
1012
+ # "msg":"upgrade match engine" #remark for operation
1013
+ # }
1014
+ # }
1015
+ #
1016
+ data = self.safe_dict(response, 'data', {})
1017
+ status = self.safe_string(data, 'status')
1018
+ return {
1019
+ 'status': 'ok' if (status == 'open') else 'maintenance',
1020
+ 'updated': None,
1021
+ 'eta': None,
1022
+ 'url': None,
1023
+ 'info': response,
1024
+ }
1025
+
1026
+ async def fetch_markets(self, params={}) -> List[Market]:
1027
+ """
1028
+ retrieves data on all markets for kucoin
1029
+ :see: https://docs.kucoin.com/#get-symbols-list-deprecated
1030
+ :see: https://docs.kucoin.com/#get-all-tickers
1031
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1032
+ :returns dict[]: an array of objects representing market data
1033
+ """
1034
+ response = await self.publicGetSymbols(params)
1035
+ #
1036
+ # {
1037
+ # "code": "200000",
1038
+ # "data": [
1039
+ # {
1040
+ # "symbol": "XLM-USDT",
1041
+ # "name": "XLM-USDT",
1042
+ # "baseCurrency": "XLM",
1043
+ # "quoteCurrency": "USDT",
1044
+ # "feeCurrency": "USDT",
1045
+ # "market": "USDS",
1046
+ # "baseMinSize": "0.1",
1047
+ # "quoteMinSize": "0.01",
1048
+ # "baseMaxSize": "10000000000",
1049
+ # "quoteMaxSize": "99999999",
1050
+ # "baseIncrement": "0.0001",
1051
+ # "quoteIncrement": "0.000001",
1052
+ # "priceIncrement": "0.000001",
1053
+ # "priceLimitRate": "0.1",
1054
+ # "isMarginEnabled": True,
1055
+ # "enableTrading": True
1056
+ # },
1057
+ # ]
1058
+ # }
1059
+ #
1060
+ data = self.safe_list(response, 'data')
1061
+ options = self.safe_dict(self.options, 'fetchMarkets', {})
1062
+ fetchTickersFees = self.safe_bool(options, 'fetchTickersFees', True)
1063
+ tickersResponse: dict = {}
1064
+ if fetchTickersFees:
1065
+ tickersResponse = await self.publicGetMarketAllTickers(params)
1066
+ #
1067
+ # {
1068
+ # "code": "200000",
1069
+ # "data": {
1070
+ # "time":1602832092060,
1071
+ # "ticker":[
1072
+ # {
1073
+ # "symbol": "BTC-USDT", # symbol
1074
+ # "symbolName":"BTC-USDT", # Name of trading pairs, it would change after renaming
1075
+ # "buy": "11328.9", # bestAsk
1076
+ # "sell": "11329", # bestBid
1077
+ # "changeRate": "-0.0055", # 24h change rate
1078
+ # "changePrice": "-63.6", # 24h change price
1079
+ # "high": "11610", # 24h highest price
1080
+ # "low": "11200", # 24h lowest price
1081
+ # "vol": "2282.70993217", # 24h volume,the aggregated trading volume in BTC
1082
+ # "volValue": "25984946.157790431", # 24h total, the trading volume in quote currency of last 24 hours
1083
+ # "last": "11328.9", # last price
1084
+ # "averagePrice": "11360.66065903", # 24h average transaction price yesterday
1085
+ # "takerFeeRate": "0.001", # Basic Taker Fee
1086
+ # "makerFeeRate": "0.001", # Basic Maker Fee
1087
+ # "takerCoefficient": "1", # Taker Fee Coefficient
1088
+ # "makerCoefficient": "1" # Maker Fee Coefficient
1089
+ # }
1090
+ # ]
1091
+ # }
1092
+ # }
1093
+ #
1094
+ tickersData = self.safe_dict(tickersResponse, 'data', {})
1095
+ tickers = self.safe_list(tickersData, 'ticker', [])
1096
+ tickersByMarketId = self.index_by(tickers, 'symbol')
1097
+ result = []
1098
+ for i in range(0, len(data)):
1099
+ market = data[i]
1100
+ id = self.safe_string(market, 'symbol')
1101
+ baseId, quoteId = id.split('-')
1102
+ base = self.safe_currency_code(baseId)
1103
+ quote = self.safe_currency_code(quoteId)
1104
+ # quoteIncrement = self.safe_number(market, 'quoteIncrement')
1105
+ ticker = self.safe_dict(tickersByMarketId, id, {})
1106
+ makerFeeRate = self.safe_string(ticker, 'makerFeeRate')
1107
+ takerFeeRate = self.safe_string(ticker, 'takerFeeRate')
1108
+ makerCoefficient = self.safe_string(ticker, 'makerCoefficient')
1109
+ takerCoefficient = self.safe_string(ticker, 'takerCoefficient')
1110
+ result.append({
1111
+ 'id': id,
1112
+ 'symbol': base + '/' + quote,
1113
+ 'base': base,
1114
+ 'quote': quote,
1115
+ 'settle': None,
1116
+ 'baseId': baseId,
1117
+ 'quoteId': quoteId,
1118
+ 'settleId': None,
1119
+ 'type': 'spot',
1120
+ 'spot': True,
1121
+ 'margin': self.safe_bool(market, 'isMarginEnabled'),
1122
+ 'swap': False,
1123
+ 'future': False,
1124
+ 'option': False,
1125
+ 'active': self.safe_bool(market, 'enableTrading'),
1126
+ 'contract': False,
1127
+ 'linear': None,
1128
+ 'inverse': None,
1129
+ 'taker': self.parse_number(Precise.string_mul(takerFeeRate, takerCoefficient)),
1130
+ 'maker': self.parse_number(Precise.string_mul(makerFeeRate, makerCoefficient)),
1131
+ 'contractSize': None,
1132
+ 'expiry': None,
1133
+ 'expiryDatetime': None,
1134
+ 'strike': None,
1135
+ 'optionType': None,
1136
+ 'precision': {
1137
+ 'amount': self.safe_number(market, 'baseIncrement'),
1138
+ 'price': self.safe_number(market, 'priceIncrement'),
1139
+ },
1140
+ 'limits': {
1141
+ 'leverage': {
1142
+ 'min': None,
1143
+ 'max': None,
1144
+ },
1145
+ 'amount': {
1146
+ 'min': self.safe_number(market, 'baseMinSize'),
1147
+ 'max': self.safe_number(market, 'baseMaxSize'),
1148
+ },
1149
+ 'price': {
1150
+ 'min': None,
1151
+ 'max': None,
1152
+ },
1153
+ 'cost': {
1154
+ 'min': self.safe_number(market, 'quoteMinSize'),
1155
+ 'max': self.safe_number(market, 'quoteMaxSize'),
1156
+ },
1157
+ },
1158
+ 'created': None,
1159
+ 'info': market,
1160
+ })
1161
+ return result
1162
+
1163
+ async def fetch_currencies(self, params={}) -> Currencies:
1164
+ """
1165
+ fetches all available currencies on an exchange
1166
+ :see: https://docs.kucoin.com/#get-currencies
1167
+ :param dict params: extra parameters specific to the exchange API endpoint
1168
+ :returns dict: an associative dictionary of currencies
1169
+ """
1170
+ promises = []
1171
+ promises.append(self.publicGetCurrencies(params))
1172
+ #
1173
+ # {
1174
+ # "code":"200000",
1175
+ # "data":[
1176
+ # {
1177
+ # "currency":"CSP",
1178
+ # "name":"CSP",
1179
+ # "fullName":"Caspian",
1180
+ # "precision":8,
1181
+ # "confirms":null,
1182
+ # "contractAddress":null,
1183
+ # "isMarginEnabled":false,
1184
+ # "isDebitEnabled":false,
1185
+ # "chains":[
1186
+ # {
1187
+ # "chainName":"ERC20",
1188
+ # "chainId": "eth"
1189
+ # "withdrawalMinSize":"2999",
1190
+ # "depositMinSize":null,
1191
+ # "withdrawFeeRate":"0",
1192
+ # "withdrawalMinFee":"2999",
1193
+ # "isWithdrawEnabled":false,
1194
+ # "isDepositEnabled":false,
1195
+ # "confirms":12,
1196
+ # "preConfirms":12,
1197
+ # "contractAddress":"0xa6446d655a0c34bc4f05042ee88170d056cbaf45",
1198
+ # "depositFeeRate": "0.001", # present for some currencies/networks
1199
+ # }
1200
+ # ]
1201
+ # },
1202
+ # }
1203
+ #
1204
+ promises.append(self.fetch_web_endpoint('fetchCurrencies', 'webExchangeGetCurrencyCurrencyChainInfo', True))
1205
+ #
1206
+ # {
1207
+ # "success": True,
1208
+ # "code": "200",
1209
+ # "msg": "success",
1210
+ # "retry": False,
1211
+ # "data": [
1212
+ # {
1213
+ # "status": "enabled",
1214
+ # "currency": "BTC",
1215
+ # "isChainEnabled": "true",
1216
+ # "chain": "btc",
1217
+ # "chainName": "BTC",
1218
+ # "chainFullName": "Bitcoin",
1219
+ # "walletPrecision": "8",
1220
+ # "isDepositEnabled": "true",
1221
+ # "depositMinSize": "0.00005",
1222
+ # "confirmationCount": "2",
1223
+ # "isWithdrawEnabled": "true",
1224
+ # "withdrawMinSize": "0.001",
1225
+ # "withdrawMinFee": "0.0005",
1226
+ # "withdrawFeeRate": "0",
1227
+ # "depositDisabledTip": "Wallet Maintenance",
1228
+ # "preDepositTipEnabled": "true",
1229
+ # "preDepositTip": "Do not transfer from ETH network directly",
1230
+ # "withdrawDisabledTip": "",
1231
+ # "preWithdrawTipEnabled": "false",
1232
+ # "preWithdrawTip": "",
1233
+ # "orgAddress": "",
1234
+ # "userAddressName": "Memo",
1235
+ # },
1236
+ # ]
1237
+ # }
1238
+ #
1239
+ responses = await asyncio.gather(*promises)
1240
+ currenciesResponse = self.safe_dict(responses, 0, {})
1241
+ currenciesData = self.safe_list(currenciesResponse, 'data', [])
1242
+ additionalResponse = self.safe_dict(responses, 1, {})
1243
+ additionalData = self.safe_list(additionalResponse, 'data', [])
1244
+ additionalDataGrouped = self.group_by(additionalData, 'currency')
1245
+ result: dict = {}
1246
+ for i in range(0, len(currenciesData)):
1247
+ entry = currenciesData[i]
1248
+ id = self.safe_string(entry, 'currency')
1249
+ name = self.safe_string(entry, 'fullName')
1250
+ code = self.safe_currency_code(id)
1251
+ isWithdrawEnabled = None
1252
+ isDepositEnabled = None
1253
+ networks: dict = {}
1254
+ chains = self.safe_list(entry, 'chains', [])
1255
+ extraChainsData = self.index_by(self.safe_list(additionalDataGrouped, id, []), 'chain')
1256
+ rawPrecision = self.safe_string(entry, 'precision')
1257
+ precision = self.parse_number(self.parse_precision(rawPrecision))
1258
+ chainsLength = len(chains)
1259
+ if not chainsLength:
1260
+ # https://t.me/KuCoin_API/173118
1261
+ isWithdrawEnabled = False
1262
+ isDepositEnabled = False
1263
+ for j in range(0, chainsLength):
1264
+ chain = chains[j]
1265
+ chainId = self.safe_string(chain, 'chainId')
1266
+ networkCode = self.network_id_to_code(chainId)
1267
+ chainWithdrawEnabled = self.safe_bool(chain, 'isWithdrawEnabled', False)
1268
+ if isWithdrawEnabled is None:
1269
+ isWithdrawEnabled = chainWithdrawEnabled
1270
+ else:
1271
+ isWithdrawEnabled = isWithdrawEnabled or chainWithdrawEnabled
1272
+ chainDepositEnabled = self.safe_bool(chain, 'isDepositEnabled', False)
1273
+ if isDepositEnabled is None:
1274
+ isDepositEnabled = chainDepositEnabled
1275
+ else:
1276
+ isDepositEnabled = isDepositEnabled or chainDepositEnabled
1277
+ chainExtraData = self.safe_dict(extraChainsData, chainId, {})
1278
+ networks[networkCode] = {
1279
+ 'info': chain,
1280
+ 'id': chainId,
1281
+ 'name': self.safe_string(chain, 'chainName'),
1282
+ 'code': networkCode,
1283
+ 'active': chainWithdrawEnabled and chainDepositEnabled,
1284
+ 'fee': self.safe_number(chain, 'withdrawalMinFee'),
1285
+ 'deposit': chainDepositEnabled,
1286
+ 'withdraw': chainWithdrawEnabled,
1287
+ 'precision': self.parse_number(self.parse_precision(self.safe_string(chainExtraData, 'walletPrecision'))),
1288
+ 'limits': {
1289
+ 'withdraw': {
1290
+ 'min': self.safe_number(chain, 'withdrawalMinSize'),
1291
+ 'max': None,
1292
+ },
1293
+ 'deposit': {
1294
+ 'min': self.safe_number(chain, 'depositMinSize'),
1295
+ 'max': None,
1296
+ },
1297
+ },
1298
+ }
1299
+ # kucoin has determined 'fiat' currencies with below logic
1300
+ isFiat = (rawPrecision == '2') and (chainsLength == 0)
1301
+ result[code] = {
1302
+ 'id': id,
1303
+ 'name': name,
1304
+ 'code': code,
1305
+ 'type': 'fiat' if isFiat else 'crypto',
1306
+ 'precision': precision,
1307
+ 'info': entry,
1308
+ 'active': (isDepositEnabled or isWithdrawEnabled),
1309
+ 'deposit': isDepositEnabled,
1310
+ 'withdraw': isWithdrawEnabled,
1311
+ 'fee': None,
1312
+ 'limits': self.limits,
1313
+ 'networks': networks,
1314
+ }
1315
+ return result
1316
+
1317
+ async def fetch_accounts(self, params={}) -> List[Account]:
1318
+ """
1319
+ fetch all the accounts associated with a profile
1320
+ :see: https://docs.kucoin.com/#list-accounts
1321
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1322
+ :returns dict: a dictionary of `account structures <https://docs.ccxt.com/#/?id=account-structure>` indexed by the account type
1323
+ """
1324
+ response = await self.privateGetAccounts(params)
1325
+ #
1326
+ # {
1327
+ # "code": "200000",
1328
+ # "data": [
1329
+ # {
1330
+ # "balance": "0.00009788",
1331
+ # "available": "0.00009788",
1332
+ # "holds": "0",
1333
+ # "currency": "BTC",
1334
+ # "id": "5c6a4fd399a1d81c4f9cc4d0",
1335
+ # "type": "trade"
1336
+ # },
1337
+ # {
1338
+ # "balance": "0.00000001",
1339
+ # "available": "0.00000001",
1340
+ # "holds": "0",
1341
+ # "currency": "ETH",
1342
+ # "id": "5c6a49ec99a1d819392e8e9f",
1343
+ # "type": "trade"
1344
+ # }
1345
+ # ]
1346
+ # }
1347
+ #
1348
+ data = self.safe_list(response, 'data', [])
1349
+ result = []
1350
+ for i in range(0, len(data)):
1351
+ account = data[i]
1352
+ accountId = self.safe_string(account, 'id')
1353
+ currencyId = self.safe_string(account, 'currency')
1354
+ code = self.safe_currency_code(currencyId)
1355
+ type = self.safe_string(account, 'type') # main or trade
1356
+ result.append({
1357
+ 'id': accountId,
1358
+ 'type': type,
1359
+ 'currency': code,
1360
+ 'code': code,
1361
+ 'info': account,
1362
+ })
1363
+ return result
1364
+
1365
+ async def fetch_transaction_fee(self, code: str, params={}):
1366
+ """
1367
+ *DEPRECATED* please use fetchDepositWithdrawFee instead
1368
+ :see: https://docs.kucoin.com/#get-withdrawal-quotas
1369
+ :param str code: unified currency code
1370
+ :param dict params: extra parameters specific to the exchange API endpoint
1371
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
1372
+ """
1373
+ await self.load_markets()
1374
+ currency = self.currency(code)
1375
+ request: dict = {
1376
+ 'currency': currency['id'],
1377
+ }
1378
+ networkCode = None
1379
+ networkCode, params = self.handle_network_code_and_params(params)
1380
+ if networkCode is not None:
1381
+ request['chain'] = self.network_code_to_id(networkCode).lower()
1382
+ response = await self.privateGetWithdrawalsQuotas(self.extend(request, params))
1383
+ data = self.safe_dict(response, 'data', {})
1384
+ withdrawFees: dict = {}
1385
+ withdrawFees[code] = self.safe_number(data, 'withdrawMinFee')
1386
+ return {
1387
+ 'info': response,
1388
+ 'withdraw': withdrawFees,
1389
+ 'deposit': {},
1390
+ }
1391
+
1392
+ async def fetch_deposit_withdraw_fee(self, code: str, params={}):
1393
+ """
1394
+ fetch the fee for deposits and withdrawals
1395
+ :see: https://docs.kucoin.com/#get-withdrawal-quotas
1396
+ :param str code: unified currency code
1397
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1398
+ :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
1399
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
1400
+ """
1401
+ await self.load_markets()
1402
+ currency = self.currency(code)
1403
+ request: dict = {
1404
+ 'currency': currency['id'],
1405
+ }
1406
+ networkCode = None
1407
+ networkCode, params = self.handle_network_code_and_params(params)
1408
+ if networkCode is not None:
1409
+ request['chain'] = self.network_code_to_id(networkCode).lower()
1410
+ response = await self.privateGetWithdrawalsQuotas(self.extend(request, params))
1411
+ #
1412
+ # {
1413
+ # "code": "200000",
1414
+ # "data": {
1415
+ # "currency": "USDT",
1416
+ # "limitBTCAmount": "1.00000000",
1417
+ # "usedBTCAmount": "0.00000000",
1418
+ # "remainAmount": "16548.072149",
1419
+ # "availableAmount": "0",
1420
+ # "withdrawMinFee": "25",
1421
+ # "innerWithdrawMinFee": "0",
1422
+ # "withdrawMinSize": "50",
1423
+ # "isWithdrawEnabled": True,
1424
+ # "precision": 6,
1425
+ # "chain": "ERC20"
1426
+ # }
1427
+ # }
1428
+ #
1429
+ data = self.safe_dict(response, 'data')
1430
+ return self.parse_deposit_withdraw_fee(data, currency)
1431
+
1432
+ def parse_deposit_withdraw_fee(self, fee, currency: Currency = None):
1433
+ #
1434
+ # {
1435
+ # "currency": "USDT",
1436
+ # "limitBTCAmount": "1.00000000",
1437
+ # "usedBTCAmount": "0.00000000",
1438
+ # "remainAmount": "16548.072149",
1439
+ # "availableAmount": "0",
1440
+ # "withdrawMinFee": "25",
1441
+ # "innerWithdrawMinFee": "0",
1442
+ # "withdrawMinSize": "50",
1443
+ # "isWithdrawEnabled": True,
1444
+ # "precision": 6,
1445
+ # "chain": "ERC20"
1446
+ # }
1447
+ #
1448
+ result: dict = {
1449
+ 'info': fee,
1450
+ 'withdraw': {
1451
+ 'fee': None,
1452
+ 'percentage': None,
1453
+ },
1454
+ 'deposit': {
1455
+ 'fee': None,
1456
+ 'percentage': None,
1457
+ },
1458
+ 'networks': {},
1459
+ }
1460
+ isWithdrawEnabled = self.safe_bool(fee, 'isWithdrawEnabled')
1461
+ if isWithdrawEnabled:
1462
+ result['withdraw']['fee'] = self.safe_number_2(fee, 'withdrawalMinFee', 'withdrawMinFee')
1463
+ result['withdraw']['percentage'] = False
1464
+ networkId = self.safe_string(fee, 'chain')
1465
+ if networkId:
1466
+ networkCode = self.network_id_to_code(networkId, self.safe_string(currency, 'code'))
1467
+ result['networks'][networkCode] = {
1468
+ 'withdraw': result['withdraw'],
1469
+ 'deposit': {
1470
+ 'fee': None,
1471
+ 'percentage': None,
1472
+ },
1473
+ }
1474
+ return result
1475
+
1476
+ def is_futures_method(self, methodName, params):
1477
+ #
1478
+ # Helper
1479
+ # @methodName(string): The name of the method
1480
+ # @params(dict): The parameters passed into {methodName}
1481
+ # @return: True if the method used is meant for futures trading, False otherwise
1482
+ #
1483
+ defaultType = self.safe_string_2(self.options, methodName, 'defaultType', 'trade')
1484
+ requestedType = self.safe_string(params, 'type', defaultType)
1485
+ accountsByType = self.safe_dict(self.options, 'accountsByType')
1486
+ type = self.safe_string(accountsByType, requestedType)
1487
+ if type is None:
1488
+ keys = list(accountsByType.keys())
1489
+ raise ExchangeError(self.id + ' isFuturesMethod() type must be one of ' + ', '.join(keys))
1490
+ params = self.omit(params, 'type')
1491
+ return(type == 'contract') or (type == 'future') or (type == 'futures') # * (type == 'futures') deprecated, use(type == 'future')
1492
+
1493
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1494
+ #
1495
+ # {
1496
+ # "symbol": "BTC-USDT", # symbol
1497
+ # "symbolName":"BTC-USDT", # Name of trading pairs, it would change after renaming
1498
+ # "buy": "11328.9", # bestAsk
1499
+ # "sell": "11329", # bestBid
1500
+ # "changeRate": "-0.0055", # 24h change rate
1501
+ # "changePrice": "-63.6", # 24h change price
1502
+ # "high": "11610", # 24h highest price
1503
+ # "low": "11200", # 24h lowest price
1504
+ # "vol": "2282.70993217", # 24h volume,the aggregated trading volume in BTC
1505
+ # "volValue": "25984946.157790431", # 24h total, the trading volume in quote currency of last 24 hours
1506
+ # "last": "11328.9", # last price
1507
+ # "averagePrice": "11360.66065903", # 24h average transaction price yesterday
1508
+ # "takerFeeRate": "0.001", # Basic Taker Fee
1509
+ # "makerFeeRate": "0.001", # Basic Maker Fee
1510
+ # "takerCoefficient": "1", # Taker Fee Coefficient
1511
+ # "makerCoefficient": "1" # Maker Fee Coefficient
1512
+ # }
1513
+ #
1514
+ # {
1515
+ # "trading": True,
1516
+ # "symbol": "KCS-BTC",
1517
+ # "buy": 0.00011,
1518
+ # "sell": 0.00012,
1519
+ # "sort": 100,
1520
+ # "volValue": 3.13851792584, #total
1521
+ # "baseCurrency": "KCS",
1522
+ # "market": "BTC",
1523
+ # "quoteCurrency": "BTC",
1524
+ # "symbolCode": "KCS-BTC",
1525
+ # "datetime": 1548388122031,
1526
+ # "high": 0.00013,
1527
+ # "vol": 27514.34842,
1528
+ # "low": 0.0001,
1529
+ # "changePrice": -1.0e-5,
1530
+ # "changeRate": -0.0769,
1531
+ # "lastTradedPrice": 0.00012,
1532
+ # "board": 0,
1533
+ # "mark": 0
1534
+ # }
1535
+ #
1536
+ # market/ticker ws subscription
1537
+ #
1538
+ # {
1539
+ # "bestAsk": "62258.9",
1540
+ # "bestAskSize": "0.38579986",
1541
+ # "bestBid": "62258.8",
1542
+ # "bestBidSize": "0.0078381",
1543
+ # "price": "62260.7",
1544
+ # "sequence": "1621383297064",
1545
+ # "size": "0.00002841",
1546
+ # "time": 1634641777363
1547
+ # }
1548
+ #
1549
+ percentage = self.safe_string(ticker, 'changeRate')
1550
+ if percentage is not None:
1551
+ percentage = Precise.string_mul(percentage, '100')
1552
+ last = self.safe_string_2(ticker, 'last', 'lastTradedPrice')
1553
+ last = self.safe_string(ticker, 'price', last)
1554
+ marketId = self.safe_string(ticker, 'symbol')
1555
+ market = self.safe_market(marketId, market, '-')
1556
+ symbol = market['symbol']
1557
+ baseVolume = self.safe_string(ticker, 'vol')
1558
+ quoteVolume = self.safe_string(ticker, 'volValue')
1559
+ timestamp = self.safe_integer_2(ticker, 'time', 'datetime')
1560
+ return self.safe_ticker({
1561
+ 'symbol': symbol,
1562
+ 'timestamp': timestamp,
1563
+ 'datetime': self.iso8601(timestamp),
1564
+ 'high': self.safe_string(ticker, 'high'),
1565
+ 'low': self.safe_string(ticker, 'low'),
1566
+ 'bid': self.safe_string_2(ticker, 'buy', 'bestBid'),
1567
+ 'bidVolume': self.safe_string(ticker, 'bestBidSize'),
1568
+ 'ask': self.safe_string_2(ticker, 'sell', 'bestAsk'),
1569
+ 'askVolume': self.safe_string(ticker, 'bestAskSize'),
1570
+ 'vwap': None,
1571
+ 'open': self.safe_string(ticker, 'open'),
1572
+ 'close': last,
1573
+ 'last': last,
1574
+ 'previousClose': None,
1575
+ 'change': self.safe_string(ticker, 'changePrice'),
1576
+ 'percentage': percentage,
1577
+ 'average': self.safe_string(ticker, 'averagePrice'),
1578
+ 'baseVolume': baseVolume,
1579
+ 'quoteVolume': quoteVolume,
1580
+ 'info': ticker,
1581
+ }, market)
1582
+
1583
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1584
+ """
1585
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1586
+ :see: https://docs.kucoin.com/#get-all-tickers
1587
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1588
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1589
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1590
+ """
1591
+ await self.load_markets()
1592
+ symbols = self.market_symbols(symbols)
1593
+ response = await self.publicGetMarketAllTickers(params)
1594
+ #
1595
+ # {
1596
+ # "code": "200000",
1597
+ # "data": {
1598
+ # "time":1602832092060,
1599
+ # "ticker":[
1600
+ # {
1601
+ # "symbol": "BTC-USDT", # symbol
1602
+ # "symbolName":"BTC-USDT", # Name of trading pairs, it would change after renaming
1603
+ # "buy": "11328.9", # bestAsk
1604
+ # "sell": "11329", # bestBid
1605
+ # "changeRate": "-0.0055", # 24h change rate
1606
+ # "changePrice": "-63.6", # 24h change price
1607
+ # "high": "11610", # 24h highest price
1608
+ # "low": "11200", # 24h lowest price
1609
+ # "vol": "2282.70993217", # 24h volume,the aggregated trading volume in BTC
1610
+ # "volValue": "25984946.157790431", # 24h total, the trading volume in quote currency of last 24 hours
1611
+ # "last": "11328.9", # last price
1612
+ # "averagePrice": "11360.66065903", # 24h average transaction price yesterday
1613
+ # "takerFeeRate": "0.001", # Basic Taker Fee
1614
+ # "makerFeeRate": "0.001", # Basic Maker Fee
1615
+ # "takerCoefficient": "1", # Taker Fee Coefficient
1616
+ # "makerCoefficient": "1" # Maker Fee Coefficient
1617
+ # }
1618
+ # ]
1619
+ # }
1620
+ # }
1621
+ #
1622
+ data = self.safe_dict(response, 'data', {})
1623
+ tickers = self.safe_list(data, 'ticker', [])
1624
+ time = self.safe_integer(data, 'time')
1625
+ result: dict = {}
1626
+ for i in range(0, len(tickers)):
1627
+ tickers[i]['time'] = time
1628
+ ticker = self.parse_ticker(tickers[i])
1629
+ symbol = self.safe_string(ticker, 'symbol')
1630
+ if symbol is not None:
1631
+ result[symbol] = ticker
1632
+ return self.filter_by_array_tickers(result, 'symbol', symbols)
1633
+
1634
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1635
+ """
1636
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1637
+ :see: https://docs.kucoin.com/#get-24hr-stats
1638
+ :param str symbol: unified symbol of the market to fetch the ticker for
1639
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1640
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1641
+ """
1642
+ await self.load_markets()
1643
+ market = self.market(symbol)
1644
+ request: dict = {
1645
+ 'symbol': market['id'],
1646
+ }
1647
+ response = await self.publicGetMarketStats(self.extend(request, params))
1648
+ #
1649
+ # {
1650
+ # "code": "200000",
1651
+ # "data": {
1652
+ # "time": 1602832092060, # time
1653
+ # "symbol": "BTC-USDT", # symbol
1654
+ # "buy": "11328.9", # bestAsk
1655
+ # "sell": "11329", # bestBid
1656
+ # "changeRate": "-0.0055", # 24h change rate
1657
+ # "changePrice": "-63.6", # 24h change price
1658
+ # "high": "11610", # 24h highest price
1659
+ # "low": "11200", # 24h lowest price
1660
+ # "vol": "2282.70993217", # 24h volume,the aggregated trading volume in BTC
1661
+ # "volValue": "25984946.157790431", # 24h total, the trading volume in quote currency of last 24 hours
1662
+ # "last": "11328.9", # last price
1663
+ # "averagePrice": "11360.66065903", # 24h average transaction price yesterday
1664
+ # "takerFeeRate": "0.001", # Basic Taker Fee
1665
+ # "makerFeeRate": "0.001", # Basic Maker Fee
1666
+ # "takerCoefficient": "1", # Taker Fee Coefficient
1667
+ # "makerCoefficient": "1" # Maker Fee Coefficient
1668
+ # }
1669
+ # }
1670
+ #
1671
+ return self.parse_ticker(response['data'], market)
1672
+
1673
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1674
+ #
1675
+ # [
1676
+ # "1545904980", # Start time of the candle cycle
1677
+ # "0.058", # opening price
1678
+ # "0.049", # closing price
1679
+ # "0.058", # highest price
1680
+ # "0.049", # lowest price
1681
+ # "0.018", # base volume
1682
+ # "0.000945", # quote volume
1683
+ # ]
1684
+ #
1685
+ return [
1686
+ self.safe_timestamp(ohlcv, 0),
1687
+ self.safe_number(ohlcv, 1),
1688
+ self.safe_number(ohlcv, 3),
1689
+ self.safe_number(ohlcv, 4),
1690
+ self.safe_number(ohlcv, 2),
1691
+ self.safe_number(ohlcv, 5),
1692
+ ]
1693
+
1694
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1695
+ """
1696
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1697
+ :see: https://docs.kucoin.com/#get-klines
1698
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1699
+ :param str timeframe: the length of time each candle represents
1700
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1701
+ :param int [limit]: the maximum amount of candles to fetch
1702
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1703
+ :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)
1704
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1705
+ """
1706
+ await self.load_markets()
1707
+ paginate = False
1708
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
1709
+ if paginate:
1710
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1500)
1711
+ market = self.market(symbol)
1712
+ marketId = market['id']
1713
+ request: dict = {
1714
+ 'symbol': marketId,
1715
+ 'type': self.safe_string(self.timeframes, timeframe, timeframe),
1716
+ }
1717
+ duration = self.parse_timeframe(timeframe) * 1000
1718
+ endAt = self.milliseconds() # required param
1719
+ if since is not None:
1720
+ request['startAt'] = self.parse_to_int(int(math.floor(since / 1000)))
1721
+ if limit is None:
1722
+ # https://docs.kucoin.com/#get-klines
1723
+ # https://docs.kucoin.com/#details
1724
+ # For each query, the system would return at most 1500 pieces of data.
1725
+ # To obtain more data, please page the data by time.
1726
+ limit = self.safe_integer(self.options, 'fetchOHLCVLimit', 1500)
1727
+ endAt = self.sum(since, limit * duration)
1728
+ elif limit is not None:
1729
+ since = endAt - limit * duration
1730
+ request['startAt'] = self.parse_to_int(int(math.floor(since / 1000)))
1731
+ request['endAt'] = self.parse_to_int(int(math.floor(endAt / 1000)))
1732
+ response = await self.publicGetMarketCandles(self.extend(request, params))
1733
+ #
1734
+ # {
1735
+ # "code":"200000",
1736
+ # "data":[
1737
+ # ["1591517700","0.025078","0.025069","0.025084","0.025064","18.9883256","0.4761861079404"],
1738
+ # ["1591516800","0.025089","0.025079","0.025089","0.02506","99.4716622","2.494143499081"],
1739
+ # ["1591515900","0.025079","0.02509","0.025091","0.025068","59.83701271","1.50060885172798"],
1740
+ # ]
1741
+ # }
1742
+ #
1743
+ data = self.safe_list(response, 'data', [])
1744
+ return self.parse_ohlcvs(data, market, timeframe, since, limit)
1745
+
1746
+ async def create_deposit_address(self, code: str, params={}):
1747
+ """
1748
+ :see: https://docs.kucoin.com/#create-deposit-address
1749
+ create a currency deposit address
1750
+ :param str code: unified currency code of the currency for the deposit address
1751
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1752
+ :param str [params.network]: the blockchain network name
1753
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1754
+ """
1755
+ await self.load_markets()
1756
+ currency = self.currency(code)
1757
+ request: dict = {
1758
+ 'currency': currency['id'],
1759
+ }
1760
+ networkCode = None
1761
+ networkCode, params = self.handle_network_code_and_params(params)
1762
+ if networkCode is not None:
1763
+ request['chain'] = self.network_code_to_id(networkCode).lower()
1764
+ response = await self.privatePostDepositAddresses(self.extend(request, params))
1765
+ # {"code":"260000","msg":"Deposit address already exists."}
1766
+ # BCH {"code":"200000","data":{"address":"bitcoincash:qza3m4nj9rx7l9r0cdadfqxts6f92shvhvr5ls4q7z","memo":""}}
1767
+ # BTC {"code":"200000","data":{"address":"36SjucKqQpQSvsak9A7h6qzFjrVXpRNZhE","memo":""}}
1768
+ data = self.safe_dict(response, 'data', {})
1769
+ return self.parse_deposit_address(data, currency)
1770
+
1771
+ async def fetch_deposit_address(self, code: str, params={}):
1772
+ """
1773
+ fetch the deposit address for a currency associated with self account
1774
+ :see: https://docs.kucoin.com/#get-deposit-addresses-v2
1775
+ :param str code: unified currency code
1776
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1777
+ :param str [params.network]: the blockchain network name
1778
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
1779
+ """
1780
+ await self.load_markets()
1781
+ currency = self.currency(code)
1782
+ request: dict = {
1783
+ 'currency': currency['id'],
1784
+ # for USDT - OMNI, ERC20, TRC20, default is ERC20
1785
+ # for BTC - Native, Segwit, TRC20, the parameters are bech32, btc, trx, default is Native
1786
+ # 'chain': 'ERC20', # optional
1787
+ }
1788
+ networkCode = None
1789
+ networkCode, params = self.handle_network_code_and_params(params)
1790
+ if networkCode is not None:
1791
+ request['chain'] = self.network_code_to_id(networkCode).lower()
1792
+ version = self.options['versions']['private']['GET']['deposit-addresses']
1793
+ self.options['versions']['private']['GET']['deposit-addresses'] = 'v1'
1794
+ response = await self.privateGetDepositAddresses(self.extend(request, params))
1795
+ # BCH {"code":"200000","data":{"address":"bitcoincash:qza3m4nj9rx7l9r0cdadfqxts6f92shvhvr5ls4q7z","memo":""}}
1796
+ # BTC {"code":"200000","data":{"address":"36SjucKqQpQSvsak9A7h6qzFjrVXpRNZhE","memo":""}}
1797
+ self.options['versions']['private']['GET']['deposit-addresses'] = version
1798
+ data = self.safe_value(response, 'data')
1799
+ if data is None:
1800
+ raise ExchangeError(self.id + ' fetchDepositAddress() returned an empty response, you might try to run createDepositAddress() first and try again')
1801
+ return self.parse_deposit_address(data, currency)
1802
+
1803
+ def parse_deposit_address(self, depositAddress, currency: Currency = None):
1804
+ address = self.safe_string(depositAddress, 'address')
1805
+ # BCH/BSV is returned with a "bitcoincash:" prefix, which we cut off here and only keep the address
1806
+ if address is not None:
1807
+ address = address.replace('bitcoincash:', '')
1808
+ code = None
1809
+ if currency is not None:
1810
+ code = self.safe_currency_code(currency['id'])
1811
+ if code != 'NIM':
1812
+ # contains spaces
1813
+ self.check_address(address)
1814
+ return {
1815
+ 'info': depositAddress,
1816
+ 'currency': code,
1817
+ 'address': address,
1818
+ 'tag': self.safe_string(depositAddress, 'memo'),
1819
+ 'network': self.network_id_to_code(self.safe_string(depositAddress, 'chain')),
1820
+ }
1821
+
1822
+ async def fetch_deposit_addresses_by_network(self, code: str, params={}):
1823
+ """
1824
+ :see: https://docs.kucoin.com/#get-deposit-addresses-v2
1825
+ fetch the deposit address for a currency associated with self account
1826
+ :param str code: unified currency code
1827
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1828
+ :returns dict: an array of `address structures <https://docs.ccxt.com/#/?id=address-structure>`
1829
+ """
1830
+ await self.load_markets()
1831
+ currency = self.currency(code)
1832
+ request: dict = {
1833
+ 'currency': currency['id'],
1834
+ }
1835
+ version = self.options['versions']['private']['GET']['deposit-addresses']
1836
+ self.options['versions']['private']['GET']['deposit-addresses'] = 'v2'
1837
+ response = await self.privateGetDepositAddresses(self.extend(request, params))
1838
+ #
1839
+ # {
1840
+ # "code": "200000",
1841
+ # "data": [
1842
+ # {
1843
+ # "address": "fr1qvus7d4d5fgxj5e7zvqe6yhxd7txm95h2and69r",
1844
+ # "memo": "",
1845
+ # "chain": "BTC-Segwit",
1846
+ # "contractAddress": ""
1847
+ # },
1848
+ # {"address":"37icNMEWbiF8ZkwUMxmfzMxi2A1MQ44bMn","memo":"","chain":"BTC","contractAddress":""},
1849
+ # {"address":"Deposit temporarily blocked","memo":"","chain":"TRC20","contractAddress":""}
1850
+ # ]
1851
+ # }
1852
+ #
1853
+ self.options['versions']['private']['GET']['deposit-addresses'] = version
1854
+ chains = self.safe_list(response, 'data', [])
1855
+ parsed = self.parse_deposit_addresses(chains, [currency['code']], False, {
1856
+ 'currency': currency['code'],
1857
+ })
1858
+ return self.index_by(parsed, 'network')
1859
+
1860
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1861
+ """
1862
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1863
+ :see: https://www.kucoin.com/docs/rest/spot-trading/market-data/get-part-order-book-aggregated-
1864
+ :see: https://www.kucoin.com/docs/rest/spot-trading/market-data/get-full-order-book-aggregated-
1865
+ :param str symbol: unified symbol of the market to fetch the order book for
1866
+ :param int [limit]: the maximum amount of order book entries to return
1867
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1868
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1869
+ """
1870
+ await self.load_markets()
1871
+ market = self.market(symbol)
1872
+ level = self.safe_integer(params, 'level', 2)
1873
+ request: dict = {'symbol': market['id']}
1874
+ isAuthenticated = self.check_required_credentials(False)
1875
+ response = None
1876
+ if not isAuthenticated or limit is not None:
1877
+ if level == 2:
1878
+ request['level'] = level
1879
+ if limit is not None:
1880
+ if (limit == 20) or (limit == 100):
1881
+ request['limit'] = limit
1882
+ else:
1883
+ raise ExchangeError(self.id + ' fetchOrderBook() limit argument must be 20 or 100')
1884
+ request['limit'] = limit if limit else 100
1885
+ response = await self.publicGetMarketOrderbookLevelLevelLimit(self.extend(request, params))
1886
+ else:
1887
+ response = await self.privateGetMarketOrderbookLevel2(self.extend(request, params))
1888
+ #
1889
+ # public(v1) market/orderbook/level2_20 and market/orderbook/level2_100
1890
+ #
1891
+ # {
1892
+ # "sequence": "3262786978",
1893
+ # "time": 1550653727731,
1894
+ # "bids": [
1895
+ # ["6500.12", "0.45054140"],
1896
+ # ["6500.11", "0.45054140"],
1897
+ # ],
1898
+ # "asks": [
1899
+ # ["6500.16", "0.57753524"],
1900
+ # ["6500.15", "0.57753524"],
1901
+ # ]
1902
+ # }
1903
+ #
1904
+ # private(v3) market/orderbook/level2
1905
+ #
1906
+ # {
1907
+ # "sequence": "3262786978",
1908
+ # "time": 1550653727731,
1909
+ # "bids": [
1910
+ # ["6500.12", "0.45054140"],
1911
+ # ["6500.11", "0.45054140"],
1912
+ # ],
1913
+ # "asks": [
1914
+ # ["6500.16", "0.57753524"],
1915
+ # ["6500.15", "0.57753524"],
1916
+ # ]
1917
+ # }
1918
+ #
1919
+ data = self.safe_dict(response, 'data', {})
1920
+ timestamp = self.safe_integer(data, 'time')
1921
+ orderbook = self.parse_order_book(data, market['symbol'], timestamp, 'bids', 'asks', level - 2, level - 1)
1922
+ orderbook['nonce'] = self.safe_integer(data, 'sequence')
1923
+ return orderbook
1924
+
1925
+ def handle_trigger_prices(self, params):
1926
+ triggerPrice = self.safe_value_2(params, 'triggerPrice', 'stopPrice')
1927
+ stopLossPrice = self.safe_value(params, 'stopLossPrice')
1928
+ takeProfitPrice = self.safe_value(params, 'takeProfitPrice')
1929
+ isStopLoss = stopLossPrice is not None
1930
+ isTakeProfit = takeProfitPrice is not None
1931
+ if (isStopLoss and isTakeProfit) or (triggerPrice and stopLossPrice) or (triggerPrice and isTakeProfit):
1932
+ raise ExchangeError(self.id + ' createOrder() - you should use either triggerPrice or stopLossPrice or takeProfitPrice')
1933
+ return [triggerPrice, stopLossPrice, takeProfitPrice]
1934
+
1935
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1936
+ """
1937
+ Create an order on the exchange
1938
+ :see: https://docs.kucoin.com/spot#place-a-new-order
1939
+ :see: https://docs.kucoin.com/spot#place-a-new-order-2
1940
+ :see: https://docs.kucoin.com/spot#place-a-margin-order
1941
+ :see: https://docs.kucoin.com/spot-hf/#place-hf-order
1942
+ :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-order-test
1943
+ :see: https://www.kucoin.com/docs/rest/margin-trading/orders/place-margin-order-test
1944
+ :param str symbol: Unified CCXT market symbol
1945
+ :param str type: 'limit' or 'market'
1946
+ :param str side: 'buy' or 'sell'
1947
+ :param float amount: the amount of currency to trade
1948
+ :param float [price]: *ignored in "market" orders* the price at which the order is to be fullfilled at in units of the quote currency
1949
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1950
+ :param float [params.triggerPrice]: The price at which a trigger order is triggered at
1951
+ :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
1952
+ :param str [params.timeInForce]: GTC, GTT, IOC, or FOK, default is GTC, limit orders only
1953
+ :param str [params.postOnly]: Post only flag, invalid when timeInForce is IOC or FOK
1954
+ *
1955
+ * EXCHANGE SPECIFIC PARAMETERS
1956
+ :param str [params.clientOid]: client order id, defaults to uuid if not passed
1957
+ :param str [params.remark]: remark for the order, length cannot exceed 100 utf8 characters
1958
+ :param str [params.tradeType]: 'TRADE', # TRADE, MARGIN_TRADE # not used with margin orders
1959
+ * limit orders ---------------------------------------------------
1960
+ :param float [params.cancelAfter]: long, # cancel after n seconds, requires timeInForce to be GTT
1961
+ :param bool [params.hidden]: False, # Order will not be displayed in the order book
1962
+ :param bool [params.iceberg]: False, # Only a portion of the order is displayed in the order book
1963
+ :param str [params.visibleSize]: self.amount_to_precision(symbol, visibleSize), # The maximum visible size of an iceberg order
1964
+ * market orders --------------------------------------------------
1965
+ :param str [params.funds]: # Amount of quote currency to use
1966
+ * stop orders ----------------------------------------------------
1967
+ :param str [params.stop]: Either loss or entry, the default is loss. Requires stopPrice to be defined
1968
+ * margin orders --------------------------------------------------
1969
+ :param float [params.leverage]: Leverage size of the order
1970
+ :param str [params.stp]: '', # self trade prevention, CN, CO, CB or DC
1971
+ :param bool [params.autoBorrow]: False, # The system will first borrow you funds at the optimal interest rate and then place an order for you
1972
+ :param bool [params.hf]: False, # True for hf order
1973
+ :param bool [params.test]: set to True to test an order, no order will be created but the request will be validated
1974
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1975
+ """
1976
+ await self.load_markets()
1977
+ market = self.market(symbol)
1978
+ testOrder = self.safe_bool(params, 'test', False)
1979
+ params = self.omit(params, 'test')
1980
+ isHf = self.safe_bool(params, 'hf', False)
1981
+ triggerPrice, stopLossPrice, takeProfitPrice = self.handle_trigger_prices(params)
1982
+ tradeType = self.safe_string(params, 'tradeType') # keep it for backward compatibility
1983
+ isTriggerOrder = (triggerPrice or stopLossPrice or takeProfitPrice)
1984
+ marginResult = self.handle_margin_mode_and_params('createOrder', params)
1985
+ marginMode = self.safe_string(marginResult, 0)
1986
+ isMarginOrder = tradeType == 'MARGIN_TRADE' or marginMode is not None
1987
+ # don't omit anything before calling createOrderRequest
1988
+ orderRequest = self.create_order_request(symbol, type, side, amount, price, params)
1989
+ response = None
1990
+ if testOrder:
1991
+ if isMarginOrder:
1992
+ response = await self.privatePostMarginOrderTest(orderRequest)
1993
+ else:
1994
+ response = await self.privatePostOrdersTest(orderRequest)
1995
+ elif isHf:
1996
+ response = await self.privatePostHfOrders(orderRequest)
1997
+ elif isTriggerOrder:
1998
+ response = await self.privatePostStopOrder(orderRequest)
1999
+ elif isMarginOrder:
2000
+ response = await self.privatePostMarginOrder(orderRequest)
2001
+ else:
2002
+ response = await self.privatePostOrders(orderRequest)
2003
+ #
2004
+ # {
2005
+ # "code": "200000",
2006
+ # "data": {
2007
+ # "orderId": "5bd6e9286d99522a52e458de"
2008
+ # }
2009
+ # }
2010
+ #
2011
+ data = self.safe_dict(response, 'data', {})
2012
+ return self.parse_order(data, market)
2013
+
2014
+ async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
2015
+ """
2016
+ create a market order by providing the symbol, side and cost
2017
+ :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2018
+ :param str symbol: unified symbol of the market to create an order in
2019
+ :param str side: 'buy' or 'sell'
2020
+ :param float cost: how much you want to trade in units of the quote currency
2021
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2022
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2023
+ """
2024
+ await self.load_markets()
2025
+ params['cost'] = cost
2026
+ return await self.create_order(symbol, 'market', side, cost, None, params)
2027
+
2028
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
2029
+ """
2030
+ create a market buy order by providing the symbol and cost
2031
+ :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2032
+ :param str symbol: unified symbol of the market to create an order in
2033
+ :param float cost: how much you want to trade in units of the quote currency
2034
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2035
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2036
+ """
2037
+ await self.load_markets()
2038
+ return await self.create_market_order_with_cost(symbol, 'buy', cost, params)
2039
+
2040
+ async def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}):
2041
+ """
2042
+ create a market sell order by providing the symbol and cost
2043
+ :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-order
2044
+ :param str symbol: unified symbol of the market to create an order in
2045
+ :param float cost: how much you want to trade in units of the quote currency
2046
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2047
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2048
+ """
2049
+ await self.load_markets()
2050
+ return await self.create_market_order_with_cost(symbol, 'sell', cost, params)
2051
+
2052
+ async def create_orders(self, orders: List[OrderRequest], params={}):
2053
+ """
2054
+ create a list of trade orders
2055
+ :see: https://www.kucoin.com/docs/rest/spot-trading/orders/place-multiple-orders
2056
+ :see: https://www.kucoin.com/docs/rest/spot-trading/spot-hf-trade-pro-account/place-multiple-hf-orders
2057
+ :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
2058
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2059
+ :param bool [params.hf]: False, # True for hf orders
2060
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2061
+ """
2062
+ await self.load_markets()
2063
+ ordersRequests = []
2064
+ symbol = None
2065
+ for i in range(0, len(orders)):
2066
+ rawOrder = orders[i]
2067
+ marketId = self.safe_string(rawOrder, 'symbol')
2068
+ if symbol is None:
2069
+ symbol = marketId
2070
+ else:
2071
+ if symbol != marketId:
2072
+ raise BadRequest(self.id + ' createOrders() requires all orders to have the same symbol')
2073
+ type = self.safe_string(rawOrder, 'type')
2074
+ if type != 'limit':
2075
+ raise BadRequest(self.id + ' createOrders() only supports limit orders')
2076
+ side = self.safe_string(rawOrder, 'side')
2077
+ amount = self.safe_value(rawOrder, 'amount')
2078
+ price = self.safe_value(rawOrder, 'price')
2079
+ orderParams = self.safe_value(rawOrder, 'params', {})
2080
+ orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
2081
+ ordersRequests.append(orderRequest)
2082
+ market = self.market(symbol)
2083
+ request: dict = {
2084
+ 'symbol': market['id'],
2085
+ 'orderList': ordersRequests,
2086
+ }
2087
+ hf = self.safe_bool(params, 'hf', False)
2088
+ params = self.omit(params, 'hf')
2089
+ response = None
2090
+ if hf:
2091
+ response = await self.privatePostHfOrdersMulti(self.extend(request, params))
2092
+ else:
2093
+ response = await self.privatePostOrdersMulti(self.extend(request, params))
2094
+ #
2095
+ # {
2096
+ # "code": "200000",
2097
+ # "data": {
2098
+ # "data": [
2099
+ # {
2100
+ # "symbol": "LTC-USDT",
2101
+ # "type": "limit",
2102
+ # "side": "sell",
2103
+ # "price": "90",
2104
+ # "size": "0.1",
2105
+ # "funds": null,
2106
+ # "stp": "",
2107
+ # "stop": "",
2108
+ # "stopPrice": null,
2109
+ # "timeInForce": "GTC",
2110
+ # "cancelAfter": 0,
2111
+ # "postOnly": False,
2112
+ # "hidden": False,
2113
+ # "iceberge": False,
2114
+ # "iceberg": False,
2115
+ # "visibleSize": null,
2116
+ # "channel": "API",
2117
+ # "id": "6539148443fcf500079d15e5",
2118
+ # "status": "success",
2119
+ # "failMsg": null,
2120
+ # "clientOid": "5c4c5398-8ab2-4b4e-af8a-e2d90ad2488f"
2121
+ # },
2122
+ # }
2123
+ #
2124
+ data = self.safe_dict(response, 'data', {})
2125
+ data = self.safe_list(data, 'data', [])
2126
+ return self.parse_orders(data)
2127
+
2128
+ def market_order_amount_to_precision(self, symbol: str, amount):
2129
+ market = self.market(symbol)
2130
+ result = self.decimal_to_precision(amount, TRUNCATE, market['info']['quoteIncrement'], self.precisionMode, self.paddingMode)
2131
+ if result == '0':
2132
+ raise InvalidOrder(self.id + ' amount of ' + market['symbol'] + ' must be greater than minimum amount precision of ' + self.number_to_string(market['precision']['amount']))
2133
+ return result
2134
+
2135
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2136
+ market = self.market(symbol)
2137
+ # required param, cannot be used twice
2138
+ clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId', self.uuid())
2139
+ params = self.omit(params, ['clientOid', 'clientOrderId'])
2140
+ request: dict = {
2141
+ 'clientOid': clientOrderId,
2142
+ 'side': side,
2143
+ 'symbol': market['id'],
2144
+ 'type': type, # limit or market
2145
+ }
2146
+ quoteAmount = self.safe_number_2(params, 'cost', 'funds')
2147
+ amountString = None
2148
+ costString = None
2149
+ marginMode = None
2150
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
2151
+ if type == 'market':
2152
+ if quoteAmount is not None:
2153
+ params = self.omit(params, ['cost', 'funds'])
2154
+ # kucoin uses base precision even for quote values
2155
+ costString = self.market_order_amount_to_precision(symbol, quoteAmount)
2156
+ request['funds'] = costString
2157
+ else:
2158
+ amountString = self.amount_to_precision(symbol, amount)
2159
+ request['size'] = self.amount_to_precision(symbol, amount)
2160
+ else:
2161
+ amountString = self.amount_to_precision(symbol, amount)
2162
+ request['size'] = amountString
2163
+ request['price'] = self.price_to_precision(symbol, price)
2164
+ tradeType = self.safe_string(params, 'tradeType') # keep it for backward compatibility
2165
+ triggerPrice, stopLossPrice, takeProfitPrice = self.handle_trigger_prices(params)
2166
+ isTriggerOrder = (triggerPrice or stopLossPrice or takeProfitPrice)
2167
+ isMarginOrder = tradeType == 'MARGIN_TRADE' or marginMode is not None
2168
+ params = self.omit(params, ['stopLossPrice', 'takeProfitPrice', 'triggerPrice', 'stopPrice'])
2169
+ if isTriggerOrder:
2170
+ if triggerPrice:
2171
+ request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
2172
+ elif stopLossPrice or takeProfitPrice:
2173
+ if stopLossPrice:
2174
+ request['stop'] = 'entry' if (side == 'buy') else 'loss'
2175
+ request['stopPrice'] = self.price_to_precision(symbol, stopLossPrice)
2176
+ else:
2177
+ request['stop'] = 'loss' if (side == 'buy') else 'entry'
2178
+ request['stopPrice'] = self.price_to_precision(symbol, takeProfitPrice)
2179
+ if marginMode == 'isolated':
2180
+ raise BadRequest(self.id + ' createOrder does not support isolated margin for stop orders')
2181
+ elif marginMode == 'cross':
2182
+ request['tradeType'] = self.options['marginModes'][marginMode]
2183
+ elif isMarginOrder:
2184
+ if marginMode == 'isolated':
2185
+ request['marginModel'] = 'isolated'
2186
+ postOnly = None
2187
+ postOnly, params = self.handle_post_only(type == 'market', False, params)
2188
+ if postOnly:
2189
+ request['postOnly'] = True
2190
+ return self.extend(request, params)
2191
+
2192
+ async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
2193
+ """
2194
+ edit an order, kucoin currently only supports the modification of HF orders
2195
+ :see: https://docs.kucoin.com/spot-hf/#modify-order
2196
+ :param str id: order id
2197
+ :param str symbol: unified symbol of the market to create an order in
2198
+ :param str type: not used
2199
+ :param str side: not used
2200
+ :param float amount: how much of the currency you want to trade in units of the base currency
2201
+ :param float [price]: the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
2202
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2203
+ :param str [params.clientOrderId]: client order id, defaults to id if not passed
2204
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2205
+ """
2206
+ await self.load_markets()
2207
+ market = self.market(symbol)
2208
+ request: dict = {
2209
+ 'symbol': market['id'],
2210
+ }
2211
+ clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId')
2212
+ if clientOrderId is not None:
2213
+ request['clientOid'] = clientOrderId
2214
+ else:
2215
+ request['orderId'] = id
2216
+ if amount is not None:
2217
+ request['newSize'] = self.amount_to_precision(symbol, amount)
2218
+ if price is not None:
2219
+ request['newPrice'] = self.price_to_precision(symbol, price)
2220
+ response = await self.privatePostHfOrdersAlter(self.extend(request, params))
2221
+ #
2222
+ # {
2223
+ # "code":"200000",
2224
+ # "data":{
2225
+ # "newOrderId":"6478d7a6c883280001e92d8b"
2226
+ # }
2227
+ # }
2228
+ #
2229
+ data = self.safe_dict(response, 'data', {})
2230
+ return self.parse_order(data, market)
2231
+
2232
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
2233
+ """
2234
+ cancels an open order
2235
+ :see: https://docs.kucoin.com/spot#cancel-an-order
2236
+ :see: https://docs.kucoin.com/spot#cancel-an-order-2
2237
+ :see: https://docs.kucoin.com/spot#cancel-single-order-by-clientoid
2238
+ :see: https://docs.kucoin.com/spot#cancel-single-order-by-clientoid-2
2239
+ :see: https://docs.kucoin.com/spot-hf/#cancel-orders-by-orderid
2240
+ :see: https://docs.kucoin.com/spot-hf/#cancel-order-by-clientoid
2241
+ :param str id: order id
2242
+ :param str symbol: unified symbol of the market the order was made in
2243
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2244
+ :param bool [params.stop]: True if cancelling a stop order
2245
+ :param bool [params.hf]: False, # True for hf order
2246
+ :returns: Response from the exchange
2247
+ """
2248
+ await self.load_markets()
2249
+ request: dict = {}
2250
+ clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId')
2251
+ stop = self.safe_bool_2(params, 'stop', 'trigger', False)
2252
+ hf = self.safe_bool(params, 'hf', False)
2253
+ if hf:
2254
+ if symbol is None:
2255
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol parameter for hf orders')
2256
+ market = self.market(symbol)
2257
+ request['symbol'] = market['id']
2258
+ response = None
2259
+ params = self.omit(params, ['clientOid', 'clientOrderId', 'stop', 'hf', 'trigger'])
2260
+ if clientOrderId is not None:
2261
+ request['clientOid'] = clientOrderId
2262
+ if stop:
2263
+ response = await self.privateDeleteStopOrderCancelOrderByClientOid(self.extend(request, params))
2264
+ #
2265
+ # {
2266
+ # code: '200000',
2267
+ # data: {
2268
+ # cancelledOrderId: 'vs8lgpiuao41iaft003khbbk',
2269
+ # clientOid: '123456'
2270
+ # }
2271
+ # }
2272
+ #
2273
+ elif hf:
2274
+ response = await self.privateDeleteHfOrdersClientOrderClientOid(self.extend(request, params))
2275
+ #
2276
+ # {
2277
+ # "code": "200000",
2278
+ # "data": {
2279
+ # "clientOid": "6d539dc614db3"
2280
+ # }
2281
+ # }
2282
+ #
2283
+ else:
2284
+ response = await self.privateDeleteOrderClientOrderClientOid(self.extend(request, params))
2285
+ #
2286
+ # {
2287
+ # code: '200000',
2288
+ # data: {
2289
+ # cancelledOrderId: '665e580f6660500007aba341',
2290
+ # clientOid: '1234567',
2291
+ # cancelledOcoOrderIds: null
2292
+ # }
2293
+ # }
2294
+ #
2295
+ response = self.safe_dict(response, 'data')
2296
+ return self.parse_order(response)
2297
+ else:
2298
+ request['orderId'] = id
2299
+ if stop:
2300
+ response = await self.privateDeleteStopOrderOrderId(self.extend(request, params))
2301
+ #
2302
+ # {
2303
+ # code: '200000',
2304
+ # data: {cancelledOrderIds: ['vs8lgpiuaco91qk8003vebu9']}
2305
+ # }
2306
+ #
2307
+ elif hf:
2308
+ response = await self.privateDeleteHfOrdersOrderId(self.extend(request, params))
2309
+ #
2310
+ # {
2311
+ # "code": "200000",
2312
+ # "data": {
2313
+ # "orderId": "630625dbd9180300014c8d52"
2314
+ # }
2315
+ # }
2316
+ #
2317
+ response = self.safe_dict(response, 'data')
2318
+ return self.parse_order(response)
2319
+ else:
2320
+ response = await self.privateDeleteOrdersOrderId(self.extend(request, params))
2321
+ #
2322
+ # {
2323
+ # code: '200000',
2324
+ # data: {cancelledOrderIds: ['665e4fbe28051a0007245c41']}
2325
+ # }
2326
+ #
2327
+ data = self.safe_dict(response, 'data')
2328
+ orderIds = self.safe_list(data, 'cancelledOrderIds', [])
2329
+ orderId = self.safe_string(orderIds, 0)
2330
+ return self.safe_order({
2331
+ 'info': data,
2332
+ 'id': orderId,
2333
+ })
2334
+
2335
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
2336
+ """
2337
+ cancel all open orders
2338
+ :see: https://docs.kucoin.com/spot#cancel-all-orders
2339
+ :see: https://docs.kucoin.com/spot#cancel-orders
2340
+ :see: https://docs.kucoin.com/spot-hf/#cancel-all-hf-orders-by-symbol
2341
+ :param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
2342
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2343
+ :param bool [params.stop]: *invalid for isolated margin* True if cancelling all stop orders
2344
+ :param str [params.marginMode]: 'cross' or 'isolated'
2345
+ :param str [params.orderIds]: *stop orders only* Comma seperated order IDs
2346
+ :param bool [params.stop]: True if cancelling a stop order
2347
+ :param bool [params.hf]: False, # True for hf order
2348
+ :returns: Response from the exchange
2349
+ """
2350
+ await self.load_markets()
2351
+ request: dict = {}
2352
+ stop = self.safe_bool(params, 'stop', False)
2353
+ hf = self.safe_bool(params, 'hf', False)
2354
+ params = self.omit(params, ['stop', 'hf'])
2355
+ marginMode, query = self.handle_margin_mode_and_params('cancelAllOrders', params)
2356
+ if symbol is not None:
2357
+ request['symbol'] = self.market_id(symbol)
2358
+ if marginMode is not None:
2359
+ request['tradeType'] = self.options['marginModes'][marginMode]
2360
+ if marginMode == 'isolated' and stop:
2361
+ raise BadRequest(self.id + ' cancelAllOrders does not support isolated margin for stop orders')
2362
+ response = None
2363
+ if stop:
2364
+ response = await self.privateDeleteStopOrderCancel(self.extend(request, query))
2365
+ elif hf:
2366
+ if symbol is None:
2367
+ response = await self.privateDeleteHfOrdersCancelAll(self.extend(request, query))
2368
+ else:
2369
+ response = await self.privateDeleteHfOrders(self.extend(request, query))
2370
+ else:
2371
+ response = await self.privateDeleteOrders(self.extend(request, query))
2372
+ return response
2373
+
2374
+ async def fetch_orders_by_status(self, status, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2375
+ """
2376
+ fetch a list of orders
2377
+ :see: https://docs.kucoin.com/spot#list-orders
2378
+ :see: https://docs.kucoin.com/spot#list-stop-orders
2379
+ :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2380
+ :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2381
+ :param str status: *not used for stop orders* 'open' or 'closed'
2382
+ :param str symbol: unified market symbol
2383
+ :param int [since]: timestamp in ms of the earliest order
2384
+ :param int [limit]: max number of orders to return
2385
+ :param dict [params]: exchange specific params
2386
+ :param int [params.until]: end time in ms
2387
+ :param bool [params.stop]: True if fetching stop orders
2388
+ :param str [params.side]: buy or sell
2389
+ :param str [params.type]: limit, market, limit_stop or market_stop
2390
+ :param str [params.tradeType]: TRADE for spot trading, MARGIN_TRADE for Margin Trading
2391
+ :param int [params.currentPage]: *stop orders only* current page
2392
+ :param str [params.orderIds]: *stop orders only* comma seperated order ID list
2393
+ :param bool [params.stop]: True if fetching a stop order
2394
+ :param bool [params.hf]: False, # True for hf order
2395
+ :returns: An `array of order structures <https://docs.ccxt.com/#/?id=order-structure>`
2396
+ """
2397
+ await self.load_markets()
2398
+ lowercaseStatus = status.lower()
2399
+ until = self.safe_integer(params, 'until')
2400
+ stop = self.safe_bool(params, 'stop', False)
2401
+ hf = self.safe_bool(params, 'hf', False)
2402
+ params = self.omit(params, ['stop', 'hf', 'until'])
2403
+ marginMode, query = self.handle_margin_mode_and_params('fetchOrdersByStatus', params)
2404
+ if lowercaseStatus == 'open':
2405
+ lowercaseStatus = 'active'
2406
+ elif lowercaseStatus == 'closed':
2407
+ lowercaseStatus = 'done'
2408
+ request: dict = {
2409
+ 'status': lowercaseStatus,
2410
+ }
2411
+ market = None
2412
+ if symbol is not None:
2413
+ market = self.market(symbol)
2414
+ request['symbol'] = market['id']
2415
+ if since is not None:
2416
+ request['startAt'] = since
2417
+ if limit is not None:
2418
+ request['pageSize'] = limit
2419
+ if until:
2420
+ request['endAt'] = until
2421
+ request['tradeType'] = self.safe_string(self.options['marginModes'], marginMode, 'TRADE')
2422
+ response = None
2423
+ if stop:
2424
+ response = await self.privateGetStopOrder(self.extend(request, query))
2425
+ elif hf:
2426
+ if lowercaseStatus == 'active':
2427
+ response = await self.privateGetHfOrdersActive(self.extend(request, query))
2428
+ elif lowercaseStatus == 'done':
2429
+ response = await self.privateGetHfOrdersDone(self.extend(request, query))
2430
+ else:
2431
+ response = await self.privateGetOrders(self.extend(request, query))
2432
+ #
2433
+ # {
2434
+ # "code": "200000",
2435
+ # "data": {
2436
+ # "currentPage": 1,
2437
+ # "pageSize": 1,
2438
+ # "totalNum": 153408,
2439
+ # "totalPage": 153408,
2440
+ # "items": [
2441
+ # {
2442
+ # "id": "5c35c02703aa673ceec2a168", #orderid
2443
+ # "symbol": "BTC-USDT", #symbol
2444
+ # "opType": "DEAL", # operation type,deal is pending order,cancel is cancel order
2445
+ # "type": "limit", # order type,e.g. limit,markrt,stop_limit.
2446
+ # "side": "buy", # transaction direction,include buy and sell
2447
+ # "price": "10", # order price
2448
+ # "size": "2", # order quantity
2449
+ # "funds": "0", # order funds
2450
+ # "dealFunds": "0.166", # deal funds
2451
+ # "dealSize": "2", # deal quantity
2452
+ # "fee": "0", # fee
2453
+ # "feeCurrency": "USDT", # charge fee currency
2454
+ # "stp": "", # self trade prevention,include CN,CO,DC,CB
2455
+ # "stop": "", # stop type
2456
+ # "stopTriggered": False, # stop order is triggered
2457
+ # "stopPrice": "0", # stop price
2458
+ # "timeInForce": "GTC", # time InForce,include GTC,GTT,IOC,FOK
2459
+ # "postOnly": False, # postOnly
2460
+ # "hidden": False, # hidden order
2461
+ # "iceberg": False, # iceberg order
2462
+ # "visibleSize": "0", # display quantity for iceberg order
2463
+ # "cancelAfter": 0, # cancel orders time,requires timeInForce to be GTT
2464
+ # "channel": "IOS", # order source
2465
+ # "clientOid": "", # user-entered order unique mark
2466
+ # "remark": "", # remark
2467
+ # "tags": "", # tag order source
2468
+ # "isActive": False, # status before unfilled or uncancelled
2469
+ # "cancelExist": False, # order cancellation transaction record
2470
+ # "createdAt": 1547026471000 # time
2471
+ # },
2472
+ # ]
2473
+ # }
2474
+ # }
2475
+ listData = self.safe_list(response, 'data')
2476
+ if listData is not None:
2477
+ return self.parse_orders(listData, market, since, limit)
2478
+ responseData = self.safe_dict(response, 'data', {})
2479
+ orders = self.safe_list(responseData, 'items', [])
2480
+ return self.parse_orders(orders, market, since, limit)
2481
+
2482
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2483
+ """
2484
+ fetches information on multiple closed orders made by the user
2485
+ :see: https://docs.kucoin.com/spot#list-orders
2486
+ :see: https://docs.kucoin.com/spot#list-stop-orders
2487
+ :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2488
+ :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2489
+ :param str symbol: unified market symbol of the market orders were made in
2490
+ :param int [since]: the earliest time in ms to fetch orders for
2491
+ :param int [limit]: the maximum number of order structures to retrieve
2492
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2493
+ :param int [params.until]: end time in ms
2494
+ :param str [params.side]: buy or sell
2495
+ :param str [params.type]: limit, market, limit_stop or market_stop
2496
+ :param str [params.tradeType]: TRADE for spot trading, MARGIN_TRADE for Margin Trading
2497
+ :param bool [params.stop]: True if fetching a stop order
2498
+ :param bool [params.hf]: False, # True for hf order
2499
+ :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)
2500
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2501
+ """
2502
+ await self.load_markets()
2503
+ paginate = False
2504
+ paginate, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'paginate')
2505
+ if paginate:
2506
+ return await self.fetch_paginated_call_dynamic('fetchClosedOrders', symbol, since, limit, params)
2507
+ return await self.fetch_orders_by_status('done', symbol, since, limit, params)
2508
+
2509
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2510
+ """
2511
+ fetch all unfilled currently open orders
2512
+ :see: https://docs.kucoin.com/spot#list-orders
2513
+ :see: https://docs.kucoin.com/spot#list-stop-orders
2514
+ :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-active-hf-orders
2515
+ :see: https://docs.kucoin.com/spot-hf/#obtain-list-of-filled-hf-orders
2516
+ :param str symbol: unified market symbol
2517
+ :param int [since]: the earliest time in ms to fetch open orders for
2518
+ :param int [limit]: the maximum number of open orders structures to retrieve
2519
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2520
+ :param int [params.until]: end time in ms
2521
+ :param bool [params.stop]: True if fetching stop orders
2522
+ :param str [params.side]: buy or sell
2523
+ :param str [params.type]: limit, market, limit_stop or market_stop
2524
+ :param str [params.tradeType]: TRADE for spot trading, MARGIN_TRADE for Margin Trading
2525
+ :param int [params.currentPage]: *stop orders only* current page
2526
+ :param str [params.orderIds]: *stop orders only* comma seperated order ID list
2527
+ :param bool [params.stop]: True if fetching a stop order
2528
+ :param bool [params.hf]: False, # True for hf order
2529
+ :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)
2530
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2531
+ """
2532
+ await self.load_markets()
2533
+ paginate = False
2534
+ paginate, params = self.handle_option_and_params(params, 'fetchOpenOrders', 'paginate')
2535
+ if paginate:
2536
+ return await self.fetch_paginated_call_dynamic('fetchOpenOrders', symbol, since, limit, params)
2537
+ return await self.fetch_orders_by_status('active', symbol, since, limit, params)
2538
+
2539
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
2540
+ """
2541
+ fetch an order
2542
+ :see: https://docs.kucoin.com/spot#get-an-order
2543
+ :see: https://docs.kucoin.com/spot#get-single-active-order-by-clientoid
2544
+ :see: https://docs.kucoin.com/spot#get-single-order-info
2545
+ :see: https://docs.kucoin.com/spot#get-single-order-by-clientoid
2546
+ :see: https://docs.kucoin.com/spot-hf/#details-of-a-single-hf-order
2547
+ :see: https://docs.kucoin.com/spot-hf/#obtain-details-of-a-single-hf-order-using-clientoid
2548
+ :param str id: Order id
2549
+ :param str symbol: not sent to exchange except for stop orders with clientOid, but used internally by CCXT to filter
2550
+ :param dict [params]: exchange specific parameters
2551
+ :param bool [params.stop]: True if fetching a stop order
2552
+ :param bool [params.hf]: False, # True for hf order
2553
+ :param bool [params.clientOid]: unique order id created by users to identify their orders
2554
+ :returns: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2555
+ """
2556
+ await self.load_markets()
2557
+ request: dict = {}
2558
+ clientOrderId = self.safe_string_2(params, 'clientOid', 'clientOrderId')
2559
+ stop = self.safe_bool(params, 'stop', False)
2560
+ hf = self.safe_bool(params, 'hf', False)
2561
+ market = None
2562
+ if symbol is not None:
2563
+ market = self.market(symbol)
2564
+ if hf:
2565
+ if symbol is None:
2566
+ raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol parameter for hf orders')
2567
+ request['symbol'] = market['id']
2568
+ params = self.omit(params, ['stop', 'hf', 'clientOid', 'clientOrderId'])
2569
+ response = None
2570
+ if clientOrderId is not None:
2571
+ request['clientOid'] = clientOrderId
2572
+ if stop:
2573
+ if symbol is not None:
2574
+ request['symbol'] = market['id']
2575
+ response = await self.privateGetStopOrderQueryOrderByClientOid(self.extend(request, params))
2576
+ elif hf:
2577
+ response = await self.privateGetHfOrdersClientOrderClientOid(self.extend(request, params))
2578
+ else:
2579
+ response = await self.privateGetOrderClientOrderClientOid(self.extend(request, params))
2580
+ else:
2581
+ # a special case for None ids
2582
+ # otherwise a wrong endpoint for all orders will be triggered
2583
+ # https://github.com/ccxt/ccxt/issues/7234
2584
+ if id is None:
2585
+ raise InvalidOrder(self.id + ' fetchOrder() requires an order id')
2586
+ request['orderId'] = id
2587
+ if stop:
2588
+ response = await self.privateGetStopOrderOrderId(self.extend(request, params))
2589
+ elif hf:
2590
+ response = await self.privateGetHfOrdersOrderId(self.extend(request, params))
2591
+ else:
2592
+ response = await self.privateGetOrdersOrderId(self.extend(request, params))
2593
+ responseData = self.safe_dict(response, 'data', {})
2594
+ if isinstance(responseData, list):
2595
+ responseData = self.safe_value(responseData, 0)
2596
+ return self.parse_order(responseData, market)
2597
+
2598
+ def parse_order(self, order: dict, market: Market = None) -> Order:
2599
+ #
2600
+ # createOrder
2601
+ #
2602
+ # {
2603
+ # "orderId": "63c97e47d686c5000159a656"
2604
+ # }
2605
+ #
2606
+ # cancelOrder
2607
+ #
2608
+ # {
2609
+ # "cancelledOrderIds": ["63c97e47d686c5000159a656"]
2610
+ # }
2611
+ #
2612
+ # fetchOpenOrders, fetchClosedOrders
2613
+ #
2614
+ # {
2615
+ # "id": "63c97ce8d686c500015793bb",
2616
+ # "symbol": "USDC-USDT",
2617
+ # "opType": "DEAL",
2618
+ # "type": "limit",
2619
+ # "side": "sell",
2620
+ # "price": "1.05",
2621
+ # "size": "1",
2622
+ # "funds": "0",
2623
+ # "dealFunds": "0",
2624
+ # "dealSize": "0",
2625
+ # "fee": "0",
2626
+ # "feeCurrency": "USDT",
2627
+ # "stp": "",
2628
+ # "stop": "",
2629
+ # "stopTriggered": False,
2630
+ # "stopPrice": "0",
2631
+ # "timeInForce": "GTC",
2632
+ # "postOnly": False,
2633
+ # "hidden": False,
2634
+ # "iceberg": False,
2635
+ # "visibleSize": "0",
2636
+ # "cancelAfter": 0,
2637
+ # "channel": "API",
2638
+ # "clientOid": "d602d73f-5424-4751-bef0-8debce8f0a82",
2639
+ # "remark": null,
2640
+ # "tags": "partner:ccxt",
2641
+ # "isActive": True,
2642
+ # "cancelExist": False,
2643
+ # "createdAt": 1674149096927,
2644
+ # "tradeType": "TRADE"
2645
+ # }
2646
+ #
2647
+ # stop orders(fetchOpenOrders, fetchClosedOrders)
2648
+ #
2649
+ # {
2650
+ # "id": "vs9f6ou9e864rgq8000t4qnm",
2651
+ # "symbol": "USDC-USDT",
2652
+ # "userId": "613a896885d8660006151f01",
2653
+ # "status": "NEW",
2654
+ # "type": "market",
2655
+ # "side": "sell",
2656
+ # "price": null,
2657
+ # "size": "1.00000000000000000000",
2658
+ # "funds": null,
2659
+ # "stp": null,
2660
+ # "timeInForce": "GTC",
2661
+ # "cancelAfter": -1,
2662
+ # "postOnly": False,
2663
+ # "hidden": False,
2664
+ # "iceberg": False,
2665
+ # "visibleSize": null,
2666
+ # "channel": "API",
2667
+ # "clientOid": "5d3fd727-6456-438d-9550-40d9d85eee0b",
2668
+ # "remark": null,
2669
+ # "tags": "partner:ccxt",
2670
+ # "relatedNo": null,
2671
+ # "orderTime": 1674146316994000028,
2672
+ # "domainId": "kucoin",
2673
+ # "tradeSource": "USER",
2674
+ # "tradeType": "MARGIN_TRADE",
2675
+ # "feeCurrency": "USDT",
2676
+ # "takerFeeRate": "0.00100000000000000000",
2677
+ # "makerFeeRate": "0.00100000000000000000",
2678
+ # "createdAt": 1674146316994,
2679
+ # "stop": "loss",
2680
+ # "stopTriggerTime": null,
2681
+ # "stopPrice": "0.97000000000000000000"
2682
+ # }
2683
+ # hf order
2684
+ # {
2685
+ # "id":"6478cf1439bdfc0001528a1d",
2686
+ # "symbol":"LTC-USDT",
2687
+ # "opType":"DEAL",
2688
+ # "type":"limit",
2689
+ # "side":"buy",
2690
+ # "price":"50",
2691
+ # "size":"0.1",
2692
+ # "funds":"5",
2693
+ # "dealSize":"0",
2694
+ # "dealFunds":"0",
2695
+ # "fee":"0",
2696
+ # "feeCurrency":"USDT",
2697
+ # "stp":null,
2698
+ # "timeInForce":"GTC",
2699
+ # "postOnly":false,
2700
+ # "hidden":false,
2701
+ # "iceberg":false,
2702
+ # "visibleSize":"0",
2703
+ # "cancelAfter":0,
2704
+ # "channel":"API",
2705
+ # "clientOid":"d4d2016b-8e3a-445c-aa5d-dc6df5d1678d",
2706
+ # "remark":null,
2707
+ # "tags":"partner:ccxt",
2708
+ # "cancelExist":false,
2709
+ # "createdAt":1685638932074,
2710
+ # "lastUpdatedAt":1685639013735,
2711
+ # "tradeType":"TRADE",
2712
+ # "inOrderBook":true,
2713
+ # "cancelledSize":"0",
2714
+ # "cancelledFunds":"0",
2715
+ # "remainSize":"0.1",
2716
+ # "remainFunds":"5",
2717
+ # "active":true
2718
+ # }
2719
+ #
2720
+ marketId = self.safe_string(order, 'symbol')
2721
+ timestamp = self.safe_integer(order, 'createdAt')
2722
+ feeCurrencyId = self.safe_string(order, 'feeCurrency')
2723
+ cancelExist = self.safe_bool(order, 'cancelExist', False)
2724
+ responseStop = self.safe_string(order, 'stop')
2725
+ stop = responseStop is not None
2726
+ stopTriggered = self.safe_bool(order, 'stopTriggered', False)
2727
+ isActive = self.safe_bool_2(order, 'isActive', 'active')
2728
+ responseStatus = self.safe_string(order, 'status')
2729
+ status = None
2730
+ if isActive is not None:
2731
+ if isActive is True:
2732
+ status = 'open'
2733
+ else:
2734
+ status = 'closed'
2735
+ if stop:
2736
+ if responseStatus == 'NEW':
2737
+ status = 'open'
2738
+ elif not isActive and not stopTriggered:
2739
+ status = 'cancelled'
2740
+ if cancelExist:
2741
+ status = 'canceled'
2742
+ if responseStatus == 'fail':
2743
+ status = 'rejected'
2744
+ stopPrice = self.safe_number(order, 'stopPrice')
2745
+ return self.safe_order({
2746
+ 'info': order,
2747
+ 'id': self.safe_string_n(order, ['id', 'orderId', 'newOrderId', 'cancelledOrderId']),
2748
+ 'clientOrderId': self.safe_string(order, 'clientOid'),
2749
+ 'symbol': self.safe_symbol(marketId, market, '-'),
2750
+ 'type': self.safe_string(order, 'type'),
2751
+ 'timeInForce': self.safe_string(order, 'timeInForce'),
2752
+ 'postOnly': self.safe_bool(order, 'postOnly'),
2753
+ 'side': self.safe_string(order, 'side'),
2754
+ 'amount': self.safe_string(order, 'size'),
2755
+ 'price': self.safe_string(order, 'price'), # price is zero for market order, omitZero is called in safeOrder2
2756
+ 'stopPrice': stopPrice,
2757
+ 'triggerPrice': stopPrice,
2758
+ 'cost': self.safe_string(order, 'dealFunds'),
2759
+ 'filled': self.safe_string(order, 'dealSize'),
2760
+ 'remaining': None,
2761
+ 'timestamp': timestamp,
2762
+ 'datetime': self.iso8601(timestamp),
2763
+ 'fee': {
2764
+ 'currency': self.safe_currency_code(feeCurrencyId),
2765
+ 'cost': self.safe_number(order, 'fee'),
2766
+ },
2767
+ 'status': status,
2768
+ 'lastTradeTimestamp': None,
2769
+ 'average': None,
2770
+ 'trades': None,
2771
+ }, market)
2772
+
2773
+ async def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2774
+ """
2775
+ fetch all the trades made from a single order
2776
+ :see: https://docs.kucoin.com/#list-fills
2777
+ :see: https://docs.kucoin.com/spot-hf/#transaction-details
2778
+ :param str id: order id
2779
+ :param str symbol: unified market symbol
2780
+ :param int [since]: the earliest time in ms to fetch trades for
2781
+ :param int [limit]: the maximum number of trades to retrieve
2782
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2783
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2784
+ """
2785
+ request: dict = {
2786
+ 'orderId': id,
2787
+ }
2788
+ return await self.fetch_my_trades(symbol, since, limit, self.extend(request, params))
2789
+
2790
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2791
+ """
2792
+ :see: https://docs.kucoin.com/#list-fills
2793
+ :see: https://docs.kucoin.com/spot-hf/#transaction-details
2794
+ fetch all trades made by the user
2795
+ :param str symbol: unified market symbol
2796
+ :param int [since]: the earliest time in ms to fetch trades for
2797
+ :param int [limit]: the maximum number of trades structures to retrieve
2798
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2799
+ :param int [params.until]: the latest time in ms to fetch entries for
2800
+ :param bool [params.hf]: False, # True for hf order
2801
+ :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)
2802
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2803
+ """
2804
+ await self.load_markets()
2805
+ paginate = False
2806
+ paginate, params = self.handle_option_and_params(params, 'fetchMyTrades', 'paginate')
2807
+ if paginate:
2808
+ return await self.fetch_paginated_call_dynamic('fetchMyTrades', symbol, since, limit, params)
2809
+ request: dict = {}
2810
+ hf = self.safe_bool(params, 'hf', False)
2811
+ if hf and symbol is None:
2812
+ raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol parameter for hf orders')
2813
+ market = None
2814
+ if symbol is not None:
2815
+ market = self.market(symbol)
2816
+ request['symbol'] = market['id']
2817
+ if limit is not None:
2818
+ request['pageSize'] = limit
2819
+ method = self.options['fetchMyTradesMethod']
2820
+ parseResponseData = False
2821
+ response = None
2822
+ request, params = self.handle_until_option('endAt', request, params)
2823
+ if hf:
2824
+ response = await self.privateGetHfFills(self.extend(request, params))
2825
+ elif method == 'private_get_fills':
2826
+ # does not return trades earlier than 2019-02-18T00:00:00Z
2827
+ if since is not None:
2828
+ # only returns trades up to one week after the since param
2829
+ request['startAt'] = since
2830
+ response = await self.privateGetFills(self.extend(request, params))
2831
+ elif method == 'private_get_limit_fills':
2832
+ # does not return trades earlier than 2019-02-18T00:00:00Z
2833
+ # takes no params
2834
+ # only returns first 1000 trades(not only "in the last 24 hours" in the docs)
2835
+ parseResponseData = True
2836
+ response = await self.privateGetLimitFills(self.extend(request, params))
2837
+ else:
2838
+ raise ExchangeError(self.id + ' fetchMyTradesMethod() invalid method')
2839
+ #
2840
+ # {
2841
+ # "currentPage": 1,
2842
+ # "pageSize": 50,
2843
+ # "totalNum": 1,
2844
+ # "totalPage": 1,
2845
+ # "items": [
2846
+ # {
2847
+ # "symbol":"BTC-USDT", # symbol
2848
+ # "tradeId":"5c35c02709e4f67d5266954e", # trade id
2849
+ # "orderId":"5c35c02703aa673ceec2a168", # order id
2850
+ # "counterOrderId":"5c1ab46003aa676e487fa8e3", # counter order id
2851
+ # "side":"buy", # transaction direction,include buy and sell
2852
+ # "liquidity":"taker", # include taker and maker
2853
+ # "forceTaker":true, # forced to become taker
2854
+ # "price":"0.083", # order price
2855
+ # "size":"0.8424304", # order quantity
2856
+ # "funds":"0.0699217232", # order funds
2857
+ # "fee":"0", # fee
2858
+ # "feeRate":"0", # fee rate
2859
+ # "feeCurrency":"USDT", # charge fee currency
2860
+ # "stop":"", # stop type
2861
+ # "type":"limit", # order type, e.g. limit, market, stop_limit.
2862
+ # "createdAt":1547026472000 # time
2863
+ # },
2864
+ # #------------------------------------------------------
2865
+ # # v1(historical) trade response structure
2866
+ # {
2867
+ # "symbol": "SNOV-ETH",
2868
+ # "dealPrice": "0.0000246",
2869
+ # "dealValue": "0.018942",
2870
+ # "amount": "770",
2871
+ # "fee": "0.00001137",
2872
+ # "side": "sell",
2873
+ # "createdAt": 1540080199
2874
+ # "id":"5c4d389e4c8c60413f78e2e5",
2875
+ # }
2876
+ # ]
2877
+ # }
2878
+ #
2879
+ data = self.safe_dict(response, 'data', {})
2880
+ trades = None
2881
+ if parseResponseData:
2882
+ trades = data
2883
+ else:
2884
+ trades = self.safe_list(data, 'items', [])
2885
+ return self.parse_trades(trades, market, since, limit)
2886
+
2887
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
2888
+ """
2889
+ get the list of most recent trades for a particular symbol
2890
+ :see: https://www.kucoin.com/docs/rest/spot-trading/market-data/get-trade-histories
2891
+ :param str symbol: unified symbol of the market to fetch trades for
2892
+ :param int [since]: timestamp in ms of the earliest trade to fetch
2893
+ :param int [limit]: the maximum amount of trades to fetch
2894
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2895
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
2896
+ """
2897
+ await self.load_markets()
2898
+ market = self.market(symbol)
2899
+ request: dict = {
2900
+ 'symbol': market['id'],
2901
+ }
2902
+ # pagination is not supported on the exchange side anymore
2903
+ # if since is not None:
2904
+ # request['startAt'] = int(math.floor(since / 1000))
2905
+ # }
2906
+ # if limit is not None:
2907
+ # request['pageSize'] = limit
2908
+ # }
2909
+ response = await self.publicGetMarketHistories(self.extend(request, params))
2910
+ #
2911
+ # {
2912
+ # "code": "200000",
2913
+ # "data": [
2914
+ # {
2915
+ # "sequence": "1548764654235",
2916
+ # "side": "sell",
2917
+ # "size":"0.6841354",
2918
+ # "price":"0.03202",
2919
+ # "time":1548848575203567174
2920
+ # }
2921
+ # ]
2922
+ # }
2923
+ #
2924
+ trades = self.safe_list(response, 'data', [])
2925
+ return self.parse_trades(trades, market, since, limit)
2926
+
2927
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
2928
+ #
2929
+ # fetchTrades(public)
2930
+ #
2931
+ # {
2932
+ # "sequence": "1548764654235",
2933
+ # "side": "sell",
2934
+ # "size":"0.6841354",
2935
+ # "price":"0.03202",
2936
+ # "time":1548848575203567174
2937
+ # }
2938
+ #
2939
+ # {
2940
+ # "sequence": "1568787654360",
2941
+ # "symbol": "BTC-USDT",
2942
+ # "side": "buy",
2943
+ # "size": "0.00536577",
2944
+ # "price": "9345",
2945
+ # "takerOrderId": "5e356c4a9f1a790008f8d921",
2946
+ # "time": "1580559434436443257",
2947
+ # "type": "match",
2948
+ # "makerOrderId": "5e356bffedf0010008fa5d7f",
2949
+ # "tradeId": "5e356c4aeefabd62c62a1ece"
2950
+ # }
2951
+ #
2952
+ # fetchMyTrades(private) v2
2953
+ #
2954
+ # {
2955
+ # "symbol":"BTC-USDT",
2956
+ # "tradeId":"5c35c02709e4f67d5266954e",
2957
+ # "orderId":"5c35c02703aa673ceec2a168",
2958
+ # "counterOrderId":"5c1ab46003aa676e487fa8e3",
2959
+ # "side":"buy",
2960
+ # "liquidity":"taker",
2961
+ # "forceTaker":true,
2962
+ # "price":"0.083",
2963
+ # "size":"0.8424304",
2964
+ # "funds":"0.0699217232",
2965
+ # "fee":"0",
2966
+ # "feeRate":"0",
2967
+ # "feeCurrency":"USDT",
2968
+ # "stop":"",
2969
+ # "type":"limit",
2970
+ # "createdAt":1547026472000
2971
+ # }
2972
+ #
2973
+ # fetchMyTrades v2 alternative format since 2019-05-21 https://github.com/ccxt/ccxt/pull/5162
2974
+ #
2975
+ # {
2976
+ # "symbol": "OPEN-BTC",
2977
+ # "forceTaker": False,
2978
+ # "orderId": "5ce36420054b4663b1fff2c9",
2979
+ # "fee": "0",
2980
+ # "feeCurrency": "",
2981
+ # "type": "",
2982
+ # "feeRate": "0",
2983
+ # "createdAt": 1558417615000,
2984
+ # "size": "12.8206",
2985
+ # "stop": "",
2986
+ # "price": "0",
2987
+ # "funds": "0",
2988
+ # "tradeId": "5ce390cf6e0db23b861c6e80"
2989
+ # }
2990
+ #
2991
+ # fetchMyTrades(private) v1(historical)
2992
+ #
2993
+ # {
2994
+ # "symbol": "SNOV-ETH",
2995
+ # "dealPrice": "0.0000246",
2996
+ # "dealValue": "0.018942",
2997
+ # "amount": "770",
2998
+ # "fee": "0.00001137",
2999
+ # "side": "sell",
3000
+ # "createdAt": 1540080199
3001
+ # "id":"5c4d389e4c8c60413f78e2e5",
3002
+ # }
3003
+ #
3004
+ marketId = self.safe_string(trade, 'symbol')
3005
+ market = self.safe_market(marketId, market, '-')
3006
+ id = self.safe_string_2(trade, 'tradeId', 'id')
3007
+ orderId = self.safe_string(trade, 'orderId')
3008
+ takerOrMaker = self.safe_string(trade, 'liquidity')
3009
+ timestamp = self.safe_integer(trade, 'time')
3010
+ if timestamp is not None:
3011
+ timestamp = self.parse_to_int(timestamp / 1000000)
3012
+ else:
3013
+ timestamp = self.safe_integer(trade, 'createdAt')
3014
+ # if it's a historical v1 trade, the exchange returns timestamp in seconds
3015
+ if ('dealValue' in trade) and (timestamp is not None):
3016
+ timestamp = timestamp * 1000
3017
+ priceString = self.safe_string_2(trade, 'price', 'dealPrice')
3018
+ amountString = self.safe_string_2(trade, 'size', 'amount')
3019
+ side = self.safe_string(trade, 'side')
3020
+ fee = None
3021
+ feeCostString = self.safe_string(trade, 'fee')
3022
+ if feeCostString is not None:
3023
+ feeCurrencyId = self.safe_string(trade, 'feeCurrency')
3024
+ feeCurrency = self.safe_currency_code(feeCurrencyId)
3025
+ if feeCurrency is None:
3026
+ feeCurrency = market['quote'] if (side == 'sell') else market['base']
3027
+ fee = {
3028
+ 'cost': feeCostString,
3029
+ 'currency': feeCurrency,
3030
+ 'rate': self.safe_string(trade, 'feeRate'),
3031
+ }
3032
+ type = self.safe_string(trade, 'type')
3033
+ if type == 'match':
3034
+ type = None
3035
+ costString = self.safe_string_2(trade, 'funds', 'dealValue')
3036
+ return self.safe_trade({
3037
+ 'info': trade,
3038
+ 'id': id,
3039
+ 'order': orderId,
3040
+ 'timestamp': timestamp,
3041
+ 'datetime': self.iso8601(timestamp),
3042
+ 'symbol': market['symbol'],
3043
+ 'type': type,
3044
+ 'takerOrMaker': takerOrMaker,
3045
+ 'side': side,
3046
+ 'price': priceString,
3047
+ 'amount': amountString,
3048
+ 'cost': costString,
3049
+ 'fee': fee,
3050
+ }, market)
3051
+
3052
+ async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
3053
+ """
3054
+ fetch the trading fees for a market
3055
+ :see: https://www.kucoin.com/docs/rest/funding/trade-fee/trading-pair-actual-fee-spot-margin-trade_hf
3056
+ :param str symbol: unified market symbol
3057
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3058
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
3059
+ """
3060
+ await self.load_markets()
3061
+ market = self.market(symbol)
3062
+ request: dict = {
3063
+ 'symbols': market['id'],
3064
+ }
3065
+ response = await self.privateGetTradeFees(self.extend(request, params))
3066
+ #
3067
+ # {
3068
+ # "code": "200000",
3069
+ # "data": [
3070
+ # {
3071
+ # "symbol": "BTC-USDT",
3072
+ # "takerFeeRate": "0.001",
3073
+ # "makerFeeRate": "0.001"
3074
+ # }
3075
+ # ]
3076
+ # }
3077
+ #
3078
+ data = self.safe_list(response, 'data', [])
3079
+ first = self.safe_dict(data, 0)
3080
+ marketId = self.safe_string(first, 'symbol')
3081
+ return {
3082
+ 'info': response,
3083
+ 'symbol': self.safe_symbol(marketId, market),
3084
+ 'maker': self.safe_number(first, 'makerFeeRate'),
3085
+ 'taker': self.safe_number(first, 'takerFeeRate'),
3086
+ 'percentage': True,
3087
+ 'tierBased': True,
3088
+ }
3089
+
3090
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
3091
+ """
3092
+ make a withdrawal
3093
+ :see: https://www.kucoin.com/docs/rest/funding/withdrawals/apply-withdraw
3094
+ :param str code: unified currency code
3095
+ :param float amount: the amount to withdraw
3096
+ :param str address: the address to withdraw to
3097
+ :param str tag:
3098
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3099
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
3100
+ """
3101
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
3102
+ await self.load_markets()
3103
+ self.check_address(address)
3104
+ currency = self.currency(code)
3105
+ request: dict = {
3106
+ 'currency': currency['id'],
3107
+ 'address': address,
3108
+ # 'memo': tag,
3109
+ # 'isInner': False, # internal transfer or external withdrawal
3110
+ # 'remark': 'optional',
3111
+ # 'chain': 'OMNI', # 'ERC20', 'TRC20', default is ERC20, This only apply for multi-chain currency, and there is no need for single chain currency.
3112
+ }
3113
+ if tag is not None:
3114
+ request['memo'] = tag
3115
+ networkCode = None
3116
+ networkCode, params = self.handle_network_code_and_params(params)
3117
+ if networkCode is not None:
3118
+ request['chain'] = self.network_code_to_id(networkCode).lower()
3119
+ await self.load_currency_precision(currency, networkCode)
3120
+ request['amount'] = self.currency_to_precision(code, amount, networkCode)
3121
+ includeFee = None
3122
+ includeFee, params = self.handle_option_and_params(params, 'withdraw', 'includeFee', False)
3123
+ if includeFee:
3124
+ request['feeDeductType'] = 'INTERNAL'
3125
+ response = await self.privatePostWithdrawals(self.extend(request, params))
3126
+ #
3127
+ # https://github.com/ccxt/ccxt/issues/5558
3128
+ #
3129
+ # {
3130
+ # "code": 200000,
3131
+ # "data": {
3132
+ # "withdrawalId": "5bffb63303aa675e8bbe18f9"
3133
+ # }
3134
+ # }
3135
+ #
3136
+ data = self.safe_dict(response, 'data', {})
3137
+ return self.parse_transaction(data, currency)
3138
+
3139
+ async def load_currency_precision(self, currency, networkCode: Str = None):
3140
+ # might not have network specific precisions defined in fetchCurrencies(because of webapi failure)
3141
+ # we should check and refetch precision once-per-instance for that specific currency & network
3142
+ # so avoids thorwing exceptions and burden to users
3143
+ # Note: self needs to be executed only if networkCode was provided
3144
+ if networkCode is not None:
3145
+ networks = currency['networks']
3146
+ network = self.safe_dict(networks, networkCode)
3147
+ if self.safe_number(network, 'precision') is not None:
3148
+ # if precision exists, no need to refetch
3149
+ return
3150
+ # otherwise try to fetch and store in instance
3151
+ request: dict = {
3152
+ 'currency': currency['id'],
3153
+ 'chain': self.network_code_to_id(networkCode).lower(),
3154
+ }
3155
+ response = await self.privateGetWithdrawalsQuotas(request)
3156
+ #
3157
+ # {
3158
+ # "code": "200000",
3159
+ # "data": {
3160
+ # "currency": "USDT",
3161
+ # "limitBTCAmount": "14.24094850",
3162
+ # "usedBTCAmount": "0.00000000",
3163
+ # "quotaCurrency": "USDT",
3164
+ # "limitQuotaCurrencyAmount": "999999.00000000",
3165
+ # "usedQuotaCurrencyAmount": "0",
3166
+ # "remainAmount": "999999.0000",
3167
+ # "availableAmount": "10.77545071",
3168
+ # "withdrawMinFee": "1",
3169
+ # "innerWithdrawMinFee": "0",
3170
+ # "withdrawMinSize": "10",
3171
+ # "isWithdrawEnabled": True,
3172
+ # "precision": 4,
3173
+ # "chain": "EOS",
3174
+ # "reason": null,
3175
+ # "lockedAmount": "0"
3176
+ # }
3177
+ # }
3178
+ #
3179
+ data = self.safe_dict(response, 'data', {})
3180
+ precision = self.parse_number(self.parse_precision(self.safe_string(data, 'precision')))
3181
+ code = currency['code']
3182
+ self.currencies[code]['networks'][networkCode]['precision'] = precision
3183
+
3184
+ def parse_transaction_status(self, status: Str):
3185
+ statuses: dict = {
3186
+ 'SUCCESS': 'ok',
3187
+ 'PROCESSING': 'pending',
3188
+ 'WALLET_PROCESSING': 'pending',
3189
+ 'FAILURE': 'failed',
3190
+ }
3191
+ return self.safe_string(statuses, status, status)
3192
+
3193
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
3194
+ #
3195
+ # fetchDeposits
3196
+ #
3197
+ # {
3198
+ # "address": "0x5f047b29041bcfdbf0e4478cdfa753a336ba6989",
3199
+ # "memo": "5c247c8a03aa677cea2a251d",
3200
+ # "amount": 1,
3201
+ # "fee": 0.0001,
3202
+ # "currency": "KCS",
3203
+ # "chain": "",
3204
+ # "isInner": False,
3205
+ # "walletTxId": "5bbb57386d99522d9f954c5a@test004",
3206
+ # "status": "SUCCESS",
3207
+ # "createdAt": 1544178843000,
3208
+ # "updatedAt": 1544178891000
3209
+ # "remark":"foobar"
3210
+ # }
3211
+ #
3212
+ # fetchWithdrawals
3213
+ #
3214
+ # {
3215
+ # "id": "5c2dc64e03aa675aa263f1ac",
3216
+ # "address": "0x5bedb060b8eb8d823e2414d82acce78d38be7fe9",
3217
+ # "memo": "",
3218
+ # "currency": "ETH",
3219
+ # "chain": "",
3220
+ # "amount": 1.0000000,
3221
+ # "fee": 0.0100000,
3222
+ # "walletTxId": "3e2414d82acce78d38be7fe9",
3223
+ # "isInner": False,
3224
+ # "status": "FAILURE",
3225
+ # "createdAt": 1546503758000,
3226
+ # "updatedAt": 1546504603000
3227
+ # "remark":"foobar"
3228
+ # }
3229
+ #
3230
+ # withdraw
3231
+ #
3232
+ # {
3233
+ # "withdrawalId": "5bffb63303aa675e8bbe18f9"
3234
+ # }
3235
+ #
3236
+ currencyId = self.safe_string(transaction, 'currency')
3237
+ code = self.safe_currency_code(currencyId, currency)
3238
+ address = self.safe_string(transaction, 'address')
3239
+ amount = self.safe_string(transaction, 'amount')
3240
+ txid = self.safe_string(transaction, 'walletTxId')
3241
+ if txid is not None:
3242
+ txidParts = txid.split('@')
3243
+ numTxidParts = len(txidParts)
3244
+ if numTxidParts > 1:
3245
+ if address is None:
3246
+ if len(txidParts[1]) > 1:
3247
+ address = txidParts[1]
3248
+ txid = txidParts[0]
3249
+ type = 'withdrawal' if (txid is None) else 'deposit'
3250
+ rawStatus = self.safe_string(transaction, 'status')
3251
+ fee = None
3252
+ feeCost = self.safe_string(transaction, 'fee')
3253
+ if feeCost is not None:
3254
+ rate = None
3255
+ if amount is not None:
3256
+ rate = Precise.string_div(feeCost, amount)
3257
+ fee = {
3258
+ 'cost': self.parse_number(feeCost),
3259
+ 'rate': self.parse_number(rate),
3260
+ 'currency': code,
3261
+ }
3262
+ timestamp = self.safe_integer_2(transaction, 'createdAt', 'createAt')
3263
+ updated = self.safe_integer(transaction, 'updatedAt')
3264
+ isV1 = not ('createdAt' in transaction)
3265
+ # if it's a v1 structure
3266
+ if isV1:
3267
+ type = 'withdrawal' if ('address' in transaction) else 'deposit'
3268
+ if timestamp is not None:
3269
+ timestamp = timestamp * 1000
3270
+ if updated is not None:
3271
+ updated = updated * 1000
3272
+ internal = self.safe_bool(transaction, 'isInner')
3273
+ tag = self.safe_string(transaction, 'memo')
3274
+ return {
3275
+ 'info': transaction,
3276
+ 'id': self.safe_string_2(transaction, 'id', 'withdrawalId'),
3277
+ 'timestamp': timestamp,
3278
+ 'datetime': self.iso8601(timestamp),
3279
+ 'network': self.network_id_to_code(self.safe_string(transaction, 'chain')),
3280
+ 'address': address,
3281
+ 'addressTo': address,
3282
+ 'addressFrom': None,
3283
+ 'tag': tag,
3284
+ 'tagTo': tag,
3285
+ 'tagFrom': None,
3286
+ 'currency': code,
3287
+ 'amount': self.parse_number(amount),
3288
+ 'txid': txid,
3289
+ 'type': type,
3290
+ 'status': self.parse_transaction_status(rawStatus),
3291
+ 'comment': self.safe_string(transaction, 'remark'),
3292
+ 'internal': internal,
3293
+ 'fee': fee,
3294
+ 'updated': updated,
3295
+ }
3296
+
3297
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3298
+ """
3299
+ fetch all deposits made to an account
3300
+ :see: https://www.kucoin.com/docs/rest/funding/deposit/get-deposit-list
3301
+ :see: https://www.kucoin.com/docs/rest/funding/deposit/get-v1-historical-deposits-list
3302
+ :param str code: unified currency code
3303
+ :param int [since]: the earliest time in ms to fetch deposits for
3304
+ :param int [limit]: the maximum number of deposits structures to retrieve
3305
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3306
+ :param int [params.until]: the latest time in ms to fetch entries for
3307
+ :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)
3308
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3309
+ """
3310
+ await self.load_markets()
3311
+ paginate = False
3312
+ paginate, params = self.handle_option_and_params(params, 'fetchDeposits', 'paginate')
3313
+ if paginate:
3314
+ return await self.fetch_paginated_call_dynamic('fetchDeposits', code, since, limit, params)
3315
+ request: dict = {}
3316
+ currency = None
3317
+ if code is not None:
3318
+ currency = self.currency(code)
3319
+ request['currency'] = currency['id']
3320
+ if limit is not None:
3321
+ request['pageSize'] = limit
3322
+ request, params = self.handle_until_option('endAt', request, params)
3323
+ response = None
3324
+ if since is not None and since < 1550448000000:
3325
+ # if since is earlier than 2019-02-18T00:00:00Z
3326
+ request['startAt'] = self.parse_to_int(since / 1000)
3327
+ response = await self.privateGetHistDeposits(self.extend(request, params))
3328
+ else:
3329
+ if since is not None:
3330
+ request['startAt'] = since
3331
+ response = await self.privateGetDeposits(self.extend(request, params))
3332
+ #
3333
+ # {
3334
+ # "code": "200000",
3335
+ # "data": {
3336
+ # "currentPage": 1,
3337
+ # "pageSize": 5,
3338
+ # "totalNum": 2,
3339
+ # "totalPage": 1,
3340
+ # "items": [
3341
+ # #--------------------------------------------------
3342
+ # # version 2 deposit response structure
3343
+ # {
3344
+ # "address": "0x5f047b29041bcfdbf0e4478cdfa753a336ba6989",
3345
+ # "memo": "5c247c8a03aa677cea2a251d",
3346
+ # "amount": 1,
3347
+ # "fee": 0.0001,
3348
+ # "currency": "KCS",
3349
+ # "isInner": False,
3350
+ # "walletTxId": "5bbb57386d99522d9f954c5a@test004",
3351
+ # "status": "SUCCESS",
3352
+ # "createdAt": 1544178843000,
3353
+ # "updatedAt": 1544178891000
3354
+ # "remark":"foobar"
3355
+ # },
3356
+ # #--------------------------------------------------
3357
+ # # version 1(historical) deposit response structure
3358
+ # {
3359
+ # "currency": "BTC",
3360
+ # "createAt": 1528536998,
3361
+ # "amount": "0.03266638",
3362
+ # "walletTxId": "55c643bc2c68d6f17266383ac1be9e454038864b929ae7cee0bc408cc5c869e8@12ffGWmMMD1zA1WbFm7Ho3JZ1w6NYXjpFk@234",
3363
+ # "isInner": False,
3364
+ # "status": "SUCCESS",
3365
+ # }
3366
+ # ]
3367
+ # }
3368
+ # }
3369
+ #
3370
+ responseData = response['data']['items']
3371
+ return self.parse_transactions(responseData, currency, since, limit, {'type': 'deposit'})
3372
+
3373
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3374
+ """
3375
+ fetch all withdrawals made from an account
3376
+ :see: https://www.kucoin.com/docs/rest/funding/withdrawals/get-withdrawals-list
3377
+ :see: https://www.kucoin.com/docs/rest/funding/withdrawals/get-v1-historical-withdrawals-list
3378
+ :param str code: unified currency code
3379
+ :param int [since]: the earliest time in ms to fetch withdrawals for
3380
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
3381
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3382
+ :param int [params.until]: the latest time in ms to fetch entries for
3383
+ :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)
3384
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3385
+ """
3386
+ await self.load_markets()
3387
+ paginate = False
3388
+ paginate, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'paginate')
3389
+ if paginate:
3390
+ return await self.fetch_paginated_call_dynamic('fetchWithdrawals', code, since, limit, params)
3391
+ request: dict = {}
3392
+ currency = None
3393
+ if code is not None:
3394
+ currency = self.currency(code)
3395
+ request['currency'] = currency['id']
3396
+ if limit is not None:
3397
+ request['pageSize'] = limit
3398
+ request, params = self.handle_until_option('endAt', request, params)
3399
+ response = None
3400
+ if since is not None and since < 1550448000000:
3401
+ # if since is earlier than 2019-02-18T00:00:00Z
3402
+ request['startAt'] = self.parse_to_int(since / 1000)
3403
+ response = await self.privateGetHistWithdrawals(self.extend(request, params))
3404
+ else:
3405
+ if since is not None:
3406
+ request['startAt'] = since
3407
+ response = await self.privateGetWithdrawals(self.extend(request, params))
3408
+ #
3409
+ # {
3410
+ # "code": "200000",
3411
+ # "data": {
3412
+ # "currentPage": 1,
3413
+ # "pageSize": 5,
3414
+ # "totalNum": 2,
3415
+ # "totalPage": 1,
3416
+ # "items": [
3417
+ # #--------------------------------------------------
3418
+ # # version 2 withdrawal response structure
3419
+ # {
3420
+ # "id": "5c2dc64e03aa675aa263f1ac",
3421
+ # "address": "0x5bedb060b8eb8d823e2414d82acce78d38be7fe9",
3422
+ # "memo": "",
3423
+ # "currency": "ETH",
3424
+ # "amount": 1.0000000,
3425
+ # "fee": 0.0100000,
3426
+ # "walletTxId": "3e2414d82acce78d38be7fe9",
3427
+ # "isInner": False,
3428
+ # "status": "FAILURE",
3429
+ # "createdAt": 1546503758000,
3430
+ # "updatedAt": 1546504603000
3431
+ # },
3432
+ # #--------------------------------------------------
3433
+ # # version 1(historical) withdrawal response structure
3434
+ # {
3435
+ # "currency": "BTC",
3436
+ # "createAt": 1526723468,
3437
+ # "amount": "0.534",
3438
+ # "address": "33xW37ZSW4tQvg443Pc7NLCAs167Yc2XUV",
3439
+ # "walletTxId": "aeacea864c020acf58e51606169240e96774838dcd4f7ce48acf38e3651323f4",
3440
+ # "isInner": False,
3441
+ # "status": "SUCCESS"
3442
+ # }
3443
+ # ]
3444
+ # }
3445
+ # }
3446
+ #
3447
+ responseData = response['data']['items']
3448
+ return self.parse_transactions(responseData, currency, since, limit, {'type': 'withdrawal'})
3449
+
3450
+ def parse_balance_helper(self, entry):
3451
+ account = self.account()
3452
+ account['used'] = self.safe_string_2(entry, 'holdBalance', 'hold')
3453
+ account['free'] = self.safe_string_2(entry, 'availableBalance', 'available')
3454
+ account['total'] = self.safe_string_2(entry, 'totalBalance', 'total')
3455
+ debt = self.safe_string(entry, 'liability')
3456
+ interest = self.safe_string(entry, 'interest')
3457
+ account['debt'] = Precise.string_add(debt, interest)
3458
+ return account
3459
+
3460
+ async def fetch_balance(self, params={}) -> Balances:
3461
+ """
3462
+ query for balance and get the amount of funds available for trading or funds locked in orders
3463
+ :see: https://www.kucoin.com/docs/rest/account/basic-info/get-account-list-spot-margin-trade_hf
3464
+ :see: https://www.kucoin.com/docs/rest/funding/funding-overview/get-account-detail-margin
3465
+ :see: https://www.kucoin.com/docs/rest/funding/funding-overview/get-account-detail-isolated-margin
3466
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3467
+ :param dict [params.marginMode]: 'cross' or 'isolated', margin type for fetching margin balance
3468
+ :param dict [params.type]: extra parameters specific to the exchange API endpoint
3469
+ :param dict [params.hf]: *default if False* if True, the result includes the balance of the high frequency account
3470
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
3471
+ """
3472
+ await self.load_markets()
3473
+ code = self.safe_string(params, 'code')
3474
+ currency = None
3475
+ if code is not None:
3476
+ currency = self.currency(code)
3477
+ defaultType = self.safe_string_2(self.options, 'fetchBalance', 'defaultType', 'spot')
3478
+ requestedType = self.safe_string(params, 'type', defaultType)
3479
+ accountsByType = self.safe_dict(self.options, 'accountsByType')
3480
+ type = self.safe_string(accountsByType, requestedType, requestedType)
3481
+ params = self.omit(params, 'type')
3482
+ isHf = self.safe_bool(params, 'hf', False)
3483
+ if isHf:
3484
+ type = 'trade_hf'
3485
+ params = self.omit(params, 'hf')
3486
+ marginMode, query = self.handle_margin_mode_and_params('fetchBalance', params)
3487
+ response = None
3488
+ request: dict = {}
3489
+ isolated = (marginMode == 'isolated') or (type == 'isolated')
3490
+ cross = (marginMode == 'cross') or (type == 'margin')
3491
+ if isolated:
3492
+ if currency is not None:
3493
+ request['balanceCurrency'] = currency['id']
3494
+ response = await self.privateGetIsolatedAccounts(self.extend(request, query))
3495
+ elif cross:
3496
+ response = await self.privateGetMarginAccount(self.extend(request, query))
3497
+ else:
3498
+ if currency is not None:
3499
+ request['currency'] = currency['id']
3500
+ request['type'] = type
3501
+ response = await self.privateGetAccounts(self.extend(request, query))
3502
+ #
3503
+ # Spot
3504
+ #
3505
+ # {
3506
+ # "code": "200000",
3507
+ # "data": [
3508
+ # {
3509
+ # "balance": "0.00009788",
3510
+ # "available": "0.00009788",
3511
+ # "holds": "0",
3512
+ # "currency": "BTC",
3513
+ # "id": "5c6a4fd399a1d81c4f9cc4d0",
3514
+ # "type": "trade",
3515
+ # },
3516
+ # ]
3517
+ # }
3518
+ #
3519
+ # Cross
3520
+ #
3521
+ # {
3522
+ # "code": "200000",
3523
+ # "data": {
3524
+ # "debtRatio": "0",
3525
+ # "accounts": [
3526
+ # {
3527
+ # "currency": "USDT",
3528
+ # "totalBalance": "5",
3529
+ # "availableBalance": "5",
3530
+ # "holdBalance": "0",
3531
+ # "liability": "0",
3532
+ # "maxBorrowSize": "20"
3533
+ # },
3534
+ # ]
3535
+ # }
3536
+ # }
3537
+ #
3538
+ # Isolated
3539
+ #
3540
+ # {
3541
+ # "code": "200000",
3542
+ # "data": {
3543
+ # "totalAssetOfQuoteCurrency": "0",
3544
+ # "totalLiabilityOfQuoteCurrency": "0",
3545
+ # "timestamp": 1712085661155,
3546
+ # "assets": [
3547
+ # {
3548
+ # "symbol": "MANA-USDT",
3549
+ # "status": "EFFECTIVE",
3550
+ # "debtRatio": "0",
3551
+ # "baseAsset": {
3552
+ # "currency": "MANA",
3553
+ # "borrowEnabled": True,
3554
+ # "transferInEnabled": True,
3555
+ # "total": "0",
3556
+ # "hold": "0",
3557
+ # "available": "0",
3558
+ # "liability": "0",
3559
+ # "interest": "0",
3560
+ # "maxBorrowSize": "0"
3561
+ # },
3562
+ # "quoteAsset": {
3563
+ # "currency": "USDT",
3564
+ # "borrowEnabled": True,
3565
+ # "transferInEnabled": True,
3566
+ # "total": "0",
3567
+ # "hold": "0",
3568
+ # "available": "0",
3569
+ # "liability": "0",
3570
+ # "interest": "0",
3571
+ # "maxBorrowSize": "0"
3572
+ # }
3573
+ # },
3574
+ # ...
3575
+ # ]
3576
+ # }
3577
+ # }
3578
+ #
3579
+ data = None
3580
+ result: dict = {
3581
+ 'info': response,
3582
+ 'timestamp': None,
3583
+ 'datetime': None,
3584
+ }
3585
+ if isolated:
3586
+ data = self.safe_dict(response, 'data', {})
3587
+ assets = self.safe_value(data, 'assets', data)
3588
+ for i in range(0, len(assets)):
3589
+ entry = assets[i]
3590
+ marketId = self.safe_string(entry, 'symbol')
3591
+ symbol = self.safe_symbol(marketId, None, '_')
3592
+ base = self.safe_dict(entry, 'baseAsset', {})
3593
+ quote = self.safe_dict(entry, 'quoteAsset', {})
3594
+ baseCode = self.safe_currency_code(self.safe_string(base, 'currency'))
3595
+ quoteCode = self.safe_currency_code(self.safe_string(quote, 'currency'))
3596
+ subResult: dict = {}
3597
+ subResult[baseCode] = self.parse_balance_helper(base)
3598
+ subResult[quoteCode] = self.parse_balance_helper(quote)
3599
+ result[symbol] = self.safe_balance(subResult)
3600
+ elif cross:
3601
+ data = self.safe_dict(response, 'data', {})
3602
+ accounts = self.safe_list(data, 'accounts', [])
3603
+ for i in range(0, len(accounts)):
3604
+ balance = accounts[i]
3605
+ currencyId = self.safe_string(balance, 'currency')
3606
+ codeInner = self.safe_currency_code(currencyId)
3607
+ result[codeInner] = self.parse_balance_helper(balance)
3608
+ else:
3609
+ data = self.safe_list(response, 'data', [])
3610
+ for i in range(0, len(data)):
3611
+ balance = data[i]
3612
+ balanceType = self.safe_string(balance, 'type')
3613
+ if balanceType == type:
3614
+ currencyId = self.safe_string(balance, 'currency')
3615
+ codeInner2 = self.safe_currency_code(currencyId)
3616
+ account = self.account()
3617
+ account['total'] = self.safe_string(balance, 'balance')
3618
+ account['free'] = self.safe_string(balance, 'available')
3619
+ account['used'] = self.safe_string(balance, 'holds')
3620
+ result[codeInner2] = account
3621
+ returnType = result if isolated else self.safe_balance(result)
3622
+ return returnType
3623
+
3624
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
3625
+ """
3626
+ transfer currency internally between wallets on the same account
3627
+ :see: https://www.kucoin.com/docs/rest/funding/transfer/inner-transfer
3628
+ :see: https://docs.kucoin.com/futures/#transfer-funds-to-kucoin-main-account-2
3629
+ :see: https://docs.kucoin.com/spot-hf/#internal-funds-transfers-in-high-frequency-trading-accounts
3630
+ :param str code: unified currency code
3631
+ :param float amount: amount to transfer
3632
+ :param str fromAccount: account to transfer from
3633
+ :param str toAccount: account to transfer to
3634
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3635
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
3636
+ """
3637
+ await self.load_markets()
3638
+ currency = self.currency(code)
3639
+ requestedAmount = self.currency_to_precision(code, amount)
3640
+ fromId = self.convert_type_to_account(fromAccount)
3641
+ toId = self.convert_type_to_account(toAccount)
3642
+ fromIsolated = self.in_array(fromId, self.ids)
3643
+ toIsolated = self.in_array(toId, self.ids)
3644
+ if fromId == 'contract':
3645
+ if toId != 'main':
3646
+ raise ExchangeError(self.id + ' transfer() only supports transferring from futures account to main account')
3647
+ request: dict = {
3648
+ 'currency': currency['id'],
3649
+ 'amount': requestedAmount,
3650
+ }
3651
+ if not ('bizNo' in params):
3652
+ # it doesn't like more than 24 characters
3653
+ request['bizNo'] = self.uuid22()
3654
+ response = await self.futuresPrivatePostTransferOut(self.extend(request, params))
3655
+ #
3656
+ # {
3657
+ # "code": "200000",
3658
+ # "data": {
3659
+ # "applyId": "605a87217dff1500063d485d",
3660
+ # "bizNo": "bcd6e5e1291f4905af84dc",
3661
+ # "payAccountType": "CONTRACT",
3662
+ # "payTag": "DEFAULT",
3663
+ # "remark": '',
3664
+ # "recAccountType": "MAIN",
3665
+ # "recTag": "DEFAULT",
3666
+ # "recRemark": '',
3667
+ # "recSystem": "KUCOIN",
3668
+ # "status": "PROCESSING",
3669
+ # "currency": "XBT",
3670
+ # "amount": "0.00001",
3671
+ # "fee": "0",
3672
+ # "sn": "573688685663948",
3673
+ # "reason": '',
3674
+ # "createdAt": 1616545569000,
3675
+ # "updatedAt": 1616545569000
3676
+ # }
3677
+ # }
3678
+ #
3679
+ data = self.safe_dict(response, 'data')
3680
+ return self.parse_transfer(data, currency)
3681
+ else:
3682
+ request: dict = {
3683
+ 'currency': currency['id'],
3684
+ 'amount': requestedAmount,
3685
+ }
3686
+ if fromIsolated or toIsolated:
3687
+ if self.in_array(fromId, self.ids):
3688
+ request['fromTag'] = fromId
3689
+ fromId = 'isolated'
3690
+ if self.in_array(toId, self.ids):
3691
+ request['toTag'] = toId
3692
+ toId = 'isolated'
3693
+ request['from'] = fromId
3694
+ request['to'] = toId
3695
+ if not ('clientOid' in params):
3696
+ request['clientOid'] = self.uuid()
3697
+ response = await self.privatePostAccountsInnerTransfer(self.extend(request, params))
3698
+ #
3699
+ # {
3700
+ # "code": "200000",
3701
+ # "data": {
3702
+ # "orderId": "605a6211e657f00006ad0ad6"
3703
+ # }
3704
+ # }
3705
+ #
3706
+ data = self.safe_dict(response, 'data')
3707
+ return self.parse_transfer(data, currency)
3708
+
3709
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
3710
+ #
3711
+ # transfer(spot)
3712
+ #
3713
+ # {
3714
+ # "orderId": "605a6211e657f00006ad0ad6"
3715
+ # }
3716
+ #
3717
+ # {
3718
+ # "code": "200000",
3719
+ # "msg": "Failed to transfer out. The amount exceeds the upper limit"
3720
+ # }
3721
+ #
3722
+ # transfer(futures)
3723
+ #
3724
+ # {
3725
+ # "applyId": "605a87217dff1500063d485d",
3726
+ # "bizNo": "bcd6e5e1291f4905af84dc",
3727
+ # "payAccountType": "CONTRACT",
3728
+ # "payTag": "DEFAULT",
3729
+ # "remark": '',
3730
+ # "recAccountType": "MAIN",
3731
+ # "recTag": "DEFAULT",
3732
+ # "recRemark": '',
3733
+ # "recSystem": "KUCOIN",
3734
+ # "status": "PROCESSING",
3735
+ # "currency": "XBT",
3736
+ # "amount": "0.00001",
3737
+ # "fee": "0",
3738
+ # "sn": "573688685663948",
3739
+ # "reason": '',
3740
+ # "createdAt": 1616545569000,
3741
+ # "updatedAt": 1616545569000
3742
+ # }
3743
+ #
3744
+ timestamp = self.safe_integer(transfer, 'createdAt')
3745
+ currencyId = self.safe_string(transfer, 'currency')
3746
+ rawStatus = self.safe_string(transfer, 'status')
3747
+ accountFromRaw = self.safe_string_lower(transfer, 'payAccountType')
3748
+ accountToRaw = self.safe_string_lower(transfer, 'recAccountType')
3749
+ accountsByType = self.safe_dict(self.options, 'accountsByType')
3750
+ accountFrom = self.safe_string(accountsByType, accountFromRaw, accountFromRaw)
3751
+ accountTo = self.safe_string(accountsByType, accountToRaw, accountToRaw)
3752
+ return {
3753
+ 'id': self.safe_string_2(transfer, 'applyId', 'orderId'),
3754
+ 'currency': self.safe_currency_code(currencyId, currency),
3755
+ 'timestamp': timestamp,
3756
+ 'datetime': self.iso8601(timestamp),
3757
+ 'amount': self.safe_number(transfer, 'amount'),
3758
+ 'fromAccount': accountFrom,
3759
+ 'toAccount': accountTo,
3760
+ 'status': self.parse_transfer_status(rawStatus),
3761
+ 'info': transfer,
3762
+ }
3763
+
3764
+ def parse_transfer_status(self, status: Str) -> Str:
3765
+ statuses: dict = {
3766
+ 'PROCESSING': 'pending',
3767
+ }
3768
+ return self.safe_string(statuses, status, status)
3769
+
3770
+ def parse_ledger_entry_type(self, type):
3771
+ types: dict = {
3772
+ 'Assets Transferred in After Upgrading': 'transfer', # Assets Transferred in After V1 to V2 Upgrading
3773
+ 'Deposit': 'transaction', # Deposit
3774
+ 'Withdrawal': 'transaction', # Withdrawal
3775
+ 'Transfer': 'transfer', # Transfer
3776
+ 'Trade_Exchange': 'trade', # Trade
3777
+ # 'Vote for Coin': 'Vote for Coin', # Vote for Coin
3778
+ 'KuCoin Bonus': 'bonus', # KuCoin Bonus
3779
+ 'Referral Bonus': 'referral', # Referral Bonus
3780
+ 'Rewards': 'bonus', # Activities Rewards
3781
+ # 'Distribution': 'Distribution', # Distribution, such GAS by holding NEO
3782
+ 'Airdrop/Fork': 'airdrop', # Airdrop/Fork
3783
+ 'Other rewards': 'bonus', # Other rewards, except Vote, Airdrop, Fork
3784
+ 'Fee Rebate': 'rebate', # Fee Rebate
3785
+ 'Buy Crypto': 'trade', # Use credit card to buy crypto
3786
+ 'Sell Crypto': 'sell', # Use credit card to sell crypto
3787
+ 'Public Offering Purchase': 'trade', # Public Offering Purchase for Spotlight
3788
+ # 'Send red envelope': 'Send red envelope', # Send red envelope
3789
+ # 'Open red envelope': 'Open red envelope', # Open red envelope
3790
+ # 'Staking': 'Staking', # Staking
3791
+ # 'LockDrop Vesting': 'LockDrop Vesting', # LockDrop Vesting
3792
+ # 'Staking Profits': 'Staking Profits', # Staking Profits
3793
+ # 'Redemption': 'Redemption', # Redemption
3794
+ 'Refunded Fees': 'fee', # Refunded Fees
3795
+ 'KCS Pay Fees': 'fee', # KCS Pay Fees
3796
+ 'Margin Trade': 'trade', # Margin Trade
3797
+ 'Loans': 'Loans', # Loans
3798
+ # 'Borrowings': 'Borrowings', # Borrowings
3799
+ # 'Debt Repayment': 'Debt Repayment', # Debt Repayment
3800
+ # 'Loans Repaid': 'Loans Repaid', # Loans Repaid
3801
+ # 'Lendings': 'Lendings', # Lendings
3802
+ # 'Pool transactions': 'Pool transactions', # Pool-X transactions
3803
+ 'Instant Exchange': 'trade', # Instant Exchange
3804
+ 'Sub-account transfer': 'transfer', # Sub-account transfer
3805
+ 'Liquidation Fees': 'fee', # Liquidation Fees
3806
+ # 'Soft Staking Profits': 'Soft Staking Profits', # Soft Staking Profits
3807
+ # 'Voting Earnings': 'Voting Earnings', # Voting Earnings on Pool-X
3808
+ # 'Redemption of Voting': 'Redemption of Voting', # Redemption of Voting on Pool-X
3809
+ # 'Voting': 'Voting', # Voting on Pool-X
3810
+ # 'Convert to KCS': 'Convert to KCS', # Convert to KCS
3811
+ }
3812
+ return self.safe_string(types, type, type)
3813
+
3814
+ def parse_ledger_entry(self, item: dict, currency: Currency = None):
3815
+ #
3816
+ # {
3817
+ # "id": "611a1e7c6a053300067a88d9", #unique key for each ledger entry
3818
+ # "currency": "USDT", #Currency
3819
+ # "amount": "10.00059547", #The total amount of assets(fees included) involved in assets changes such, withdrawal and bonus distribution.
3820
+ # "fee": "0", #Deposit or withdrawal fee
3821
+ # "balance": "0", #Total assets of a currency remaining funds after transaction
3822
+ # "accountType": "MAIN", #Account Type
3823
+ # "bizType": "Loans Repaid", #business type
3824
+ # "direction": "in", #side, in or out
3825
+ # "createdAt": 1629101692950, #Creation time
3826
+ # "context": "{\"borrowerUserId\":\"601ad03e50dc810006d242ea\",\"loanRepayDetailNo\":\"611a1e7cc913d000066cf7ec\"}" #Business core parameters
3827
+ # }
3828
+ #
3829
+ id = self.safe_string(item, 'id')
3830
+ currencyId = self.safe_string(item, 'currency')
3831
+ code = self.safe_currency_code(currencyId, currency)
3832
+ amount = self.safe_number(item, 'amount')
3833
+ balanceAfter = None
3834
+ # balanceAfter = self.safe_number(item, 'balance'); only returns zero string
3835
+ bizType = self.safe_string(item, 'bizType')
3836
+ type = self.parse_ledger_entry_type(bizType)
3837
+ direction = self.safe_string(item, 'direction')
3838
+ timestamp = self.safe_integer(item, 'createdAt')
3839
+ datetime = self.iso8601(timestamp)
3840
+ account = self.safe_string(item, 'accountType') # MAIN, TRADE, MARGIN, or CONTRACT
3841
+ context = self.safe_string(item, 'context') # contains other information about the ledger entry
3842
+ #
3843
+ # withdrawal transaction
3844
+ #
3845
+ # "{\"orderId\":\"617bb2d09e7b3b000196dac8\",\"txId\":\"0x79bb9855f86b351a45cab4dc69d78ca09586a94c45dde49475722b98f401b054\"}"
3846
+ #
3847
+ # deposit to MAIN, trade via MAIN
3848
+ #
3849
+ # "{\"orderId\":\"617ab9949e7b3b0001948081\",\"txId\":\"0x7a06b16bbd6b03dbc3d96df5683b15229fc35e7184fd7179a5f3a310bd67d1fa@default@0\"}"
3850
+ #
3851
+ # sell trade
3852
+ #
3853
+ # "{\"symbol\":\"ETH-USDT\",\"orderId\":\"617adcd1eb3fa20001dd29a1\",\"tradeId\":\"617adcd12e113d2b91222ff9\"}"
3854
+ #
3855
+ referenceId = None
3856
+ if context is not None and context != '':
3857
+ try:
3858
+ parsed = json.loads(context)
3859
+ orderId = self.safe_string(parsed, 'orderId')
3860
+ tradeId = self.safe_string(parsed, 'tradeId')
3861
+ # transactions only have an orderId but for trades we wish to use tradeId
3862
+ if tradeId is not None:
3863
+ referenceId = tradeId
3864
+ else:
3865
+ referenceId = orderId
3866
+ except Exception as exc:
3867
+ referenceId = context
3868
+ fee = None
3869
+ feeCost = self.safe_string(item, 'fee')
3870
+ feeCurrency = None
3871
+ if feeCost != '0':
3872
+ feeCurrency = code
3873
+ fee = {'cost': self.parse_number(feeCost), 'currency': feeCurrency}
3874
+ return {
3875
+ 'id': id,
3876
+ 'direction': direction,
3877
+ 'account': account,
3878
+ 'referenceId': referenceId,
3879
+ 'referenceAccount': account,
3880
+ 'type': type,
3881
+ 'currency': code,
3882
+ 'amount': amount,
3883
+ 'timestamp': timestamp,
3884
+ 'datetime': datetime,
3885
+ 'before': None,
3886
+ 'after': balanceAfter, # None
3887
+ 'status': None,
3888
+ 'fee': fee,
3889
+ 'info': item,
3890
+ }
3891
+
3892
+ async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
3893
+ """
3894
+ :see: https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-spot-margin
3895
+ :see: https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-trade_hf
3896
+ :see: https://www.kucoin.com/docs/rest/account/basic-info/get-account-ledgers-margin_hf
3897
+ fetch the history of changes, actions done by the user or operations that altered balance of the user
3898
+ :param str code: unified currency code, default is None
3899
+ :param int [since]: timestamp in ms of the earliest ledger entry, default is None
3900
+ :param int [limit]: max number of ledger entrys to return, default is None
3901
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3902
+ :param boolean [params.hf]: default False, when True will fetch ledger entries for the high frequency trading account
3903
+ :param int [params.until]: the latest time in ms to fetch entries for
3904
+ :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)
3905
+ :returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
3906
+ """
3907
+ await self.load_markets()
3908
+ await self.load_accounts()
3909
+ paginate = False
3910
+ paginate, params = self.handle_option_and_params(params, 'fetchLedger', 'paginate')
3911
+ isHf = self.safe_bool(params, 'hf')
3912
+ params = self.omit(params, 'hf')
3913
+ if paginate:
3914
+ return await self.fetch_paginated_call_dynamic('fetchLedger', code, since, limit, params)
3915
+ request: dict = {
3916
+ # 'currency': currency['id'], # can choose up to 10, if not provided returns for all currencies by default
3917
+ # 'direction': 'in', # 'out'
3918
+ # 'bizType': 'DEPOSIT', # DEPOSIT, WITHDRAW, TRANSFER, SUB_TRANSFER,TRADE_EXCHANGE, MARGIN_EXCHANGE, KUCOIN_BONUS(optional)
3919
+ # 'startAt': since,
3920
+ # 'endAt': exchange.milliseconds(),
3921
+ }
3922
+ if since is not None:
3923
+ request['startAt'] = since
3924
+ # atm only single currency retrieval is supported
3925
+ currency = None
3926
+ if code is not None:
3927
+ currency = self.currency(code)
3928
+ request['currency'] = currency['id']
3929
+ request, params = self.handle_until_option('endAt', request, params)
3930
+ marginMode = None
3931
+ marginMode, params = self.handle_margin_mode_and_params('fetchLedger', params)
3932
+ response = None
3933
+ if isHf:
3934
+ if marginMode is not None:
3935
+ response = await self.privateGetHfMarginAccountLedgers(self.extend(request, params))
3936
+ else:
3937
+ response = await self.privateGetHfAccountsLedgers(self.extend(request, params))
3938
+ else:
3939
+ response = await self.privateGetAccountsLedgers(self.extend(request, params))
3940
+ #
3941
+ # {
3942
+ # "code":"200000",
3943
+ # "data":{
3944
+ # "currentPage":1,
3945
+ # "pageSize":50,
3946
+ # "totalNum":1,
3947
+ # "totalPage":1,
3948
+ # "items":[
3949
+ # {
3950
+ # "id":"617cc528729f5f0001c03ceb",
3951
+ # "currency":"GAS",
3952
+ # "amount":"0.00000339",
3953
+ # "fee":"0",
3954
+ # "balance":"0",
3955
+ # "accountType":"MAIN",
3956
+ # "bizType":"Distribution",
3957
+ # "direction":"in",
3958
+ # "createdAt":1635566888183,
3959
+ # "context":"{\"orderId\":\"617cc47a1c47ed0001ce3606\",\"description\":\"Holding NEO,distribute GAS(2021/10/30)\"}"
3960
+ # }
3961
+ # {
3962
+ # "id": "611a1e7c6a053300067a88d9",//unique key
3963
+ # "currency": "USDT", #Currency
3964
+ # "amount": "10.00059547", #Change amount of the funds
3965
+ # "fee": "0", #Deposit or withdrawal fee
3966
+ # "balance": "0", #Total assets of a currency
3967
+ # "accountType": "MAIN", #Account Type
3968
+ # "bizType": "Loans Repaid", #business type
3969
+ # "direction": "in", #side, in or out
3970
+ # "createdAt": 1629101692950, #Creation time
3971
+ # "context": "{\"borrowerUserId\":\"601ad03e50dc810006d242ea\",\"loanRepayDetailNo\":\"611a1e7cc913d000066cf7ec\"}"
3972
+ # },
3973
+ # ]
3974
+ # }
3975
+ # }
3976
+ #
3977
+ dataList = self.safe_list(response, 'data')
3978
+ if dataList is not None:
3979
+ return self.parse_ledger(dataList, currency, since, limit)
3980
+ data = self.safe_dict(response, 'data')
3981
+ items = self.safe_list(data, 'items', [])
3982
+ return self.parse_ledger(items, currency, since, limit)
3983
+
3984
+ def calculate_rate_limiter_cost(self, api, method, path, params, config={}):
3985
+ versions = self.safe_dict(self.options, 'versions', {})
3986
+ apiVersions = self.safe_dict(versions, api, {})
3987
+ methodVersions = self.safe_dict(apiVersions, method, {})
3988
+ defaultVersion = self.safe_string(methodVersions, path, self.options['version'])
3989
+ version = self.safe_string(params, 'version', defaultVersion)
3990
+ if version == 'v3' and ('v3' in config):
3991
+ return config['v3']
3992
+ elif version == 'v2' and ('v2' in config):
3993
+ return config['v2']
3994
+ elif version == 'v1' and ('v1' in config):
3995
+ return config['v1']
3996
+ return self.safe_value(config, 'cost', 1)
3997
+
3998
+ def parse_borrow_rate_history(self, response, code, since, limit):
3999
+ result = []
4000
+ for i in range(0, len(response)):
4001
+ item = response[i]
4002
+ borrowRate = self.parse_borrow_rate(item)
4003
+ result.append(borrowRate)
4004
+ sorted = self.sort_by(result, 'timestamp')
4005
+ return self.filter_by_currency_since_limit(sorted, code, since, limit)
4006
+
4007
+ def parse_borrow_rate(self, info, currency: Currency = None):
4008
+ #
4009
+ # {
4010
+ # "tradeId": "62db2dcaff219600012b56cd",
4011
+ # "currency": "USDT",
4012
+ # "size": "10",
4013
+ # "dailyIntRate": "0.00003",
4014
+ # "term": 7,
4015
+ # "timestamp": 1658531274508488480
4016
+ # },
4017
+ #
4018
+ # {
4019
+ # "createdAt": 1697783812257,
4020
+ # "currency": "XMR",
4021
+ # "interestAmount": "0.1",
4022
+ # "dayRatio": "0.001"
4023
+ # }
4024
+ #
4025
+ timestampId = self.safe_string_2(info, 'createdAt', 'timestamp')
4026
+ timestamp = self.parse_to_int(timestampId[0:13])
4027
+ currencyId = self.safe_string(info, 'currency')
4028
+ return {
4029
+ 'currency': self.safe_currency_code(currencyId, currency),
4030
+ 'rate': self.safe_number_2(info, 'dailyIntRate', 'dayRatio'),
4031
+ 'period': 86400000,
4032
+ 'timestamp': timestamp,
4033
+ 'datetime': self.iso8601(timestamp),
4034
+ 'info': info,
4035
+ }
4036
+
4037
+ async def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4038
+ """
4039
+ fetch the interest owed by the user for borrowing currency for margin trading
4040
+ :see: https://docs.kucoin.com/#get-repay-record
4041
+ :see: https://docs.kucoin.com/#query-isolated-margin-account-info
4042
+ :param str code: unified currency code
4043
+ :param str symbol: unified market symbol, required for isolated margin
4044
+ :param int [since]: the earliest time in ms to fetch borrrow interest for
4045
+ :param int [limit]: the maximum number of structures to retrieve
4046
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4047
+ :param str [params.marginMode]: 'cross' or 'isolated' default is 'cross'
4048
+ :returns dict[]: a list of `borrow interest structures <https://docs.ccxt.com/#/?id=borrow-interest-structure>`
4049
+ """
4050
+ await self.load_markets()
4051
+ marginMode = None
4052
+ marginMode, params = self.handle_margin_mode_and_params('fetchBorrowInterest', params)
4053
+ if marginMode is None:
4054
+ marginMode = 'cross' # cross marginMode
4055
+ request: dict = {}
4056
+ response = None
4057
+ if code is not None:
4058
+ currency = self.currency(code)
4059
+ request['quoteCurrency'] = currency['id']
4060
+ if marginMode == 'isolated':
4061
+ response = await self.privateGetIsolatedAccounts(self.extend(request, params))
4062
+ else:
4063
+ response = await self.privateGetMarginAccounts(self.extend(request, params))
4064
+ #
4065
+ # Cross
4066
+ #
4067
+ # {
4068
+ # "code": "200000",
4069
+ # "data": {
4070
+ # "totalAssetOfQuoteCurrency": "0",
4071
+ # "totalLiabilityOfQuoteCurrency": "0",
4072
+ # "debtRatio": "0",
4073
+ # "status": "EFFECTIVE",
4074
+ # "accounts": [
4075
+ # {
4076
+ # "currency": "1INCH",
4077
+ # "total": "0",
4078
+ # "available": "0",
4079
+ # "hold": "0",
4080
+ # "liability": "0",
4081
+ # "maxBorrowSize": "0",
4082
+ # "borrowEnabled": True,
4083
+ # "transferInEnabled": True
4084
+ # }
4085
+ # ]
4086
+ # }
4087
+ # }
4088
+ #
4089
+ # Isolated
4090
+ #
4091
+ # {
4092
+ # "code": "200000",
4093
+ # "data": {
4094
+ # "totalConversionBalance": "0.02138647",
4095
+ # "liabilityConversionBalance": "0.01480001",
4096
+ # "assets": [
4097
+ # {
4098
+ # "symbol": "MANA-USDT",
4099
+ # "debtRatio": "0",
4100
+ # "status": "BORROW",
4101
+ # "baseAsset": {
4102
+ # "currency": "MANA",
4103
+ # "borrowEnabled": True,
4104
+ # "repayEnabled": True,
4105
+ # "transferEnabled": True,
4106
+ # "borrowed": "0",
4107
+ # "totalAsset": "0",
4108
+ # "available": "0",
4109
+ # "hold": "0",
4110
+ # "maxBorrowSize": "1000"
4111
+ # },
4112
+ # "quoteAsset": {
4113
+ # "currency": "USDT",
4114
+ # "borrowEnabled": True,
4115
+ # "repayEnabled": True,
4116
+ # "transferEnabled": True,
4117
+ # "borrowed": "0",
4118
+ # "totalAsset": "0",
4119
+ # "available": "0",
4120
+ # "hold": "0",
4121
+ # "maxBorrowSize": "50000"
4122
+ # }
4123
+ # }
4124
+ # ]
4125
+ # }
4126
+ # }
4127
+ #
4128
+ data = self.safe_dict(response, 'data', {})
4129
+ assets = self.safe_list(data, 'assets', []) if (marginMode == 'isolated') else self.safe_list(data, 'accounts', [])
4130
+ return self.parse_borrow_interests(assets, None)
4131
+
4132
+ def parse_borrow_interest(self, info: dict, market: Market = None):
4133
+ #
4134
+ # Cross
4135
+ #
4136
+ # {
4137
+ # "currency": "1INCH",
4138
+ # "total": "0",
4139
+ # "available": "0",
4140
+ # "hold": "0",
4141
+ # "liability": "0",
4142
+ # "maxBorrowSize": "0",
4143
+ # "borrowEnabled": True,
4144
+ # "transferInEnabled": True
4145
+ # }
4146
+ #
4147
+ # Isolated
4148
+ #
4149
+ # {
4150
+ # "symbol": "MANA-USDT",
4151
+ # "debtRatio": "0",
4152
+ # "status": "BORROW",
4153
+ # "baseAsset": {
4154
+ # "currency": "MANA",
4155
+ # "borrowEnabled": True,
4156
+ # "repayEnabled": True,
4157
+ # "transferEnabled": True,
4158
+ # "borrowed": "0",
4159
+ # "totalAsset": "0",
4160
+ # "available": "0",
4161
+ # "hold": "0",
4162
+ # "maxBorrowSize": "1000"
4163
+ # },
4164
+ # "quoteAsset": {
4165
+ # "currency": "USDT",
4166
+ # "borrowEnabled": True,
4167
+ # "repayEnabled": True,
4168
+ # "transferEnabled": True,
4169
+ # "borrowed": "0",
4170
+ # "totalAsset": "0",
4171
+ # "available": "0",
4172
+ # "hold": "0",
4173
+ # "maxBorrowSize": "50000"
4174
+ # }
4175
+ # }
4176
+ #
4177
+ marketId = self.safe_string(info, 'symbol')
4178
+ marginMode = 'cross' if (marketId is None) else 'isolated'
4179
+ market = self.safe_market(marketId, market)
4180
+ symbol = self.safe_string(market, 'symbol')
4181
+ timestamp = self.safe_integer(info, 'createdAt')
4182
+ isolatedBase = self.safe_dict(info, 'baseAsset', {})
4183
+ amountBorrowed = None
4184
+ interest = None
4185
+ currencyId = None
4186
+ if marginMode == 'isolated':
4187
+ amountBorrowed = self.safe_number(isolatedBase, 'liability')
4188
+ interest = self.safe_number(isolatedBase, 'interest')
4189
+ currencyId = self.safe_string(isolatedBase, 'currency')
4190
+ else:
4191
+ amountBorrowed = self.safe_number(info, 'liability')
4192
+ interest = self.safe_number(info, 'accruedInterest')
4193
+ currencyId = self.safe_string(info, 'currency')
4194
+ return {
4195
+ 'symbol': symbol,
4196
+ 'marginMode': marginMode,
4197
+ 'currency': self.safe_currency_code(currencyId),
4198
+ 'interest': interest,
4199
+ 'interestRate': self.safe_number(info, 'dailyIntRate'),
4200
+ 'amountBorrowed': amountBorrowed,
4201
+ 'timestamp': timestamp, # create time
4202
+ 'datetime': self.iso8601(timestamp),
4203
+ 'info': info,
4204
+ }
4205
+
4206
+ async def fetch_borrow_rate_histories(self, codes=None, since: Int = None, limit: Int = None, params={}):
4207
+ """
4208
+ retrieves a history of a multiple currencies borrow interest rate at specific time slots, returns all currencies if no symbols passed, default is None
4209
+ :see: https://www.kucoin.com/docs/rest/margin-trading/margin-trading-v3-/get-cross-isolated-margin-interest-records
4210
+ :param str[]|None codes: list of unified currency codes, default is None
4211
+ :param int [since]: timestamp in ms of the earliest borrowRate, default is None
4212
+ :param int [limit]: max number of borrow rate prices to return, default is None
4213
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4214
+ :param str [params.marginMode]: 'cross' or 'isolated' default is 'cross'
4215
+ :param int [params.until]: the latest time in ms to fetch entries for
4216
+ :returns dict: a dictionary of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>` indexed by the market symbol
4217
+ """
4218
+ await self.load_markets()
4219
+ marginResult = self.handle_margin_mode_and_params('fetchBorrowRateHistories', params)
4220
+ marginMode = self.safe_string(marginResult, 0, 'cross')
4221
+ isIsolated = (marginMode == 'isolated') # True-isolated, False-cross
4222
+ request: dict = {
4223
+ 'isIsolated': isIsolated,
4224
+ }
4225
+ if since is not None:
4226
+ request['startTime'] = since
4227
+ request, params = self.handle_until_option('endTime', request, params)
4228
+ if limit is not None:
4229
+ request['pageSize'] = limit # default:50, min:10, max:500
4230
+ response = await self.privateGetMarginInterest(self.extend(request, params))
4231
+ #
4232
+ # {
4233
+ # "code": "200000",
4234
+ # "data": {
4235
+ # "timestamp": 1710829939673,
4236
+ # "currentPage": 1,
4237
+ # "pageSize": 50,
4238
+ # "totalNum": 0,
4239
+ # "totalPage": 0,
4240
+ # "items": [
4241
+ # {
4242
+ # "createdAt": 1697783812257,
4243
+ # "currency": "XMR",
4244
+ # "interestAmount": "0.1",
4245
+ # "dayRatio": "0.001"
4246
+ # }
4247
+ # ]
4248
+ # }
4249
+ # }
4250
+ #
4251
+ data = self.safe_dict(response, 'data')
4252
+ rows = self.safe_list(data, 'items')
4253
+ return self.parse_borrow_rate_histories(rows, codes, since, limit)
4254
+
4255
+ async def fetch_borrow_rate_history(self, code: str, since: Int = None, limit: Int = None, params={}):
4256
+ """
4257
+ retrieves a history of a currencies borrow interest rate at specific time slots
4258
+ :see: https://www.kucoin.com/docs/rest/margin-trading/margin-trading-v3-/get-cross-isolated-margin-interest-records
4259
+ :param str code: unified currency code
4260
+ :param int [since]: timestamp for the earliest borrow rate
4261
+ :param int [limit]: the maximum number of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>` to retrieve
4262
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4263
+ :param str [params.marginMode]: 'cross' or 'isolated' default is 'cross'
4264
+ :param int [params.until]: the latest time in ms to fetch entries for
4265
+ :returns dict[]: an array of `borrow rate structures <https://docs.ccxt.com/#/?id=borrow-rate-structure>`
4266
+ """
4267
+ await self.load_markets()
4268
+ marginResult = self.handle_margin_mode_and_params('fetchBorrowRateHistories', params)
4269
+ marginMode = self.safe_string(marginResult, 0, 'cross')
4270
+ isIsolated = (marginMode == 'isolated') # True-isolated, False-cross
4271
+ currency = self.currency(code)
4272
+ request: dict = {
4273
+ 'isIsolated': isIsolated,
4274
+ 'currency': currency['id'],
4275
+ }
4276
+ if since is not None:
4277
+ request['startTime'] = since
4278
+ request, params = self.handle_until_option('endTime', request, params)
4279
+ if limit is not None:
4280
+ request['pageSize'] = limit # default:50, min:10, max:500
4281
+ response = await self.privateGetMarginInterest(self.extend(request, params))
4282
+ #
4283
+ # {
4284
+ # "code": "200000",
4285
+ # "data": {
4286
+ # "timestamp": 1710829939673,
4287
+ # "currentPage": 1,
4288
+ # "pageSize": 50,
4289
+ # "totalNum": 0,
4290
+ # "totalPage": 0,
4291
+ # "items": [
4292
+ # {
4293
+ # "createdAt": 1697783812257,
4294
+ # "currency": "XMR",
4295
+ # "interestAmount": "0.1",
4296
+ # "dayRatio": "0.001"
4297
+ # }
4298
+ # ]
4299
+ # }
4300
+ # }
4301
+ #
4302
+ data = self.safe_dict(response, 'data')
4303
+ rows = self.safe_list(data, 'items')
4304
+ return self.parse_borrow_rate_history(rows, code, since, limit)
4305
+
4306
+ def parse_borrow_rate_histories(self, response, codes, since, limit):
4307
+ #
4308
+ # [
4309
+ # {
4310
+ # "createdAt": 1697783812257,
4311
+ # "currency": "XMR",
4312
+ # "interestAmount": "0.1",
4313
+ # "dayRatio": "0.001"
4314
+ # }
4315
+ # ]
4316
+ #
4317
+ borrowRateHistories: dict = {}
4318
+ for i in range(0, len(response)):
4319
+ item = response[i]
4320
+ code = self.safe_currency_code(self.safe_string(item, 'currency'))
4321
+ if codes is None or self.in_array(code, codes):
4322
+ if not (code in borrowRateHistories):
4323
+ borrowRateHistories[code] = []
4324
+ borrowRateStructure = self.parse_borrow_rate(item)
4325
+ borrowRateHistories[code].append(borrowRateStructure)
4326
+ keys = list(borrowRateHistories.keys())
4327
+ for i in range(0, len(keys)):
4328
+ code = keys[i]
4329
+ borrowRateHistories[code] = self.filter_by_currency_since_limit(borrowRateHistories[code], code, since, limit)
4330
+ return borrowRateHistories
4331
+
4332
+ async def borrow_cross_margin(self, code: str, amount: float, params={}):
4333
+ """
4334
+ create a loan to borrow margin
4335
+ :see: https://docs.kucoin.com/#1-margin-borrowing
4336
+ :param str code: unified currency code of the currency to borrow
4337
+ :param float amount: the amount to borrow
4338
+ :param dict [params]: extra parameters specific to the exchange API endpoints
4339
+ :param str [params.timeInForce]: either IOC or FOK
4340
+ :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
4341
+ """
4342
+ await self.load_markets()
4343
+ currency = self.currency(code)
4344
+ request: dict = {
4345
+ 'currency': currency['id'],
4346
+ 'size': self.currency_to_precision(code, amount),
4347
+ 'timeInForce': 'FOK',
4348
+ }
4349
+ response = await self.privatePostMarginBorrow(self.extend(request, params))
4350
+ #
4351
+ # {
4352
+ # "success": True,
4353
+ # "code": "200",
4354
+ # "msg": "success",
4355
+ # "retry": False,
4356
+ # "data": {
4357
+ # "orderNo": "5da6dba0f943c0c81f5d5db5",
4358
+ # "actualSize": 10
4359
+ # }
4360
+ # }
4361
+ #
4362
+ data = self.safe_dict(response, 'data', {})
4363
+ return self.parse_margin_loan(data, currency)
4364
+
4365
+ async def borrow_isolated_margin(self, symbol: str, code: str, amount: float, params={}):
4366
+ """
4367
+ create a loan to borrow margin
4368
+ :see: https://docs.kucoin.com/#1-margin-borrowing
4369
+ :param str symbol: unified market symbol, required for isolated margin
4370
+ :param str code: unified currency code of the currency to borrow
4371
+ :param float amount: the amount to borrow
4372
+ :param dict [params]: extra parameters specific to the exchange API endpoints
4373
+ :param str [params.timeInForce]: either IOC or FOK
4374
+ :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
4375
+ """
4376
+ await self.load_markets()
4377
+ market = self.market(symbol)
4378
+ currency = self.currency(code)
4379
+ request: dict = {
4380
+ 'currency': currency['id'],
4381
+ 'size': self.currency_to_precision(code, amount),
4382
+ 'symbol': market['id'],
4383
+ 'timeInForce': 'FOK',
4384
+ 'isIsolated': True,
4385
+ }
4386
+ response = await self.privatePostMarginBorrow(self.extend(request, params))
4387
+ #
4388
+ # {
4389
+ # "success": True,
4390
+ # "code": "200",
4391
+ # "msg": "success",
4392
+ # "retry": False,
4393
+ # "data": {
4394
+ # "orderNo": "5da6dba0f943c0c81f5d5db5",
4395
+ # "actualSize": 10
4396
+ # }
4397
+ # }
4398
+ #
4399
+ data = self.safe_dict(response, 'data', {})
4400
+ return self.parse_margin_loan(data, currency)
4401
+
4402
+ async def repay_cross_margin(self, code: str, amount, params={}):
4403
+ """
4404
+ repay borrowed margin and interest
4405
+ :see: https://docs.kucoin.com/#2-repayment
4406
+ :param str code: unified currency code of the currency to repay
4407
+ :param float amount: the amount to repay
4408
+ :param dict [params]: extra parameters specific to the exchange API endpoints
4409
+ :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
4410
+ """
4411
+ await self.load_markets()
4412
+ currency = self.currency(code)
4413
+ request: dict = {
4414
+ 'currency': currency['id'],
4415
+ 'size': self.currency_to_precision(code, amount),
4416
+ }
4417
+ response = await self.privatePostMarginRepay(self.extend(request, params))
4418
+ #
4419
+ # {
4420
+ # "success": True,
4421
+ # "code": "200",
4422
+ # "msg": "success",
4423
+ # "retry": False,
4424
+ # "data": {
4425
+ # "orderNo": "5da6dba0f943c0c81f5d5db5",
4426
+ # "actualSize": 10
4427
+ # }
4428
+ # }
4429
+ #
4430
+ data = self.safe_dict(response, 'data', {})
4431
+ return self.parse_margin_loan(data, currency)
4432
+
4433
+ async def repay_isolated_margin(self, symbol: str, code: str, amount, params={}):
4434
+ """
4435
+ repay borrowed margin and interest
4436
+ :see: https://docs.kucoin.com/#2-repayment
4437
+ :param str symbol: unified market symbol
4438
+ :param str code: unified currency code of the currency to repay
4439
+ :param float amount: the amount to repay
4440
+ :param dict [params]: extra parameters specific to the exchange API endpoints
4441
+ :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
4442
+ """
4443
+ await self.load_markets()
4444
+ market = self.market(symbol)
4445
+ currency = self.currency(code)
4446
+ request: dict = {
4447
+ 'currency': currency['id'],
4448
+ 'size': self.currency_to_precision(code, amount),
4449
+ 'symbol': market['id'],
4450
+ 'isIsolated': True,
4451
+ }
4452
+ response = await self.privatePostMarginRepay(self.extend(request, params))
4453
+ #
4454
+ # {
4455
+ # "success": True,
4456
+ # "code": "200",
4457
+ # "msg": "success",
4458
+ # "retry": False,
4459
+ # "data": {
4460
+ # "orderNo": "5da6dba0f943c0c81f5d5db5",
4461
+ # "actualSize": 10
4462
+ # }
4463
+ # }
4464
+ #
4465
+ data = self.safe_dict(response, 'data', {})
4466
+ return self.parse_margin_loan(data, currency)
4467
+
4468
+ def parse_margin_loan(self, info, currency: Currency = None):
4469
+ #
4470
+ # {
4471
+ # "orderNo": "5da6dba0f943c0c81f5d5db5",
4472
+ # "actualSize": 10
4473
+ # }
4474
+ #
4475
+ timestamp = self.milliseconds()
4476
+ currencyId = self.safe_string(info, 'currency')
4477
+ return {
4478
+ 'id': self.safe_string(info, 'orderNo'),
4479
+ 'currency': self.safe_currency_code(currencyId, currency),
4480
+ 'amount': self.safe_number(info, 'actualSize'),
4481
+ 'symbol': None,
4482
+ 'timestamp': timestamp,
4483
+ 'datetime': self.iso8601(timestamp),
4484
+ 'info': info,
4485
+ }
4486
+
4487
+ async def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
4488
+ """
4489
+ fetch deposit and withdraw fees - *IMPORTANT* use fetchDepositWithdrawFee to get more in-depth info
4490
+ :see: https://docs.kucoin.com/#get-currencies
4491
+ :param str[]|None codes: list of unified currency codes
4492
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4493
+ :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
4494
+ """
4495
+ await self.load_markets()
4496
+ response = await self.publicGetCurrencies(params)
4497
+ #
4498
+ # [
4499
+ # {
4500
+ # "currency": "CSP",
4501
+ # "name": "CSP",
4502
+ # "fullName": "Caspian",
4503
+ # "precision": 8,
4504
+ # "confirms": 12,
4505
+ # "contractAddress": "0xa6446d655a0c34bc4f05042ee88170d056cbaf45",
4506
+ # "withdrawalMinSize": "2000",
4507
+ # "withdrawalMinFee": "1000",
4508
+ # "isWithdrawEnabled": True,
4509
+ # "isDepositEnabled": True,
4510
+ # "isMarginEnabled": False,
4511
+ # "isDebitEnabled": False
4512
+ # },
4513
+ # ]
4514
+ #
4515
+ data = self.safe_list(response, 'data', [])
4516
+ return self.parse_deposit_withdraw_fees(data, codes, 'currency')
4517
+
4518
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
4519
+ #
4520
+ # the v2 URL is https://openapi-v2.kucoin.com/api/v1/endpoint
4521
+ # ↑ ↑
4522
+ # ↑ ↑
4523
+ #
4524
+ versions = self.safe_dict(self.options, 'versions', {})
4525
+ apiVersions = self.safe_dict(versions, api, {})
4526
+ methodVersions = self.safe_dict(apiVersions, method, {})
4527
+ defaultVersion = self.safe_string(methodVersions, path, self.options['version'])
4528
+ version = self.safe_string(params, 'version', defaultVersion)
4529
+ params = self.omit(params, 'version')
4530
+ endpoint = '/api/' + version + '/' + self.implode_params(path, params)
4531
+ if api == 'webExchange':
4532
+ endpoint = '/' + self.implode_params(path, params)
4533
+ if api == 'earn':
4534
+ endpoint = '/api/v1/' + self.implode_params(path, params)
4535
+ query = self.omit(params, self.extract_params(path))
4536
+ endpart = ''
4537
+ headers = headers if (headers is not None) else {}
4538
+ url = self.urls['api'][api]
4539
+ if not self.is_empty(query):
4540
+ if (method == 'GET') or (method == 'DELETE'):
4541
+ endpoint += '?' + self.rawencode(query)
4542
+ else:
4543
+ body = self.json(query)
4544
+ endpart = body
4545
+ headers['Content-Type'] = 'application/json'
4546
+ url = url + endpoint
4547
+ isFuturePrivate = (api == 'futuresPrivate')
4548
+ isPrivate = (api == 'private')
4549
+ isBroker = (api == 'broker')
4550
+ isEarn = (api == 'earn')
4551
+ if isPrivate or isFuturePrivate or isBroker or isEarn:
4552
+ self.check_required_credentials()
4553
+ timestamp = str(self.nonce())
4554
+ headers = self.extend({
4555
+ 'KC-API-KEY-VERSION': '2',
4556
+ 'KC-API-KEY': self.apiKey,
4557
+ 'KC-API-TIMESTAMP': timestamp,
4558
+ }, headers)
4559
+ apiKeyVersion = self.safe_string(headers, 'KC-API-KEY-VERSION')
4560
+ if apiKeyVersion == '2':
4561
+ passphrase = self.hmac(self.encode(self.password), self.encode(self.secret), hashlib.sha256, 'base64')
4562
+ headers['KC-API-PASSPHRASE'] = passphrase
4563
+ else:
4564
+ headers['KC-API-PASSPHRASE'] = self.password
4565
+ payload = timestamp + method + endpoint + endpart
4566
+ signature = self.hmac(self.encode(payload), self.encode(self.secret), hashlib.sha256, 'base64')
4567
+ headers['KC-API-SIGN'] = signature
4568
+ partner = self.safe_dict(self.options, 'partner', {})
4569
+ partner = self.safe_value(partner, 'future', partner) if isFuturePrivate else self.safe_value(partner, 'spot', partner)
4570
+ partnerId = self.safe_string(partner, 'id')
4571
+ partnerSecret = self.safe_string_2(partner, 'secret', 'key')
4572
+ if (partnerId is not None) and (partnerSecret is not None):
4573
+ partnerPayload = timestamp + partnerId + self.apiKey
4574
+ partnerSignature = self.hmac(self.encode(partnerPayload), self.encode(partnerSecret), hashlib.sha256, 'base64')
4575
+ headers['KC-API-PARTNER-SIGN'] = partnerSignature
4576
+ headers['KC-API-PARTNER'] = partnerId
4577
+ headers['KC-API-PARTNER-VERIFY'] = 'true'
4578
+ if isBroker:
4579
+ brokerName = self.safe_string(partner, 'name')
4580
+ if brokerName is not None:
4581
+ headers['KC-BROKER-NAME'] = brokerName
4582
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
4583
+
4584
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
4585
+ if not response:
4586
+ self.throw_broadly_matched_exception(self.exceptions['broad'], body, body)
4587
+ return None
4588
+ #
4589
+ # bad
4590
+ # {"code": "400100", "msg": "validation.createOrder.clientOidIsRequired"}
4591
+ # good
4592
+ # {code: '200000', data: {...}}
4593
+ #
4594
+ errorCode = self.safe_string(response, 'code')
4595
+ message = self.safe_string_2(response, 'msg', 'data', '')
4596
+ feedback = self.id + ' ' + message
4597
+ self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
4598
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
4599
+ self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
4600
+ if errorCode != '200000' and errorCode != '200':
4601
+ raise ExchangeError(feedback)
4602
+ return None