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

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