ccxt-ir 4.3.46.0.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (772) hide show
  1. ccxt/__init__.py +358 -0
  2. ccxt/abantether.py +316 -0
  3. ccxt/abstract/__init__.py +0 -0
  4. ccxt/abstract/abantether.py +5 -0
  5. ccxt/abstract/ace.py +15 -0
  6. ccxt/abstract/afratether.py +6 -0
  7. ccxt/abstract/alpaca.py +70 -0
  8. ccxt/abstract/arzinja.py +5 -0
  9. ccxt/abstract/arzplus.py +7 -0
  10. ccxt/abstract/ascendex.py +77 -0
  11. ccxt/abstract/bequant.py +115 -0
  12. ccxt/abstract/bigone.py +45 -0
  13. ccxt/abstract/binance.py +712 -0
  14. ccxt/abstract/binancecoinm.py +712 -0
  15. ccxt/abstract/binanceus.py +764 -0
  16. ccxt/abstract/binanceusdm.py +712 -0
  17. ccxt/abstract/bingx.py +113 -0
  18. ccxt/abstract/bit2c.py +27 -0
  19. ccxt/abstract/bitbank.py +27 -0
  20. ccxt/abstract/bitbay.py +53 -0
  21. ccxt/abstract/bitbns.py +40 -0
  22. ccxt/abstract/bitcoincom.py +115 -0
  23. ccxt/abstract/bitfinex.py +69 -0
  24. ccxt/abstract/bitfinex2.py +139 -0
  25. ccxt/abstract/bitflyer.py +38 -0
  26. ccxt/abstract/bitget.py +508 -0
  27. ccxt/abstract/bithumb.py +32 -0
  28. ccxt/abstract/bitimen.py +7 -0
  29. ccxt/abstract/bitir.py +7 -0
  30. ccxt/abstract/bitmart.py +99 -0
  31. ccxt/abstract/bitmex.py +97 -0
  32. ccxt/abstract/bitopro.py +29 -0
  33. ccxt/abstract/bitpanda.py +35 -0
  34. ccxt/abstract/bitpin.py +7 -0
  35. ccxt/abstract/bitrue.py +72 -0
  36. ccxt/abstract/bitso.py +43 -0
  37. ccxt/abstract/bitstamp.py +258 -0
  38. ccxt/abstract/bitteam.py +29 -0
  39. ccxt/abstract/bitvavo.py +27 -0
  40. ccxt/abstract/bl3p.py +19 -0
  41. ccxt/abstract/blockchaincom.py +28 -0
  42. ccxt/abstract/blofin.py +37 -0
  43. ccxt/abstract/btcalpha.py +18 -0
  44. ccxt/abstract/btcbox.py +13 -0
  45. ccxt/abstract/btcmarkets.py +39 -0
  46. ccxt/abstract/btcturk.py +20 -0
  47. ccxt/abstract/bybit.py +298 -0
  48. ccxt/abstract/cex.py +33 -0
  49. ccxt/abstract/coinbase.py +94 -0
  50. ccxt/abstract/coinbaseadvanced.py +94 -0
  51. ccxt/abstract/coinbaseexchange.py +67 -0
  52. ccxt/abstract/coinbaseinternational.py +39 -0
  53. ccxt/abstract/coincatch.py +94 -0
  54. ccxt/abstract/coincheck.py +33 -0
  55. ccxt/abstract/coinex.py +237 -0
  56. ccxt/abstract/coinlist.py +54 -0
  57. ccxt/abstract/coinmate.py +62 -0
  58. ccxt/abstract/coinmetro.py +34 -0
  59. ccxt/abstract/coinone.py +67 -0
  60. ccxt/abstract/coinsph.py +54 -0
  61. ccxt/abstract/coinspot.py +28 -0
  62. ccxt/abstract/cryptocom.py +107 -0
  63. ccxt/abstract/currencycom.py +68 -0
  64. ccxt/abstract/delta.py +50 -0
  65. ccxt/abstract/deribit.py +125 -0
  66. ccxt/abstract/digifinex.py +91 -0
  67. ccxt/abstract/eterex.py +5 -0
  68. ccxt/abstract/excoino.py +7 -0
  69. ccxt/abstract/exir.py +8 -0
  70. ccxt/abstract/exmo.py +55 -0
  71. ccxt/abstract/exnovin.py +6 -0
  72. ccxt/abstract/farhadexchange.py +5 -0
  73. ccxt/abstract/fmfwio.py +115 -0
  74. ccxt/abstract/gate.py +265 -0
  75. ccxt/abstract/gateio.py +265 -0
  76. ccxt/abstract/gemini.py +58 -0
  77. ccxt/abstract/hashkey.py +67 -0
  78. ccxt/abstract/hitbtc.py +115 -0
  79. ccxt/abstract/hitbtc3.py +115 -0
  80. ccxt/abstract/hitobit.py +8 -0
  81. ccxt/abstract/hollaex.py +33 -0
  82. ccxt/abstract/htx.py +548 -0
  83. ccxt/abstract/huobi.py +548 -0
  84. ccxt/abstract/huobijp.py +114 -0
  85. ccxt/abstract/hyperliquid.py +6 -0
  86. ccxt/abstract/idex.py +26 -0
  87. ccxt/abstract/independentreserve.py +37 -0
  88. ccxt/abstract/indodax.py +26 -0
  89. ccxt/abstract/jibitex.py +7 -0
  90. ccxt/abstract/kraken.py +57 -0
  91. ccxt/abstract/krakenfutures.py +38 -0
  92. ccxt/abstract/kucoin.py +214 -0
  93. ccxt/abstract/kucoinfutures.py +233 -0
  94. ccxt/abstract/kuna.py +182 -0
  95. ccxt/abstract/latoken.py +56 -0
  96. ccxt/abstract/lbank.py +61 -0
  97. ccxt/abstract/luno.py +37 -0
  98. ccxt/abstract/lykke.py +29 -0
  99. ccxt/abstract/mercado.py +25 -0
  100. ccxt/abstract/mexc.py +178 -0
  101. ccxt/abstract/ndax.py +97 -0
  102. ccxt/abstract/nobitex.py +7 -0
  103. ccxt/abstract/novadax.py +29 -0
  104. ccxt/abstract/oceanex.py +22 -0
  105. ccxt/abstract/okcoin.py +74 -0
  106. ccxt/abstract/okexchange.py +8 -0
  107. ccxt/abstract/okx.py +324 -0
  108. ccxt/abstract/ompfinex.py +7 -0
  109. ccxt/abstract/onetrading.py +35 -0
  110. ccxt/abstract/oxfun.py +34 -0
  111. ccxt/abstract/p2b.py +22 -0
  112. ccxt/abstract/paradex.py +40 -0
  113. ccxt/abstract/paymium.py +28 -0
  114. ccxt/abstract/phemex.py +115 -0
  115. ccxt/abstract/poloniex.py +69 -0
  116. ccxt/abstract/poloniexfutures.py +48 -0
  117. ccxt/abstract/probit.py +23 -0
  118. ccxt/abstract/ramzinex.py +7 -0
  119. ccxt/abstract/sarmayex.py +5 -0
  120. ccxt/abstract/sarrafex.py +7 -0
  121. ccxt/abstract/tabdeal.py +7 -0
  122. ccxt/abstract/tetherland.py +5 -0
  123. ccxt/abstract/timex.py +62 -0
  124. ccxt/abstract/tokocrypto.py +37 -0
  125. ccxt/abstract/tradeogre.py +16 -0
  126. ccxt/abstract/twox.py +5 -0
  127. ccxt/abstract/ubitex.py +7 -0
  128. ccxt/abstract/upbit.py +38 -0
  129. ccxt/abstract/vertex.py +19 -0
  130. ccxt/abstract/wallex.py +8 -0
  131. ccxt/abstract/wavesexchange.py +154 -0
  132. ccxt/abstract/wazirx.py +30 -0
  133. ccxt/abstract/whitebit.py +98 -0
  134. ccxt/abstract/woo.py +83 -0
  135. ccxt/abstract/woofipro.py +119 -0
  136. ccxt/abstract/xt.py +152 -0
  137. ccxt/abstract/yobit.py +16 -0
  138. ccxt/abstract/zaif.py +38 -0
  139. ccxt/abstract/zonda.py +53 -0
  140. ccxt/ace.py +1012 -0
  141. ccxt/afratether.py +293 -0
  142. ccxt/alpaca.py +1083 -0
  143. ccxt/arzinja.py +285 -0
  144. ccxt/arzplus.py +412 -0
  145. ccxt/ascendex.py +3330 -0
  146. ccxt/async_support/__init__.py +337 -0
  147. ccxt/async_support/abantether.py +316 -0
  148. ccxt/async_support/ace.py +1012 -0
  149. ccxt/async_support/afratether.py +293 -0
  150. ccxt/async_support/alpaca.py +1083 -0
  151. ccxt/async_support/arzinja.py +285 -0
  152. ccxt/async_support/arzplus.py +412 -0
  153. ccxt/async_support/ascendex.py +3330 -0
  154. ccxt/async_support/base/__init__.py +1 -0
  155. ccxt/async_support/base/exchange.py +1966 -0
  156. ccxt/async_support/base/throttler.py +50 -0
  157. ccxt/async_support/base/ws/__init__.py +38 -0
  158. ccxt/async_support/base/ws/aiohttp_client.py +125 -0
  159. ccxt/async_support/base/ws/cache.py +212 -0
  160. ccxt/async_support/base/ws/client.py +193 -0
  161. ccxt/async_support/base/ws/fast_client.py +96 -0
  162. ccxt/async_support/base/ws/functions.py +59 -0
  163. ccxt/async_support/base/ws/future.py +58 -0
  164. ccxt/async_support/base/ws/order_book.py +78 -0
  165. ccxt/async_support/base/ws/order_book_side.py +174 -0
  166. ccxt/async_support/bequant.py +33 -0
  167. ccxt/async_support/bigone.py +2113 -0
  168. ccxt/async_support/binance.py +12234 -0
  169. ccxt/async_support/binancecoinm.py +45 -0
  170. ccxt/async_support/binanceus.py +211 -0
  171. ccxt/async_support/binanceusdm.py +58 -0
  172. ccxt/async_support/bingx.py +4325 -0
  173. ccxt/async_support/bit2c.py +866 -0
  174. ccxt/async_support/bitbank.py +1001 -0
  175. ccxt/async_support/bitbay.py +17 -0
  176. ccxt/async_support/bitbns.py +1154 -0
  177. ccxt/async_support/bitcoincom.py +17 -0
  178. ccxt/async_support/bitfinex.py +1617 -0
  179. ccxt/async_support/bitfinex2.py +3552 -0
  180. ccxt/async_support/bitflyer.py +995 -0
  181. ccxt/async_support/bitget.py +8273 -0
  182. ccxt/async_support/bithumb.py +1061 -0
  183. ccxt/async_support/bitimen.py +401 -0
  184. ccxt/async_support/bitir.py +490 -0
  185. ccxt/async_support/bitmart.py +4415 -0
  186. ccxt/async_support/bitmex.py +2756 -0
  187. ccxt/async_support/bitopro.py +1630 -0
  188. ccxt/async_support/bitpanda.py +16 -0
  189. ccxt/async_support/bitpin.py +454 -0
  190. ccxt/async_support/bitrue.py +3027 -0
  191. ccxt/async_support/bitso.py +1670 -0
  192. ccxt/async_support/bitstamp.py +2203 -0
  193. ccxt/async_support/bitteam.py +2239 -0
  194. ccxt/async_support/bitvavo.py +1968 -0
  195. ccxt/async_support/bl3p.py +485 -0
  196. ccxt/async_support/blockchaincom.py +1104 -0
  197. ccxt/async_support/blofin.py +2066 -0
  198. ccxt/async_support/btcalpha.py +891 -0
  199. ccxt/async_support/btcbox.py +544 -0
  200. ccxt/async_support/btcmarkets.py +1221 -0
  201. ccxt/async_support/btcturk.py +911 -0
  202. ccxt/async_support/bybit.py +8159 -0
  203. ccxt/async_support/cex.py +1605 -0
  204. ccxt/async_support/coinbase.py +4475 -0
  205. ccxt/async_support/coinbaseadvanced.py +17 -0
  206. ccxt/async_support/coinbaseexchange.py +1734 -0
  207. ccxt/async_support/coinbaseinternational.py +1899 -0
  208. ccxt/async_support/coincatch.py +5069 -0
  209. ccxt/async_support/coincheck.py +815 -0
  210. ccxt/async_support/coinex.py +5526 -0
  211. ccxt/async_support/coinlist.py +2243 -0
  212. ccxt/async_support/coinmate.py +1067 -0
  213. ccxt/async_support/coinmetro.py +1797 -0
  214. ccxt/async_support/coinone.py +1127 -0
  215. ccxt/async_support/coinsph.py +1850 -0
  216. ccxt/async_support/coinspot.py +534 -0
  217. ccxt/async_support/cryptocom.py +2822 -0
  218. ccxt/async_support/currencycom.py +1950 -0
  219. ccxt/async_support/delta.py +3376 -0
  220. ccxt/async_support/deribit.py +3437 -0
  221. ccxt/async_support/digifinex.py +3960 -0
  222. ccxt/async_support/eterex.py +286 -0
  223. ccxt/async_support/excoino.py +399 -0
  224. ccxt/async_support/exir.py +375 -0
  225. ccxt/async_support/exmo.py +2462 -0
  226. ccxt/async_support/exnovin.py +360 -0
  227. ccxt/async_support/farhadexchange.py +266 -0
  228. ccxt/async_support/fmfwio.py +34 -0
  229. ccxt/async_support/gate.py +6976 -0
  230. ccxt/async_support/gateio.py +16 -0
  231. ccxt/async_support/gemini.py +1825 -0
  232. ccxt/async_support/hashkey.py +4150 -0
  233. ccxt/async_support/hitbtc.py +3423 -0
  234. ccxt/async_support/hitbtc3.py +16 -0
  235. ccxt/async_support/hitobit.py +391 -0
  236. ccxt/async_support/hollaex.py +1813 -0
  237. ccxt/async_support/htx.py +8506 -0
  238. ccxt/async_support/huobi.py +16 -0
  239. ccxt/async_support/huobijp.py +1801 -0
  240. ccxt/async_support/hyperliquid.py +2431 -0
  241. ccxt/async_support/idex.py +1766 -0
  242. ccxt/async_support/independentreserve.py +784 -0
  243. ccxt/async_support/indodax.py +1247 -0
  244. ccxt/async_support/jibitex.py +395 -0
  245. ccxt/async_support/kraken.py +2894 -0
  246. ccxt/async_support/krakenfutures.py +2601 -0
  247. ccxt/async_support/kucoin.py +4602 -0
  248. ccxt/async_support/kucoinfutures.py +2698 -0
  249. ccxt/async_support/kuna.py +1841 -0
  250. ccxt/async_support/latoken.py +1664 -0
  251. ccxt/async_support/lbank.py +2683 -0
  252. ccxt/async_support/luno.py +1067 -0
  253. ccxt/async_support/lykke.py +1270 -0
  254. ccxt/async_support/mercado.py +842 -0
  255. ccxt/async_support/mexc.py +5369 -0
  256. ccxt/async_support/ndax.py +2354 -0
  257. ccxt/async_support/nobitex.py +419 -0
  258. ccxt/async_support/novadax.py +1484 -0
  259. ccxt/async_support/oceanex.py +903 -0
  260. ccxt/async_support/okcoin.py +2936 -0
  261. ccxt/async_support/okexchange.py +349 -0
  262. ccxt/async_support/okx.py +7827 -0
  263. ccxt/async_support/ompfinex.py +472 -0
  264. ccxt/async_support/onetrading.py +1911 -0
  265. ccxt/async_support/oxfun.py +2773 -0
  266. ccxt/async_support/p2b.py +1194 -0
  267. ccxt/async_support/paradex.py +2015 -0
  268. ccxt/async_support/paymium.py +564 -0
  269. ccxt/async_support/phemex.py +4473 -0
  270. ccxt/async_support/poloniex.py +2232 -0
  271. ccxt/async_support/poloniexfutures.py +1717 -0
  272. ccxt/async_support/probit.py +1734 -0
  273. ccxt/async_support/ramzinex.py +476 -0
  274. ccxt/async_support/sarmayex.py +357 -0
  275. ccxt/async_support/sarrafex.py +478 -0
  276. ccxt/async_support/tabdeal.py +364 -0
  277. ccxt/async_support/tetherland.py +349 -0
  278. ccxt/async_support/timex.py +1593 -0
  279. ccxt/async_support/tokocrypto.py +2405 -0
  280. ccxt/async_support/tradeogre.py +608 -0
  281. ccxt/async_support/twox.py +326 -0
  282. ccxt/async_support/ubitex.py +409 -0
  283. ccxt/async_support/upbit.py +1833 -0
  284. ccxt/async_support/vertex.py +2922 -0
  285. ccxt/async_support/wallex.py +445 -0
  286. ccxt/async_support/wavesexchange.py +2473 -0
  287. ccxt/async_support/wazirx.py +1224 -0
  288. ccxt/async_support/whitebit.py +2469 -0
  289. ccxt/async_support/woo.py +3114 -0
  290. ccxt/async_support/woofipro.py +2533 -0
  291. ccxt/async_support/xt.py +4454 -0
  292. ccxt/async_support/yobit.py +1283 -0
  293. ccxt/async_support/zaif.py +725 -0
  294. ccxt/async_support/zonda.py +1828 -0
  295. ccxt/base/__init__.py +27 -0
  296. ccxt/base/decimal_to_precision.py +174 -0
  297. ccxt/base/errors.py +242 -0
  298. ccxt/base/exchange.py +5941 -0
  299. ccxt/base/precise.py +287 -0
  300. ccxt/base/types.py +502 -0
  301. ccxt/bequant.py +33 -0
  302. ccxt/bigone.py +2112 -0
  303. ccxt/binance.py +12233 -0
  304. ccxt/binancecoinm.py +45 -0
  305. ccxt/binanceus.py +211 -0
  306. ccxt/binanceusdm.py +58 -0
  307. ccxt/bingx.py +4324 -0
  308. ccxt/bit2c.py +866 -0
  309. ccxt/bitbank.py +1001 -0
  310. ccxt/bitbay.py +17 -0
  311. ccxt/bitbns.py +1154 -0
  312. ccxt/bitcoincom.py +17 -0
  313. ccxt/bitfinex.py +1617 -0
  314. ccxt/bitfinex2.py +3552 -0
  315. ccxt/bitflyer.py +995 -0
  316. ccxt/bitget.py +8272 -0
  317. ccxt/bithumb.py +1061 -0
  318. ccxt/bitimen.py +401 -0
  319. ccxt/bitir.py +490 -0
  320. ccxt/bitmart.py +4415 -0
  321. ccxt/bitmex.py +2756 -0
  322. ccxt/bitopro.py +1630 -0
  323. ccxt/bitpanda.py +16 -0
  324. ccxt/bitpin.py +454 -0
  325. ccxt/bitrue.py +3026 -0
  326. ccxt/bitso.py +1670 -0
  327. ccxt/bitstamp.py +2203 -0
  328. ccxt/bitteam.py +2239 -0
  329. ccxt/bitvavo.py +1968 -0
  330. ccxt/bl3p.py +485 -0
  331. ccxt/blockchaincom.py +1104 -0
  332. ccxt/blofin.py +2066 -0
  333. ccxt/btcalpha.py +891 -0
  334. ccxt/btcbox.py +544 -0
  335. ccxt/btcmarkets.py +1221 -0
  336. ccxt/btcturk.py +911 -0
  337. ccxt/bybit.py +8158 -0
  338. ccxt/cex.py +1605 -0
  339. ccxt/coinbase.py +4474 -0
  340. ccxt/coinbaseadvanced.py +17 -0
  341. ccxt/coinbaseexchange.py +1734 -0
  342. ccxt/coinbaseinternational.py +1899 -0
  343. ccxt/coincatch.py +5069 -0
  344. ccxt/coincheck.py +815 -0
  345. ccxt/coinex.py +5525 -0
  346. ccxt/coinlist.py +2243 -0
  347. ccxt/coinmate.py +1067 -0
  348. ccxt/coinmetro.py +1797 -0
  349. ccxt/coinone.py +1127 -0
  350. ccxt/coinsph.py +1850 -0
  351. ccxt/coinspot.py +534 -0
  352. ccxt/cryptocom.py +2822 -0
  353. ccxt/currencycom.py +1950 -0
  354. ccxt/delta.py +3376 -0
  355. ccxt/deribit.py +3437 -0
  356. ccxt/digifinex.py +3959 -0
  357. ccxt/eterex.py +286 -0
  358. ccxt/excoino.py +399 -0
  359. ccxt/exir.py +375 -0
  360. ccxt/exmo.py +2462 -0
  361. ccxt/exnovin.py +360 -0
  362. ccxt/farhadexchange.py +266 -0
  363. ccxt/fmfwio.py +34 -0
  364. ccxt/gate.py +6975 -0
  365. ccxt/gateio.py +16 -0
  366. ccxt/gemini.py +1824 -0
  367. ccxt/hashkey.py +4150 -0
  368. ccxt/hitbtc.py +3423 -0
  369. ccxt/hitbtc3.py +16 -0
  370. ccxt/hitobit.py +391 -0
  371. ccxt/hollaex.py +1813 -0
  372. ccxt/htx.py +8505 -0
  373. ccxt/huobi.py +16 -0
  374. ccxt/huobijp.py +1801 -0
  375. ccxt/hyperliquid.py +2430 -0
  376. ccxt/idex.py +1766 -0
  377. ccxt/independentreserve.py +784 -0
  378. ccxt/indodax.py +1247 -0
  379. ccxt/jibitex.py +395 -0
  380. ccxt/kraken.py +2894 -0
  381. ccxt/krakenfutures.py +2601 -0
  382. ccxt/kucoin.py +4601 -0
  383. ccxt/kucoinfutures.py +2698 -0
  384. ccxt/kuna.py +1841 -0
  385. ccxt/latoken.py +1664 -0
  386. ccxt/lbank.py +2682 -0
  387. ccxt/luno.py +1067 -0
  388. ccxt/lykke.py +1270 -0
  389. ccxt/mercado.py +842 -0
  390. ccxt/mexc.py +5369 -0
  391. ccxt/ndax.py +2354 -0
  392. ccxt/nobitex.py +419 -0
  393. ccxt/novadax.py +1484 -0
  394. ccxt/oceanex.py +903 -0
  395. ccxt/okcoin.py +2936 -0
  396. ccxt/okexchange.py +349 -0
  397. ccxt/okx.py +7826 -0
  398. ccxt/ompfinex.py +472 -0
  399. ccxt/onetrading.py +1911 -0
  400. ccxt/oxfun.py +2772 -0
  401. ccxt/p2b.py +1194 -0
  402. ccxt/paradex.py +2015 -0
  403. ccxt/paymium.py +564 -0
  404. ccxt/phemex.py +4473 -0
  405. ccxt/poloniex.py +2232 -0
  406. ccxt/poloniexfutures.py +1717 -0
  407. ccxt/pro/__init__.py +149 -0
  408. ccxt/pro/alpaca.py +685 -0
  409. ccxt/pro/ascendex.py +916 -0
  410. ccxt/pro/bequant.py +38 -0
  411. ccxt/pro/binance.py +3488 -0
  412. ccxt/pro/binancecoinm.py +28 -0
  413. ccxt/pro/binanceus.py +48 -0
  414. ccxt/pro/binanceusdm.py +31 -0
  415. ccxt/pro/bingx.py +1264 -0
  416. ccxt/pro/bitcoincom.py +34 -0
  417. ccxt/pro/bitfinex.py +621 -0
  418. ccxt/pro/bitfinex2.py +1083 -0
  419. ccxt/pro/bitget.py +1692 -0
  420. ccxt/pro/bithumb.py +368 -0
  421. ccxt/pro/bitmart.py +1449 -0
  422. ccxt/pro/bitmex.py +1656 -0
  423. ccxt/pro/bitopro.py +445 -0
  424. ccxt/pro/bitpanda.py +15 -0
  425. ccxt/pro/bitrue.py +447 -0
  426. ccxt/pro/bitstamp.py +522 -0
  427. ccxt/pro/bitvavo.py +1270 -0
  428. ccxt/pro/blockchaincom.py +738 -0
  429. ccxt/pro/blofin.py +692 -0
  430. ccxt/pro/bybit.py +2000 -0
  431. ccxt/pro/cex.py +1440 -0
  432. ccxt/pro/coinbase.py +678 -0
  433. ccxt/pro/coinbaseadvanced.py +16 -0
  434. ccxt/pro/coinbaseexchange.py +895 -0
  435. ccxt/pro/coinbaseinternational.py +620 -0
  436. ccxt/pro/coincatch.py +1464 -0
  437. ccxt/pro/coincheck.py +199 -0
  438. ccxt/pro/coinex.py +1061 -0
  439. ccxt/pro/coinone.py +395 -0
  440. ccxt/pro/cryptocom.py +947 -0
  441. ccxt/pro/currencycom.py +536 -0
  442. ccxt/pro/deribit.py +892 -0
  443. ccxt/pro/exmo.py +629 -0
  444. ccxt/pro/gate.py +1416 -0
  445. ccxt/pro/gateio.py +15 -0
  446. ccxt/pro/gemini.py +865 -0
  447. ccxt/pro/hashkey.py +802 -0
  448. ccxt/pro/hitbtc.py +1216 -0
  449. ccxt/pro/hollaex.py +563 -0
  450. ccxt/pro/htx.py +2215 -0
  451. ccxt/pro/huobi.py +15 -0
  452. ccxt/pro/huobijp.py +570 -0
  453. ccxt/pro/hyperliquid.py +525 -0
  454. ccxt/pro/idex.py +672 -0
  455. ccxt/pro/independentreserve.py +270 -0
  456. ccxt/pro/kraken.py +1356 -0
  457. ccxt/pro/krakenfutures.py +1492 -0
  458. ccxt/pro/kucoin.py +1133 -0
  459. ccxt/pro/kucoinfutures.py +1081 -0
  460. ccxt/pro/lbank.py +843 -0
  461. ccxt/pro/luno.py +303 -0
  462. ccxt/pro/mexc.py +1122 -0
  463. ccxt/pro/ndax.py +506 -0
  464. ccxt/pro/okcoin.py +698 -0
  465. ccxt/pro/okx.py +1851 -0
  466. ccxt/pro/onetrading.py +1275 -0
  467. ccxt/pro/oxfun.py +950 -0
  468. ccxt/pro/p2b.py +419 -0
  469. ccxt/pro/paradex.py +352 -0
  470. ccxt/pro/phemex.py +1441 -0
  471. ccxt/pro/poloniex.py +1166 -0
  472. ccxt/pro/poloniexfutures.py +990 -0
  473. ccxt/pro/probit.py +551 -0
  474. ccxt/pro/upbit.py +520 -0
  475. ccxt/pro/vertex.py +943 -0
  476. ccxt/pro/wazirx.py +749 -0
  477. ccxt/pro/whitebit.py +864 -0
  478. ccxt/pro/woo.py +1078 -0
  479. ccxt/pro/woofipro.py +1183 -0
  480. ccxt/pro/xt.py +1067 -0
  481. ccxt/probit.py +1734 -0
  482. ccxt/ramzinex.py +476 -0
  483. ccxt/sarmayex.py +357 -0
  484. ccxt/sarrafex.py +478 -0
  485. ccxt/static_dependencies/__init__.py +1 -0
  486. ccxt/static_dependencies/ecdsa/__init__.py +14 -0
  487. ccxt/static_dependencies/ecdsa/_version.py +520 -0
  488. ccxt/static_dependencies/ecdsa/curves.py +56 -0
  489. ccxt/static_dependencies/ecdsa/der.py +221 -0
  490. ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
  491. ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
  492. ccxt/static_dependencies/ecdsa/keys.py +332 -0
  493. ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
  494. ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
  495. ccxt/static_dependencies/ecdsa/util.py +266 -0
  496. ccxt/static_dependencies/ethereum/__init__.py +7 -0
  497. ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
  498. ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
  499. ccxt/static_dependencies/ethereum/abi/base.py +152 -0
  500. ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
  501. ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
  502. ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
  503. ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
  504. ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
  505. ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
  506. ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
  507. ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
  508. ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
  509. ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
  510. ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
  511. ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
  512. ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
  513. ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
  514. ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
  515. ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
  516. ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
  517. ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
  518. ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
  519. ccxt/static_dependencies/ethereum/account/messages.py +263 -0
  520. ccxt/static_dependencies/ethereum/account/py.typed +0 -0
  521. ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
  522. ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
  523. ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
  524. ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
  525. ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
  526. ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
  527. ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
  528. ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
  529. ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
  530. ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
  531. ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
  532. ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
  533. ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
  534. ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
  535. ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
  536. ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
  537. ccxt/static_dependencies/ethereum/utils/address.py +171 -0
  538. ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
  539. ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
  540. ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
  541. ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
  542. ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
  543. ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
  544. ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
  545. ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
  546. ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
  547. ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
  548. ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
  549. ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
  550. ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
  551. ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
  552. ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
  553. ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
  554. ccxt/static_dependencies/ethereum/utils/types.py +54 -0
  555. ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
  556. ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
  557. ccxt/static_dependencies/ethereum/utils/units.py +31 -0
  558. ccxt/static_dependencies/keccak/__init__.py +3 -0
  559. ccxt/static_dependencies/keccak/keccak.py +197 -0
  560. ccxt/static_dependencies/lark/__init__.py +38 -0
  561. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  562. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  563. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  564. ccxt/static_dependencies/lark/common.py +86 -0
  565. ccxt/static_dependencies/lark/exceptions.py +292 -0
  566. ccxt/static_dependencies/lark/grammar.py +130 -0
  567. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  568. ccxt/static_dependencies/lark/indenter.py +143 -0
  569. ccxt/static_dependencies/lark/lark.py +658 -0
  570. ccxt/static_dependencies/lark/lexer.py +678 -0
  571. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  572. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  573. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  574. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  575. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  576. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  577. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  578. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  579. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  580. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  581. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  582. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  583. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  584. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  585. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  586. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  587. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  588. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  589. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  590. ccxt/static_dependencies/lark/tree.py +267 -0
  591. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  592. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  593. ccxt/static_dependencies/lark/utils.py +343 -0
  594. ccxt/static_dependencies/lark/visitors.py +596 -0
  595. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  596. ccxt/static_dependencies/marshmallow/base.py +65 -0
  597. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  598. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  599. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  600. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  601. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  602. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  603. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  604. ccxt/static_dependencies/marshmallow/types.py +12 -0
  605. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  606. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  607. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  608. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  609. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  610. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  611. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  612. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  613. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  614. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  615. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  616. ccxt/static_dependencies/msgpack/__init__.py +55 -0
  617. ccxt/static_dependencies/msgpack/exceptions.py +48 -0
  618. ccxt/static_dependencies/msgpack/ext.py +168 -0
  619. ccxt/static_dependencies/msgpack/fallback.py +951 -0
  620. ccxt/static_dependencies/parsimonious/__init__.py +10 -0
  621. ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
  622. ccxt/static_dependencies/parsimonious/expressions.py +479 -0
  623. ccxt/static_dependencies/parsimonious/grammar.py +487 -0
  624. ccxt/static_dependencies/parsimonious/nodes.py +325 -0
  625. ccxt/static_dependencies/parsimonious/utils.py +40 -0
  626. ccxt/static_dependencies/starknet/__init__.py +0 -0
  627. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  628. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  629. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  630. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  631. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  632. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  633. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  634. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  635. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  636. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  637. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  638. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  639. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  640. ccxt/static_dependencies/starknet/common.py +15 -0
  641. ccxt/static_dependencies/starknet/constants.py +39 -0
  642. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  643. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  644. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  645. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  646. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  647. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  648. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  649. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  650. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  651. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  652. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  653. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  654. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  655. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  656. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  657. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  658. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  659. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  660. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  661. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  662. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  663. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  664. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  665. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  666. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  667. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  668. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  669. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  670. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  671. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  672. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  673. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  674. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  675. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  676. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  677. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  678. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  679. ccxt/static_dependencies/starkware/__init__.py +0 -0
  680. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  681. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  682. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  683. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  684. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  685. ccxt/static_dependencies/sympy/__init__.py +0 -0
  686. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  687. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  688. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  689. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  690. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  691. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  692. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  693. ccxt/static_dependencies/toolz/__init__.py +26 -0
  694. ccxt/static_dependencies/toolz/_signatures.py +784 -0
  695. ccxt/static_dependencies/toolz/_version.py +520 -0
  696. ccxt/static_dependencies/toolz/compatibility.py +30 -0
  697. ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
  698. ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
  699. ccxt/static_dependencies/toolz/curried/operator.py +22 -0
  700. ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
  701. ccxt/static_dependencies/toolz/functoolz.py +1049 -0
  702. ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
  703. ccxt/static_dependencies/toolz/recipes.py +46 -0
  704. ccxt/static_dependencies/toolz/utils.py +9 -0
  705. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  706. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  707. ccxt/tabdeal.py +364 -0
  708. ccxt/test/__init__.py +3 -0
  709. ccxt/test/base/__init__.py +29 -0
  710. ccxt/test/base/test_account.py +26 -0
  711. ccxt/test/base/test_balance.py +56 -0
  712. ccxt/test/base/test_borrow_interest.py +35 -0
  713. ccxt/test/base/test_borrow_rate.py +32 -0
  714. ccxt/test/base/test_calculate_fee.py +51 -0
  715. ccxt/test/base/test_crypto.py +127 -0
  716. ccxt/test/base/test_currency.py +76 -0
  717. ccxt/test/base/test_datetime.py +109 -0
  718. ccxt/test/base/test_decimal_to_precision.py +392 -0
  719. ccxt/test/base/test_deep_extend.py +68 -0
  720. ccxt/test/base/test_deposit_withdrawal.py +50 -0
  721. ccxt/test/base/test_exchange_datetime_functions.py +76 -0
  722. ccxt/test/base/test_funding_rate_history.py +29 -0
  723. ccxt/test/base/test_last_price.py +31 -0
  724. ccxt/test/base/test_ledger_entry.py +45 -0
  725. ccxt/test/base/test_ledger_item.py +48 -0
  726. ccxt/test/base/test_leverage_tier.py +33 -0
  727. ccxt/test/base/test_liquidation.py +50 -0
  728. ccxt/test/base/test_margin_mode.py +24 -0
  729. ccxt/test/base/test_margin_modification.py +35 -0
  730. ccxt/test/base/test_market.py +193 -0
  731. ccxt/test/base/test_number.py +411 -0
  732. ccxt/test/base/test_ohlcv.py +33 -0
  733. ccxt/test/base/test_open_interest.py +32 -0
  734. ccxt/test/base/test_order.py +64 -0
  735. ccxt/test/base/test_order_book.py +69 -0
  736. ccxt/test/base/test_position.py +60 -0
  737. ccxt/test/base/test_shared_methods.py +353 -0
  738. ccxt/test/base/test_status.py +24 -0
  739. ccxt/test/base/test_throttle.py +126 -0
  740. ccxt/test/base/test_ticker.py +92 -0
  741. ccxt/test/base/test_trade.py +47 -0
  742. ccxt/test/base/test_trading_fee.py +26 -0
  743. ccxt/test/base/test_transaction.py +39 -0
  744. ccxt/test/test_async.py +1649 -0
  745. ccxt/test/test_sync.py +1648 -0
  746. ccxt/test/tests_async.py +1558 -0
  747. ccxt/test/tests_helpers.py +287 -0
  748. ccxt/test/tests_init.py +39 -0
  749. ccxt/test/tests_sync.py +1555 -0
  750. ccxt/tetherland.py +349 -0
  751. ccxt/timex.py +1593 -0
  752. ccxt/tokocrypto.py +2405 -0
  753. ccxt/tradeogre.py +608 -0
  754. ccxt/twox.py +326 -0
  755. ccxt/ubitex.py +409 -0
  756. ccxt/upbit.py +1833 -0
  757. ccxt/vertex.py +2922 -0
  758. ccxt/wallex.py +445 -0
  759. ccxt/wavesexchange.py +2472 -0
  760. ccxt/wazirx.py +1224 -0
  761. ccxt/whitebit.py +2469 -0
  762. ccxt/woo.py +3114 -0
  763. ccxt/woofipro.py +2533 -0
  764. ccxt/xt.py +4453 -0
  765. ccxt/yobit.py +1283 -0
  766. ccxt/zaif.py +725 -0
  767. ccxt/zonda.py +1828 -0
  768. ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
  769. ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
  770. ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
  771. ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
  772. ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,3027 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.bitrue import ImplicitAPI
