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