8
+ import asyncio
9
+ import hashlib
10
+ import json
11
+ from ccxt.base.types import Balances, Currencies, Currency, Int, MarginModification, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry, TransferEntries
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 InvalidOrder
22
+ from ccxt.base.errors import OrderNotFound
23
+ from ccxt.base.errors import OrderImmediatelyFillable
24
+ from ccxt.base.errors import NotSupported
25
+ from ccxt.base.errors import DDoSProtection
26
+ from ccxt.base.errors import RateLimitExceeded
27
+ from ccxt.base.errors import ExchangeNotAvailable
28
+ from ccxt.base.errors import OnMaintenance
29
+ from ccxt.base.errors import InvalidNonce
30
+ from ccxt.base.decimal_to_precision import TRUNCATE
31
+ from ccxt.base.decimal_to_precision import TICK_SIZE
32
+ from ccxt.base.precise import Precise
33
+
34
+
35
+ class bitrue(Exchange, ImplicitAPI):
36
+
37
+ def describe(self):
38
+ return self.deep_extend(super(bitrue, self).describe(), {
39
+ 'id': 'bitrue',
40
+ 'name': 'Bitrue',
41
+ 'countries': ['SG'], # Singapore, Malta
42
+ 'rateLimit': 1000,
43
+ 'certified': False,
44
+ 'version': 'v1',
45
+ 'pro': True,
46
+ # new metainfo interface
47
+ 'has': {
48
+ 'CORS': None,
49
+ 'spot': True,
50
+ 'margin': False,
51
+ 'swap': True,
52
+ 'future': False,
53
+ 'option': False,
54
+ 'cancelAllOrders': True,
55
+ 'cancelOrder': True,
56
+ 'createMarketBuyOrderWithCost': True,
57
+ 'createMarketOrderWithCost': False,
58
+ 'createMarketSellOrderWithCost': False,
59
+ 'createOrder': True,
60
+ 'createStopLimitOrder': True,
61
+ 'createStopMarketOrder': True,
62
+ 'createStopOrder': True,
63
+ 'fetchBalance': True,
64
+ 'fetchBidsAsks': True,
65
+ 'fetchBorrowRateHistories': False,
66
+ 'fetchBorrowRateHistory': False,
67
+ 'fetchClosedOrders': True,
68
+ 'fetchCrossBorrowRate': False,
69
+ 'fetchCrossBorrowRates': False,
70
+ 'fetchCurrencies': True,
71
+ 'fetchDepositAddress': False,
72
+ 'fetchDeposits': True,
73
+ 'fetchDepositsWithdrawals': False,
74
+ 'fetchDepositWithdrawFee': 'emulated',
75
+ 'fetchDepositWithdrawFees': True,
76
+ 'fetchFundingRate': False,
77
+ 'fetchIsolatedBorrowRate': False,
78
+ 'fetchIsolatedBorrowRates': False,
79
+ 'fetchMarginMode': False,
80
+ 'fetchMarkets': True,
81
+ 'fetchMyTrades': True,
82
+ 'fetchOHLCV': True,
83
+ 'fetchOpenOrders': True,
84
+ 'fetchOrder': True,
85
+ 'fetchOrderBook': True,
86
+ 'fetchOrders': False,
87
+ 'fetchPositionMode': False,
88
+ 'fetchStatus': True,
89
+ 'fetchTicker': True,
90
+ 'fetchTickers': True,
91
+ 'fetchTime': True,
92
+ 'fetchTrades': True,
93
+ 'fetchTradingFee': False,
94
+ 'fetchTradingFees': False,
95
+ 'fetchTransactionFees': False,
96
+ 'fetchTransactions': False,
97
+ 'fetchTransfers': True,
98
+ 'fetchWithdrawals': True,
99
+ 'setLeverage': True,
100
+ 'setMargin': True,
101
+ 'transfer': True,
102
+ 'withdraw': True,
103
+ },
104
+ 'timeframes': {
105
+ '1m': '1m',
106
+ '5m': '5m',
107
+ '15m': '15m',
108
+ '30m': '30m',
109
+ '1h': '1H',
110
+ '2h': '2H',
111
+ '4h': '4H',
112
+ '1d': '1D',
113
+ '1w': '1W',
114
+ },
115
+ 'urls': {
116
+ 'logo': 'https://user-images.githubusercontent.com/1294454/139516488-243a830d-05dd-446b-91c6-c1f18fe30c63.jpg',
117
+ 'api': {
118
+ 'spot': 'https://www.bitrue.com/api',
119
+ 'fapi': 'https://fapi.bitrue.com/fapi',
120
+ 'dapi': 'https://fapi.bitrue.com/dapi',
121
+ 'kline': 'https://www.bitrue.com/kline-api',
122
+ },
123
+ 'www': 'https://www.bitrue.com',
124
+ 'referral': 'https://www.bitrue.com/affiliate/landing?cn=600000&inviteCode=EZWETQE',
125
+ 'doc': [
126
+ 'https://github.com/Bitrue-exchange/bitrue-official-api-docs',
127
+ 'https://www.bitrue.com/api-docs',
128
+ ],
129
+ 'fees': 'https://bitrue.zendesk.com/hc/en-001/articles/4405479952537',
130
+ },
131
+ 'api': {
132
+ 'spot': {
133
+ 'kline': {
134
+ 'public': {
135
+ 'get': {
136
+ 'public.json': 1,
137
+ 'public{currency}.json': 1,
138
+ },
139
+ },
140
+ },
141
+ 'v1': {
142
+ 'public': {
143
+ 'get': {
144
+ 'ping': 1,
145
+ 'time': 1,
146
+ 'exchangeInfo': 1,
147
+ 'depth': {'cost': 1, 'byLimit': [[100, 1], [500, 5], [1000, 10]]},
148
+ 'trades': 1,
149
+ 'historicalTrades': 5,
150
+ 'aggTrades': 1,
151
+ 'ticker/24hr': {'cost': 1, 'noSymbol': 40},
152
+ 'ticker/price': {'cost': 1, 'noSymbol': 2},
153
+ 'ticker/bookTicker': {'cost': 1, 'noSymbol': 2},
154
+ 'market/kline': 1,
155
+ },
156
+ },
157
+ 'private': {
158
+ 'get': {
159
+ 'order': 1,
160
+ 'openOrders': 1,
161
+ 'allOrders': 5,
162
+ 'account': 5,
163
+ 'myTrades': {'cost': 5, 'noSymbol': 40},
164
+ 'etf/net-value/{symbol}': 1,
165
+ 'withdraw/history': 1,
166
+ 'deposit/history': 1,
167
+ },
168
+ 'post': {
169
+ 'order': 4,
170
+ 'withdraw/commit': 1,
171
+ },
172
+ 'delete': {
173
+ 'order': 1,
174
+ },
175
+ },
176
+ },
177
+ 'v2': {
178
+ 'private': {
179
+ 'get': {
180
+ 'myTrades': 5,
181
+ },
182
+ },
183
+ },
184
+ },
185
+ 'fapi': {
186
+ 'v1': {
187
+ 'public': {
188
+ 'get': {
189
+ 'ping': 1,
190
+ 'time': 1,
191
+ 'contracts': 1,
192
+ 'depth': 1,
193
+ 'ticker': 1,
194
+ 'klines': 1,
195
+ },
196
+ },
197
+ },
198
+ 'v2': {
199
+ 'private': {
200
+ 'get': {
201
+ 'myTrades': 1,
202
+ 'openOrders': 1,
203
+ 'order': 1,
204
+ 'account': 1,
205
+ 'leverageBracket': 1,
206
+ 'commissionRate': 1,
207
+ 'futures_transfer_history': 1,
208
+ 'forceOrdersHistory': 1,
209
+ },
210
+ 'post': {
211
+ 'positionMargin': 1,
212
+ 'level_edit': 1,
213
+ 'cancel': 1,
214
+ 'order': 1,
215
+ 'allOpenOrders': 1,
216
+ 'futures_transfer': 1,
217
+ },
218
+ },
219
+ },
220
+ },
221
+ 'dapi': {
222
+ 'v1': {
223
+ 'public': {
224
+ 'get': {
225
+ 'ping': 1,
226
+ 'time': 1,
227
+ 'contracts': 1,
228
+ 'depth': 1,
229
+ 'ticker': 1,
230
+ 'klines': 1,
231
+ },
232
+ },
233
+ },
234
+ 'v2': {
235
+ 'private': {
236
+ 'get': {
237
+ 'myTrades': 1,
238
+ 'openOrders': 1,
239
+ 'order': 1,
240
+ 'account': 1,
241
+ 'leverageBracket': 1,
242
+ 'commissionRate': 1,
243
+ 'futures_transfer_history': 1,
244
+ 'forceOrdersHistory': 1,
245
+ },
246
+ 'post': {
247
+ 'positionMargin': 1,
248
+ 'level_edit': 1,
249
+ 'cancel': 1,
250
+ 'order': 1,
251
+ 'allOpenOrders': 1,
252
+ 'futures_transfer': 1,
253
+ },
254
+ },
255
+ },
256
+ },
257
+ },
258
+ 'fees': {
259
+ 'trading': {
260
+ 'feeSide': 'get',
261
+ 'tierBased': False,
262
+ 'percentage': True,
263
+ 'taker': self.parse_number('0.00098'),
264
+ 'maker': self.parse_number('0.00098'),
265
+ },
266
+ 'future': {
267
+ 'trading': {
268
+ 'feeSide': 'quote',
269
+ 'tierBased': True,
270
+ 'percentage': True,
271
+ 'taker': self.parse_number('0.000400'),
272
+ 'maker': self.parse_number('0.000200'),
273
+ 'tiers': {
274
+ 'taker': [
275
+ [self.parse_number('0'), self.parse_number('0.000400')],
276
+ [self.parse_number('250'), self.parse_number('0.000400')],
277
+ [self.parse_number('2500'), self.parse_number('0.000350')],
278
+ [self.parse_number('7500'), self.parse_number('0.000320')],
279
+ [self.parse_number('22500'), self.parse_number('0.000300')],
280
+ [self.parse_number('50000'), self.parse_number('0.000270')],
281
+ [self.parse_number('100000'), self.parse_number('0.000250')],
282
+ [self.parse_number('200000'), self.parse_number('0.000220')],
283
+ [self.parse_number('400000'), self.parse_number('0.000200')],
284
+ [self.parse_number('750000'), self.parse_number('0.000170')],
285
+ ],
286
+ 'maker': [
287
+ [self.parse_number('0'), self.parse_number('0.000200')],
288
+ [self.parse_number('250'), self.parse_number('0.000160')],
289
+ [self.parse_number('2500'), self.parse_number('0.000140')],
290
+ [self.parse_number('7500'), self.parse_number('0.000120')],
291
+ [self.parse_number('22500'), self.parse_number('0.000100')],
292
+ [self.parse_number('50000'), self.parse_number('0.000080')],
293
+ [self.parse_number('100000'), self.parse_number('0.000060')],
294
+ [self.parse_number('200000'), self.parse_number('0.000040')],
295
+ [self.parse_number('400000'), self.parse_number('0.000020')],
296
+ [self.parse_number('750000'), self.parse_number('0')],
297
+ ],
298
+ },
299
+ },
300
+ },
301
+ 'delivery': {
302
+ 'trading': {
303
+ 'feeSide': 'base',
304
+ 'tierBased': True,
305
+ 'percentage': True,
306
+ 'taker': self.parse_number('0.000500'),
307
+ 'maker': self.parse_number('0.000100'),
308
+ 'tiers': {
309
+ 'taker': [
310
+ [self.parse_number('0'), self.parse_number('0.000500')],
311
+ [self.parse_number('250'), self.parse_number('0.000450')],
312
+ [self.parse_number('2500'), self.parse_number('0.000400')],
313
+ [self.parse_number('7500'), self.parse_number('0.000300')],
314
+ [self.parse_number('22500'), self.parse_number('0.000250')],
315
+ [self.parse_number('50000'), self.parse_number('0.000240')],
316
+ [self.parse_number('100000'), self.parse_number('0.000240')],
317
+ [self.parse_number('200000'), self.parse_number('0.000240')],
318
+ [self.parse_number('400000'), self.parse_number('0.000240')],
319
+ [self.parse_number('750000'), self.parse_number('0.000240')],
320
+ ],
321
+ 'maker': [
322
+ [self.parse_number('0'), self.parse_number('0.000100')],
323
+ [self.parse_number('250'), self.parse_number('0.000080')],
324
+ [self.parse_number('2500'), self.parse_number('0.000050')],
325
+ [self.parse_number('7500'), self.parse_number('0.0000030')],
326
+ [self.parse_number('22500'), self.parse_number('0')],
327
+ [self.parse_number('50000'), self.parse_number('-0.000050')],
328
+ [self.parse_number('100000'), self.parse_number('-0.000060')],
329
+ [self.parse_number('200000'), self.parse_number('-0.000070')],
330
+ [self.parse_number('400000'), self.parse_number('-0.000080')],
331
+ [self.parse_number('750000'), self.parse_number('-0.000090')],
332
+ ],
333
+ },
334
+ },
335
+ },
336
+ },
337
+ # exchange-specific options
338
+ 'options': {
339
+ 'createMarketBuyOrderRequiresPrice': True,
340
+ 'fetchMarkets': [
341
+ 'spot',
342
+ 'linear',
343
+ 'inverse',
344
+ ],
345
+ # 'fetchTradesMethod': 'publicGetAggTrades', # publicGetTrades, publicGetHistoricalTrades
346
+ 'fetchMyTradesMethod': 'v2PrivateGetMyTrades', # spotV1PrivateGetMyTrades
347
+ 'hasAlreadyAuthenticatedSuccessfully': False,
348
+ 'recvWindow': 5 * 1000, # 5 sec, binance default
349
+ 'timeDifference': 0, # the difference between system clock and Binance clock
350
+ 'adjustForTimeDifference': False, # controls the adjustment logic upon instantiation
351
+ 'parseOrderToPrecision': False, # force amounts and costs in parseOrder to precision
352
+ 'newOrderRespType': {
353
+ 'market': 'FULL', # 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
354
+ 'limit': 'FULL', # we change it from 'ACK' by default to 'FULL'(returns immediately if limit is not hit)
355
+ },
356
+ 'networks': {
357
+ 'ERC20': 'ETH',
358
+ 'TRC20': 'TRX',
359
+ },
360
+ 'defaultType': 'spot',
361
+ 'timeframes': {
362
+ 'spot': {
363
+ '1m': '1m',
364
+ '5m': '5m',
365
+ '15m': '15m',
366
+ '30m': '30m',
367
+ '1h': '1H',
368
+ '2h': '2H',
369
+ '4h': '4H',
370
+ '12h': '12H',
371
+ '1d': '1D',
372
+ '1w': '1W',
373
+ },
374
+ 'future': {
375
+ '1m': '1min',
376
+ '5m': '5min',
377
+ '15m': '15min',
378
+ '30m': '30min',
379
+ '1h': '1h',
380
+ '1d': '1day',
381
+ '1w': '1week',
382
+ '1M': '1month',
383
+ },
384
+ },
385
+ 'accountsByType': {
386
+ 'spot': 'wallet',
387
+ 'future': 'contract',
388
+ 'swap': 'contract',
389
+ 'funding': 'wallet',
390
+ 'fund': 'wallet',
391
+ 'contract': 'contract',
392
+ },
393
+ },
394
+ 'commonCurrencies': {
395
+ 'MIM': 'MIM Swarm',
396
+ },
397
+ 'precisionMode': TICK_SIZE,
398
+ # https://binance-docs.github.io/apidocs/spot/en/#error-codes-2
399
+ 'exceptions': {
400
+ 'exact': {
401
+ 'System is under maintenance.': OnMaintenance, # {"code":1,"msg":"System is under maintenance."}
402
+ 'System abnormality': ExchangeError, # {"code":-1000,"msg":"System abnormality"}
403
+ 'You are not authorized to execute self request.': PermissionDenied, # {"msg":"You are not authorized to execute self request."}
404
+ 'API key does not exist': AuthenticationError,
405
+ 'Order would trigger immediately.': OrderImmediatelyFillable,
406
+ 'Stop price would trigger immediately.': OrderImmediatelyFillable, # {"code":-2010,"msg":"Stop price would trigger immediately."}
407
+ 'Order would immediately match and take.': OrderImmediatelyFillable, # {"code":-2010,"msg":"Order would immediately match and take."}
408
+ 'Account has insufficient balance for requested action.': InsufficientFunds,
409
+ 'Rest API trading is not enabled.': ExchangeNotAvailable,
410
+ "You don't have permission.": PermissionDenied, # {"msg":"You don't have permission.","success":false}
411
+ 'Market is closed.': ExchangeNotAvailable, # {"code":-1013,"msg":"Market is closed."}
412
+ 'Too many requests. Please try again later.': DDoSProtection, # {"msg":"Too many requests. Please try again later.","success":false}
413
+ '-1000': ExchangeNotAvailable, # {"code":-1000,"msg":"An unknown error occured while processing the request."}
414
+ '-1001': ExchangeNotAvailable, # 'Internal error; unable to process your request. Please try again.'
415
+ '-1002': AuthenticationError, # 'You are not authorized to execute self request.'
416
+ '-1003': RateLimitExceeded, # {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."}
417
+ '-1013': InvalidOrder, # createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL
418
+ '-1015': RateLimitExceeded, # 'Too many new orders; current limit is %s orders per %s.'
419
+ '-1016': ExchangeNotAvailable, # 'This service is no longer available.',
420
+ '-1020': BadRequest, # 'This operation is not supported.'
421
+ '-1021': InvalidNonce, # 'your time is ahead of server'
422
+ '-1022': AuthenticationError, # {"code":-1022,"msg":"Signature for self request is not valid."}
423
+ '-1100': BadRequest, # createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'
424
+ '-1101': BadRequest, # Too many parameters; expected %s and received %s.
425
+ '-1102': BadRequest, # Param %s or %s must be sent, but both were empty # {"code":-1102,"msg":"timestamp IllegalArgumentException.","data":null}
426
+ '-1103': BadRequest, # An unknown parameter was sent.
427
+ '-1104': BadRequest, # Not all sent parameters were read, read 8 parameters but was sent 9
428
+ '-1105': BadRequest, # Parameter %s was empty.
429
+ '-1106': BadRequest, # Parameter %s sent when not required.
430
+ '-1111': BadRequest, # Precision is over the maximum defined for self asset.
431
+ '-1112': InvalidOrder, # No orders on book for symbol.
432
+ '-1114': BadRequest, # TimeInForce parameter sent when not required.
433
+ '-1115': BadRequest, # Invalid timeInForce.
434
+ '-1116': BadRequest, # Invalid orderType.
435
+ '-1117': BadRequest, # Invalid side.
436
+ '-1166': InvalidOrder, # {"code":"-1166","msg":"The leverage value of the order is inconsistent with the user contract configuration 5","data":null}
437
+ '-1118': BadRequest, # New client order ID was empty.
438
+ '-1119': BadRequest, # Original client order ID was empty.
439
+ '-1120': BadRequest, # Invalid interval.
440
+ '-1121': BadSymbol, # Invalid symbol.
441
+ '-1125': AuthenticationError, # This listenKey does not exist.
442
+ '-1127': BadRequest, # More than %s hours between startTime and endTime.
443
+ '-1128': BadRequest, # {"code":-1128,"msg":"Combination of optional parameters invalid."}
444
+ '-1130': BadRequest, # Data sent for paramter %s is not valid.
445
+ '-1131': BadRequest, # recvWindow must be less than 60000
446
+ '-1160': InvalidOrder, # {"code":"-1160","msg":"Minimum order amount 10","data":null}
447
+ '-1156': InvalidOrder, # {"code":"-1156","msg":"The number of closed positions exceeds the total number of positions","data":null}
448
+ '-2008': AuthenticationError, # {"code":-2008,"msg":"Invalid Api-Key ID."}
449
+ '-2010': ExchangeError, # generic error code for createOrder -> 'Account has insufficient balance for requested action.', {"code":-2010,"msg":"Rest API trading is not enabled."}, etc...
450
+ '-2011': OrderNotFound, # cancelOrder(1, 'BTC/USDT') -> 'UNKNOWN_ORDER'
451
+ '-2013': OrderNotFound, # fetchOrder(1, 'BTC/USDT') -> 'Order does not exist'
452
+ '-2014': AuthenticationError, # {"code":-2014, "msg": "API-key format invalid."}
453
+ '-2015': AuthenticationError, # "Invalid API-key, IP, or permissions for action."
454
+ '-2017': InsufficientFunds, # {code":"-2017","msg":"Insufficient balance","data":null}
455
+ '-2019': InsufficientFunds, # {"code":-2019,"msg":"Margin is insufficient."}
456
+ '-3005': InsufficientFunds, # {"code":-3005,"msg":"Transferring out not allowed. Transfer out amount exceeds max amount."}
457
+ '-3006': InsufficientFunds, # {"code":-3006,"msg":"Your borrow amount has exceed maximum borrow amount."}
458
+ '-3008': InsufficientFunds, # {"code":-3008,"msg":"Borrow not allowed. Your borrow amount has exceed maximum borrow amount."}
459
+ '-3010': ExchangeError, # {"code":-3010,"msg":"Repay not allowed. Repay amount exceeds borrow amount."}
460
+ '-3015': ExchangeError, # {"code":-3015,"msg":"Repay amount exceeds borrow amount."}
461
+ '-3022': AccountSuspended, # You account's trading is banned.
462
+ '-4028': BadRequest, # {"code":-4028,"msg":"Leverage 100 is not valid"}
463
+ '-3020': InsufficientFunds, # {"code":-3020,"msg":"Transfer out amount exceeds max amount."}
464
+ '-3041': InsufficientFunds, # {"code":-3041,"msg":"Balance is not enough"}
465
+ '-5013': InsufficientFunds, # Asset transfer failed: insufficient balance"
466
+ '-11008': InsufficientFunds, # {"code":-11008,"msg":"Exceeding the account's maximum borrowable limit."}
467
+ '-4051': InsufficientFunds, # {"code":-4051,"msg":"Isolated balance insufficient."}
468
+ },
469
+ 'broad': {
470
+ 'has no operation privilege': PermissionDenied,
471
+ 'MAX_POSITION': InvalidOrder, # {"code":-2010,"msg":"Filter failure: MAX_POSITION"}
472
+ },
473
+ },
474
+ })
475
+
476
+ def currency_to_precision(self, code, fee, networkCode=None):
477
+ # info is available in currencies only if the user has configured his api keys
478
+ if self.safe_value(self.currencies[code], 'precision') is not None:
479
+ return self.decimal_to_precision(fee, TRUNCATE, self.currencies[code]['precision'], self.precisionMode, self.paddingMode)
480
+ else:
481
+ return self.number_to_string(fee)
482
+
483
+ def nonce(self):
484
+ return self.milliseconds() - self.options['timeDifference']
485
+
486
+ async def fetch_status(self, params={}):
487
+ """
488
+ the latest known information on the availability of the exchange API
489
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#test-connectivity
490
+ :param dict [params]: extra parameters specific to the exchange API endpoint
491
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
492
+ """
493
+ response = await self.spotV1PublicGetPing(params)
494
+ #
495
+ # empty means working status.
496
+ #
497
+ # {}
498
+ #
499
+ keys = list(response.keys())
500
+ keysLength = len(keys)
501
+ formattedStatus = 'maintenance' if keysLength else 'ok'
502
+ return {
503
+ 'status': formattedStatus,
504
+ 'updated': None,
505
+ 'eta': None,
506
+ 'url': None,
507
+ 'info': response,
508
+ }
509
+
510
+ async def fetch_time(self, params={}):
511
+ """
512
+ fetches the current integer timestamp in milliseconds from the exchange server
513
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#check-server-time
514
+ :param dict [params]: extra parameters specific to the exchange API endpoint
515
+ :returns int: the current integer timestamp in milliseconds from the exchange server
516
+ """
517
+ response = await self.spotV1PublicGetTime(params)
518
+ #
519
+ # {
520
+ # "serverTime":1635467280514
521
+ # }
522
+ #
523
+ return self.safe_integer(response, 'serverTime')
524
+
525
+ def safe_network(self, networkId):
526
+ uppercaseNetworkId = networkId.upper()
527
+ networksById: dict = {
528
+ 'Aeternity': 'Aeternity',
529
+ 'AION': 'AION',
530
+ 'Algorand': 'Algorand',
531
+ 'ASK': 'ASK',
532
+ 'ATOM': 'ATOM',
533
+ 'AVAX C-Chain': 'AVAX C-Chain',
534
+ 'bch': 'bch',
535
+ 'BCH': 'BCH',
536
+ 'BEP2': 'BEP2',
537
+ 'BEP20': 'BEP20',
538
+ 'Bitcoin': 'Bitcoin',
539
+ 'BRP20': 'BRP20',
540
+ 'Cardano': 'ADA',
541
+ 'CasinoCoin': 'CasinoCoin',
542
+ 'CasinoCoin XRPL': 'CasinoCoin XRPL',
543
+ 'Contentos': 'Contentos',
544
+ 'Dash': 'Dash',
545
+ 'Decoin': 'Decoin',
546
+ 'DeFiChain': 'DeFiChain',
547
+ 'DGB': 'DGB',
548
+ 'Divi': 'Divi',
549
+ 'dogecoin': 'DOGE',
550
+ 'EOS': 'EOS',
551
+ 'ERC20': 'ERC20',
552
+ 'ETC': 'ETC',
553
+ 'Filecoin': 'Filecoin',
554
+ 'FREETON': 'FREETON',
555
+ 'HBAR': 'HBAR',
556
+ 'Hedera Hashgraph': 'Hedera Hashgraph',
557
+ 'HRC20': 'HRC20',
558
+ 'ICON': 'ICON',
559
+ 'ICP': 'ICP',
560
+ 'Ignis': 'Ignis',
561
+ 'Internet Computer': 'Internet Computer',
562
+ 'IOTA': 'IOTA',
563
+ 'KAVA': 'KAVA',
564
+ 'KSM': 'KSM',
565
+ 'LiteCoin': 'LiteCoin',
566
+ 'Luna': 'Luna',
567
+ 'MATIC': 'MATIC',
568
+ 'Mobile Coin': 'Mobile Coin',
569
+ 'MonaCoin': 'MonaCoin',
570
+ 'Monero': 'Monero',
571
+ 'NEM': 'NEM',
572
+ 'NEP5': 'NEP5',
573
+ 'OMNI': 'OMNI',
574
+ 'PAC': 'PAC',
575
+ 'Polkadot': 'Polkadot',
576
+ 'Ravencoin': 'Ravencoin',
577
+ 'Safex': 'Safex',
578
+ 'SOLANA': 'SOL',
579
+ 'Songbird': 'Songbird',
580
+ 'Stellar Lumens': 'Stellar Lumens',
581
+ 'Symbol': 'Symbol',
582
+ 'Tezos': 'XTZ',
583
+ 'theta': 'theta',
584
+ 'THETA': 'THETA',
585
+ 'TRC20': 'TRC20',
586
+ 'VeChain': 'VeChain',
587
+ 'VECHAIN': 'VECHAIN',
588
+ 'Wanchain': 'Wanchain',
589
+ 'XinFin Network': 'XinFin Network',
590
+ 'XRP': 'XRP',
591
+ 'XRPL': 'XRPL',
592
+ 'ZIL': 'ZIL',
593
+ }
594
+ return self.safe_string_2(networksById, networkId, uppercaseNetworkId, networkId)
595
+
596
+ async def fetch_currencies(self, params={}) -> Currencies:
597
+ """
598
+ fetches all available currencies on an exchange
599
+ :param dict [params]: extra parameters specific to the exchange API endpoint
600
+ :returns dict: an associative dictionary of currencies
601
+ """
602
+ response = await self.spotV1PublicGetExchangeInfo(params)
603
+ #
604
+ # {
605
+ # "timezone":"CTT",
606
+ # "serverTime":1635464889117,
607
+ # "rateLimits":[
608
+ # {"rateLimitType":"REQUESTS_WEIGHT","interval":"MINUTES","limit":6000},
609
+ # {"rateLimitType":"ORDERS","interval":"SECONDS","limit":150},
610
+ # {"rateLimitType":"ORDERS","interval":"DAYS","limit":288000},
611
+ # ],
612
+ # "exchangeFilters":[],
613
+ # "symbols":[
614
+ # {
615
+ # "symbol":"SHABTC",
616
+ # "status":"TRADING",
617
+ # "baseAsset":"sha",
618
+ # "baseAssetPrecision":0,
619
+ # "quoteAsset":"btc",
620
+ # "quotePrecision":10,
621
+ # "orderTypes":["MARKET","LIMIT"],
622
+ # "icebergAllowed":false,
623
+ # "filters":[
624
+ # {"filterType":"PRICE_FILTER","minPrice":"0.00000001349","maxPrice":"0.00000017537","priceScale":10},
625
+ # {"filterType":"LOT_SIZE","minQty":"1.0","minVal":"0.00020","maxQty":"1000000000","volumeScale":0},
626
+ # ],
627
+ # "defaultPrice":"0.0000006100",
628
+ # },
629
+ # ],
630
+ # "coins":[
631
+ # {
632
+ # "coin": "near",
633
+ # "coinFulName": "NEAR Protocol",
634
+ # "chains": ["BEP20",],
635
+ # "chainDetail": [
636
+ # {
637
+ # "chain": "BEP20",
638
+ # "enableWithdraw": True,
639
+ # "enableDeposit": True,
640
+ # "withdrawFee": "0.2000",
641
+ # "minWithdraw": "5.0000",
642
+ # "maxWithdraw": "1000000000000000.0000",
643
+ # },
644
+ # ],
645
+ # },
646
+ # ],
647
+ # }
648
+ #
649
+ result: dict = {}
650
+ coins = self.safe_value(response, 'coins', [])
651
+ for i in range(0, len(coins)):
652
+ currency = coins[i]
653
+ id = self.safe_string(currency, 'coin')
654
+ name = self.safe_string(currency, 'coinFulName')
655
+ code = self.safe_currency_code(id)
656
+ deposit = None
657
+ withdraw = None
658
+ minWithdrawString = None
659
+ maxWithdrawString = None
660
+ minWithdrawFeeString = None
661
+ networkDetails = self.safe_value(currency, 'chainDetail', [])
662
+ networks: dict = {}
663
+ for j in range(0, len(networkDetails)):
664
+ entry = networkDetails[j]
665
+ networkId = self.safe_string(entry, 'chain')
666
+ network = self.network_id_to_code(networkId, code)
667
+ enableDeposit = self.safe_value(entry, 'enableDeposit')
668
+ deposit = enableDeposit if (enableDeposit) else deposit
669
+ enableWithdraw = self.safe_value(entry, 'enableWithdraw')
670
+ withdraw = enableWithdraw if (enableWithdraw) else withdraw
671
+ networkWithdrawFeeString = self.safe_string(entry, 'withdrawFee')
672
+ if networkWithdrawFeeString is not None:
673
+ minWithdrawFeeString = networkWithdrawFeeString if (minWithdrawFeeString is None) else Precise.string_min(networkWithdrawFeeString, minWithdrawFeeString)
674
+ networkMinWithdrawString = self.safe_string(entry, 'minWithdraw')
675
+ if networkMinWithdrawString is not None:
676
+ minWithdrawString = networkMinWithdrawString if (minWithdrawString is None) else Precise.string_min(networkMinWithdrawString, minWithdrawString)
677
+ networkMaxWithdrawString = self.safe_string(entry, 'maxWithdraw')
678
+ if networkMaxWithdrawString is not None:
679
+ maxWithdrawString = networkMaxWithdrawString if (maxWithdrawString is None) else Precise.string_max(networkMaxWithdrawString, maxWithdrawString)
680
+ networks[network] = {
681
+ 'info': entry,
682
+ 'id': networkId,
683
+ 'network': network,
684
+ 'deposit': enableDeposit,
685
+ 'withdraw': enableWithdraw,
686
+ 'active': enableDeposit and enableWithdraw,
687
+ 'fee': self.parse_number(networkWithdrawFeeString),
688
+ 'precision': None,
689
+ 'limits': {
690
+ 'withdraw': {
691
+ 'min': self.parse_number(networkMinWithdrawString),
692
+ 'max': self.parse_number(networkMaxWithdrawString),
693
+ },
694
+ },
695
+ }
696
+ result[code] = {
697
+ 'id': id,
698
+ 'name': name,
699
+ 'code': code,
700
+ 'precision': None,
701
+ 'info': currency,
702
+ 'active': deposit and withdraw,
703
+ 'deposit': deposit,
704
+ 'withdraw': withdraw,
705
+ 'networks': networks,
706
+ 'fee': self.parse_number(minWithdrawFeeString),
707
+ # 'fees': fees,
708
+ 'limits': {
709
+ 'withdraw': {
710
+ 'min': self.parse_number(minWithdrawString),
711
+ 'max': self.parse_number(maxWithdrawString),
712
+ },
713
+ },
714
+ }
715
+ return result
716
+
717
+ async def fetch_markets(self, params={}) -> List[Market]:
718
+ """
719
+ retrieves data on all markets for bitrue
720
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#exchangeInfo_endpoint
721
+ :see: https://www.bitrue.com/api-docs#current-open-contract
722
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#current-open-contract
723
+ :param dict [params]: extra parameters specific to the exchange api endpoint
724
+ :returns dict[]: an array of objects representing market data
725
+ """
726
+ promisesRaw = []
727
+ fetchMarkets = self.safe_value(self.options, 'fetchMarkets', ['spot', 'linear', 'inverse'])
728
+ for i in range(0, len(fetchMarkets)):
729
+ marketType = fetchMarkets[i]
730
+ if marketType == 'spot':
731
+ promisesRaw.append(self.spotV1PublicGetExchangeInfo(params))
732
+ elif marketType == 'linear':
733
+ promisesRaw.append(self.fapiV1PublicGetContracts(params))
734
+ elif marketType == 'inverse':
735
+ promisesRaw.append(self.dapiV1PublicGetContracts(params))
736
+ else:
737
+ raise ExchangeError(self.id + ' fetchMarkets() self.options fetchMarkets "' + marketType + '" is not a supported market type')
738
+ promises = await asyncio.gather(*promisesRaw)
739
+ spotMarkets = self.safe_value(self.safe_value(promises, 0), 'symbols', [])
740
+ futureMarkets = self.safe_value(promises, 1)
741
+ deliveryMarkets = self.safe_value(promises, 2)
742
+ markets = spotMarkets
743
+ markets = self.array_concat(markets, futureMarkets)
744
+ markets = self.array_concat(markets, deliveryMarkets)
745
+ #
746
+ # spot
747
+ #
748
+ # {
749
+ # "timezone":"CTT",
750
+ # "serverTime":1635464889117,
751
+ # "rateLimits":[
752
+ # {"rateLimitType":"REQUESTS_WEIGHT","interval":"MINUTES","limit":6000},
753
+ # {"rateLimitType":"ORDERS","interval":"SECONDS","limit":150},
754
+ # {"rateLimitType":"ORDERS","interval":"DAYS","limit":288000},
755
+ # ],
756
+ # "exchangeFilters":[],
757
+ # "symbols":[
758
+ # {
759
+ # "symbol":"SHABTC",
760
+ # "status":"TRADING",
761
+ # "baseAsset":"sha",
762
+ # "baseAssetPrecision":0,
763
+ # "quoteAsset":"btc",
764
+ # "quotePrecision":10,
765
+ # "orderTypes":["MARKET","LIMIT"],
766
+ # "icebergAllowed":false,
767
+ # "filters":[
768
+ # {"filterType":"PRICE_FILTER","minPrice":"0.00000001349","maxPrice":"0.00000017537","priceScale":10},
769
+ # {"filterType":"LOT_SIZE","minQty":"1.0","minVal":"0.00020","maxQty":"1000000000","volumeScale":0},
770
+ # ],
771
+ # "defaultPrice":"0.0000006100",
772
+ # },
773
+ # ],
774
+ # "coins":[
775
+ # {
776
+ # "coin":"sbr",
777
+ # "coinFulName":"Saber",
778
+ # "enableWithdraw":true,
779
+ # "enableDeposit":true,
780
+ # "chains":["SOLANA"],
781
+ # "withdrawFee":"2.0",
782
+ # "minWithdraw":"5.0",
783
+ # "maxWithdraw":"1000000000000000",
784
+ # },
785
+ # ],
786
+ # }
787
+ #
788
+ # swap / delivery
789
+ #
790
+ # [
791
+ # {
792
+ # "symbol": "H-HT-USDT",
793
+ # "pricePrecision": 8,
794
+ # "side": 1,
795
+ # "maxMarketVolume": 100000,
796
+ # "multiplier": 6,
797
+ # "minOrderVolume": 1,
798
+ # "maxMarketMoney": 10000000,
799
+ # "type": "H", # E: perpetual contract, S: test contract, others are mixed contract
800
+ # "maxLimitVolume": 1000000,
801
+ # "maxValidOrder": 20,
802
+ # "multiplierCoin": "HT",
803
+ # "minOrderMoney": 0.001,
804
+ # "maxLimitMoney": 1000000,
805
+ # "status": 1
806
+ # }
807
+ # ]
808
+ #
809
+ if self.options['adjustForTimeDifference']:
810
+ await self.load_time_difference()
811
+ return self.parse_markets(markets)
812
+
813
+ def parse_market(self, market: dict) -> Market:
814
+ id = self.safe_string(market, 'symbol')
815
+ lowercaseId = self.safe_string_lower(market, 'symbol')
816
+ side = self.safe_integer(market, 'side') # 1 linear, 0 inverse, None spot
817
+ type = None
818
+ isLinear = None
819
+ isInverse = None
820
+ if side is None:
821
+ type = 'spot'
822
+ else:
823
+ type = 'swap'
824
+ isLinear = (side == 1)
825
+ isInverse = (side == 0)
826
+ isContract = (type != 'spot')
827
+ baseId = self.safe_string(market, 'baseAsset')
828
+ quoteId = self.safe_string(market, 'quoteAsset')
829
+ settleId = None
830
+ settle = None
831
+ if isContract:
832
+ symbolSplit = id.split('-')
833
+ baseId = self.safe_string(symbolSplit, 1)
834
+ quoteId = self.safe_string(symbolSplit, 2)
835
+ if isLinear:
836
+ settleId = quoteId
837
+ else:
838
+ settleId = baseId
839
+ settle = self.safe_currency_code(settleId)
840
+ base = self.safe_currency_code(baseId)
841
+ quote = self.safe_currency_code(quoteId)
842
+ symbol = base + '/' + quote
843
+ if settle is not None:
844
+ symbol += ':' + settle
845
+ filters = self.safe_value(market, 'filters', [])
846
+ filtersByType = self.index_by(filters, 'filterType')
847
+ status = self.safe_string(market, 'status')
848
+ priceFilter = self.safe_value(filtersByType, 'PRICE_FILTER', {})
849
+ amountFilter = self.safe_value(filtersByType, 'LOT_SIZE', {})
850
+ defaultPricePrecision = self.safe_string(market, 'pricePrecision')
851
+ defaultAmountPrecision = self.safe_string(market, 'quantityPrecision')
852
+ pricePrecision = self.safe_string(priceFilter, 'priceScale', defaultPricePrecision)
853
+ amountPrecision = self.safe_string(amountFilter, 'volumeScale', defaultAmountPrecision)
854
+ multiplier = self.safe_string(market, 'multiplier')
855
+ maxQuantity = self.safe_number(amountFilter, 'maxQty')
856
+ if maxQuantity is None:
857
+ maxQuantity = self.safe_number(market, 'maxValidOrder')
858
+ minCost = self.safe_number(amountFilter, 'minVal')
859
+ if minCost is None:
860
+ minCost = self.safe_number(market, 'minOrderMoney')
861
+ return {
862
+ 'id': id,
863
+ 'lowercaseId': lowercaseId,
864
+ 'symbol': symbol,
865
+ 'base': base,
866
+ 'quote': quote,
867
+ 'settle': settle,
868
+ 'baseId': baseId,
869
+ 'quoteId': quoteId,
870
+ 'settleId': settleId,
871
+ 'type': type,
872
+ 'spot': (type == 'spot'),
873
+ 'margin': False,
874
+ 'swap': isContract,
875
+ 'future': False,
876
+ 'option': False,
877
+ 'active': (status == 'TRADING'),
878
+ 'contract': isContract,
879
+ 'linear': isLinear,
880
+ 'inverse': isInverse,
881
+ 'contractSize': self.parse_number(Precise.string_abs(multiplier)),
882
+ 'expiry': None,
883
+ 'expiryDatetime': None,
884
+ 'strike': None,
885
+ 'optionType': None,
886
+ 'precision': {
887
+ 'amount': self.parse_number(self.parse_precision(amountPrecision)),
888
+ 'price': self.parse_number(self.parse_precision(pricePrecision)),
889
+ },
890
+ 'limits': {
891
+ 'leverage': {
892
+ 'min': None,
893
+ 'max': None,
894
+ },
895
+ 'amount': {
896
+ 'min': self.safe_number(amountFilter, 'minQty'),
897
+ 'max': maxQuantity,
898
+ },
899
+ 'price': {
900
+ 'min': self.safe_number(priceFilter, 'minPrice'),
901
+ 'max': self.safe_number(priceFilter, 'maxPrice'),
902
+ },
903
+ 'cost': {
904
+ 'min': minCost,
905
+ 'max': None,
906
+ },
907
+ },
908
+ 'created': None,
909
+ 'info': market,
910
+ }
911
+
912
+ def parse_balance(self, response) -> Balances:
913
+ #
914
+ # spot
915
+ #
916
+ # {
917
+ # "makerCommission":0,
918
+ # "takerCommission":0,
919
+ # "buyerCommission":0,
920
+ # "sellerCommission":0,
921
+ # "updateTime":null,
922
+ # "balances":[
923
+ # {"asset":"sbr","free":"0","locked":"0"},
924
+ # {"asset":"ksm","free":"0","locked":"0"},
925
+ # {"asset":"neo3s","free":"0","locked":"0"},
926
+ # ],
927
+ # "canTrade":false,
928
+ # "canWithdraw":false,
929
+ # "canDeposit":false
930
+ # }
931
+ #
932
+ # swap
933
+ #
934
+ # {
935
+ # "account":[
936
+ # {
937
+ # "marginCoin":"USDT",
938
+ # "coinPrecious":4,
939
+ # "accountNormal":1010.4043400372839856,
940
+ # "accountLock":2.9827889600000006,
941
+ # "partPositionNormal":0,
942
+ # "totalPositionNormal":0,
943
+ # "achievedAmount":0,
944
+ # "unrealizedAmount":0,
945
+ # "totalMarginRate":0,
946
+ # "totalEquity":1010.4043400372839856,
947
+ # "partEquity":0,
948
+ # "totalCost":0,
949
+ # "sumMarginRate":0,
950
+ # "sumOpenRealizedAmount":0,
951
+ # "canUseTrialFund":0,
952
+ # "sumMaintenanceMargin":null,
953
+ # "futureModel":null,
954
+ # "positionVos":[]
955
+ # }
956
+ # ]
957
+ # }
958
+ #
959
+ result: dict = {
960
+ 'info': response,
961
+ }
962
+ timestamp = self.safe_integer(response, 'updateTime')
963
+ balances = self.safe_value_2(response, 'balances', 'account', [])
964
+ for i in range(0, len(balances)):
965
+ balance = balances[i]
966
+ currencyId = self.safe_string_2(balance, 'asset', 'marginCoin')
967
+ code = self.safe_currency_code(currencyId)
968
+ account = self.account()
969
+ account['free'] = self.safe_string_2(balance, 'free', 'accountNormal')
970
+ account['used'] = self.safe_string_2(balance, 'locked', 'accountLock')
971
+ result[code] = account
972
+ result['timestamp'] = timestamp
973
+ result['datetime'] = self.iso8601(timestamp)
974
+ return self.safe_balance(result)
975
+
976
+ async def fetch_balance(self, params={}) -> Balances:
977
+ """
978
+ query for balance and get the amount of funds available for trading or funds locked in orders
979
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#account-information-user_data
980
+ :see: https://www.bitrue.com/api-docs#account-information-v2-user_data-hmac-sha256
981
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#account-information-v2-user_data-hmac-sha256
982
+ :param dict [params]: extra parameters specific to the exchange API endpoint
983
+ :param str [params.type]: 'future', 'delivery', 'spot', 'swap'
984
+ :param str [params.subType]: 'linear', 'inverse'
985
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
986
+ """
987
+ await self.load_markets()
988
+ type = None
989
+ type, params = self.handle_market_type_and_params('fetchBalance', None, params)
990
+ subType = None
991
+ subType, params = self.handle_sub_type_and_params('fetchBalance', None, params)
992
+ response = None
993
+ result = None
994
+ if type == 'swap':
995
+ if subType is not None and subType == 'inverse':
996
+ response = await self.dapiV2PrivateGetAccount(params)
997
+ result = self.safe_value(response, 'data', {})
998
+ #
999
+ # {
1000
+ # "code":"0",
1001
+ # "msg":"Success",
1002
+ # "data":{
1003
+ # "account":[
1004
+ # {
1005
+ # "marginCoin":"USD",
1006
+ # "coinPrecious":4,
1007
+ # "accountNormal":1010.4043400372839856,
1008
+ # "accountLock":2.9827889600000006,
1009
+ # "partPositionNormal":0,
1010
+ # "totalPositionNormal":0,
1011
+ # "achievedAmount":0,
1012
+ # "unrealizedAmount":0,
1013
+ # "totalMarginRate":0,
1014
+ # "totalEquity":1010.4043400372839856,
1015
+ # "partEquity":0,
1016
+ # "totalCost":0,
1017
+ # "sumMarginRate":0,
1018
+ # "sumOpenRealizedAmount":0,
1019
+ # "canUseTrialFund":0,
1020
+ # "sumMaintenanceMargin":null,
1021
+ # "futureModel":null,
1022
+ # "positionVos":[]
1023
+ # }
1024
+ # ]
1025
+ # }
1026
+ # }
1027
+ #
1028
+ else:
1029
+ response = await self.fapiV2PrivateGetAccount(params)
1030
+ result = self.safe_value(response, 'data', {})
1031
+ #
1032
+ # {
1033
+ # "code":"0",
1034
+ # "msg":"Success",
1035
+ # "data":{
1036
+ # "account":[
1037
+ # {
1038
+ # "marginCoin":"USDT",
1039
+ # "coinPrecious":4,
1040
+ # "accountNormal":1010.4043400372839856,
1041
+ # "accountLock":2.9827889600000006,
1042
+ # "partPositionNormal":0,
1043
+ # "totalPositionNormal":0,
1044
+ # "achievedAmount":0,
1045
+ # "unrealizedAmount":0,
1046
+ # "totalMarginRate":0,
1047
+ # "totalEquity":1010.4043400372839856,
1048
+ # "partEquity":0,
1049
+ # "totalCost":0,
1050
+ # "sumMarginRate":0,
1051
+ # "sumOpenRealizedAmount":0,
1052
+ # "canUseTrialFund":0,
1053
+ # "sumMaintenanceMargin":null,
1054
+ # "futureModel":null,
1055
+ # "positionVos":[]
1056
+ # }
1057
+ # ]
1058
+ # }
1059
+ # }
1060
+ #
1061
+ else:
1062
+ response = await self.spotV1PrivateGetAccount(params)
1063
+ result = response
1064
+ #
1065
+ # {
1066
+ # "makerCommission":0,
1067
+ # "takerCommission":0,
1068
+ # "buyerCommission":0,
1069
+ # "sellerCommission":0,
1070
+ # "updateTime":null,
1071
+ # "balances":[
1072
+ # {"asset":"sbr","free":"0","locked":"0"},
1073
+ # {"asset":"ksm","free":"0","locked":"0"},
1074
+ # {"asset":"neo3s","free":"0","locked":"0"},
1075
+ # ],
1076
+ # "canTrade":false,
1077
+ # "canWithdraw":false,
1078
+ # "canDeposit":false
1079
+ # }
1080
+ #
1081
+ return self.parse_balance(result)
1082
+
1083
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1084
+ """
1085
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1086
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#order-book
1087
+ :see: https://www.bitrue.com/api-docs#order-book
1088
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#order-book
1089
+ :param str symbol: unified symbol of the market to fetch the order book for
1090
+ :param int [limit]: the maximum amount of order book entries to return
1091
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1092
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1093
+ """
1094
+ await self.load_markets()
1095
+ market = self.market(symbol)
1096
+ response = None
1097
+ if market['swap']:
1098
+ request: dict = {
1099
+ 'contractName': market['id'],
1100
+ }
1101
+ if limit is not None:
1102
+ if limit > 100:
1103
+ limit = 100
1104
+ request['limit'] = limit # default 100, max 100, see https://www.bitrue.com/api-docs#order-book
1105
+ if market['linear']:
1106
+ response = await self.fapiV1PublicGetDepth(self.extend(request, params))
1107
+ elif market['inverse']:
1108
+ response = await self.dapiV1PublicGetDepth(self.extend(request, params))
1109
+ elif market['spot']:
1110
+ request: dict = {
1111
+ 'symbol': market['id'],
1112
+ }
1113
+ if limit is not None:
1114
+ if limit > 1000:
1115
+ limit = 1000
1116
+ request['limit'] = limit # default 100, max 1000, see https://github.com/Bitrue-exchange/bitrue-official-api-docs#order-book
1117
+ response = await self.spotV1PublicGetDepth(self.extend(request, params))
1118
+ else:
1119
+ raise NotSupported(self.id + ' fetchOrderBook only support spot & swap markets')
1120
+ #
1121
+ # spot
1122
+ #
1123
+ # {
1124
+ # "lastUpdateId":1635474910177,
1125
+ # "bids":[
1126
+ # ["61436.84","0.05",[]],
1127
+ # ["61435.77","0.0124",[]],
1128
+ # ["61434.88","0.012",[]],
1129
+ # ],
1130
+ # "asks":[
1131
+ # ["61452.46","0.0001",[]],
1132
+ # ["61452.47","0.0597",[]],
1133
+ # ["61452.76","0.0713",[]],
1134
+ # ]
1135
+ # }
1136
+ #
1137
+ # swap
1138
+ #
1139
+ # {
1140
+ # "asks": [[34916.5, 2582], [34916.6, 2193], [34916.7, 2629], [34916.8, 3478], [34916.9, 2718]],
1141
+ # "bids": [[34916.4, 92065], [34916.3, 25703], [34916.2, 37259], [34916.1, 26446], [34916, 44456]],
1142
+ # "time": 1699338305000
1143
+ # }
1144
+ #
1145
+ timestamp = self.safe_integer(response, 'time')
1146
+ orderbook = self.parse_order_book(response, symbol, timestamp)
1147
+ orderbook['nonce'] = self.safe_integer(response, 'lastUpdateId')
1148
+ return orderbook
1149
+
1150
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1151
+ #
1152
+ # fetchBidsAsks
1153
+ #
1154
+ # {
1155
+ # "symbol": "LTCBTC",
1156
+ # "bidPrice": "4.00000000",
1157
+ # "bidQty": "431.00000000",
1158
+ # "askPrice": "4.00000200",
1159
+ # "askQty": "9.00000000"
1160
+ # }
1161
+ #
1162
+ # fetchTicker
1163
+ #
1164
+ # {
1165
+ # "symbol": "BNBBTC",
1166
+ # "priceChange": "0.000248",
1167
+ # "priceChangePercent": "3.5500",
1168
+ # "weightedAvgPrice": null,
1169
+ # "prevClosePrice": null,
1170
+ # "lastPrice": "0.007226",
1171
+ # "lastQty": null,
1172
+ # "bidPrice": "0.007208",
1173
+ # "askPrice": "0.007240",
1174
+ # "openPrice": "0.006978",
1175
+ # "highPrice": "0.007295",
1176
+ # "lowPrice": "0.006935",
1177
+ # "volume": "11749.86",
1178
+ # "quoteVolume": "84.1066211",
1179
+ # "openTime": 0,
1180
+ # "closeTime": 0,
1181
+ # "firstId": 0,
1182
+ # "lastId": 0,
1183
+ # "count": 0
1184
+ # }
1185
+ #
1186
+ symbol = self.safe_symbol(None, market)
1187
+ last = self.safe_string_2(ticker, 'lastPrice', 'last')
1188
+ timestamp = self.safe_integer(ticker, 'time')
1189
+ percentage = None
1190
+ if market['swap']:
1191
+ percentage = Precise.string_mul(self.safe_string(ticker, 'rose'), '100')
1192
+ else:
1193
+ percentage = self.safe_string(ticker, 'priceChangePercent')
1194
+ return self.safe_ticker({
1195
+ 'symbol': symbol,
1196
+ 'timestamp': timestamp,
1197
+ 'datetime': self.iso8601(timestamp),
1198
+ 'high': self.safe_string_2(ticker, 'highPrice', 'high'),
1199
+ 'low': self.safe_string_2(ticker, 'lowPrice', 'low'),
1200
+ 'bid': self.safe_string_2(ticker, 'bidPrice', 'buy'),
1201
+ 'bidVolume': self.safe_string(ticker, 'bidQty'),
1202
+ 'ask': self.safe_string_2(ticker, 'askPrice', 'sell'),
1203
+ 'askVolume': self.safe_string(ticker, 'askQty'),
1204
+ 'vwap': self.safe_string(ticker, 'weightedAvgPrice'),
1205
+ 'open': self.safe_string(ticker, 'openPrice'),
1206
+ 'close': last,
1207
+ 'last': last,
1208
+ 'previousClose': None,
1209
+ 'change': self.safe_string(ticker, 'priceChange'),
1210
+ 'percentage': percentage,
1211
+ 'average': None,
1212
+ 'baseVolume': self.safe_string_2(ticker, 'volume', 'vol'),
1213
+ 'quoteVolume': self.safe_string(ticker, 'quoteVolume'),
1214
+ 'info': ticker,
1215
+ }, market)
1216
+
1217
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1218
+ """
1219
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1220
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#24hr-ticker-price-change-statistics
1221
+ :see: https://www.bitrue.com/api-docs#ticker
1222
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#ticker
1223
+ :param str symbol: unified symbol of the market to fetch the ticker for
1224
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1225
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1226
+ """
1227
+ await self.load_markets()
1228
+ market = self.market(symbol)
1229
+ response = None
1230
+ data = None
1231
+ if market['swap']:
1232
+ request: dict = {
1233
+ 'contractName': market['id'],
1234
+ }
1235
+ if market['linear']:
1236
+ response = await self.fapiV1PublicGetTicker(self.extend(request, params))
1237
+ elif market['inverse']:
1238
+ response = await self.dapiV1PublicGetTicker(self.extend(request, params))
1239
+ data = response
1240
+ elif market['spot']:
1241
+ request: dict = {
1242
+ 'symbol': market['id'],
1243
+ }
1244
+ response = await self.spotV1PublicGetTicker24hr(self.extend(request, params))
1245
+ data = self.safe_value(response, 0, {})
1246
+ else:
1247
+ raise NotSupported(self.id + ' fetchTicker only support spot & swap markets')
1248
+ #
1249
+ # spot
1250
+ #
1251
+ # [{
1252
+ # symbol: 'BTCUSDT',
1253
+ # priceChange: '105.20',
1254
+ # priceChangePercent: '0.3000',
1255
+ # weightedAvgPrice: null,
1256
+ # prevClosePrice: null,
1257
+ # lastPrice: '34905.21',
1258
+ # lastQty: null,
1259
+ # bidPrice: '34905.21',
1260
+ # askPrice: '34905.22',
1261
+ # openPrice: '34800.01',
1262
+ # highPrice: '35276.33',
1263
+ # lowPrice: '34787.51',
1264
+ # volume: '12549.6481',
1265
+ # quoteVolume: '439390492.917',
1266
+ # openTime: '0',
1267
+ # closeTime: '0',
1268
+ # firstId: '0',
1269
+ # lastId: '0',
1270
+ # count: '0'
1271
+ # }]
1272
+ #
1273
+ # swap
1274
+ #
1275
+ # {
1276
+ # "high": "35296",
1277
+ # "vol": "779308354",
1278
+ # "last": "34884.1",
1279
+ # "low": "34806.7",
1280
+ # "buy": 34883.9,
1281
+ # "sell": 34884,
1282
+ # "rose": "-0.0027957315",
1283
+ # "time": 1699348013000
1284
+ # }
1285
+ #
1286
+ return self.parse_ticker(data, market)
1287
+
1288
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1289
+ """
1290
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1291
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#kline-data
1292
+ :see: https://www.bitrue.com/api-docs#kline-candlestick-data
1293
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#kline-candlestick-data
1294
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1295
+ :param str timeframe: the length of time each candle represents
1296
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1297
+ :param int [limit]: the maximum amount of candles to fetch
1298
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1299
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1300
+ """
1301
+ await self.load_markets()
1302
+ market = self.market(symbol)
1303
+ timeframes = self.safe_value(self.options, 'timeframes', {})
1304
+ response = None
1305
+ data = None
1306
+ if market['swap']:
1307
+ timeframesFuture = self.safe_value(timeframes, 'future', {})
1308
+ request: dict = {
1309
+ 'contractName': market['id'],
1310
+ # 1min / 5min / 15min / 30min / 1h / 1day / 1week / 1month
1311
+ 'interval': self.safe_string(timeframesFuture, timeframe, '1min'),
1312
+ }
1313
+ if limit is not None:
1314
+ request['limit'] = limit
1315
+ if market['linear']:
1316
+ response = await self.fapiV1PublicGetKlines(self.extend(request, params))
1317
+ elif market['inverse']:
1318
+ response = await self.dapiV1PublicGetKlines(self.extend(request, params))
1319
+ data = response
1320
+ elif market['spot']:
1321
+ timeframesSpot = self.safe_value(timeframes, 'spot', {})
1322
+ request: dict = {
1323
+ 'symbol': market['id'],
1324
+ # 1m / 5m / 15m / 30m / 1H / 2H / 4H / 12H / 1D / 1W
1325
+ 'scale': self.safe_string(timeframesSpot, timeframe, '1m'),
1326
+ }
1327
+ if limit is not None:
1328
+ request['limit'] = limit
1329
+ if since is not None:
1330
+ request['fromIdx'] = since
1331
+ response = await self.spotV1PublicGetMarketKline(self.extend(request, params))
1332
+ data = self.safe_value(response, 'data', [])
1333
+ else:
1334
+ raise NotSupported(self.id + ' fetchOHLCV only support spot & swap markets')
1335
+ #
1336
+ # spot
1337
+ #
1338
+ # {
1339
+ # "symbol":"BTCUSDT",
1340
+ # "scale":"KLINE_1MIN",
1341
+ # "data":[
1342
+ # {
1343
+ # "i":"1660825020",
1344
+ # "a":"93458.778",
1345
+ # "v":"3.9774",
1346
+ # "c":"23494.99",
1347
+ # "h":"23509.63",
1348
+ # "l":"23491.93",
1349
+ # "o":"23508.34"
1350
+ # }
1351
+ # ]
1352
+ # }
1353
+ #
1354
+ # swap
1355
+ #
1356
+ # [
1357
+ # {
1358
+ # "high": "35360.7",
1359
+ # "vol": "110288",
1360
+ # "low": "35347.9",
1361
+ # "idx": 1699411680000,
1362
+ # "close": "35347.9",
1363
+ # "open": "35349.4"
1364
+ # }
1365
+ # ]
1366
+ #
1367
+ return self.parse_ohlcvs(data, market, timeframe, since, limit)
1368
+
1369
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1370
+ #
1371
+ # spot
1372
+ #
1373
+ # {
1374
+ # "i":"1660825020",
1375
+ # "a":"93458.778",
1376
+ # "v":"3.9774",
1377
+ # "c":"23494.99",
1378
+ # "h":"23509.63",
1379
+ # "l":"23491.93",
1380
+ # "o":"23508.34"
1381
+ # }
1382
+ #
1383
+ # swap
1384
+ #
1385
+ # {
1386
+ # "high": "35360.7",
1387
+ # "vol": "110288",
1388
+ # "low": "35347.9",
1389
+ # "idx": 1699411680000,
1390
+ # "close": "35347.9",
1391
+ # "open": "35349.4"
1392
+ # }
1393
+ #
1394
+ timestamp = self.safe_timestamp(ohlcv, 'i')
1395
+ if timestamp is None:
1396
+ timestamp = self.safe_integer(ohlcv, 'idx')
1397
+ return [
1398
+ timestamp,
1399
+ self.safe_number_2(ohlcv, 'o', 'open'),
1400
+ self.safe_number_2(ohlcv, 'h', 'high'),
1401
+ self.safe_number_2(ohlcv, 'l', 'low'),
1402
+ self.safe_number_2(ohlcv, 'c', 'close'),
1403
+ self.safe_number_2(ohlcv, 'v', 'vol'),
1404
+ ]
1405
+
1406
+ async def fetch_bids_asks(self, symbols: Strings = None, params={}):
1407
+ """
1408
+ fetches the bid and ask price and volume for multiple markets
1409
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#symbol-order-book-ticker
1410
+ :see: https://www.bitrue.com/api-docs#ticker
1411
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#ticker
1412
+ :param str[]|None symbols: unified symbols of the markets to fetch the bids and asks for, all markets are returned if not assigned
1413
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1414
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1415
+ """
1416
+ await self.load_markets()
1417
+ symbols = self.market_symbols(symbols, None, False)
1418
+ first = self.safe_string(symbols, 0)
1419
+ market = self.market(first)
1420
+ response = None
1421
+ if market['swap']:
1422
+ request: dict = {
1423
+ 'contractName': market['id'],
1424
+ }
1425
+ if market['linear']:
1426
+ response = await self.fapiV1PublicGetTicker(self.extend(request, params))
1427
+ elif market['inverse']:
1428
+ response = await self.dapiV1PublicGetTicker(self.extend(request, params))
1429
+ elif market['spot']:
1430
+ request: dict = {
1431
+ 'symbol': market['id'],
1432
+ }
1433
+ response = await self.spotV1PublicGetTickerBookTicker(self.extend(request, params))
1434
+ else:
1435
+ raise NotSupported(self.id + ' fetchBidsAsks only support spot & swap markets')
1436
+ #
1437
+ # spot
1438
+ #
1439
+ # {
1440
+ # "symbol": "LTCBTC",
1441
+ # "bidPrice": "4.00000000",
1442
+ # "bidQty": "431.00000000",
1443
+ # "askPrice": "4.00000200",
1444
+ # "askQty": "9.00000000"
1445
+ # }
1446
+ #
1447
+ # swap
1448
+ #
1449
+ # {
1450
+ # "high": "35296",
1451
+ # "vol": "779308354",
1452
+ # "last": "34884.1",
1453
+ # "low": "34806.7",
1454
+ # "buy": 34883.9,
1455
+ # "sell": 34884,
1456
+ # "rose": "-0.0027957315",
1457
+ # "time": 1699348013000
1458
+ # }
1459
+ #
1460
+ data: dict = {}
1461
+ data[market['id']] = response
1462
+ return self.parse_tickers(data, symbols)
1463
+
1464
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1465
+ """
1466
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1467
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#24hr-ticker-price-change-statistics
1468
+ :see: https://www.bitrue.com/api-docs#ticker
1469
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#ticker
1470
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1471
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1472
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1473
+ """
1474
+ await self.load_markets()
1475
+ symbols = self.market_symbols(symbols)
1476
+ response = None
1477
+ data = None
1478
+ request: dict = {}
1479
+ type = None
1480
+ if symbols is not None:
1481
+ first = self.safe_string(symbols, 0)
1482
+ market = self.market(first)
1483
+ if market['swap']:
1484
+ raise NotSupported(self.id + ' fetchTickers does not support swap markets, please use fetchTicker instead')
1485
+ elif market['spot']:
1486
+ response = await self.spotV1PublicGetTicker24hr(self.extend(request, params))
1487
+ data = response
1488
+ else:
1489
+ raise NotSupported(self.id + ' fetchTickers only support spot & swap markets')
1490
+ else:
1491
+ type, params = self.handle_market_type_and_params('fetchTickers', None, params)
1492
+ if type != 'spot':
1493
+ raise NotSupported(self.id + ' fetchTickers only support spot when symbols are not proved')
1494
+ response = await self.spotV1PublicGetTicker24hr(self.extend(request, params))
1495
+ data = response
1496
+ #
1497
+ # spot
1498
+ #
1499
+ # [{
1500
+ # symbol: 'BTCUSDT',
1501
+ # priceChange: '105.20',
1502
+ # priceChangePercent: '0.3000',
1503
+ # weightedAvgPrice: null,
1504
+ # prevClosePrice: null,
1505
+ # lastPrice: '34905.21',
1506
+ # lastQty: null,
1507
+ # bidPrice: '34905.21',
1508
+ # askPrice: '34905.22',
1509
+ # openPrice: '34800.01',
1510
+ # highPrice: '35276.33',
1511
+ # lowPrice: '34787.51',
1512
+ # volume: '12549.6481',
1513
+ # quoteVolume: '439390492.917',
1514
+ # openTime: '0',
1515
+ # closeTime: '0',
1516
+ # firstId: '0',
1517
+ # lastId: '0',
1518
+ # count: '0'
1519
+ # }]
1520
+ #
1521
+ # swap
1522
+ #
1523
+ # {
1524
+ # "high": "35296",
1525
+ # "vol": "779308354",
1526
+ # "last": "34884.1",
1527
+ # "low": "34806.7",
1528
+ # "buy": 34883.9,
1529
+ # "sell": 34884,
1530
+ # "rose": "-0.0027957315",
1531
+ # "time": 1699348013000
1532
+ # }
1533
+ #
1534
+ # the exchange returns market ids with an underscore from the tickers endpoint
1535
+ # the market ids do not have an underscore, so it has to be removed
1536
+ # https://github.com/ccxt/ccxt/issues/13856
1537
+ tickers: dict = {}
1538
+ for i in range(0, len(data)):
1539
+ ticker = self.safe_value(data, i, {})
1540
+ market = self.market(self.safe_value(ticker, 'symbol'))
1541
+ tickers[market['id']] = ticker
1542
+ return self.parse_tickers(tickers, symbols)
1543
+
1544
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1545
+ #
1546
+ # fetchTrades
1547
+ #
1548
+ # {
1549
+ # "id": 28457,
1550
+ # "price": "4.00000100",
1551
+ # "qty": "12.00000000",
1552
+ # "time": 1499865549590, # Actual timestamp of trade
1553
+ # "isBuyerMaker": True,
1554
+ # "isBestMatch": True
1555
+ # }
1556
+ #
1557
+ # fetchTrades - spot
1558
+ #
1559
+ # {
1560
+ # "symbol":"USDCUSDT",
1561
+ # "id":20725156,
1562
+ # "orderId":2880918576,
1563
+ # "origClientOrderId":null,
1564
+ # "price":"0.9996000000000000",
1565
+ # "qty":"100.0000000000000000",
1566
+ # "commission":null,
1567
+ # "commissionAssert":null,
1568
+ # "time":1635558511000,
1569
+ # "isBuyer":false,
1570
+ # "isMaker":false,
1571
+ # "isBestMatch":true
1572
+ # }
1573
+ #
1574
+ # fetchTrades - future
1575
+ #
1576
+ # {
1577
+ # "tradeId":12,
1578
+ # "price":0.9,
1579
+ # "qty":1,
1580
+ # "amount":9,
1581
+ # "contractName":"E-SAND-USDT",
1582
+ # "side":"BUY",
1583
+ # "fee":"0.0018",
1584
+ # "bidId":1558124009467904992,
1585
+ # "askId":1558124043827644908,
1586
+ # "bidUserId":10294,
1587
+ # "askUserId":10467,
1588
+ # "isBuyer":true,
1589
+ # "isMaker":true,
1590
+ # "ctime":1678426306000
1591
+ # }
1592
+ #
1593
+ timestamp = self.safe_integer_2(trade, 'ctime', 'time')
1594
+ priceString = self.safe_string(trade, 'price')
1595
+ amountString = self.safe_string(trade, 'qty')
1596
+ marketId = self.safe_string_2(trade, 'symbol', 'contractName')
1597
+ symbol = self.safe_symbol(marketId, market)
1598
+ orderId = self.safe_string(trade, 'orderId')
1599
+ id = self.safe_string_2(trade, 'id', 'tradeId')
1600
+ side = None
1601
+ buyerMaker = self.safe_value(trade, 'isBuyerMaker') # ignore "m" until Bitrue fixes api
1602
+ isBuyer = self.safe_value(trade, 'isBuyer')
1603
+ if buyerMaker is not None:
1604
+ side = 'sell' if buyerMaker else 'buy'
1605
+ if isBuyer is not None:
1606
+ side = 'buy' if isBuyer else 'sell' # self is a True side
1607
+ fee = None
1608
+ if 'commission' in trade:
1609
+ fee = {
1610
+ 'cost': self.safe_string_2(trade, 'commission', 'fee'),
1611
+ 'currency': self.safe_currency_code(self.safe_string(trade, 'commissionAssert')),
1612
+ }
1613
+ takerOrMaker = None
1614
+ isMaker = self.safe_value(trade, 'isMaker')
1615
+ if isMaker is not None:
1616
+ takerOrMaker = 'maker' if isMaker else 'taker'
1617
+ return self.safe_trade({
1618
+ 'info': trade,
1619
+ 'timestamp': timestamp,
1620
+ 'datetime': self.iso8601(timestamp),
1621
+ 'symbol': symbol,
1622
+ 'id': id,
1623
+ 'order': orderId,
1624
+ 'type': None,
1625
+ 'side': side,
1626
+ 'takerOrMaker': takerOrMaker,
1627
+ 'price': priceString,
1628
+ 'amount': amountString,
1629
+ 'cost': None,
1630
+ 'fee': fee,
1631
+ }, market)
1632
+
1633
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1634
+ """
1635
+ get the list of most recent trades for a particular symbol
1636
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#recent-trades-list
1637
+ :param str symbol: unified symbol of the market to fetch trades for
1638
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1639
+ :param int [limit]: the maximum amount of trades to fetch
1640
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1641
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1642
+ """
1643
+ await self.load_markets()
1644
+ market = self.market(symbol)
1645
+ response = None
1646
+ if market['spot']:
1647
+ request: dict = {
1648
+ 'symbol': market['id'],
1649
+ # 'limit': 100, # default 100, max = 1000
1650
+ }
1651
+ if limit is not None:
1652
+ request['limit'] = limit # default 100, max 1000
1653
+ response = await self.spotV1PublicGetTrades(self.extend(request, params))
1654
+ else:
1655
+ raise NotSupported(self.id + ' fetchTrades only support spot markets')
1656
+ #
1657
+ # spot
1658
+ #
1659
+ # [
1660
+ # {
1661
+ # "id": 28457,
1662
+ # "price": "4.00000100",
1663
+ # "qty": "12.00000000",
1664
+ # "time": 1499865549590,
1665
+ # "isBuyerMaker": True,
1666
+ # "isBestMatch": True
1667
+ # }
1668
+ # ]
1669
+ #
1670
+ return self.parse_trades(response, market, since, limit)
1671
+
1672
+ def parse_order_status(self, status: Str):
1673
+ statuses: dict = {
1674
+ 'INIT': 'open',
1675
+ 'PENDING_CREATE': 'open',
1676
+ 'NEW': 'open',
1677
+ 'PARTIALLY_FILLED': 'open',
1678
+ 'FILLED': 'closed',
1679
+ 'CANCELED': 'canceled',
1680
+ 'PENDING_CANCEL': 'canceling', # currently unused
1681
+ 'REJECTED': 'rejected',
1682
+ 'EXPIRED': 'expired',
1683
+ }
1684
+ return self.safe_string(statuses, status, status)
1685
+
1686
+ def parse_order(self, order: dict, market: Market = None) -> Order:
1687
+ #
1688
+ # createOrder - spot
1689
+ #
1690
+ # {
1691
+ # "symbol":"USDCUSDT",
1692
+ # "orderId":2878854881,
1693
+ # "clientOrderId":"",
1694
+ # "transactTime":1635551031276
1695
+ # }
1696
+ #
1697
+ # createOrder - future
1698
+ #
1699
+ # {
1700
+ # "orderId":1690615676032452985,
1701
+ # }
1702
+ #
1703
+ # fetchOrders - spot
1704
+ #
1705
+ # {
1706
+ # "symbol":"USDCUSDT",
1707
+ # "orderId":"2878854881",
1708
+ # "clientOrderId":"",
1709
+ # "price":"1.1000000000000000",
1710
+ # "origQty":"100.0000000000000000",
1711
+ # "executedQty":"0.0000000000000000",
1712
+ # "cummulativeQuoteQty":"0.0000000000000000",
1713
+ # "status":"NEW",
1714
+ # "timeInForce":"",
1715
+ # "type":"LIMIT",
1716
+ # "side":"SELL",
1717
+ # "stopPrice":"",
1718
+ # "icebergQty":"",
1719
+ # "time":1635551031000,
1720
+ # "updateTime":1635551031000,
1721
+ # "isWorking":false
1722
+ # }
1723
+ #
1724
+ # fetchOrders - future
1725
+ #
1726
+ # {
1727
+ # "orderId":1917641,
1728
+ # "price":100,
1729
+ # "origQty":10,
1730
+ # "origAmount":10,
1731
+ # "executedQty":1,
1732
+ # "avgPrice":10000,
1733
+ # "status":"INIT",
1734
+ # "type":"LIMIT",
1735
+ # "side":"BUY",
1736
+ # "action":"OPEN",
1737
+ # "transactTime":1686716571425
1738
+ # "clientOrderId":4949299210
1739
+ # }
1740
+ #
1741
+ status = self.parse_order_status(self.safe_string_2(order, 'status', 'orderStatus'))
1742
+ marketId = self.safe_string(order, 'symbol')
1743
+ symbol = self.safe_symbol(marketId, market)
1744
+ filled = self.safe_string(order, 'executedQty')
1745
+ timestamp = None
1746
+ lastTradeTimestamp = None
1747
+ if 'time' in order:
1748
+ timestamp = self.safe_integer(order, 'time')
1749
+ elif 'transactTime' in order:
1750
+ timestamp = self.safe_integer(order, 'transactTime')
1751
+ elif 'updateTime' in order:
1752
+ if status == 'open':
1753
+ if Precise.string_gt(filled, '0'):
1754
+ lastTradeTimestamp = self.safe_integer(order, 'updateTime')
1755
+ else:
1756
+ timestamp = self.safe_integer(order, 'updateTime')
1757
+ average = self.safe_string(order, 'avgPrice')
1758
+ price = self.safe_string(order, 'price')
1759
+ amount = self.safe_string(order, 'origQty')
1760
+ # - Spot/Margin market: cummulativeQuoteQty
1761
+ # - Futures market: cumQuote.
1762
+ # Note self is not the actual cost, since Binance futures uses leverage to calculate margins.
1763
+ cost = self.safe_string_2(order, 'cummulativeQuoteQty', 'cumQuote')
1764
+ id = self.safe_string(order, 'orderId')
1765
+ type = self.safe_string_lower(order, 'type')
1766
+ side = self.safe_string_lower(order, 'side')
1767
+ fills = self.safe_value(order, 'fills', [])
1768
+ clientOrderId = self.safe_string(order, 'clientOrderId')
1769
+ timeInForce = self.safe_string(order, 'timeInForce')
1770
+ postOnly = (type == 'limit_maker') or (timeInForce == 'GTX') or (type == 'post_only')
1771
+ if type == 'limit_maker':
1772
+ type = 'limit'
1773
+ stopPriceString = self.safe_string(order, 'stopPrice')
1774
+ stopPrice = self.parse_number(self.omit_zero(stopPriceString))
1775
+ return self.safe_order({
1776
+ 'info': order,
1777
+ 'id': id,
1778
+ 'clientOrderId': clientOrderId,
1779
+ 'timestamp': timestamp,
1780
+ 'datetime': self.iso8601(timestamp),
1781
+ 'lastTradeTimestamp': lastTradeTimestamp,
1782
+ 'symbol': symbol,
1783
+ 'type': type,
1784
+ 'timeInForce': timeInForce,
1785
+ 'postOnly': postOnly,
1786
+ 'side': side,
1787
+ 'price': price,
1788
+ 'stopPrice': stopPrice,
1789
+ 'triggerPrice': stopPrice,
1790
+ 'amount': amount,
1791
+ 'cost': cost,
1792
+ 'average': average,
1793
+ 'filled': filled,
1794
+ 'remaining': None,
1795
+ 'status': status,
1796
+ 'fee': None,
1797
+ 'trades': fills,
1798
+ }, market)
1799
+
1800
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1801
+ """
1802
+ create a market buy order by providing the symbol and cost
1803
+ :see: https://www.bitrue.com/api-docs#new-order-trade-hmac-sha256
1804
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#new-order-trade-hmac-sha256
1805
+ :param str symbol: unified symbol of the market to create an order in
1806
+ :param float cost: how much you want to trade in units of the quote currency
1807
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1808
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1809
+ """
1810
+ await self.load_markets()
1811
+ market = self.market(symbol)
1812
+ if not market['swap']:
1813
+ raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports swap orders only')
1814
+ params['createMarketBuyOrderRequiresPrice'] = False
1815
+ return await self.create_order(symbol, 'market', 'buy', cost, None, params)
1816
+
1817
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1818
+ """
1819
+ create a trade order
1820
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#recent-trades-list
1821
+ :see: https://www.bitrue.com/api-docs#new-order-trade-hmac-sha256
1822
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#new-order-trade-hmac-sha256
1823
+ :param str symbol: unified symbol of the market to create an order in
1824
+ :param str type: 'market' or 'limit'
1825
+ :param str side: 'buy' or 'sell'
1826
+ :param float amount: how much of currency you want to trade in units of base currency
1827
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1828
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1829
+ :param float [params.triggerPrice]: *spot only* the price at which a trigger order is triggered at
1830
+ :param str [params.clientOrderId]: a unique id for the order, automatically generated if not sent
1831
+ :param decimal [params.leverage]: in future order, the leverage value of the order should consistent with the user contract configuration, default is 1
1832
+ :param str [params.timeInForce]: 'fok', 'ioc' or 'po'
1833
+ :param bool [params.postOnly]: default False
1834
+ :param bool [params.reduceOnly]: default False
1835
+ * EXCHANGE SPECIFIC PARAMETERS
1836
+ :param decimal [params.icebergQty]:
1837
+ :param long [params.recvWindow]:
1838
+ :param float [params.cost]: *swap market buy only* the quote quantity that can be used alternative for the amount
1839
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1840
+ """
1841
+ await self.load_markets()
1842
+ market = self.market(symbol)
1843
+ response = None
1844
+ data = None
1845
+ uppercaseType = type.upper()
1846
+ request: dict = {
1847
+ 'side': side.upper(),
1848
+ 'type': uppercaseType,
1849
+ # 'timeInForce': '',
1850
+ # 'price': self.price_to_precision(symbol, price),
1851
+ # 'newClientOrderId': clientOrderId, # automatically generated if not sent
1852
+ # 'stopPrice': self.price_to_precision(symbol, 'stopPrice'),
1853
+ # 'icebergQty': self.amount_to_precision(symbol, icebergQty),
1854
+ }
1855
+ if uppercaseType == 'LIMIT':
1856
+ if price is None:
1857
+ raise InvalidOrder(self.id + ' createOrder() requires a price argument')
1858
+ request['price'] = self.price_to_precision(symbol, price)
1859
+ if market['swap']:
1860
+ isMarket = uppercaseType == 'MARKET'
1861
+ timeInForce = self.safe_string_lower(params, 'timeInForce')
1862
+ postOnly = self.is_post_only(isMarket, None, params)
1863
+ if postOnly:
1864
+ request['type'] = 'POST_ONLY'
1865
+ elif timeInForce == 'fok':
1866
+ request['type'] = 'FOK'
1867
+ elif timeInForce == 'ioc':
1868
+ request['type'] = 'IOC'
1869
+ request['contractName'] = market['id']
1870
+ createMarketBuyOrderRequiresPrice = True
1871
+ createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
1872
+ if isMarket and (side == 'buy') and createMarketBuyOrderRequiresPrice:
1873
+ cost = self.safe_string(params, 'cost')
1874
+ params = self.omit(params, 'cost')
1875
+ if price is None and cost is None:
1876
+ raise InvalidOrder(self.id + ' createOrder() requires the price argument with swap market buy orders to calculate total order cost(amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options["createMarketBuyOrderRequiresPrice"] = False to supply the cost in the amount argument(the exchange-specific behaviour)')
1877
+ else:
1878
+ amountString = self.number_to_string(amount)
1879
+ priceString = self.number_to_string(price)
1880
+ quoteAmount = Precise.string_mul(amountString, priceString)
1881
+ requestAmount = cost if (cost is not None) else quoteAmount
1882
+ request['amount'] = self.cost_to_precision(symbol, requestAmount)
1883
+ request['volume'] = self.cost_to_precision(symbol, requestAmount)
1884
+ else:
1885
+ request['amount'] = self.parse_to_numeric(amount)
1886
+ request['volume'] = self.parse_to_numeric(amount)
1887
+ request['positionType'] = 1
1888
+ reduceOnly = self.safe_value_2(params, 'reduceOnly', 'reduce_only')
1889
+ request['open'] = 'CLOSE' if reduceOnly else 'OPEN'
1890
+ leverage = self.safe_string(params, 'leverage', '1')
1891
+ request['leverage'] = self.parse_to_numeric(leverage)
1892
+ params = self.omit(params, ['leverage', 'reduceOnly', 'reduce_only', 'timeInForce'])
1893
+ if market['linear']:
1894
+ response = await self.fapiV2PrivatePostOrder(self.extend(request, params))
1895
+ elif market['inverse']:
1896
+ response = await self.dapiV2PrivatePostOrder(self.extend(request, params))
1897
+ data = self.safe_value(response, 'data', {})
1898
+ elif market['spot']:
1899
+ request['symbol'] = market['id']
1900
+ request['quantity'] = self.amount_to_precision(symbol, amount)
1901
+ validOrderTypes = self.safe_value(market['info'], 'orderTypes')
1902
+ if not self.in_array(uppercaseType, validOrderTypes):
1903
+ raise InvalidOrder(self.id + ' ' + type + ' is not a valid order type in market ' + symbol)
1904
+ clientOrderId = self.safe_string_2(params, 'newClientOrderId', 'clientOrderId')
1905
+ if clientOrderId is not None:
1906
+ params = self.omit(params, ['newClientOrderId', 'clientOrderId'])
1907
+ request['newClientOrderId'] = clientOrderId
1908
+ stopPrice = self.safe_value_2(params, 'triggerPrice', 'stopPrice')
1909
+ if stopPrice is not None:
1910
+ params = self.omit(params, ['triggerPrice', 'stopPrice'])
1911
+ request['stopPrice'] = self.price_to_precision(symbol, stopPrice)
1912
+ response = await self.spotV1PrivatePostOrder(self.extend(request, params))
1913
+ data = response
1914
+ else:
1915
+ raise NotSupported(self.id + ' createOrder only support spot & swap markets')
1916
+ #
1917
+ # spot
1918
+ #
1919
+ # {
1920
+ # "symbol": "BTCUSDT",
1921
+ # "orderId": 307650651173648896,
1922
+ # "orderIdStr": "307650651173648896",
1923
+ # "clientOrderId": "6gCrw2kRUAF9CvJDGP16IP",
1924
+ # "transactTime": 1507725176595
1925
+ # }
1926
+ #
1927
+ # swap
1928
+ #
1929
+ # {
1930
+ # "code": "0",
1931
+ # "msg": "Success",
1932
+ # "data": {
1933
+ # "orderId": 1690615676032452985
1934
+ # }
1935
+ # }
1936
+ #
1937
+ return self.parse_order(data, market)
1938
+
1939
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
1940
+ """
1941
+ fetches information on an order made by the user
1942
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#query-order-user_data
1943
+ :see: https://www.bitrue.com/api-docs#query-order-user_data-hmac-sha256
1944
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#query-order-user_data-hmac-sha256
1945
+ :param str symbol: unified symbol of the market the order was made in
1946
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1947
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1948
+ """
1949
+ if symbol is None:
1950
+ raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
1951
+ await self.load_markets()
1952
+ market = self.market(symbol)
1953
+ origClientOrderId = self.safe_value_2(params, 'origClientOrderId', 'clientOrderId')
1954
+ params = self.omit(params, ['origClientOrderId', 'clientOrderId'])
1955
+ response = None
1956
+ data = None
1957
+ request: dict = {}
1958
+ if origClientOrderId is None:
1959
+ request['orderId'] = id
1960
+ else:
1961
+ if market['swap']:
1962
+ request['clientOrderId'] = origClientOrderId
1963
+ else:
1964
+ request['origClientOrderId'] = origClientOrderId
1965
+ if market['swap']:
1966
+ request['contractName'] = market['id']
1967
+ if market['linear']:
1968
+ response = await self.fapiV2PrivateGetOrder(self.extend(request, params))
1969
+ elif market['inverse']:
1970
+ response = await self.dapiV2PrivateGetOrder(self.extend(request, params))
1971
+ data = self.safe_value(response, 'data', {})
1972
+ elif market['spot']:
1973
+ request['orderId'] = id # spot market id is mandatory
1974
+ request['symbol'] = market['id']
1975
+ response = await self.spotV1PrivateGetOrder(self.extend(request, params))
1976
+ data = response
1977
+ else:
1978
+ raise NotSupported(self.id + ' fetchOrder only support spot & swap markets')
1979
+ #
1980
+ # spot
1981
+ #
1982
+ # {
1983
+ # "symbol": "LTCBTC",
1984
+ # "orderId": 1,
1985
+ # "clientOrderId": "myOrder1",
1986
+ # "price": "0.1",
1987
+ # "origQty": "1.0",
1988
+ # "executedQty": "0.0",
1989
+ # "cummulativeQuoteQty": "0.0",
1990
+ # "status": "NEW",
1991
+ # "timeInForce": "GTC",
1992
+ # "type": "LIMIT",
1993
+ # "side": "BUY",
1994
+ # "stopPrice": "0.0",
1995
+ # "icebergQty": "0.0",
1996
+ # "time": 1499827319559,
1997
+ # "updateTime": 1499827319559,
1998
+ # "isWorking": True
1999
+ # }
2000
+ #
2001
+ # swap
2002
+ #
2003
+ # {
2004
+ # "code":0,
2005
+ # "msg":"success",
2006
+ # "data":{
2007
+ # "orderId":1917641,
2008
+ # "price":100,
2009
+ # "origQty":10,
2010
+ # "origAmount":10,
2011
+ # "executedQty":1,
2012
+ # "avgPrice":10000,
2013
+ # "status":"INIT",
2014
+ # "type":"LIMIT",
2015
+ # "side":"BUY",
2016
+ # "action":"OPEN",
2017
+ # "transactTime":1686716571425
2018
+ # "clientOrderId":4949299210
2019
+ # }
2020
+ # }
2021
+ #
2022
+ return self.parse_order(data, market)
2023
+
2024
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2025
+ """
2026
+ fetches information on multiple closed orders made by the user
2027
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#all-orders-user_data
2028
+ :param str symbol: unified market symbol of the market orders were made in
2029
+ :param int [since]: the earliest time in ms to fetch orders for
2030
+ :param int [limit]: the maximum number of order structures to retrieve
2031
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2032
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2033
+ """
2034
+ if symbol is None:
2035
+ raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
2036
+ await self.load_markets()
2037
+ market = self.market(symbol)
2038
+ if not market['spot']:
2039
+ raise NotSupported(self.id + ' fetchClosedOrders only support spot markets')
2040
+ request: dict = {
2041
+ 'symbol': market['id'],
2042
+ # 'orderId': 123445, # long
2043
+ # 'startTime': since,
2044
+ # 'endTime': self.milliseconds(),
2045
+ # 'limit': limit, # default 100, max 1000
2046
+ }
2047
+ if since is not None:
2048
+ request['startTime'] = since
2049
+ if limit is not None:
2050
+ request['limit'] = limit # default 100, max 1000
2051
+ response = await self.spotV1PrivateGetAllOrders(self.extend(request, params))
2052
+ #
2053
+ # [
2054
+ # {
2055
+ # "symbol": "LTCBTC",
2056
+ # "orderId": 1,
2057
+ # "clientOrderId": "myOrder1",
2058
+ # "price": "0.1",
2059
+ # "origQty": "1.0",
2060
+ # "executedQty": "0.0",
2061
+ # "cummulativeQuoteQty": "0.0",
2062
+ # "status": "NEW",
2063
+ # "timeInForce": "GTC",
2064
+ # "type": "LIMIT",
2065
+ # "side": "BUY",
2066
+ # "stopPrice": "0.0",
2067
+ # "icebergQty": "0.0",
2068
+ # "time": 1499827319559,
2069
+ # "updateTime": 1499827319559,
2070
+ # "isWorking": True
2071
+ # }
2072
+ # ]
2073
+ #
2074
+ return self.parse_orders(response, market, since, limit)
2075
+
2076
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2077
+ """
2078
+ fetch all unfilled currently open orders
2079
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#current-open-orders-user_data
2080
+ :see: https://www.bitrue.com/api-docs#current-all-open-orders-user_data-hmac-sha256
2081
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#current-all-open-orders-user_data-hmac-sha256
2082
+ :param str symbol: unified market symbol
2083
+ :param int [since]: the earliest time in ms to fetch open orders for
2084
+ :param int [limit]: the maximum number of open order structures to retrieve
2085
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2086
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2087
+ """
2088
+ if symbol is None:
2089
+ raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
2090
+ await self.load_markets()
2091
+ market = self.market(symbol)
2092
+ response = None
2093
+ data = None
2094
+ request: dict = {}
2095
+ if market['swap']:
2096
+ request['contractName'] = market['id']
2097
+ if market['linear']:
2098
+ response = await self.fapiV2PrivateGetOpenOrders(self.extend(request, params))
2099
+ elif market['inverse']:
2100
+ response = await self.dapiV2PrivateGetOpenOrders(self.extend(request, params))
2101
+ data = self.safe_value(response, 'data', [])
2102
+ elif market['spot']:
2103
+ request['symbol'] = market['id']
2104
+ response = await self.spotV1PrivateGetOpenOrders(self.extend(request, params))
2105
+ data = response
2106
+ else:
2107
+ raise NotSupported(self.id + ' fetchOpenOrders only support spot & swap markets')
2108
+ #
2109
+ # spot
2110
+ #
2111
+ # [
2112
+ # {
2113
+ # "symbol":"USDCUSDT",
2114
+ # "orderId":"2878854881",
2115
+ # "clientOrderId":"",
2116
+ # "price":"1.1000000000000000",
2117
+ # "origQty":"100.0000000000000000",
2118
+ # "executedQty":"0.0000000000000000",
2119
+ # "cummulativeQuoteQty":"0.0000000000000000",
2120
+ # "status":"NEW",
2121
+ # "timeInForce":"",
2122
+ # "type":"LIMIT",
2123
+ # "side":"SELL",
2124
+ # "stopPrice":"",
2125
+ # "icebergQty":"",
2126
+ # "time":1635551031000,
2127
+ # "updateTime":1635551031000,
2128
+ # "isWorking":false
2129
+ # }
2130
+ # ]
2131
+ #
2132
+ # swap
2133
+ #
2134
+ # {
2135
+ # "code": "0",
2136
+ # "msg": "Success",
2137
+ # "data": [{
2138
+ # "orderId": 1917641,
2139
+ # "clientOrderId": "2488514315",
2140
+ # "price": 100,
2141
+ # "origQty": 10,
2142
+ # "origAmount": 10,
2143
+ # "executedQty": 1,
2144
+ # "avgPrice": 12451,
2145
+ # "status": "INIT",
2146
+ # "type": "LIMIT",
2147
+ # "side": "BUY",
2148
+ # "action": "OPEN",
2149
+ # "transactTime": 1686717303975
2150
+ # }
2151
+ # ]
2152
+ # }
2153
+ #
2154
+ return self.parse_orders(data, market, since, limit)
2155
+
2156
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
2157
+ """
2158
+ cancels an open order
2159
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#cancel-order-trade
2160
+ :see: https://www.bitrue.com/api-docs#cancel-order-trade-hmac-sha256
2161
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#cancel-order-trade-hmac-sha256
2162
+ :param str id: order id
2163
+ :param str symbol: unified symbol of the market the order was made in
2164
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2165
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2166
+ """
2167
+ if symbol is None:
2168
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
2169
+ await self.load_markets()
2170
+ market = self.market(symbol)
2171
+ origClientOrderId = self.safe_value_2(params, 'origClientOrderId', 'clientOrderId')
2172
+ params = self.omit(params, ['origClientOrderId', 'clientOrderId'])
2173
+ response = None
2174
+ data = None
2175
+ request: dict = {}
2176
+ if origClientOrderId is None:
2177
+ request['orderId'] = id
2178
+ else:
2179
+ if market['swap']:
2180
+ request['clientOrderId'] = origClientOrderId
2181
+ else:
2182
+ request['origClientOrderId'] = origClientOrderId
2183
+ if market['swap']:
2184
+ request['contractName'] = market['id']
2185
+ if market['linear']:
2186
+ response = await self.fapiV2PrivatePostCancel(self.extend(request, params))
2187
+ elif market['inverse']:
2188
+ response = await self.dapiV2PrivatePostCancel(self.extend(request, params))
2189
+ data = self.safe_value(response, 'data', {})
2190
+ elif market['spot']:
2191
+ request['symbol'] = market['id']
2192
+ response = await self.spotV1PrivateDeleteOrder(self.extend(request, params))
2193
+ data = response
2194
+ else:
2195
+ raise NotSupported(self.id + ' cancelOrder only support spot & swap markets')
2196
+ #
2197
+ # spot
2198
+ #
2199
+ # {
2200
+ # "symbol": "LTCBTC",
2201
+ # "origClientOrderId": "myOrder1",
2202
+ # "orderId": 1,
2203
+ # "clientOrderId": "cancelMyOrder1"
2204
+ # }
2205
+ #
2206
+ # swap
2207
+ #
2208
+ # {
2209
+ # "code": "0",
2210
+ # "msg": "Success",
2211
+ # "data": {
2212
+ # "orderId": 1690615847831143159
2213
+ # }
2214
+ # }
2215
+ #
2216
+ return self.parse_order(data, market)
2217
+
2218
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
2219
+ """
2220
+ cancel all open orders in a market
2221
+ :see: https://www.bitrue.com/api-docs#cancel-all-open-orders-trade-hmac-sha256
2222
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#cancel-all-open-orders-trade-hmac-sha256
2223
+ :param str symbol: unified market symbol of the market to cancel orders in
2224
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2225
+ :param str [params.marginMode]: 'cross' or 'isolated', for spot margin trading
2226
+ :returns dict[]: a list of `order structures <https://github.com/ccxt/ccxt/wiki/Manual#order-structure>`
2227
+ """
2228
+ await self.load_markets()
2229
+ market = self.market(symbol)
2230
+ response = None
2231
+ data = None
2232
+ if market['swap']:
2233
+ request: dict = {
2234
+ 'contractName': market['id'],
2235
+ }
2236
+ if market['linear']:
2237
+ response = await self.fapiV2PrivatePostAllOpenOrders(self.extend(request, params))
2238
+ elif market['inverse']:
2239
+ response = await self.dapiV2PrivatePostAllOpenOrders(self.extend(request, params))
2240
+ data = self.safe_value(response, 'data', [])
2241
+ else:
2242
+ raise NotSupported(self.id + ' cancelAllOrders only support future markets')
2243
+ #
2244
+ # swap
2245
+ #
2246
+ # {
2247
+ # 'code': '0',
2248
+ # 'msg': 'Success',
2249
+ # 'data': null
2250
+ # }
2251
+ #
2252
+ return self.parse_orders(data, market)
2253
+
2254
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2255
+ """
2256
+ fetch all trades made by the user
2257
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#account-trade-list-user_data
2258
+ :see: https://www.bitrue.com/api-docs#account-trade-list-user_data-hmac-sha256
2259
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#account-trade-list-user_data-hmac-sha256
2260
+ :param str symbol: unified market symbol
2261
+ :param int [since]: the earliest time in ms to fetch trades for
2262
+ :param int [limit]: the maximum number of trades structures to retrieve
2263
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2264
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
2265
+ """
2266
+ await self.load_markets()
2267
+ if symbol is None:
2268
+ raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
2269
+ market = self.market(symbol)
2270
+ response = None
2271
+ data = None
2272
+ request: dict = {}
2273
+ if since is not None:
2274
+ request['startTime'] = since
2275
+ if limit is not None:
2276
+ if limit > 1000:
2277
+ limit = 1000
2278
+ request['limit'] = limit
2279
+ if market['swap']:
2280
+ request['contractName'] = market['id']
2281
+ if market['linear']:
2282
+ response = await self.fapiV2PrivateGetMyTrades(self.extend(request, params))
2283
+ elif market['inverse']:
2284
+ response = await self.dapiV2PrivateGetMyTrades(self.extend(request, params))
2285
+ data = self.safe_value(response, 'data', [])
2286
+ elif market['spot']:
2287
+ request['symbol'] = market['id']
2288
+ response = await self.spotV2PrivateGetMyTrades(self.extend(request, params))
2289
+ data = response
2290
+ else:
2291
+ raise NotSupported(self.id + ' fetchMyTrades only support spot & swap markets')
2292
+ #
2293
+ # spot
2294
+ #
2295
+ # [
2296
+ # {
2297
+ # "symbol":"USDCUSDT",
2298
+ # "id":20725156,
2299
+ # "orderId":2880918576,
2300
+ # "origClientOrderId":null,
2301
+ # "price":"0.9996000000000000",
2302
+ # "qty":"100.0000000000000000",
2303
+ # "commission":null,
2304
+ # "commissionAssert":null,
2305
+ # "time":1635558511000,
2306
+ # "isBuyer":false,
2307
+ # "isMaker":false,
2308
+ # "isBestMatch":true
2309
+ # }
2310
+ # ]
2311
+ #
2312
+ # swap
2313
+ #
2314
+ # {
2315
+ # "code":"0",
2316
+ # "msg":"Success",
2317
+ # "data":[
2318
+ # {
2319
+ # "tradeId":12,
2320
+ # "price":0.9,
2321
+ # "qty":1,
2322
+ # "amount":9,
2323
+ # "contractName":"E-SAND-USDT",
2324
+ # "side":"BUY",
2325
+ # "fee":"0.0018",
2326
+ # "bidId":1558124009467904992,
2327
+ # "askId":1558124043827644908,
2328
+ # "bidUserId":10294,
2329
+ # "askUserId":10467,
2330
+ # "isBuyer":true,
2331
+ # "isMaker":true,
2332
+ # "ctime":1678426306000
2333
+ # }
2334
+ # ]
2335
+ # }
2336
+ #
2337
+ return self.parse_trades(data, market, since, limit)
2338
+
2339
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2340
+ """
2341
+ fetch all deposits made to an account
2342
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#deposit-history--withdraw_data
2343
+ :param str code: unified currency code
2344
+ :param int [since]: the earliest time in ms to fetch deposits for
2345
+ :param int [limit]: the maximum number of deposits structures to retrieve
2346
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2347
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2348
+ """
2349
+ if code is None:
2350
+ raise ArgumentsRequired(self.id + ' fetchDeposits() requires a code argument')
2351
+ await self.load_markets()
2352
+ currency = self.currency(code)
2353
+ request: dict = {
2354
+ 'coin': currency['id'],
2355
+ 'status': 1, # 0 init, 1 finished, default 0
2356
+ # 'offset': 0,
2357
+ # 'limit': limit, # default 10, max 1000
2358
+ # 'startTime': since,
2359
+ # 'endTime': self.milliseconds(),
2360
+ }
2361
+ if since is not None:
2362
+ request['startTime'] = since
2363
+ # request['endTime'] = self.sum(since, 7776000000)
2364
+ if limit is not None:
2365
+ request['limit'] = limit
2366
+ response = await self.spotV1PrivateGetDepositHistory(self.extend(request, params))
2367
+ #
2368
+ # {
2369
+ # "code":200,
2370
+ # "msg":"succ",
2371
+ # "data":[
2372
+ # {
2373
+ # "id":2659137,
2374
+ # "symbol":"USDC",
2375
+ # "amount":"200.0000000000000000",
2376
+ # "fee":"0.0E-15",
2377
+ # "createdAt":1635503169000,
2378
+ # "updatedAt":1635503202000,
2379
+ # "addressFrom":"0x2faf487a4414fe77e2327f0bf4ae2a264a776ad2",
2380
+ # "addressTo":"0x190ceccb1f8bfbec1749180f0ba8922b488d865b",
2381
+ # "txid":"0x9970aec41099ac385568859517308707bc7d716df8dabae7b52f5b17351c3ed0",
2382
+ # "confirmations":5,
2383
+ # "status":0,
2384
+ # "tagType":null,
2385
+ # },
2386
+ # {
2387
+ # "id":2659137,
2388
+ # "symbol": "XRP",
2389
+ # "amount": "20.0000000000000000",
2390
+ # "fee": "0.0E-15",
2391
+ # "createdAt": 1544669393000,
2392
+ # "updatedAt": 1544669413000,
2393
+ # "addressFrom": "",
2394
+ # "addressTo": "raLPjTYeGezfdb6crXZzcC8RkLBEwbBHJ5_18113641",
2395
+ # "txid": "515B23E1F9864D3AF7F5B4C4FCBED784BAE861854FAB95F4031922B6AAEFC7AC",
2396
+ # "confirmations": 7,
2397
+ # "status": 1,
2398
+ # "tagType": "Tag"
2399
+ # }
2400
+ # ]
2401
+ # }
2402
+ #
2403
+ data = self.safe_list(response, 'data', [])
2404
+ return self.parse_transactions(data, currency, since, limit)
2405
+
2406
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
2407
+ """
2408
+ fetch all withdrawals made from an account
2409
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#withdraw-history--withdraw_data
2410
+ :param str code: unified currency code
2411
+ :param int [since]: the earliest time in ms to fetch withdrawals for
2412
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
2413
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2414
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
2415
+ """
2416
+ if code is None:
2417
+ raise ArgumentsRequired(self.id + ' fetchWithdrawals() requires a code argument')
2418
+ await self.load_markets()
2419
+ currency = self.currency(code)
2420
+ request: dict = {
2421
+ 'coin': currency['id'],
2422
+ 'status': 5, # 0 init, 5 finished, 6 canceled, default 0
2423
+ # 'offset': 0,
2424
+ # 'limit': limit, # default 10, max 1000
2425
+ # 'startTime': since,
2426
+ # 'endTime': self.milliseconds(),
2427
+ }
2428
+ if since is not None:
2429
+ request['startTime'] = since
2430
+ # request['endTime'] = self.sum(since, 7776000000)
2431
+ if limit is not None:
2432
+ request['limit'] = limit
2433
+ response = await self.spotV1PrivateGetWithdrawHistory(self.extend(request, params))
2434
+ #
2435
+ # {
2436
+ # "code": 200,
2437
+ # "msg": "succ",
2438
+ # "data": [
2439
+ # {
2440
+ # "id": 183745,
2441
+ # "symbol": "usdt_erc20",
2442
+ # "amount": "8.4000000000000000",
2443
+ # "fee": "1.6000000000000000",
2444
+ # "payAmount": "0.0000000000000000",
2445
+ # "createdAt": 1595336441000,
2446
+ # "updatedAt": 1595336576000,
2447
+ # "addressFrom": "",
2448
+ # "addressTo": "0x2edfae3878d7b6db70ce4abed177ab2636f60c83",
2449
+ # "txid": "",
2450
+ # "confirmations": 0,
2451
+ # "status": 6,
2452
+ # "tagType": null
2453
+ # }
2454
+ # ]
2455
+ # }
2456
+ #
2457
+ data = self.safe_list(response, 'data', [])
2458
+ return self.parse_transactions(data, currency)
2459
+
2460
+ def parse_transaction_status_by_type(self, status, type=None):
2461
+ statusesByType: dict = {
2462
+ 'deposit': {
2463
+ '0': 'pending',
2464
+ '1': 'ok',
2465
+ },
2466
+ 'withdrawal': {
2467
+ '0': 'pending', # Email Sent
2468
+ '5': 'ok', # Failure
2469
+ '6': 'canceled',
2470
+ },
2471
+ }
2472
+ statuses = self.safe_value(statusesByType, type, {})
2473
+ return self.safe_string(statuses, status, status)
2474
+
2475
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
2476
+ #
2477
+ # fetchDeposits
2478
+ #
2479
+ # {
2480
+ # "symbol": "XRP",
2481
+ # "amount": "261.3361000000000000",
2482
+ # "fee": "0.0E-15",
2483
+ # "createdAt": 1548816979000,
2484
+ # "updatedAt": 1548816999000,
2485
+ # "addressFrom": "",
2486
+ # "addressTo": "raLPjTYeGezfdb6crXZzcC8RkLBEwbBHJ5_18113641",
2487
+ # "txid": "86D6EB68A7A28938BCE06BD348F8C07DEF500C5F7FE92069EF8C0551CE0F2C7D",
2488
+ # "confirmations": 8,
2489
+ # "status": 1,
2490
+ # "tagType": "Tag"
2491
+ # },
2492
+ # {
2493
+ # "symbol": "XRP",
2494
+ # "amount": "20.0000000000000000",
2495
+ # "fee": "0.0E-15",
2496
+ # "createdAt": 1544669393000,
2497
+ # "updatedAt": 1544669413000,
2498
+ # "addressFrom": "",
2499
+ # "addressTo": "raLPjTYeGezfdb6crXZzcC8RkLBEwbBHJ5_18113641",
2500
+ # "txid": "515B23E1F9864D3AF7F5B4C4FCBED784BAE861854FAB95F4031922B6AAEFC7AC",
2501
+ # "confirmations": 7,
2502
+ # "status": 1,
2503
+ # "tagType": "Tag"
2504
+ # }
2505
+ #
2506
+ # fetchWithdrawals
2507
+ #
2508
+ # {
2509
+ # "id": 183745,
2510
+ # "symbol": "usdt_erc20",
2511
+ # "amount": "8.4000000000000000",
2512
+ # "fee": "1.6000000000000000",
2513
+ # "payAmount": "0.0000000000000000",
2514
+ # "createdAt": 1595336441000,
2515
+ # "updatedAt": 1595336576000,
2516
+ # "addressFrom": "",
2517
+ # "addressTo": "0x2edfae3878d7b6db70ce4abed177ab2636f60c83",
2518
+ # "txid": "",
2519
+ # "confirmations": 0,
2520
+ # "status": 6,
2521
+ # "tagType": null
2522
+ # }
2523
+ #
2524
+ # withdraw
2525
+ #
2526
+ # {
2527
+ # "msg": null,
2528
+ # "amount": 1000,
2529
+ # "fee": 1,
2530
+ # "ctime": null,
2531
+ # "coin": "usdt_erc20",
2532
+ # "withdrawId": 1156423,
2533
+ # "addressTo": "0x2edfae3878d7b6db70ce4abed177ab2636f60c83"
2534
+ # }
2535
+ #
2536
+ id = self.safe_string_2(transaction, 'id', 'withdrawId')
2537
+ tagType = self.safe_string(transaction, 'tagType')
2538
+ addressTo = self.safe_string(transaction, 'addressTo')
2539
+ addressFrom = self.safe_string(transaction, 'addressFrom')
2540
+ tagTo = None
2541
+ tagFrom = None
2542
+ if tagType is not None:
2543
+ if addressTo is not None:
2544
+ parts = addressTo.split('_')
2545
+ addressTo = self.safe_string(parts, 0)
2546
+ tagTo = self.safe_string(parts, 1)
2547
+ if addressFrom is not None:
2548
+ parts = addressFrom.split('_')
2549
+ addressFrom = self.safe_string(parts, 0)
2550
+ tagFrom = self.safe_string(parts, 1)
2551
+ txid = self.safe_string(transaction, 'txid')
2552
+ timestamp = self.safe_integer(transaction, 'createdAt')
2553
+ updated = self.safe_integer(transaction, 'updatedAt')
2554
+ payAmount = ('payAmount' in transaction)
2555
+ ctime = ('ctime' in transaction)
2556
+ type = 'withdrawal' if (payAmount or ctime) else 'deposit'
2557
+ status = self.parse_transaction_status_by_type(self.safe_string(transaction, 'status'), type)
2558
+ amount = self.safe_number(transaction, 'amount')
2559
+ network = None
2560
+ currencyId = self.safe_string_2(transaction, 'symbol', 'coin')
2561
+ if currencyId is not None:
2562
+ parts = currencyId.split('_')
2563
+ currencyId = self.safe_string(parts, 0)
2564
+ networkId = self.safe_string(parts, 1)
2565
+ if networkId is not None:
2566
+ network = networkId.upper()
2567
+ code = self.safe_currency_code(currencyId, currency)
2568
+ feeCost = self.safe_number(transaction, 'fee')
2569
+ fee = None
2570
+ if feeCost is not None:
2571
+ fee = {'currency': code, 'cost': feeCost}
2572
+ return {
2573
+ 'info': transaction,
2574
+ 'id': id,
2575
+ 'txid': txid,
2576
+ 'timestamp': timestamp,
2577
+ 'datetime': self.iso8601(timestamp),
2578
+ 'network': network,
2579
+ 'address': addressTo,
2580
+ 'addressTo': addressTo,
2581
+ 'addressFrom': addressFrom,
2582
+ 'tag': tagTo,
2583
+ 'tagTo': tagTo,
2584
+ 'tagFrom': tagFrom,
2585
+ 'type': type,
2586
+ 'amount': amount,
2587
+ 'currency': code,
2588
+ 'status': status,
2589
+ 'updated': updated,
2590
+ 'internal': False,
2591
+ 'comment': None,
2592
+ 'fee': fee,
2593
+ }
2594
+
2595
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
2596
+ """
2597
+ make a withdrawal
2598
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#withdraw-commit--withdraw_data
2599
+ :param str code: unified currency code
2600
+ :param float amount: the amount to withdraw
2601
+ :param str address: the address to withdraw to
2602
+ :param str tag:
2603
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2604
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
2605
+ """
2606
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
2607
+ self.check_address(address)
2608
+ await self.load_markets()
2609
+ currency = self.currency(code)
2610
+ request: dict = {
2611
+ 'coin': currency['id'],
2612
+ 'amount': amount,
2613
+ 'addressTo': address,
2614
+ # 'chainName': chainName, # 'ERC20', 'TRC20', 'SOL'
2615
+ # 'addressMark': '', # mark of address
2616
+ # 'addrType': '', # type of address
2617
+ # 'tag': tag,
2618
+ }
2619
+ networkCode = None
2620
+ networkCode, params = self.handle_network_code_and_params(params)
2621
+ if networkCode is not None:
2622
+ request['chainName'] = self.network_code_to_id(networkCode)
2623
+ if tag is not None:
2624
+ request['tag'] = tag
2625
+ response = await self.spotV1PrivatePostWithdrawCommit(self.extend(request, params))
2626
+ #
2627
+ # {
2628
+ # "code": 200,
2629
+ # "msg": "succ",
2630
+ # "data": {
2631
+ # "msg": null,
2632
+ # "amount": 1000,
2633
+ # "fee": 1,
2634
+ # "ctime": null,
2635
+ # "coin": "usdt_erc20",
2636
+ # "withdrawId": 1156423,
2637
+ # "addressTo": "0x2edfae3878d7b6db70ce4abed177ab2636f60c83"
2638
+ # }
2639
+ # }
2640
+ #
2641
+ data = self.safe_dict(response, 'data', {})
2642
+ return self.parse_transaction(data, currency)
2643
+
2644
+ def parse_deposit_withdraw_fee(self, fee, currency: Currency = None):
2645
+ #
2646
+ # {
2647
+ # "coin": "adx",
2648
+ # "coinFulName": "Ambire AdEx",
2649
+ # "chains": ["BSC"],
2650
+ # "chainDetail": [[Object]]
2651
+ # }
2652
+ #
2653
+ chainDetails = self.safe_value(fee, 'chainDetail', [])
2654
+ chainDetailLength = len(chainDetails)
2655
+ result: dict = {
2656
+ 'info': fee,
2657
+ 'withdraw': {
2658
+ 'fee': None,
2659
+ 'percentage': None,
2660
+ },
2661
+ 'deposit': {
2662
+ 'fee': None,
2663
+ 'percentage': None,
2664
+ },
2665
+ 'networks': {},
2666
+ }
2667
+ if chainDetailLength != 0:
2668
+ for i in range(0, chainDetailLength):
2669
+ chainDetail = chainDetails[i]
2670
+ networkId = self.safe_string(chainDetail, 'chain')
2671
+ currencyCode = self.safe_string(currency, 'code')
2672
+ networkCode = self.network_id_to_code(networkId, currencyCode)
2673
+ result['networks'][networkCode] = {
2674
+ 'deposit': {'fee': None, 'percentage': None},
2675
+ 'withdraw': {'fee': self.safe_number(chainDetail, 'withdrawFee'), 'percentage': False},
2676
+ }
2677
+ if chainDetailLength == 1:
2678
+ result['withdraw']['fee'] = self.safe_number(chainDetail, 'withdrawFee')
2679
+ result['withdraw']['percentage'] = False
2680
+ return result
2681
+
2682
+ async def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
2683
+ """
2684
+ fetch deposit and withdraw fees
2685
+ :see: https://github.com/Bitrue-exchange/Spot-official-api-docs#exchangeInfo_endpoint
2686
+ :param str[]|None codes: list of unified currency codes
2687
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2688
+ :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
2689
+ """
2690
+ await self.load_markets()
2691
+ response = await self.spotV1PublicGetExchangeInfo(params)
2692
+ coins = self.safe_list(response, 'coins')
2693
+ return self.parse_deposit_withdraw_fees(coins, codes, 'coin')
2694
+
2695
+ def parse_transfer(self, transfer, currency=None):
2696
+ #
2697
+ # fetchTransfers
2698
+ #
2699
+ # {
2700
+ # 'transferType': 'wallet_to_contract',
2701
+ # 'symbol': 'USDT',
2702
+ # 'amount': 1.0,
2703
+ # 'status': 1,
2704
+ # 'ctime': 1685404575000
2705
+ # }
2706
+ #
2707
+ # transfer
2708
+ #
2709
+ # {}
2710
+ #
2711
+ transferType = self.safe_string(transfer, 'transferType')
2712
+ fromAccount = None
2713
+ toAccount = None
2714
+ if transferType is not None:
2715
+ accountSplit = transferType.split('_to_')
2716
+ fromAccount = self.safe_string(accountSplit, 0)
2717
+ toAccount = self.safe_string(accountSplit, 1)
2718
+ timestamp = self.safe_integer(transfer, 'ctime')
2719
+ return {
2720
+ 'info': transfer,
2721
+ 'id': None,
2722
+ 'timestamp': timestamp,
2723
+ 'datetime': self.iso8601(timestamp),
2724
+ 'currency': self.safe_string(currency, 'code'),
2725
+ 'amount': self.safe_number(transfer, 'amount'),
2726
+ 'fromAccount': fromAccount,
2727
+ 'toAccount': toAccount,
2728
+ 'status': 'ok',
2729
+ }
2730
+
2731
+ async def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> TransferEntries:
2732
+ """
2733
+ fetch a history of internal transfers made on an account
2734
+ :see: https://www.bitrue.com/api-docs#get-future-account-transfer-history-list-user_data-hmac-sha256
2735
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#get-future-account-transfer-history-list-user_data-hmac-sha256
2736
+ :param str code: unified currency code of the currency transferred
2737
+ :param int [since]: the earliest time in ms to fetch transfers for
2738
+ :param int [limit]: the maximum number of transfers structures to retrieve
2739
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2740
+ :param int [params.until]: the latest time in ms to fetch transfers for
2741
+ :param str [params.type]: transfer type wallet_to_contract or contract_to_wallet
2742
+ :returns dict[]: a list of `transfer structures <https://github.com/ccxt/ccxt/wiki/Manual#transfer-structure>`
2743
+ """
2744
+ await self.load_markets()
2745
+ type = self.safe_string_2(params, 'type', 'transferType')
2746
+ request: dict = {
2747
+ 'transferType': type,
2748
+ }
2749
+ currency = None
2750
+ if code is not None:
2751
+ currency = self.currency(code)
2752
+ request['coinSymbol'] = currency['id']
2753
+ if since is not None:
2754
+ request['beginTime'] = since
2755
+ if limit is not None:
2756
+ if limit > 200:
2757
+ limit = 200
2758
+ request['limit'] = limit
2759
+ until = self.safe_integer(params, 'until')
2760
+ if until is not None:
2761
+ params = self.omit(params, 'until')
2762
+ request['endTime'] = until
2763
+ response = await self.fapiV2PrivateGetFuturesTransferHistory(self.extend(request, params))
2764
+ #
2765
+ # {
2766
+ # 'code': '0',
2767
+ # 'msg': 'Success',
2768
+ # 'data': [{
2769
+ # 'transferType': 'wallet_to_contract',
2770
+ # 'symbol': 'USDT',
2771
+ # 'amount': 1.0,
2772
+ # 'status': 1,
2773
+ # 'ctime': 1685404575000
2774
+ # }]
2775
+ # }
2776
+ #
2777
+ data = self.safe_list(response, 'data', [])
2778
+ return self.parse_transfers(data, currency, since, limit)
2779
+
2780
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
2781
+ """
2782
+ transfer currency internally between wallets on the same account
2783
+ :see: https://www.bitrue.com/api-docs#new-future-account-transfer-user_data-hmac-sha256
2784
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#user-commission-rate-user_data-hmac-sha256
2785
+ :param str code: unified currency code
2786
+ :param float amount: amount to transfer
2787
+ :param str fromAccount: account to transfer from
2788
+ :param str toAccount: account to transfer to
2789
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2790
+ :returns dict: a `transfer structure <https://github.com/ccxt/ccxt/wiki/Manual#transfer-structure>`
2791
+ """
2792
+ await self.load_markets()
2793
+ currency = self.currency(code)
2794
+ accountTypes = self.safe_value(self.options, 'accountsByType', {})
2795
+ fromId = self.safe_string(accountTypes, fromAccount, fromAccount)
2796
+ toId = self.safe_string(accountTypes, toAccount, toAccount)
2797
+ request: dict = {
2798
+ 'coinSymbol': currency['id'],
2799
+ 'amount': self.currency_to_precision(code, amount),
2800
+ 'transferType': fromId + '_to_' + toId,
2801
+ }
2802
+ response = await self.fapiV2PrivatePostFuturesTransfer(self.extend(request, params))
2803
+ #
2804
+ # {
2805
+ # 'code': '0',
2806
+ # 'msg': 'Success',
2807
+ # 'data': null
2808
+ # }
2809
+ #
2810
+ data = self.safe_dict(response, 'data', {})
2811
+ return self.parse_transfer(data, currency)
2812
+
2813
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
2814
+ """
2815
+ set the level of leverage for a market
2816
+ :see: https://www.bitrue.com/api-docs#change-initial-leverage-trade-hmac-sha256
2817
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#change-initial-leverage-trade-hmac-sha256
2818
+ :param float leverage: the rate of leverage
2819
+ :param str symbol: unified market symbol
2820
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2821
+ :returns dict: response from the exchange
2822
+ """
2823
+ if symbol is None:
2824
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
2825
+ if (leverage < 1) or (leverage > 125):
2826
+ raise BadRequest(self.id + ' leverage should be between 1 and 125')
2827
+ await self.load_markets()
2828
+ market = self.market(symbol)
2829
+ response = None
2830
+ request: dict = {
2831
+ 'contractName': market['id'],
2832
+ 'leverage': leverage,
2833
+ }
2834
+ if not market['swap']:
2835
+ raise NotSupported(self.id + ' setLeverage only support swap markets')
2836
+ if market['linear']:
2837
+ response = await self.fapiV2PrivatePostLevelEdit(self.extend(request, params))
2838
+ elif market['inverse']:
2839
+ response = await self.dapiV2PrivatePostLevelEdit(self.extend(request, params))
2840
+ return response
2841
+
2842
+ def parse_margin_modification(self, data, market=None) -> MarginModification:
2843
+ #
2844
+ # setMargin
2845
+ #
2846
+ # {
2847
+ # "code": 0,
2848
+ # "msg": "success"
2849
+ # "data": null
2850
+ # }
2851
+ #
2852
+ return {
2853
+ 'info': data,
2854
+ 'symbol': market['symbol'],
2855
+ 'type': None,
2856
+ 'marginMode': 'isolated',
2857
+ 'amount': None,
2858
+ 'total': None,
2859
+ 'code': None,
2860
+ 'status': None,
2861
+ 'timestamp': None,
2862
+ 'datetime': None,
2863
+ }
2864
+
2865
+ async def set_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
2866
+ """
2867
+ Either adds or reduces margin in an isolated position in order to set the margin to a specific value
2868
+ :see: https://www.bitrue.com/api-docs#modify-isolated-position-margin-trade-hmac-sha256
2869
+ :see: https://www.bitrue.com/api_docs_includes_file/delivery.html#modify-isolated-position-margin-trade-hmac-sha256
2870
+ :param str symbol: unified market symbol of the market to set margin in
2871
+ :param float amount: the amount to set the margin to
2872
+ :param dict [params]: parameters specific to the exchange API endpoint
2873
+ :returns dict: A `margin structure <https://github.com/ccxt/ccxt/wiki/Manual#add-margin-structure>`
2874
+ """
2875
+ await self.load_markets()
2876
+ market = self.market(symbol)
2877
+ if not market['swap']:
2878
+ raise NotSupported(self.id + ' setMargin only support swap markets')
2879
+ response = None
2880
+ request: dict = {
2881
+ 'contractName': market['id'],
2882
+ 'amount': self.parse_to_numeric(amount),
2883
+ }
2884
+ if market['linear']:
2885
+ response = await self.fapiV2PrivatePostPositionMargin(self.extend(request, params))
2886
+ elif market['inverse']:
2887
+ response = await self.dapiV2PrivatePostPositionMargin(self.extend(request, params))
2888
+ #
2889
+ # {
2890
+ # "code": 0,
2891
+ # "msg": "success"
2892
+ # "data": null
2893
+ # }
2894
+ #
2895
+ return self.parse_margin_modification(response, market)
2896
+
2897
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
2898
+ type = self.safe_string(api, 0)
2899
+ version = self.safe_string(api, 1)
2900
+ access = self.safe_string(api, 2)
2901
+ url = None
2902
+ if type == 'api' and version == 'kline':
2903
+ url = self.urls['api'][type]
2904
+ else:
2905
+ url = self.urls['api'][type] + '/' + version
2906
+ url = url + '/' + self.implode_params(path, params)
2907
+ params = self.omit(params, self.extract_params(path))
2908
+ if access == 'private':
2909
+ self.check_required_credentials()
2910
+ recvWindow = self.safe_integer(self.options, 'recvWindow', 5000)
2911
+ if type == 'spot':
2912
+ query = self.urlencode(self.extend({
2913
+ 'timestamp': self.nonce(),
2914
+ 'recvWindow': recvWindow,
2915
+ }, params))
2916
+ signature = self.hmac(self.encode(query), self.encode(self.secret), hashlib.sha256)
2917
+ query += '&' + 'signature=' + signature
2918
+ headers = {
2919
+ 'X-MBX-APIKEY': self.apiKey,
2920
+ }
2921
+ if (method == 'GET') or (method == 'DELETE'):
2922
+ url += '?' + query
2923
+ else:
2924
+ body = query
2925
+ headers['Content-Type'] = 'application/x-www-form-urlencoded'
2926
+ else:
2927
+ timestamp = str(self.nonce())
2928
+ signPath = None
2929
+ if type == 'fapi':
2930
+ signPath = '/fapi'
2931
+ elif type == 'dapi':
2932
+ signPath = '/dapi'
2933
+ signPath = signPath + '/' + version + '/' + path
2934
+ signMessage = timestamp + method + signPath
2935
+ if method == 'GET':
2936
+ keys = list(params.keys())
2937
+ keysLength = len(keys)
2938
+ if keysLength > 0:
2939
+ signMessage += '?' + self.urlencode(params)
2940
+ signature = self.hmac(self.encode(signMessage), self.encode(self.secret), hashlib.sha256)
2941
+ headers = {
2942
+ 'X-CH-APIKEY': self.apiKey,
2943
+ 'X-CH-SIGN': signature,
2944
+ 'X-CH-TS': timestamp,
2945
+ }
2946
+ url += '?' + self.urlencode(params)
2947
+ else:
2948
+ query = self.extend({
2949
+ 'recvWindow': recvWindow,
2950
+ }, params)
2951
+ body = self.json(query)
2952
+ signMessage += body
2953
+ signature = self.hmac(self.encode(signMessage), self.encode(self.secret), hashlib.sha256)
2954
+ headers = {
2955
+ 'Content-Type': 'application/json',
2956
+ 'X-CH-APIKEY': self.apiKey,
2957
+ 'X-CH-SIGN': signature,
2958
+ 'X-CH-TS': timestamp,
2959
+ }
2960
+ else:
2961
+ if params:
2962
+ url += '?' + self.urlencode(params)
2963
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
2964
+
2965
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
2966
+ if (code == 418) or (code == 429):
2967
+ raise DDoSProtection(self.id + ' ' + str(code) + ' ' + reason + ' ' + body)
2968
+ # error response in a form: {"code": -1013, "msg": "Invalid quantity."}
2969
+ # following block cointains legacy checks against message patterns in "msg" property
2970
+ # will switch "code" checks eventually, when we know all of them
2971
+ if code >= 400:
2972
+ if body.find('Price * QTY is zero or less') >= 0:
2973
+ raise InvalidOrder(self.id + ' order cost = amount * price is zero or less ' + body)
2974
+ if body.find('LOT_SIZE') >= 0:
2975
+ raise InvalidOrder(self.id + ' order amount should be evenly divisible by lot size ' + body)
2976
+ if body.find('PRICE_FILTER') >= 0:
2977
+ raise InvalidOrder(self.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use self.price_to_precision(symbol, amount) ' + body)
2978
+ if response is None:
2979
+ return None # fallback to default error handler
2980
+ # check success value for wapi endpoints
2981
+ # response in format {'msg': 'The coin does not exist.', 'success': True/false}
2982
+ success = self.safe_bool(response, 'success', True)
2983
+ if not success:
2984
+ messageInner = self.safe_string(response, 'msg')
2985
+ parsedMessage = None
2986
+ if messageInner is not None:
2987
+ try:
2988
+ parsedMessage = json.loads(messageInner)
2989
+ except Exception as e:
2990
+ # do nothing
2991
+ parsedMessage = None
2992
+ if parsedMessage is not None:
2993
+ response = parsedMessage
2994
+ message = self.safe_string(response, 'msg')
2995
+ if message is not None:
2996
+ self.throw_exactly_matched_exception(self.exceptions['exact'], message, self.id + ' ' + message)
2997
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, self.id + ' ' + message)
2998
+ # checks against error codes
2999
+ error = self.safe_string(response, 'code')
3000
+ if error is not None:
3001
+ # https://github.com/ccxt/ccxt/issues/6501
3002
+ # https://github.com/ccxt/ccxt/issues/7742
3003
+ if (error == '200') or Precise.string_equals(error, '0'):
3004
+ return None
3005
+ # a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
3006
+ # despite that their message is very confusing, it is raised by Binance
3007
+ # on a temporary ban, the API key is valid, but disabled for a while
3008
+ if (error == '-2015') and self.options['hasAlreadyAuthenticatedSuccessfully']:
3009
+ raise DDoSProtection(self.id + ' temporary banned: ' + body)
3010
+ feedback = self.id + ' ' + body
3011
+ self.throw_exactly_matched_exception(self.exceptions['exact'], error, feedback)
3012
+ raise ExchangeError(feedback)
3013
+ if not success:
3014
+ raise ExchangeError(self.id + ' ' + body)
3015
+ return None
3016
+
3017
+ def calculate_rate_limiter_cost(self, api, method, path, params, config={}):
3018
+ if ('noSymbol' in config) and not ('symbol' in params):
3019
+ return config['noSymbol']
3020
+ elif ('byLimit' in config) and ('limit' in params):
3021
+ limit = params['limit']
3022
+ byLimit = config['byLimit']
3023
+ for i in range(0, len(byLimit)):
3024
+ entry = byLimit[i]
3025
+ if limit <= entry[0]:
3026
+ return entry[1]
3027
+ return self.safe_value(config, 'cost', 1)