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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (772) hide show
  1. ccxt/__init__.py +358 -0
  2. ccxt/abantether.py +316 -0
  3. ccxt/abstract/__init__.py +0 -0
  4. ccxt/abstract/abantether.py +5 -0
  5. ccxt/abstract/ace.py +15 -0
  6. ccxt/abstract/afratether.py +6 -0
  7. ccxt/abstract/alpaca.py +70 -0
  8. ccxt/abstract/arzinja.py +5 -0
  9. ccxt/abstract/arzplus.py +7 -0
  10. ccxt/abstract/ascendex.py +77 -0
  11. ccxt/abstract/bequant.py +115 -0
  12. ccxt/abstract/bigone.py +45 -0
  13. ccxt/abstract/binance.py +712 -0
  14. ccxt/abstract/binancecoinm.py +712 -0
  15. ccxt/abstract/binanceus.py +764 -0
  16. ccxt/abstract/binanceusdm.py +712 -0
  17. ccxt/abstract/bingx.py +113 -0
  18. ccxt/abstract/bit2c.py +27 -0
  19. ccxt/abstract/bitbank.py +27 -0
  20. ccxt/abstract/bitbay.py +53 -0
  21. ccxt/abstract/bitbns.py +40 -0
  22. ccxt/abstract/bitcoincom.py +115 -0
  23. ccxt/abstract/bitfinex.py +69 -0
  24. ccxt/abstract/bitfinex2.py +139 -0
  25. ccxt/abstract/bitflyer.py +38 -0
  26. ccxt/abstract/bitget.py +508 -0
  27. ccxt/abstract/bithumb.py +32 -0
  28. ccxt/abstract/bitimen.py +7 -0
  29. ccxt/abstract/bitir.py +7 -0
  30. ccxt/abstract/bitmart.py +99 -0
  31. ccxt/abstract/bitmex.py +97 -0
  32. ccxt/abstract/bitopro.py +29 -0
  33. ccxt/abstract/bitpanda.py +35 -0
  34. ccxt/abstract/bitpin.py +7 -0
  35. ccxt/abstract/bitrue.py +72 -0
  36. ccxt/abstract/bitso.py +43 -0
  37. ccxt/abstract/bitstamp.py +258 -0
  38. ccxt/abstract/bitteam.py +29 -0
  39. ccxt/abstract/bitvavo.py +27 -0
  40. ccxt/abstract/bl3p.py +19 -0
  41. ccxt/abstract/blockchaincom.py +28 -0
  42. ccxt/abstract/blofin.py +37 -0
  43. ccxt/abstract/btcalpha.py +18 -0
  44. ccxt/abstract/btcbox.py +13 -0
  45. ccxt/abstract/btcmarkets.py +39 -0
  46. ccxt/abstract/btcturk.py +20 -0
  47. ccxt/abstract/bybit.py +298 -0
  48. ccxt/abstract/cex.py +33 -0
  49. ccxt/abstract/coinbase.py +94 -0
  50. ccxt/abstract/coinbaseadvanced.py +94 -0
  51. ccxt/abstract/coinbaseexchange.py +67 -0
  52. ccxt/abstract/coinbaseinternational.py +39 -0
  53. ccxt/abstract/coincatch.py +94 -0
  54. ccxt/abstract/coincheck.py +33 -0
  55. ccxt/abstract/coinex.py +237 -0
  56. ccxt/abstract/coinlist.py +54 -0
  57. ccxt/abstract/coinmate.py +62 -0
  58. ccxt/abstract/coinmetro.py +34 -0
  59. ccxt/abstract/coinone.py +67 -0
  60. ccxt/abstract/coinsph.py +54 -0
  61. ccxt/abstract/coinspot.py +28 -0
  62. ccxt/abstract/cryptocom.py +107 -0
  63. ccxt/abstract/currencycom.py +68 -0
  64. ccxt/abstract/delta.py +50 -0
  65. ccxt/abstract/deribit.py +125 -0
  66. ccxt/abstract/digifinex.py +91 -0
  67. ccxt/abstract/eterex.py +5 -0
  68. ccxt/abstract/excoino.py +7 -0
  69. ccxt/abstract/exir.py +8 -0
  70. ccxt/abstract/exmo.py +55 -0
  71. ccxt/abstract/exnovin.py +6 -0
  72. ccxt/abstract/farhadexchange.py +5 -0
  73. ccxt/abstract/fmfwio.py +115 -0
  74. ccxt/abstract/gate.py +265 -0
  75. ccxt/abstract/gateio.py +265 -0
  76. ccxt/abstract/gemini.py +58 -0
  77. ccxt/abstract/hashkey.py +67 -0
  78. ccxt/abstract/hitbtc.py +115 -0
  79. ccxt/abstract/hitbtc3.py +115 -0
  80. ccxt/abstract/hitobit.py +8 -0
  81. ccxt/abstract/hollaex.py +33 -0
  82. ccxt/abstract/htx.py +548 -0
  83. ccxt/abstract/huobi.py +548 -0
  84. ccxt/abstract/huobijp.py +114 -0
  85. ccxt/abstract/hyperliquid.py +6 -0
  86. ccxt/abstract/idex.py +26 -0
  87. ccxt/abstract/independentreserve.py +37 -0
  88. ccxt/abstract/indodax.py +26 -0
  89. ccxt/abstract/jibitex.py +7 -0
  90. ccxt/abstract/kraken.py +57 -0
  91. ccxt/abstract/krakenfutures.py +38 -0
  92. ccxt/abstract/kucoin.py +214 -0
  93. ccxt/abstract/kucoinfutures.py +233 -0
  94. ccxt/abstract/kuna.py +182 -0
  95. ccxt/abstract/latoken.py +56 -0
  96. ccxt/abstract/lbank.py +61 -0
  97. ccxt/abstract/luno.py +37 -0
  98. ccxt/abstract/lykke.py +29 -0
  99. ccxt/abstract/mercado.py +25 -0
  100. ccxt/abstract/mexc.py +178 -0
  101. ccxt/abstract/ndax.py +97 -0
  102. ccxt/abstract/nobitex.py +7 -0
  103. ccxt/abstract/novadax.py +29 -0
  104. ccxt/abstract/oceanex.py +22 -0
  105. ccxt/abstract/okcoin.py +74 -0
  106. ccxt/abstract/okexchange.py +8 -0
  107. ccxt/abstract/okx.py +324 -0
  108. ccxt/abstract/ompfinex.py +7 -0
  109. ccxt/abstract/onetrading.py +35 -0
  110. ccxt/abstract/oxfun.py +34 -0
  111. ccxt/abstract/p2b.py +22 -0
  112. ccxt/abstract/paradex.py +40 -0
  113. ccxt/abstract/paymium.py +28 -0
  114. ccxt/abstract/phemex.py +115 -0
  115. ccxt/abstract/poloniex.py +69 -0
  116. ccxt/abstract/poloniexfutures.py +48 -0
  117. ccxt/abstract/probit.py +23 -0
  118. ccxt/abstract/ramzinex.py +7 -0
  119. ccxt/abstract/sarmayex.py +5 -0
  120. ccxt/abstract/sarrafex.py +7 -0
  121. ccxt/abstract/tabdeal.py +7 -0
  122. ccxt/abstract/tetherland.py +5 -0
  123. ccxt/abstract/timex.py +62 -0
  124. ccxt/abstract/tokocrypto.py +37 -0
  125. ccxt/abstract/tradeogre.py +16 -0
  126. ccxt/abstract/twox.py +5 -0
  127. ccxt/abstract/ubitex.py +7 -0
  128. ccxt/abstract/upbit.py +38 -0
  129. ccxt/abstract/vertex.py +19 -0
  130. ccxt/abstract/wallex.py +8 -0
  131. ccxt/abstract/wavesexchange.py +154 -0
  132. ccxt/abstract/wazirx.py +30 -0
  133. ccxt/abstract/whitebit.py +98 -0
  134. ccxt/abstract/woo.py +83 -0
  135. ccxt/abstract/woofipro.py +119 -0
  136. ccxt/abstract/xt.py +152 -0
  137. ccxt/abstract/yobit.py +16 -0
  138. ccxt/abstract/zaif.py +38 -0
  139. ccxt/abstract/zonda.py +53 -0
  140. ccxt/ace.py +1012 -0
  141. ccxt/afratether.py +293 -0
  142. ccxt/alpaca.py +1083 -0
  143. ccxt/arzinja.py +285 -0
  144. ccxt/arzplus.py +412 -0
  145. ccxt/ascendex.py +3330 -0
  146. ccxt/async_support/__init__.py +337 -0
  147. ccxt/async_support/abantether.py +316 -0
  148. ccxt/async_support/ace.py +1012 -0
  149. ccxt/async_support/afratether.py +293 -0
  150. ccxt/async_support/alpaca.py +1083 -0
  151. ccxt/async_support/arzinja.py +285 -0
  152. ccxt/async_support/arzplus.py +412 -0
  153. ccxt/async_support/ascendex.py +3330 -0
  154. ccxt/async_support/base/__init__.py +1 -0
  155. ccxt/async_support/base/exchange.py +1966 -0
  156. ccxt/async_support/base/throttler.py +50 -0
  157. ccxt/async_support/base/ws/__init__.py +38 -0
  158. ccxt/async_support/base/ws/aiohttp_client.py +125 -0
  159. ccxt/async_support/base/ws/cache.py +212 -0
  160. ccxt/async_support/base/ws/client.py +193 -0
  161. ccxt/async_support/base/ws/fast_client.py +96 -0
  162. ccxt/async_support/base/ws/functions.py +59 -0
  163. ccxt/async_support/base/ws/future.py +58 -0
  164. ccxt/async_support/base/ws/order_book.py +78 -0
  165. ccxt/async_support/base/ws/order_book_side.py +174 -0
  166. ccxt/async_support/bequant.py +33 -0
  167. ccxt/async_support/bigone.py +2113 -0
  168. ccxt/async_support/binance.py +12234 -0
  169. ccxt/async_support/binancecoinm.py +45 -0
  170. ccxt/async_support/binanceus.py +211 -0
  171. ccxt/async_support/binanceusdm.py +58 -0
  172. ccxt/async_support/bingx.py +4325 -0
  173. ccxt/async_support/bit2c.py +866 -0
  174. ccxt/async_support/bitbank.py +1001 -0
  175. ccxt/async_support/bitbay.py +17 -0
  176. ccxt/async_support/bitbns.py +1154 -0
  177. ccxt/async_support/bitcoincom.py +17 -0
  178. ccxt/async_support/bitfinex.py +1617 -0
  179. ccxt/async_support/bitfinex2.py +3552 -0
  180. ccxt/async_support/bitflyer.py +995 -0
  181. ccxt/async_support/bitget.py +8273 -0
  182. ccxt/async_support/bithumb.py +1061 -0
  183. ccxt/async_support/bitimen.py +401 -0
  184. ccxt/async_support/bitir.py +490 -0
  185. ccxt/async_support/bitmart.py +4415 -0
  186. ccxt/async_support/bitmex.py +2756 -0
  187. ccxt/async_support/bitopro.py +1630 -0
  188. ccxt/async_support/bitpanda.py +16 -0
  189. ccxt/async_support/bitpin.py +454 -0
  190. ccxt/async_support/bitrue.py +3027 -0
  191. ccxt/async_support/bitso.py +1670 -0
  192. ccxt/async_support/bitstamp.py +2203 -0
  193. ccxt/async_support/bitteam.py +2239 -0
  194. ccxt/async_support/bitvavo.py +1968 -0
  195. ccxt/async_support/bl3p.py +485 -0
  196. ccxt/async_support/blockchaincom.py +1104 -0
  197. ccxt/async_support/blofin.py +2066 -0
  198. ccxt/async_support/btcalpha.py +891 -0
  199. ccxt/async_support/btcbox.py +544 -0
  200. ccxt/async_support/btcmarkets.py +1221 -0
  201. ccxt/async_support/btcturk.py +911 -0
  202. ccxt/async_support/bybit.py +8159 -0
  203. ccxt/async_support/cex.py +1605 -0
  204. ccxt/async_support/coinbase.py +4475 -0
  205. ccxt/async_support/coinbaseadvanced.py +17 -0
  206. ccxt/async_support/coinbaseexchange.py +1734 -0
  207. ccxt/async_support/coinbaseinternational.py +1899 -0
  208. ccxt/async_support/coincatch.py +5069 -0
  209. ccxt/async_support/coincheck.py +815 -0
  210. ccxt/async_support/coinex.py +5526 -0
  211. ccxt/async_support/coinlist.py +2243 -0
  212. ccxt/async_support/coinmate.py +1067 -0
  213. ccxt/async_support/coinmetro.py +1797 -0
  214. ccxt/async_support/coinone.py +1127 -0
  215. ccxt/async_support/coinsph.py +1850 -0
  216. ccxt/async_support/coinspot.py +534 -0
  217. ccxt/async_support/cryptocom.py +2822 -0
  218. ccxt/async_support/currencycom.py +1950 -0
  219. ccxt/async_support/delta.py +3376 -0
  220. ccxt/async_support/deribit.py +3437 -0
  221. ccxt/async_support/digifinex.py +3960 -0
  222. ccxt/async_support/eterex.py +286 -0
  223. ccxt/async_support/excoino.py +399 -0
  224. ccxt/async_support/exir.py +375 -0
  225. ccxt/async_support/exmo.py +2462 -0
  226. ccxt/async_support/exnovin.py +360 -0
  227. ccxt/async_support/farhadexchange.py +266 -0
  228. ccxt/async_support/fmfwio.py +34 -0
  229. ccxt/async_support/gate.py +6976 -0
  230. ccxt/async_support/gateio.py +16 -0
  231. ccxt/async_support/gemini.py +1825 -0
  232. ccxt/async_support/hashkey.py +4150 -0
  233. ccxt/async_support/hitbtc.py +3423 -0
  234. ccxt/async_support/hitbtc3.py +16 -0
  235. ccxt/async_support/hitobit.py +391 -0
  236. ccxt/async_support/hollaex.py +1813 -0
  237. ccxt/async_support/htx.py +8506 -0
  238. ccxt/async_support/huobi.py +16 -0
  239. ccxt/async_support/huobijp.py +1801 -0
  240. ccxt/async_support/hyperliquid.py +2431 -0
  241. ccxt/async_support/idex.py +1766 -0
  242. ccxt/async_support/independentreserve.py +784 -0
  243. ccxt/async_support/indodax.py +1247 -0
  244. ccxt/async_support/jibitex.py +395 -0
  245. ccxt/async_support/kraken.py +2894 -0
  246. ccxt/async_support/krakenfutures.py +2601 -0
  247. ccxt/async_support/kucoin.py +4602 -0
  248. ccxt/async_support/kucoinfutures.py +2698 -0
  249. ccxt/async_support/kuna.py +1841 -0
  250. ccxt/async_support/latoken.py +1664 -0
  251. ccxt/async_support/lbank.py +2683 -0
  252. ccxt/async_support/luno.py +1067 -0
  253. ccxt/async_support/lykke.py +1270 -0
  254. ccxt/async_support/mercado.py +842 -0
  255. ccxt/async_support/mexc.py +5369 -0
  256. ccxt/async_support/ndax.py +2354 -0
  257. ccxt/async_support/nobitex.py +419 -0
  258. ccxt/async_support/novadax.py +1484 -0
  259. ccxt/async_support/oceanex.py +903 -0
  260. ccxt/async_support/okcoin.py +2936 -0
  261. ccxt/async_support/okexchange.py +349 -0
  262. ccxt/async_support/okx.py +7827 -0
  263. ccxt/async_support/ompfinex.py +472 -0
  264. ccxt/async_support/onetrading.py +1911 -0
  265. ccxt/async_support/oxfun.py +2773 -0
  266. ccxt/async_support/p2b.py +1194 -0
  267. ccxt/async_support/paradex.py +2015 -0
  268. ccxt/async_support/paymium.py +564 -0
  269. ccxt/async_support/phemex.py +4473 -0
  270. ccxt/async_support/poloniex.py +2232 -0
  271. ccxt/async_support/poloniexfutures.py +1717 -0
  272. ccxt/async_support/probit.py +1734 -0
  273. ccxt/async_support/ramzinex.py +476 -0
  274. ccxt/async_support/sarmayex.py +357 -0
  275. ccxt/async_support/sarrafex.py +478 -0
  276. ccxt/async_support/tabdeal.py +364 -0
  277. ccxt/async_support/tetherland.py +349 -0
  278. ccxt/async_support/timex.py +1593 -0
  279. ccxt/async_support/tokocrypto.py +2405 -0
  280. ccxt/async_support/tradeogre.py +608 -0
  281. ccxt/async_support/twox.py +326 -0
  282. ccxt/async_support/ubitex.py +409 -0
  283. ccxt/async_support/upbit.py +1833 -0
  284. ccxt/async_support/vertex.py +2922 -0
  285. ccxt/async_support/wallex.py +445 -0
  286. ccxt/async_support/wavesexchange.py +2473 -0
  287. ccxt/async_support/wazirx.py +1224 -0
  288. ccxt/async_support/whitebit.py +2469 -0
  289. ccxt/async_support/woo.py +3114 -0
  290. ccxt/async_support/woofipro.py +2533 -0
  291. ccxt/async_support/xt.py +4454 -0
  292. ccxt/async_support/yobit.py +1283 -0
  293. ccxt/async_support/zaif.py +725 -0
  294. ccxt/async_support/zonda.py +1828 -0
  295. ccxt/base/__init__.py +27 -0
  296. ccxt/base/decimal_to_precision.py +174 -0
  297. ccxt/base/errors.py +242 -0
  298. ccxt/base/exchange.py +5941 -0
  299. ccxt/base/precise.py +287 -0
  300. ccxt/base/types.py +502 -0
  301. ccxt/bequant.py +33 -0
  302. ccxt/bigone.py +2112 -0
  303. ccxt/binance.py +12233 -0
  304. ccxt/binancecoinm.py +45 -0
  305. ccxt/binanceus.py +211 -0
  306. ccxt/binanceusdm.py +58 -0
  307. ccxt/bingx.py +4324 -0
  308. ccxt/bit2c.py +866 -0
  309. ccxt/bitbank.py +1001 -0
  310. ccxt/bitbay.py +17 -0
  311. ccxt/bitbns.py +1154 -0
  312. ccxt/bitcoincom.py +17 -0
  313. ccxt/bitfinex.py +1617 -0
  314. ccxt/bitfinex2.py +3552 -0
  315. ccxt/bitflyer.py +995 -0
  316. ccxt/bitget.py +8272 -0
  317. ccxt/bithumb.py +1061 -0
  318. ccxt/bitimen.py +401 -0
  319. ccxt/bitir.py +490 -0
  320. ccxt/bitmart.py +4415 -0
  321. ccxt/bitmex.py +2756 -0
  322. ccxt/bitopro.py +1630 -0
  323. ccxt/bitpanda.py +16 -0
  324. ccxt/bitpin.py +454 -0
  325. ccxt/bitrue.py +3026 -0
  326. ccxt/bitso.py +1670 -0
  327. ccxt/bitstamp.py +2203 -0
  328. ccxt/bitteam.py +2239 -0
  329. ccxt/bitvavo.py +1968 -0
  330. ccxt/bl3p.py +485 -0
  331. ccxt/blockchaincom.py +1104 -0
  332. ccxt/blofin.py +2066 -0
  333. ccxt/btcalpha.py +891 -0
  334. ccxt/btcbox.py +544 -0
  335. ccxt/btcmarkets.py +1221 -0
  336. ccxt/btcturk.py +911 -0
  337. ccxt/bybit.py +8158 -0
  338. ccxt/cex.py +1605 -0
  339. ccxt/coinbase.py +4474 -0
  340. ccxt/coinbaseadvanced.py +17 -0
  341. ccxt/coinbaseexchange.py +1734 -0
  342. ccxt/coinbaseinternational.py +1899 -0
  343. ccxt/coincatch.py +5069 -0
  344. ccxt/coincheck.py +815 -0
  345. ccxt/coinex.py +5525 -0
  346. ccxt/coinlist.py +2243 -0
  347. ccxt/coinmate.py +1067 -0
  348. ccxt/coinmetro.py +1797 -0
  349. ccxt/coinone.py +1127 -0
  350. ccxt/coinsph.py +1850 -0
  351. ccxt/coinspot.py +534 -0
  352. ccxt/cryptocom.py +2822 -0
  353. ccxt/currencycom.py +1950 -0
  354. ccxt/delta.py +3376 -0
  355. ccxt/deribit.py +3437 -0
  356. ccxt/digifinex.py +3959 -0
  357. ccxt/eterex.py +286 -0
  358. ccxt/excoino.py +399 -0
  359. ccxt/exir.py +375 -0
  360. ccxt/exmo.py +2462 -0
  361. ccxt/exnovin.py +360 -0
  362. ccxt/farhadexchange.py +266 -0
  363. ccxt/fmfwio.py +34 -0
  364. ccxt/gate.py +6975 -0
  365. ccxt/gateio.py +16 -0
  366. ccxt/gemini.py +1824 -0
  367. ccxt/hashkey.py +4150 -0
  368. ccxt/hitbtc.py +3423 -0
  369. ccxt/hitbtc3.py +16 -0
  370. ccxt/hitobit.py +391 -0
  371. ccxt/hollaex.py +1813 -0
  372. ccxt/htx.py +8505 -0
  373. ccxt/huobi.py +16 -0
  374. ccxt/huobijp.py +1801 -0
  375. ccxt/hyperliquid.py +2430 -0
  376. ccxt/idex.py +1766 -0
  377. ccxt/independentreserve.py +784 -0
  378. ccxt/indodax.py +1247 -0
  379. ccxt/jibitex.py +395 -0
  380. ccxt/kraken.py +2894 -0
  381. ccxt/krakenfutures.py +2601 -0
  382. ccxt/kucoin.py +4601 -0
  383. ccxt/kucoinfutures.py +2698 -0
  384. ccxt/kuna.py +1841 -0
  385. ccxt/latoken.py +1664 -0
  386. ccxt/lbank.py +2682 -0
  387. ccxt/luno.py +1067 -0
  388. ccxt/lykke.py +1270 -0
  389. ccxt/mercado.py +842 -0
  390. ccxt/mexc.py +5369 -0
  391. ccxt/ndax.py +2354 -0
  392. ccxt/nobitex.py +419 -0
  393. ccxt/novadax.py +1484 -0
  394. ccxt/oceanex.py +903 -0
  395. ccxt/okcoin.py +2936 -0
  396. ccxt/okexchange.py +349 -0
  397. ccxt/okx.py +7826 -0
  398. ccxt/ompfinex.py +472 -0
  399. ccxt/onetrading.py +1911 -0
  400. ccxt/oxfun.py +2772 -0
  401. ccxt/p2b.py +1194 -0
  402. ccxt/paradex.py +2015 -0
  403. ccxt/paymium.py +564 -0
  404. ccxt/phemex.py +4473 -0
  405. ccxt/poloniex.py +2232 -0
  406. ccxt/poloniexfutures.py +1717 -0
  407. ccxt/pro/__init__.py +149 -0
  408. ccxt/pro/alpaca.py +685 -0
  409. ccxt/pro/ascendex.py +916 -0
  410. ccxt/pro/bequant.py +38 -0
  411. ccxt/pro/binance.py +3488 -0
  412. ccxt/pro/binancecoinm.py +28 -0
  413. ccxt/pro/binanceus.py +48 -0
  414. ccxt/pro/binanceusdm.py +31 -0
  415. ccxt/pro/bingx.py +1264 -0
  416. ccxt/pro/bitcoincom.py +34 -0
  417. ccxt/pro/bitfinex.py +621 -0
  418. ccxt/pro/bitfinex2.py +1083 -0
  419. ccxt/pro/bitget.py +1692 -0
  420. ccxt/pro/bithumb.py +368 -0
  421. ccxt/pro/bitmart.py +1449 -0
  422. ccxt/pro/bitmex.py +1656 -0
  423. ccxt/pro/bitopro.py +445 -0
  424. ccxt/pro/bitpanda.py +15 -0
  425. ccxt/pro/bitrue.py +447 -0
  426. ccxt/pro/bitstamp.py +522 -0
  427. ccxt/pro/bitvavo.py +1270 -0
  428. ccxt/pro/blockchaincom.py +738 -0
  429. ccxt/pro/blofin.py +692 -0
  430. ccxt/pro/bybit.py +2000 -0
  431. ccxt/pro/cex.py +1440 -0
  432. ccxt/pro/coinbase.py +678 -0
  433. ccxt/pro/coinbaseadvanced.py +16 -0
  434. ccxt/pro/coinbaseexchange.py +895 -0
  435. ccxt/pro/coinbaseinternational.py +620 -0
  436. ccxt/pro/coincatch.py +1464 -0
  437. ccxt/pro/coincheck.py +199 -0
  438. ccxt/pro/coinex.py +1061 -0
  439. ccxt/pro/coinone.py +395 -0
  440. ccxt/pro/cryptocom.py +947 -0
  441. ccxt/pro/currencycom.py +536 -0
  442. ccxt/pro/deribit.py +892 -0
  443. ccxt/pro/exmo.py +629 -0
  444. ccxt/pro/gate.py +1416 -0
  445. ccxt/pro/gateio.py +15 -0
  446. ccxt/pro/gemini.py +865 -0
  447. ccxt/pro/hashkey.py +802 -0
  448. ccxt/pro/hitbtc.py +1216 -0
  449. ccxt/pro/hollaex.py +563 -0
  450. ccxt/pro/htx.py +2215 -0
  451. ccxt/pro/huobi.py +15 -0
  452. ccxt/pro/huobijp.py +570 -0
  453. ccxt/pro/hyperliquid.py +525 -0
  454. ccxt/pro/idex.py +672 -0
  455. ccxt/pro/independentreserve.py +270 -0
  456. ccxt/pro/kraken.py +1356 -0
  457. ccxt/pro/krakenfutures.py +1492 -0
  458. ccxt/pro/kucoin.py +1133 -0
  459. ccxt/pro/kucoinfutures.py +1081 -0
  460. ccxt/pro/lbank.py +843 -0
  461. ccxt/pro/luno.py +303 -0
  462. ccxt/pro/mexc.py +1122 -0
  463. ccxt/pro/ndax.py +506 -0
  464. ccxt/pro/okcoin.py +698 -0
  465. ccxt/pro/okx.py +1851 -0
  466. ccxt/pro/onetrading.py +1275 -0
  467. ccxt/pro/oxfun.py +950 -0
  468. ccxt/pro/p2b.py +419 -0
  469. ccxt/pro/paradex.py +352 -0
  470. ccxt/pro/phemex.py +1441 -0
  471. ccxt/pro/poloniex.py +1166 -0
  472. ccxt/pro/poloniexfutures.py +990 -0
  473. ccxt/pro/probit.py +551 -0
  474. ccxt/pro/upbit.py +520 -0
  475. ccxt/pro/vertex.py +943 -0
  476. ccxt/pro/wazirx.py +749 -0
  477. ccxt/pro/whitebit.py +864 -0
  478. ccxt/pro/woo.py +1078 -0
  479. ccxt/pro/woofipro.py +1183 -0
  480. ccxt/pro/xt.py +1067 -0
  481. ccxt/probit.py +1734 -0
  482. ccxt/ramzinex.py +476 -0
  483. ccxt/sarmayex.py +357 -0
  484. ccxt/sarrafex.py +478 -0
  485. ccxt/static_dependencies/__init__.py +1 -0
  486. ccxt/static_dependencies/ecdsa/__init__.py +14 -0
  487. ccxt/static_dependencies/ecdsa/_version.py +520 -0
  488. ccxt/static_dependencies/ecdsa/curves.py +56 -0
  489. ccxt/static_dependencies/ecdsa/der.py +221 -0
  490. ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
  491. ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
  492. ccxt/static_dependencies/ecdsa/keys.py +332 -0
  493. ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
  494. ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
  495. ccxt/static_dependencies/ecdsa/util.py +266 -0
  496. ccxt/static_dependencies/ethereum/__init__.py +7 -0
  497. ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
  498. ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
  499. ccxt/static_dependencies/ethereum/abi/base.py +152 -0
  500. ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
  501. ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
  502. ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
  503. ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
  504. ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
  505. ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
  506. ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
  507. ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
  508. ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
  509. ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
  510. ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
  511. ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
  512. ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
  513. ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
  514. ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
  515. ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
  516. ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
  517. ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
  518. ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
  519. ccxt/static_dependencies/ethereum/account/messages.py +263 -0
  520. ccxt/static_dependencies/ethereum/account/py.typed +0 -0
  521. ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
  522. ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
  523. ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
  524. ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
  525. ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
  526. ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
  527. ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
  528. ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
  529. ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
  530. ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
  531. ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
  532. ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
  533. ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
  534. ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
  535. ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
  536. ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
  537. ccxt/static_dependencies/ethereum/utils/address.py +171 -0
  538. ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
  539. ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
  540. ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
  541. ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
  542. ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
  543. ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
  544. ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
  545. ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
  546. ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
  547. ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
  548. ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
  549. ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
  550. ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
  551. ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
  552. ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
  553. ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
  554. ccxt/static_dependencies/ethereum/utils/types.py +54 -0
  555. ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
  556. ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
  557. ccxt/static_dependencies/ethereum/utils/units.py +31 -0
  558. ccxt/static_dependencies/keccak/__init__.py +3 -0
  559. ccxt/static_dependencies/keccak/keccak.py +197 -0
  560. ccxt/static_dependencies/lark/__init__.py +38 -0
  561. ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
  562. ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
  563. ccxt/static_dependencies/lark/ast_utils.py +59 -0
  564. ccxt/static_dependencies/lark/common.py +86 -0
  565. ccxt/static_dependencies/lark/exceptions.py +292 -0
  566. ccxt/static_dependencies/lark/grammar.py +130 -0
  567. ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
  568. ccxt/static_dependencies/lark/indenter.py +143 -0
  569. ccxt/static_dependencies/lark/lark.py +658 -0
  570. ccxt/static_dependencies/lark/lexer.py +678 -0
  571. ccxt/static_dependencies/lark/load_grammar.py +1428 -0
  572. ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
  573. ccxt/static_dependencies/lark/parser_frontends.py +257 -0
  574. ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
  575. ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
  576. ccxt/static_dependencies/lark/parsers/earley.py +314 -0
  577. ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
  578. ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
  579. ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
  580. ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
  581. ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
  582. ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
  583. ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
  584. ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
  585. ccxt/static_dependencies/lark/reconstruct.py +107 -0
  586. ccxt/static_dependencies/lark/tools/__init__.py +70 -0
  587. ccxt/static_dependencies/lark/tools/nearley.py +202 -0
  588. ccxt/static_dependencies/lark/tools/serialize.py +32 -0
  589. ccxt/static_dependencies/lark/tools/standalone.py +196 -0
  590. ccxt/static_dependencies/lark/tree.py +267 -0
  591. ccxt/static_dependencies/lark/tree_matcher.py +186 -0
  592. ccxt/static_dependencies/lark/tree_templates.py +180 -0
  593. ccxt/static_dependencies/lark/utils.py +343 -0
  594. ccxt/static_dependencies/lark/visitors.py +596 -0
  595. ccxt/static_dependencies/marshmallow/__init__.py +81 -0
  596. ccxt/static_dependencies/marshmallow/base.py +65 -0
  597. ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
  598. ccxt/static_dependencies/marshmallow/decorators.py +231 -0
  599. ccxt/static_dependencies/marshmallow/error_store.py +60 -0
  600. ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
  601. ccxt/static_dependencies/marshmallow/fields.py +2114 -0
  602. ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
  603. ccxt/static_dependencies/marshmallow/schema.py +1228 -0
  604. ccxt/static_dependencies/marshmallow/types.py +12 -0
  605. ccxt/static_dependencies/marshmallow/utils.py +378 -0
  606. ccxt/static_dependencies/marshmallow/validate.py +678 -0
  607. ccxt/static_dependencies/marshmallow/warnings.py +2 -0
  608. ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
  609. ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
  610. ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
  611. ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
  612. ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
  613. ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
  614. ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
  615. ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
  616. ccxt/static_dependencies/msgpack/__init__.py +55 -0
  617. ccxt/static_dependencies/msgpack/exceptions.py +48 -0
  618. ccxt/static_dependencies/msgpack/ext.py +168 -0
  619. ccxt/static_dependencies/msgpack/fallback.py +951 -0
  620. ccxt/static_dependencies/parsimonious/__init__.py +10 -0
  621. ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
  622. ccxt/static_dependencies/parsimonious/expressions.py +479 -0
  623. ccxt/static_dependencies/parsimonious/grammar.py +487 -0
  624. ccxt/static_dependencies/parsimonious/nodes.py +325 -0
  625. ccxt/static_dependencies/parsimonious/utils.py +40 -0
  626. ccxt/static_dependencies/starknet/__init__.py +0 -0
  627. ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
  628. ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
  629. ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
  630. ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
  631. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
  632. ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
  633. ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
  634. ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
  635. ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
  636. ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
  637. ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
  638. ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
  639. ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
  640. ccxt/static_dependencies/starknet/common.py +15 -0
  641. ccxt/static_dependencies/starknet/constants.py +39 -0
  642. ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
  643. ccxt/static_dependencies/starknet/hash/address.py +79 -0
  644. ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
  645. ccxt/static_dependencies/starknet/hash/selector.py +16 -0
  646. ccxt/static_dependencies/starknet/hash/storage.py +12 -0
  647. ccxt/static_dependencies/starknet/hash/utils.py +78 -0
  648. ccxt/static_dependencies/starknet/models/__init__.py +0 -0
  649. ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
  650. ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
  651. ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
  652. ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
  653. ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
  654. ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
  655. ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
  656. ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
  657. ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
  658. ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
  659. ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
  660. ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
  661. ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
  662. ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
  663. ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
  664. ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
  665. ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
  666. ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
  667. ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
  668. ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
  669. ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
  670. ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
  671. ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
  672. ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
  673. ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
  674. ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
  675. ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
  676. ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
  677. ccxt/static_dependencies/starknet/utils/schema.py +13 -0
  678. ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
  679. ccxt/static_dependencies/starkware/__init__.py +0 -0
  680. ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
  681. ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
  682. ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
  683. ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
  684. ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
  685. ccxt/static_dependencies/sympy/__init__.py +0 -0
  686. ccxt/static_dependencies/sympy/core/__init__.py +0 -0
  687. ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
  688. ccxt/static_dependencies/sympy/external/__init__.py +0 -0
  689. ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
  690. ccxt/static_dependencies/sympy/external/importtools.py +187 -0
  691. ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
  692. ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
  693. ccxt/static_dependencies/toolz/__init__.py +26 -0
  694. ccxt/static_dependencies/toolz/_signatures.py +784 -0
  695. ccxt/static_dependencies/toolz/_version.py +520 -0
  696. ccxt/static_dependencies/toolz/compatibility.py +30 -0
  697. ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
  698. ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
  699. ccxt/static_dependencies/toolz/curried/operator.py +22 -0
  700. ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
  701. ccxt/static_dependencies/toolz/functoolz.py +1049 -0
  702. ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
  703. ccxt/static_dependencies/toolz/recipes.py +46 -0
  704. ccxt/static_dependencies/toolz/utils.py +9 -0
  705. ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
  706. ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
  707. ccxt/tabdeal.py +364 -0
  708. ccxt/test/__init__.py +3 -0
  709. ccxt/test/base/__init__.py +29 -0
  710. ccxt/test/base/test_account.py +26 -0
  711. ccxt/test/base/test_balance.py +56 -0
  712. ccxt/test/base/test_borrow_interest.py +35 -0
  713. ccxt/test/base/test_borrow_rate.py +32 -0
  714. ccxt/test/base/test_calculate_fee.py +51 -0
  715. ccxt/test/base/test_crypto.py +127 -0
  716. ccxt/test/base/test_currency.py +76 -0
  717. ccxt/test/base/test_datetime.py +109 -0
  718. ccxt/test/base/test_decimal_to_precision.py +392 -0
  719. ccxt/test/base/test_deep_extend.py +68 -0
  720. ccxt/test/base/test_deposit_withdrawal.py +50 -0
  721. ccxt/test/base/test_exchange_datetime_functions.py +76 -0
  722. ccxt/test/base/test_funding_rate_history.py +29 -0
  723. ccxt/test/base/test_last_price.py +31 -0
  724. ccxt/test/base/test_ledger_entry.py +45 -0
  725. ccxt/test/base/test_ledger_item.py +48 -0
  726. ccxt/test/base/test_leverage_tier.py +33 -0
  727. ccxt/test/base/test_liquidation.py +50 -0
  728. ccxt/test/base/test_margin_mode.py +24 -0
  729. ccxt/test/base/test_margin_modification.py +35 -0
  730. ccxt/test/base/test_market.py +193 -0
  731. ccxt/test/base/test_number.py +411 -0
  732. ccxt/test/base/test_ohlcv.py +33 -0
  733. ccxt/test/base/test_open_interest.py +32 -0
  734. ccxt/test/base/test_order.py +64 -0
  735. ccxt/test/base/test_order_book.py +69 -0
  736. ccxt/test/base/test_position.py +60 -0
  737. ccxt/test/base/test_shared_methods.py +353 -0
  738. ccxt/test/base/test_status.py +24 -0
  739. ccxt/test/base/test_throttle.py +126 -0
  740. ccxt/test/base/test_ticker.py +92 -0
  741. ccxt/test/base/test_trade.py +47 -0
  742. ccxt/test/base/test_trading_fee.py +26 -0
  743. ccxt/test/base/test_transaction.py +39 -0
  744. ccxt/test/test_async.py +1649 -0
  745. ccxt/test/test_sync.py +1648 -0
  746. ccxt/test/tests_async.py +1558 -0
  747. ccxt/test/tests_helpers.py +287 -0
  748. ccxt/test/tests_init.py +39 -0
  749. ccxt/test/tests_sync.py +1555 -0
  750. ccxt/tetherland.py +349 -0
  751. ccxt/timex.py +1593 -0
  752. ccxt/tokocrypto.py +2405 -0
  753. ccxt/tradeogre.py +608 -0
  754. ccxt/twox.py +326 -0
  755. ccxt/ubitex.py +409 -0
  756. ccxt/upbit.py +1833 -0
  757. ccxt/vertex.py +2922 -0
  758. ccxt/wallex.py +445 -0
  759. ccxt/wavesexchange.py +2472 -0
  760. ccxt/wazirx.py +1224 -0
  761. ccxt/whitebit.py +2469 -0
  762. ccxt/woo.py +3114 -0
  763. ccxt/woofipro.py +2533 -0
  764. ccxt/xt.py +4453 -0
  765. ccxt/yobit.py +1283 -0
  766. ccxt/zaif.py +725 -0
  767. ccxt/zonda.py +1828 -0
  768. ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
  769. ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
  770. ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
  771. ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
  772. ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,4415 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
4
+ # https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
5
+
6
+ from ccxt.async_support.base.exchange import Exchange
7
+ from ccxt.abstract.bitmart import ImplicitAPI
8
+ import hashlib
9
+ from ccxt.base.types import Balances, Currencies, Currency, Int, IsolatedBorrowRate, IsolatedBorrowRates, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, Transaction, TransferEntry, TransferEntries
10
+ from typing import List
11
+ from ccxt.base.errors import ExchangeError
12
+ from ccxt.base.errors import AuthenticationError
13
+ from ccxt.base.errors import PermissionDenied
14
+ from ccxt.base.errors import AccountSuspended
15
+ from ccxt.base.errors import ArgumentsRequired
16
+ from ccxt.base.errors import BadRequest
17
+ from ccxt.base.errors import BadSymbol
18
+ from ccxt.base.errors import InsufficientFunds
19
+ from ccxt.base.errors import InvalidAddress
20
+ from ccxt.base.errors import InvalidOrder
21
+ from ccxt.base.errors import OrderNotFound
22
+ from ccxt.base.errors import NotSupported
23
+ from ccxt.base.errors import NetworkError
24
+ from ccxt.base.errors import RateLimitExceeded
25
+ from ccxt.base.errors import ExchangeNotAvailable
26
+ from ccxt.base.errors import OnMaintenance
27
+ from ccxt.base.errors import InvalidNonce
28
+ from ccxt.base.decimal_to_precision import TRUNCATE
29
+ from ccxt.base.decimal_to_precision import TICK_SIZE
30
+ from ccxt.base.precise import Precise
31
+
32
+
33
+ class bitmart(Exchange, ImplicitAPI):
34
+
35
+ def describe(self):
36
+ return self.deep_extend(super(bitmart, self).describe(), {
37
+ 'id': 'bitmart',
38
+ 'name': 'BitMart',
39
+ 'countries': ['US', 'CN', 'HK', 'KR'],
40
+ # 150 per 5 seconds = 30 per second
41
+ # rateLimit = 1000ms / 30 ~= 33.334
42
+ 'rateLimit': 33.34,
43
+ 'version': 'v2',
44
+ 'certified': True,
45
+ 'pro': True,
46
+ 'has': {
47
+ 'CORS': None,
48
+ 'spot': True,
49
+ 'margin': True,
50
+ 'swap': True,
51
+ 'future': False,
52
+ 'option': False,
53
+ 'borrowCrossMargin': False,
54
+ 'borrowIsolatedMargin': True,
55
+ 'cancelAllOrders': True,
56
+ 'cancelOrder': True,
57
+ 'cancelOrders': True,
58
+ 'createMarketBuyOrderWithCost': True,
59
+ 'createMarketOrderWithCost': False,
60
+ 'createMarketSellOrderWithCost': False,
61
+ 'createOrder': True,
62
+ 'createOrders': True,
63
+ 'createPostOnlyOrder': True,
64
+ 'createStopLimitOrder': False,
65
+ 'createStopMarketOrder': False,
66
+ 'createStopOrder': False,
67
+ 'createTrailingPercentOrder': True,
68
+ 'fetchBalance': True,
69
+ 'fetchBorrowInterest': True,
70
+ 'fetchBorrowRateHistories': False,
71
+ 'fetchBorrowRateHistory': False,
72
+ 'fetchCanceledOrders': True,
73
+ 'fetchClosedOrders': True,
74
+ 'fetchCrossBorrowRate': False,
75
+ 'fetchCrossBorrowRates': False,
76
+ 'fetchCurrencies': True,
77
+ 'fetchDeposit': True,
78
+ 'fetchDepositAddress': True,
79
+ 'fetchDepositAddresses': False,
80
+ 'fetchDepositAddressesByNetwork': False,
81
+ 'fetchDeposits': True,
82
+ 'fetchDepositWithdrawFee': True,
83
+ 'fetchDepositWithdrawFees': False,
84
+ 'fetchFundingHistory': None,
85
+ 'fetchFundingRate': True,
86
+ 'fetchFundingRateHistory': False,
87
+ 'fetchFundingRates': False,
88
+ 'fetchIsolatedBorrowRate': True,
89
+ 'fetchIsolatedBorrowRates': True,
90
+ 'fetchLiquidations': False,
91
+ 'fetchMarginMode': False,
92
+ 'fetchMarkets': True,
93
+ 'fetchMyLiquidations': True,
94
+ 'fetchMyTrades': True,
95
+ 'fetchOHLCV': True,
96
+ 'fetchOpenInterest': True,
97
+ 'fetchOpenInterestHistory': False,
98
+ 'fetchOpenOrders': True,
99
+ 'fetchOrder': True,
100
+ 'fetchOrderBook': True,
101
+ 'fetchOrders': False,
102
+ 'fetchOrderTrades': True,
103
+ 'fetchPosition': True,
104
+ 'fetchPositionMode': False,
105
+ 'fetchPositions': True,
106
+ 'fetchStatus': True,
107
+ 'fetchTicker': True,
108
+ 'fetchTickers': True,
109
+ 'fetchTime': True,
110
+ 'fetchTrades': True,
111
+ 'fetchTradingFee': True,
112
+ 'fetchTradingFees': False,
113
+ 'fetchTransactionFee': True,
114
+ 'fetchTransactionFees': False,
115
+ 'fetchTransfer': False,
116
+ 'fetchTransfers': True,
117
+ 'fetchWithdrawAddressesByNetwork': False,
118
+ 'fetchWithdrawal': True,
119
+ 'fetchWithdrawals': True,
120
+ 'reduceMargin': False,
121
+ 'repayCrossMargin': False,
122
+ 'repayIsolatedMargin': True,
123
+ 'setLeverage': True,
124
+ 'setMarginMode': False,
125
+ 'transfer': True,
126
+ 'withdraw': True,
127
+ },
128
+ 'hostname': 'bitmart.com', # bitmart.info, bitmart.news for Hong Kong users
129
+ 'urls': {
130
+ 'logo': 'https://user-images.githubusercontent.com/1294454/129991357-8f47464b-d0f4-41d6-8a82-34122f0d1398.jpg',
131
+ 'api': {
132
+ 'rest': 'https://api-cloud.{hostname}', # bitmart.info for Hong Kong users
133
+ },
134
+ 'www': 'https://www.bitmart.com/',
135
+ 'doc': 'https://developer-pro.bitmart.com/',
136
+ 'referral': {
137
+ 'url': 'http://www.bitmart.com/?r=rQCFLh',
138
+ 'discount': 0.3,
139
+ },
140
+ 'fees': 'https://www.bitmart.com/fee/en',
141
+ },
142
+ 'requiredCredentials': {
143
+ 'apiKey': True,
144
+ 'secret': True,
145
+ 'uid': True,
146
+ },
147
+ 'api': {
148
+ 'public': {
149
+ 'get': {
150
+ 'system/time': 3, # 10 times/sec => 30/10 = 3
151
+ 'system/service': 3,
152
+ # spot markets
153
+ 'spot/v1/currencies': 7.5,
154
+ 'spot/v1/symbols': 7.5,
155
+ 'spot/v1/symbols/details': 5,
156
+ 'spot/quotation/v3/tickers': 6, # 10 times/2 sec = 5/s => 30/5 = 6
157
+ 'spot/quotation/v3/ticker': 4, # 15 times/2 sec = 7.5/s => 30/7.5 = 4
158
+ 'spot/quotation/v3/lite-klines': 5, # should be 4 but errors
159
+ 'spot/quotation/v3/klines': 7, # should be 6 but errors
160
+ 'spot/quotation/v3/books': 4, # 15 times/2 sec = 7.5/s => 30/7.5 = 4
161
+ 'spot/quotation/v3/trades': 4, # 15 times/2 sec = 7.5/s => 30/7.5 = 4
162
+ 'spot/v1/ticker': 5,
163
+ 'spot/v2/ticker': 30,
164
+ 'spot/v1/ticker_detail': 5, # 12 times/2 sec = 6/s => 30/6 = 5
165
+ 'spot/v1/steps': 30,
166
+ 'spot/v1/symbols/kline': 6, # should be 5 but errors
167
+ 'spot/v1/symbols/book': 5,
168
+ 'spot/v1/symbols/trades': 5,
169
+ # contract markets
170
+ 'contract/v1/tickers': 15,
171
+ 'contract/public/details': 5,
172
+ 'contract/public/depth': 5,
173
+ 'contract/public/open-interest': 30,
174
+ 'contract/public/funding-rate': 30,
175
+ 'contract/public/kline': 6, # should be 5 but errors
176
+ 'account/v1/currencies': 30,
177
+ },
178
+ },
179
+ 'private': {
180
+ 'get': {
181
+ # sub-account
182
+ 'account/sub-account/v1/transfer-list': 7.5,
183
+ 'account/sub-account/v1/transfer-history': 7.5,
184
+ 'account/sub-account/main/v1/wallet': 5,
185
+ 'account/sub-account/main/v1/subaccount-list': 7.5,
186
+ 'account/contract/sub-account/main/v1/wallet': 5,
187
+ 'account/contract/sub-account/main/v1/transfer-list': 7.5,
188
+ 'account/contract/sub-account/v1/transfer-history': 7.5,
189
+ # account
190
+ 'account/v1/wallet': 5,
191
+ 'account/v1/currencies': 30,
192
+ 'spot/v1/wallet': 5,
193
+ 'account/v1/deposit/address': 30,
194
+ 'account/v1/withdraw/charge': 32, # should be 30 but errors
195
+ 'account/v2/deposit-withdraw/history': 7.5,
196
+ 'account/v1/deposit-withdraw/detail': 7.5,
197
+ # order
198
+ 'spot/v1/order_detail': 1,
199
+ 'spot/v2/orders': 5,
200
+ 'spot/v1/trades': 5,
201
+ # newer order endpoint
202
+ 'spot/v2/trades': 4,
203
+ 'spot/v3/orders': 5,
204
+ 'spot/v2/order_detail': 1,
205
+ # margin
206
+ 'spot/v1/margin/isolated/borrow_record': 1,
207
+ 'spot/v1/margin/isolated/repay_record': 1,
208
+ 'spot/v1/margin/isolated/pairs': 30,
209
+ 'spot/v1/margin/isolated/account': 5,
210
+ 'spot/v1/trade_fee': 30,
211
+ 'spot/v1/user_fee': 30,
212
+ # broker
213
+ 'spot/v1/broker/rebate': 1,
214
+ # contract
215
+ 'contract/private/assets-detail': 5,
216
+ 'contract/private/order': 1.2,
217
+ 'contract/private/order-history': 10,
218
+ 'contract/private/position': 10,
219
+ 'contract/private/get-open-orders': 1.2,
220
+ 'contract/private/current-plan-order': 1.2,
221
+ 'contract/private/trades': 10,
222
+ },
223
+ 'post': {
224
+ # sub-account endpoints
225
+ 'account/sub-account/main/v1/sub-to-main': 30,
226
+ 'account/sub-account/sub/v1/sub-to-main': 30,
227
+ 'account/sub-account/main/v1/main-to-sub': 30,
228
+ 'account/sub-account/sub/v1/sub-to-sub': 30,
229
+ 'account/sub-account/main/v1/sub-to-sub': 30,
230
+ 'account/contract/sub-account/main/v1/sub-to-main': 7.5,
231
+ 'account/contract/sub-account/main/v1/main-to-sub': 7.5,
232
+ 'account/contract/sub-account/sub/v1/sub-to-main': 7.5,
233
+ # account
234
+ 'account/v1/withdraw/apply': 7.5,
235
+ # transaction and trading
236
+ 'spot/v1/submit_order': 1,
237
+ 'spot/v1/batch_orders': 1,
238
+ 'spot/v2/cancel_order': 1,
239
+ 'spot/v1/cancel_orders': 15,
240
+ 'spot/v4/query/order': 1, # 60 times/2 sec = 30/s => 30/30 = 1
241
+ 'spot/v4/query/client-order': 1, # 60 times/2 sec = 30/s => 30/30 = 1
242
+ 'spot/v4/query/open-orders': 5, # 12 times/2 sec = 6/s => 30/6 = 5
243
+ 'spot/v4/query/history-orders': 5, # 12 times/2 sec = 6/s => 30/6 = 5
244
+ 'spot/v4/query/trades': 5, # 12 times/2 sec = 6/s => 30/6 = 5
245
+ 'spot/v4/query/order-trades': 5, # 12 times/2 sec = 6/s => 30/6 = 5
246
+ 'spot/v4/cancel_orders': 3,
247
+ 'spot/v4/batch_orders': 3,
248
+ # newer endpoint
249
+ 'spot/v3/cancel_order': 1,
250
+ 'spot/v2/batch_orders': 1,
251
+ 'spot/v2/submit_order': 1,
252
+ # margin
253
+ 'spot/v1/margin/submit_order': 1,
254
+ 'spot/v1/margin/isolated/borrow': 30,
255
+ 'spot/v1/margin/isolated/repay': 30,
256
+ 'spot/v1/margin/isolated/transfer': 30,
257
+ # contract
258
+ 'account/v1/transfer-contract-list': 60,
259
+ 'account/v1/transfer-contract': 60,
260
+ 'contract/private/submit-order': 2.5,
261
+ 'contract/private/cancel-order': 1.5,
262
+ 'contract/private/cancel-orders': 30,
263
+ 'contract/private/submit-plan-order': 2.5,
264
+ 'contract/private/cancel-plan-order': 1.5,
265
+ 'contract/private/submit-leverage': 2.5,
266
+ },
267
+ },
268
+ },
269
+ 'timeframes': {
270
+ '1m': 1,
271
+ '3m': 3,
272
+ '5m': 5,
273
+ '15m': 15,
274
+ '30m': 30,
275
+ '45m': 45,
276
+ '1h': 60,
277
+ '2h': 120,
278
+ '3h': 180,
279
+ '4h': 240,
280
+ '1d': 1440,
281
+ '1w': 10080,
282
+ '1M': 43200,
283
+ },
284
+ 'fees': {
285
+ 'trading': {
286
+ 'tierBased': True,
287
+ 'percentage': True,
288
+ 'taker': self.parse_number('0.0040'),
289
+ 'maker': self.parse_number('0.0035'),
290
+ 'tiers': {
291
+ 'taker': [
292
+ [self.parse_number('0'), self.parse_number('0.0020')],
293
+ [self.parse_number('10'), self.parse_number('0.18')],
294
+ [self.parse_number('50'), self.parse_number('0.0016')],
295
+ [self.parse_number('250'), self.parse_number('0.0014')],
296
+ [self.parse_number('1000'), self.parse_number('0.0012')],
297
+ [self.parse_number('5000'), self.parse_number('0.0010')],
298
+ [self.parse_number('25000'), self.parse_number('0.0008')],
299
+ [self.parse_number('50000'), self.parse_number('0.0006')],
300
+ ],
301
+ 'maker': [
302
+ [self.parse_number('0'), self.parse_number('0.001')],
303
+ [self.parse_number('10'), self.parse_number('0.0009')],
304
+ [self.parse_number('50'), self.parse_number('0.0008')],
305
+ [self.parse_number('250'), self.parse_number('0.0007')],
306
+ [self.parse_number('1000'), self.parse_number('0.0006')],
307
+ [self.parse_number('5000'), self.parse_number('0.0005')],
308
+ [self.parse_number('25000'), self.parse_number('0.0004')],
309
+ [self.parse_number('50000'), self.parse_number('0.0003')],
310
+ ],
311
+ },
312
+ },
313
+ },
314
+ 'precisionMode': TICK_SIZE,
315
+ 'exceptions': {
316
+ 'exact': {
317
+ # general errors
318
+ '30000': ExchangeError, # 404, Not found
319
+ '30001': AuthenticationError, # 401, Header X-BM-KEY is empty
320
+ '30002': AuthenticationError, # 401, Header X-BM-KEY not found
321
+ '30003': AccountSuspended, # 401, Header X-BM-KEY has frozen
322
+ '30004': AuthenticationError, # 401, Header X-BM-SIGN is empty
323
+ '30005': AuthenticationError, # 401, Header X-BM-SIGN is wrong
324
+ '30006': AuthenticationError, # 401, Header X-BM-TIMESTAMP is empty
325
+ '30007': AuthenticationError, # 401, Header X-BM-TIMESTAMP range. Within a minute
326
+ '30008': AuthenticationError, # 401, Header X-BM-TIMESTAMP invalid format
327
+ '30010': PermissionDenied, # 403, IP is forbidden. We recommend enabling IP whitelist for API trading. After that reauth your account
328
+ '30011': AuthenticationError, # 403, Header X-BM-KEY over expire time
329
+ '30012': AuthenticationError, # 403, Header X-BM-KEY is forbidden to request it
330
+ '30013': RateLimitExceeded, # 429, Request too many requests
331
+ '30014': ExchangeNotAvailable, # 503, Service unavailable
332
+ '30016': OnMaintenance, # 200, Service maintenance, the function is temporarily unavailable
333
+ '30017': RateLimitExceeded, # 418, Your account request is temporarily rejected due to violation of current limiting rules
334
+ '30018': BadRequest, # 503, Request Body requires JSON format
335
+ '30019': PermissionDenied, # 200, You do not have the permissions to perform self operation
336
+ # funding account & sub account errors
337
+ '60000': BadRequest, # 400, Invalid request(maybe the body is empty, or the int parameter passes string data)
338
+ '60001': BadRequest, # 400, Asset account type does not exist
339
+ '60002': BadRequest, # 400, currency does not exist
340
+ '60003': ExchangeError, # 400, Currency has been closed recharge channel, if there is any problem, please consult customer service
341
+ '60004': ExchangeError, # 400, Currency has been closed withdraw channel, if there is any problem, please consult customer service
342
+ '60005': ExchangeError, # 400, Minimum amount is %s
343
+ '60006': ExchangeError, # 400, Maximum withdraw precision is %d
344
+ '60007': InvalidAddress, # 400, Only withdrawals from added addresses are allowed
345
+ '60008': InsufficientFunds, # 400, Balance not enough
346
+ '60009': ExchangeError, # 400, Beyond the limit
347
+ '60010': ExchangeError, # 400, Withdraw id or deposit id not found
348
+ '60011': InvalidAddress, # 400, Address is not valid
349
+ '60012': ExchangeError, # 400, This action is not hasattr(self, supported) currency(If IOTA, HLX recharge and withdraw calls are prohibited)
350
+ '60020': PermissionDenied, # 403, Your account is not allowed to recharge
351
+ '60021': PermissionDenied, # 403, Your account is not allowed to withdraw
352
+ '60022': PermissionDenied, # 403, No withdrawals for 24 hours
353
+ '60026': PermissionDenied, # 403, Sub-account does not have permission to operate
354
+ '60027': PermissionDenied, # 403, Only supports sub-account calls
355
+ '60028': AccountSuspended, # 403, Account is disabled for security reasons, please contact customer service
356
+ '60029': AccountSuspended, # 403, The account is frozen by the master account, please contact the master account to unfreeze the account
357
+ '60030': BadRequest, # 405, Method Not Allowed
358
+ '60031': BadRequest, # 415, Unsupported Media Type
359
+ '60050': ExchangeError, # 500, User account not found
360
+ '60051': ExchangeError, # 500, Internal Server Error
361
+ '61001': InsufficientFunds, # {"message":"Balance not enough","code":61001,"trace":"b85ea1f8-b9af-4001-ac5f-9e061fe93d78","data":{}}
362
+ '61003': BadRequest, # 400, {"message":"sub-account not found","code":61003,"trace":"b35ec2fd-0bc9-4ef2-a3c0-6f78d4f335a4","data":{}}
363
+ '61004': BadRequest, # 400, Duplicate requests(such an existing requestNo)
364
+ '61005': BadRequest, # 403, Asset transfer between accounts is not available
365
+ '61006': NotSupported, # 403, The sub-account api only supports organization accounts
366
+ '61007': ExchangeError, # 403, Please complete your institution verification to enable withdrawal function.
367
+ '61008': ExchangeError, # 403, Suspend transfer out
368
+ # spot public errors
369
+ '70000': ExchangeError, # 200, no data
370
+ '70001': BadRequest, # 200, request param can not be null
371
+ '70002': BadSymbol, # 200, symbol is invalid
372
+ '70003': NetworkError, # {"code":70003,"trace":"81a9d57b63be4819b65d3065e6a4682b.105.17105295323593915","message":"net error, please try later","data":null}
373
+ '71001': BadRequest, # 200, after is invalid
374
+ '71002': BadRequest, # 200, before is invalid
375
+ '71003': BadRequest, # 200, request after or before is invalid
376
+ '71004': BadRequest, # 200, request kline count limit
377
+ '71005': BadRequest, # 200, request step error
378
+ # spot & margin errors
379
+ '50000': BadRequest, # 400, Bad Request
380
+ '50001': BadSymbol, # 400, Symbol not found
381
+ '50002': BadRequest, # 400, From Or To format error
382
+ '50003': BadRequest, # 400, Step format error
383
+ '50004': BadRequest, # 400, Kline size over 500
384
+ '50005': OrderNotFound, # 400, Order Id not found
385
+ '50006': InvalidOrder, # 400, Minimum size is %s
386
+ '50007': InvalidOrder, # 400, Maximum size is %s
387
+ '50008': InvalidOrder, # 400, Minimum price is %s
388
+ '50009': InvalidOrder, # 400, Minimum count*price is %s
389
+ '50010': InvalidOrder, # 400, RequestParam size is required
390
+ '50011': InvalidOrder, # 400, RequestParam price is required
391
+ '50012': InvalidOrder, # 400, RequestParam notional is required
392
+ '50013': InvalidOrder, # 400, Maximum limit*offset is %d
393
+ '50014': BadRequest, # 400, RequestParam limit is required
394
+ '50015': BadRequest, # 400, Minimum limit is 1
395
+ '50016': BadRequest, # 400, Maximum limit is %d
396
+ '50017': BadRequest, # 400, RequestParam offset is required
397
+ '50018': BadRequest, # 400, Minimum offset is 1
398
+ '50019': ExchangeError, # 400, Invalid status. validate status is [1=Failed, 2=Success, 3=Frozen Failed, 4=Frozen Success, 5=Partially Filled, 6=Fully Fulled, 7=Canceling, 8=Canceled] '50020': InsufficientFunds, # 400, Balance not enough
399
+ '50020': InsufficientFunds, # 400, Balance not enough
400
+ '50021': BadRequest, # 400, Invalid %s
401
+ '50022': ExchangeNotAvailable, # 400, Service unavailable
402
+ '50023': BadSymbol, # 400, This Symbol can't place order by api
403
+ '50024': BadRequest, # 400, Order book size over 200
404
+ '50025': BadRequest, # 400, Maximum price is %s
405
+ '50026': BadRequest, # 400, The buy order price cannot be higher than the open price
406
+ '50027': BadRequest, # 400, The sell order price cannot be lower than the open price
407
+ '50028': BadRequest, # 400, Missing parameters
408
+ '50029': InvalidOrder, # 400, {"message":"param not match : size * price >=1000","code":50029,"trace":"f931f030-b692-401b-a0c5-65edbeadc598","data":{}}
409
+ '50030': OrderNotFound, # 400, {"message":"Order is already canceled","code":50030,"trace":"8d6f64ee-ad26-45a4-9efd-1080f9fca1fa","data":{}}
410
+ '50031': OrderNotFound, # 400, Order is already completed
411
+ '50032': OrderNotFound, # 400, {"message":"Order does not exist","code":50032,"trace":"8d6b482d-4bf2-4e6c-aab2-9dcd22bf2481","data":{}}
412
+ '50033': InvalidOrder, # 400, The order quantity should be greater than 0 and less than or equal to 10
413
+ # below Error codes used interchangeably for both failed postOnly and IOC orders depending on market price and order side
414
+ '50034': InvalidOrder, # 400, {"message":"The price is high and there is no matching depth","code":50034,"trace":"ebfae59a-ba69-4735-86b2-0ed7b9ca14ea","data":{}}
415
+ '50035': InvalidOrder, # 400, {"message":"The price is low and there is no matching depth","code":50035,"trace":"677f01c7-8b88-4346-b097-b4226c75c90e","data":{}}
416
+ '50036': ExchangeError, # 400, Cancel failed, order is not revocable status
417
+ '50037': BadRequest, # 400, The maximum length of clientOrderId cannot exceed 32
418
+ '50038': BadRequest, # 400, ClientOrderId only allows a combination of numbers and letters
419
+ '50039': BadRequest, # 400, Order_id and clientOrderId cannot be empty at the same time
420
+ '50040': BadSymbol, # 400, Symbol Not Available
421
+ '50041': ExchangeError, # 400, Out of query time range
422
+ '50042': BadRequest, # 400, clientOrderId is duplicate
423
+ '51000': BadSymbol, # 400, Currency not found
424
+ '51001': ExchangeError, # 400, Margin Account not Opened
425
+ '51002': ExchangeError, # 400, Margin Account Not Available
426
+ '51003': ExchangeError, # 400, Account Limit
427
+ '51004': InsufficientFunds, # 400, {"message":"Exceed the maximum number of borrows available.","code":51004,"trace":"4030b753-9beb-44e6-8352-1633c5edcd47","data":{}}
428
+ '51005': InvalidOrder, # 400, Less than the minimum borrowable amount
429
+ '51006': InvalidOrder, # 400, Exceeds the amount to be repaid
430
+ '51007': BadRequest, # 400, order_mode not found
431
+ '51008': ExchangeError, # 400, Operation is limited, please try again later
432
+ '51009': InvalidOrder, # 400, Parameter mismatch: limit order/market order quantity should be greater than the minimum number of should buy/sell
433
+ '51010': InvalidOrder, # 400, Parameter mismatch: limit order price should be greater than the minimum buy price
434
+ '51011': InvalidOrder, # 400, {"message":"param not match : size * price >=5","code":51011,"trace":"525e1d27bfd34d60b2d90ba13a7c0aa9.74.16696421352220797","data":{}}
435
+ '51012': InvalidOrder, # 400, Parameter mismatch: limit order price should be greater than the minimum buy price
436
+ '51013': InvalidOrder, # 400, Parameter mismatch: Limit order quantity * price should be greater than the minimum transaction amount
437
+ '51014': InvalidOrder, # 400, Participation mismatch: the number of market order buy orders should be greater than the minimum buyable amount
438
+ '51015': InvalidOrder, # 400, Parameter mismatch: the price of market order buy order placed is too small
439
+ '52000': BadRequest, # 400, Unsupported OrderMode Type
440
+ '52001': BadRequest, # 400, Unsupported Trade Type
441
+ '52002': BadRequest, # 400, Unsupported Side Type
442
+ '52003': BadRequest, # 400, Unsupported Query State Type
443
+ '52004': BadRequest, # 400, End time must be greater than or equal to Start time
444
+ '53000': AccountSuspended, # 403, Your account is frozen due to security policies. Please contact customer service
445
+ '53001': AccountSuspended, # 403, {"message":"Your kyc country is restricted. Please contact customer service.","code":53001,"trace":"8b445940-c123-4de9-86d7-73c5be2e7a24","data":{}}
446
+ '53002': PermissionDenied, # 403, Your account has not yet completed the kyc advanced certification, please complete first
447
+ '53003': PermissionDenied, # 403 No permission, please contact the main account
448
+ '53005': PermissionDenied, # 403 Don't have permission to access the interface
449
+ '53006': PermissionDenied, # 403 Please complete your personal verification(Starter)
450
+ '53007': PermissionDenied, # 403 Please complete your personal verification(Advanced)
451
+ '53008': PermissionDenied, # 403 Services is not available in your countries and areas
452
+ '53009': PermissionDenied, # 403 Your account has not yet completed the qr code certification, please complete first
453
+ '53010': PermissionDenied, # 403 This account is restricted from borrowing
454
+ '57001': BadRequest, # 405, Method Not Allowed
455
+ '58001': BadRequest, # 415, Unsupported Media Type
456
+ '59001': ExchangeError, # 500, User account not found
457
+ '59002': ExchangeError, # 500, Internal Server Error
458
+ '59003': ExchangeError, # 500, Spot wallet call fail
459
+ '59004': ExchangeError, # 500, Margin wallet service call exception
460
+ '59005': PermissionDenied, # 500, Margin wallet service restricted
461
+ '59006': ExchangeError, # 500, Transfer fail
462
+ '59007': ExchangeError, # 500, Get symbol risk data fail
463
+ '59008': ExchangeError, # 500, Trading order failure
464
+ '59009': ExchangeError, # 500, Loan success,but trading order failure
465
+ '59010': InsufficientFunds, # 500, Insufficient loan amount.
466
+ '59011': ExchangeError, # 500, The Get Wallet Balance service call fail, please try again later
467
+ # contract errors
468
+ '40001': ExchangeError, # 400, Cloud account not found
469
+ '40002': ExchangeError, # 400, out_trade_no not found
470
+ '40003': ExchangeError, # 400, out_trade_no already existed
471
+ '40004': ExchangeError, # 400, Cloud account count limit
472
+ '40005': ExchangeError, # 400, Transfer vol precision error
473
+ '40006': PermissionDenied, # 400, Invalid ip error
474
+ '40007': BadRequest, # 400, Parse parameter error
475
+ '40008': InvalidNonce, # 400, Check nonce error
476
+ '40009': BadRequest, # 400, Check ver error
477
+ '40010': BadRequest, # 400, Not found func error
478
+ '40011': BadRequest, # 400, Invalid request
479
+ '40012': ExchangeError, # 500, System error
480
+ '40013': ExchangeError, # 400, Access too often" CLIENT_TIME_INVALID, "Please check your system time.
481
+ '40014': BadSymbol, # 400, This contract is offline
482
+ '40015': BadSymbol, # 400, This contract's exchange has been paused
483
+ '40016': InvalidOrder, # 400, This order would trigger user position liquidate
484
+ '40017': InvalidOrder, # 400, It is not possible to open and close simultaneously in the same position
485
+ '40018': InvalidOrder, # 400, Your position is closed
486
+ '40019': ExchangeError, # 400, Your position is in liquidation delegating
487
+ '40020': InvalidOrder, # 400, Your position volume is not enough
488
+ '40021': ExchangeError, # 400, The position is not exsit
489
+ '40022': ExchangeError, # 400, The position is not isolated
490
+ '40023': ExchangeError, # 400, The position would liquidate when sub margin
491
+ '40024': ExchangeError, # 400, The position would be warnning of liquidation when sub margin
492
+ '40025': ExchangeError, # 400, The position’s margin shouldn’t be lower than the base limit
493
+ '40026': ExchangeError, # 400, You cross margin position is in liquidation delegating
494
+ '40027': InsufficientFunds, # 400, You contract account available balance not enough
495
+ '40028': PermissionDenied, # 400, Your plan order's count is more than system maximum limit.
496
+ '40029': InvalidOrder, # 400, The order's leverage is too large.
497
+ '40030': InvalidOrder, # 400, The order's leverage is too small.
498
+ '40031': InvalidOrder, # 400, The deviation between current price and trigger price is too large.
499
+ '40032': InvalidOrder, # 400, The plan order's life cycle is too long.
500
+ '40033': InvalidOrder, # 400, The plan order's life cycle is too short.
501
+ '40034': BadSymbol, # 400, This contract is not found
502
+ '40035': OrderNotFound, # 400, The order is not exist
503
+ '40036': InvalidOrder, # 400, The order status is invalid
504
+ '40037': OrderNotFound, # 400, The order id is not exist
505
+ '40038': BadRequest, # 400, The k-line step is invalid
506
+ '40039': BadRequest, # 400, The timestamp is invalid
507
+ '40040': InvalidOrder, # 400, The order leverage is invalid
508
+ '40041': InvalidOrder, # 400, The order side is invalid
509
+ '40042': InvalidOrder, # 400, The order type is invalid
510
+ '40043': InvalidOrder, # 400, The order precision is invalid
511
+ '40044': InvalidOrder, # 400, The order range is invalid
512
+ '40045': InvalidOrder, # 400, The order open type is invalid
513
+ '40046': PermissionDenied, # 403, The account is not opened futures
514
+ '40047': PermissionDenied, # 403, Services is not available in you countries and areas
515
+ '40048': BadRequest, # 403, ClientOrderId only allows a combination of numbers and letters
516
+ '40049': BadRequest, # 403, The maximum length of clientOrderId cannot exceed 32
517
+ '40050': InvalidOrder, # 403, Client OrderId duplicated with existing orders
518
+ },
519
+ 'broad': {},
520
+ },
521
+ 'commonCurrencies': {
522
+ '$GM': 'GOLDMINER',
523
+ '$HERO': 'Step Hero',
524
+ '$PAC': 'PAC',
525
+ 'BP': 'BEYOND',
526
+ 'GDT': 'Gorilla Diamond',
527
+ 'GLD': 'Goldario',
528
+ 'MVP': 'MVP Coin',
529
+ 'TRU': 'Truebit', # conflict with TrueFi
530
+ },
531
+ 'options': {
532
+ 'defaultNetwork': 'ERC20',
533
+ 'defaultNetworks': {
534
+ 'USDT': 'ERC20',
535
+ },
536
+ 'networks': {
537
+ 'ERC20': 'ERC20',
538
+ 'SOL': 'SOL',
539
+ 'BTC': 'BTC',
540
+ 'TRC20': 'TRC20',
541
+ # todo: should be TRX after unification
542
+ # 'TRC20': ['TRC20', 'trc20', 'TRON'], # todo: after unification i.e. TRON is returned from fetchDepositAddress
543
+ # 'ERC20': ['ERC20', 'ERC-20', 'ERC20 '], # todo: after unification
544
+ 'OMNI': 'OMNI',
545
+ 'XLM': 'XLM',
546
+ 'EOS': 'EOS',
547
+ 'NEO': 'NEO',
548
+ 'BTM': 'BTM',
549
+ 'BCH': 'BCH',
550
+ 'LTC': 'LTC',
551
+ 'BSV': 'BSV',
552
+ 'XRP': 'XRP',
553
+ # 'VECHAIN': ['VET', 'Vechain'], # todo: after unification
554
+ 'PLEX': 'PLEX',
555
+ 'XCH': 'XCH',
556
+ # 'AVALANCHE_C': ['AVAX', 'AVAX-C'], # todo: after unification
557
+ 'NEAR': 'NEAR',
558
+ 'FIO': 'FIO',
559
+ 'SCRT': 'SCRT',
560
+ 'IOTX': 'IOTX',
561
+ 'ALGO': 'ALGO',
562
+ 'ATOM': 'ATOM',
563
+ 'DOT': 'DOT',
564
+ 'ADA': 'ADA',
565
+ 'DOGE': 'DOGE',
566
+ 'XYM': 'XYM',
567
+ 'GLMR': 'GLMR',
568
+ 'MOVR': 'MOVR',
569
+ 'ZIL': 'ZIL',
570
+ 'INJ': 'INJ',
571
+ 'KSM': 'KSM',
572
+ 'ZEC': 'ZEC',
573
+ 'NAS': 'NAS',
574
+ # 'POLYGON': ['MATIC', 'Polygon', 'POLYGON'], # todo: after unification
575
+ 'HRC20': 'HECO',
576
+ 'XDC': 'XDC',
577
+ 'ONE': 'ONE',
578
+ 'LAT': 'LAT',
579
+ 'CSPR': 'Casper',
580
+ 'ICP': 'Computer',
581
+ 'XTZ': 'XTZ',
582
+ 'MINA': 'MINA',
583
+ # 'BEP20': ['BEP20', 'BSC_BNB', 'bep20'], # todo: after unification
584
+ 'THETA': 'THETA',
585
+ 'AKT': 'AKT',
586
+ 'AR': 'AR',
587
+ 'CELO': 'CELO',
588
+ 'FIL': 'FIL',
589
+ 'NULS': 'NULS',
590
+ 'ETC': 'ETC',
591
+ 'DASH': 'DASH',
592
+ 'DGB': 'DGB',
593
+ 'BEP2': 'BEP2',
594
+ 'GRIN': 'GRIN',
595
+ 'WAVES': 'WAVES',
596
+ 'ABBC': 'ABBC',
597
+ 'ACA': 'ACA',
598
+ 'QTUM': 'QTUM',
599
+ 'PAC': 'PAC',
600
+ # 'TERRACLASSIC': 'LUNC', # TBD
601
+ # 'TERRA': 'Terra', # TBD
602
+ # 'HEDERA': ['HBAR', 'Hedera', 'Hedera Mainnet'], # todo: after unification
603
+ 'TLOS': 'TLOS',
604
+ 'KARDIA': 'KardiaChain',
605
+ 'FUSE': 'FUSE',
606
+ 'TRC10': 'TRC10',
607
+ 'FIRO': 'FIRO',
608
+ 'FTM': 'Fantom',
609
+ # 'KLAYTN': ['klaytn', 'KLAY', 'Klaytn'], # todo: after unification
610
+ # 'ELROND': ['EGLD', 'Elrond eGold', 'MultiversX'], # todo: after unification
611
+ 'EVER': 'EVER',
612
+ 'KAVA': 'KAVA',
613
+ 'HYDRA': 'HYDRA',
614
+ 'PLCU': 'PLCU',
615
+ 'BRISE': 'BRISE',
616
+ # 'CRC20': ['CRO', 'CRO_Chain'], # todo: after unification
617
+ # 'CONFLUX': ['CFX eSpace', 'CFX'], # todo: after unification
618
+ 'OPTIMISM': 'OPTIMISM',
619
+ 'REEF': 'REEF',
620
+ 'SYS': 'SYS', # NEVM is different
621
+ 'VITE': 'VITE',
622
+ 'STX': 'STX',
623
+ 'SXP': 'SXP',
624
+ 'BITCI': 'BITCI',
625
+ # 'ARBITRUM': ['ARBI', 'Arbitrum'], # todo: after unification
626
+ 'XRD': 'XRD',
627
+ 'ASTR': 'ASTAR',
628
+ 'ZEN': 'HORIZEN',
629
+ 'LTO': 'LTO',
630
+ 'ETHW': 'ETHW',
631
+ 'ETHF': 'ETHF',
632
+ 'IOST': 'IOST',
633
+ # 'CHILIZ': ['CHZ', 'CHILIZ'], # todo: after unification
634
+ 'APT': 'APT',
635
+ # 'FLOW': ['FLOW', 'Flow'], # todo: after unification
636
+ 'ONT': 'ONT',
637
+ 'EVMOS': 'EVMOS',
638
+ 'XMR': 'XMR',
639
+ 'OASYS': 'OAS',
640
+ 'OSMO': 'OSMO',
641
+ 'OMAX': 'OMAX Chain',
642
+ 'DESO': 'DESO',
643
+ 'BFIC': 'BFIC',
644
+ 'OHO': 'OHO',
645
+ 'CS': 'CS',
646
+ 'CHEQ': 'CHEQ',
647
+ 'NODL': 'NODL',
648
+ 'NEM': 'XEM',
649
+ 'FRA': 'FRA',
650
+ 'ERGO': 'ERG',
651
+ # todo: below will be uncommented after unification
652
+ # 'BITCOINHD': 'BHD',
653
+ # 'CRUST': 'CRU',
654
+ # 'MINTME': 'MINTME',
655
+ # 'ZENITH': 'ZENITH',
656
+ # 'ZENIQ': 'ZENIQ', # "ZEN-20" is different
657
+ # 'BITCOINVAULT': 'BTCV',
658
+ # 'MOBILECOIN': 'MBX',
659
+ # 'PINETWORK': 'PI',
660
+ # 'PI': 'PI',
661
+ # 'REBUS': 'REBUS',
662
+ # 'XODEX': 'XODEX',
663
+ # 'ULTRONGLOW': 'UTG'
664
+ # 'QIBLOCKCHAIN': 'QIE',
665
+ # 'XIDEN': 'XDEN',
666
+ # 'PHAETON': 'PHAE',
667
+ # 'REDLIGHT': 'REDLC',
668
+ # 'VERITISE': 'VTS',
669
+ # 'VERIBLOCK': 'VBK',
670
+ # 'RAMESTTA': 'RAMA',
671
+ # 'BITICA': 'BDCC',
672
+ # 'CROWNSOVEREIGN': 'CSOV',
673
+ # 'DRAC': 'DRC20',
674
+ # 'QCHAIN': 'QDT',
675
+ # 'KINGARU': 'KRU',
676
+ # 'PROOFOFMEMES': 'POM',
677
+ # 'CUBE': 'CUBE',
678
+ # 'CADUCEUS': 'CMP',
679
+ # 'VEIL': 'VEIL',
680
+ # 'ENERGYWEB': 'EWT',
681
+ # 'CYPHERIUM': 'CPH',
682
+ # 'LBRY': 'LBC',
683
+ # 'ETHERCOIN': 'ETE',
684
+ # undetermined chains:
685
+ # LEX(for LexThum), TAYCAN(for TRICE), SFL(probably TAYCAN), OMNIA(for APEX), NAC(for NAC), KAG(Kinesis), CEM(crypto emergency), XVM(for Venidium), NEVM(for NEVM), IGT20(for IGNITE), FILM(FILMCredits), CC(CloudCoin), MERGE(MERGE), LTNM(Bitcoin latinum), PLUGCN( PlugChain), DINGO(dingo), LED(LEDGIS), AVAT(AVAT), VSOL(Vsolidus), EPIC(EPIC cash), NFC(netflowcoin), mrx(Metrix Coin), Idena(idena network), PKT(PKT Cash), BondDex(BondDex), XBN(XBN), KALAM(Kalamint), REV(RChain), KRC20(MyDeFiPet), ARC20(Hurricane Token), GMD(Coop network), BERS(Berith), ZEBI(Zebi), BRC(Baer Chain), DAPS(DAPS Coin), APL(Gold Secured Currency), NDAU(NDAU), WICC(WICC), UPG(Unipay God), TSL(TreasureSL), MXW(Maxonrow), CLC(Cifculation), SMH(SMH Coin), XIN(CPCoin), RDD(ReddCoin), OK(Okcash), KAR(KAR), CCX(ConcealNetwork),
686
+ },
687
+ 'defaultType': 'spot', # 'spot', 'swap'
688
+ 'fetchBalance': {
689
+ 'type': 'spot', # 'spot', 'swap', 'account'
690
+ },
691
+ 'accountsByType': {
692
+ 'spot': 'spot',
693
+ 'swap': 'swap',
694
+ },
695
+ 'createMarketBuyOrderRequiresPrice': True,
696
+ 'brokerId': 'CCXTxBitmart000',
697
+ },
698
+ })
699
+
700
+ async def fetch_time(self, params={}):
701
+ """
702
+ fetches the current integer timestamp in milliseconds from the exchange server
703
+ :param dict [params]: extra parameters specific to the exchange API endpoint
704
+ :returns int: the current integer timestamp in milliseconds from the exchange server
705
+ """
706
+ response = await self.publicGetSystemTime(params)
707
+ #
708
+ # {
709
+ # "message":"OK",
710
+ # "code":1000,
711
+ # "trace":"c4e5e5b7-fe9f-4191-89f7-53f6c5bf9030",
712
+ # "data":{
713
+ # "server_time":1599843709578
714
+ # }
715
+ # }
716
+ #
717
+ data = self.safe_value(response, 'data', {})
718
+ return self.safe_integer(data, 'server_time')
719
+
720
+ async def fetch_status(self, params={}):
721
+ """
722
+ the latest known information on the availability of the exchange API
723
+ :param dict [params]: extra parameters specific to the exchange API endpoint
724
+ :returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
725
+ """
726
+ options = self.safe_value(self.options, 'fetchStatus', {})
727
+ defaultType = self.safe_string(self.options, 'defaultType')
728
+ type = self.safe_string(options, 'type', defaultType)
729
+ type = self.safe_string(params, 'type', type)
730
+ params = self.omit(params, 'type')
731
+ response = await self.publicGetSystemService(params)
732
+ #
733
+ # {
734
+ # "message": "OK",
735
+ # "code": 1000,
736
+ # "trace": "1d3f28b0-763e-4f78-90c4-5e3ad19dc595",
737
+ # "data": {
738
+ # "service": [
739
+ # {
740
+ # "title": "Spot API Stop",
741
+ # "service_type": "spot",
742
+ # "status": 2,
743
+ # "start_time": 1648639069125,
744
+ # "end_time": 1648639069125
745
+ # },
746
+ # {
747
+ # "title": "Contract API Stop",
748
+ # "service_type": "contract",
749
+ # "status": 2,
750
+ # "start_time": 1648639069125,
751
+ # "end_time": 1648639069125
752
+ # }
753
+ # ]
754
+ # }
755
+ # }
756
+ #
757
+ data = self.safe_value(response, 'data', {})
758
+ services = self.safe_value(data, 'service', [])
759
+ servicesByType = self.index_by(services, 'service_type')
760
+ if type == 'swap':
761
+ type = 'contract'
762
+ service = self.safe_value(servicesByType, type)
763
+ status = None
764
+ eta = None
765
+ if service is not None:
766
+ statusCode = self.safe_integer(service, 'status')
767
+ if statusCode == 2:
768
+ status = 'ok'
769
+ else:
770
+ status = 'maintenance'
771
+ eta = self.safe_integer(service, 'end_time')
772
+ return {
773
+ 'status': status,
774
+ 'updated': None,
775
+ 'eta': eta,
776
+ 'url': None,
777
+ 'info': response,
778
+ }
779
+
780
+ async def fetch_spot_markets(self, params={}):
781
+ response = await self.publicGetSpotV1SymbolsDetails(params)
782
+ #
783
+ # {
784
+ # "message":"OK",
785
+ # "code":1000,
786
+ # "trace":"a67c9146-086d-4d3f-9897-5636a9bb26e1",
787
+ # "data":{
788
+ # "symbols":[
789
+ # {
790
+ # "symbol": "BTC_USDT",
791
+ # "symbol_id": 53,
792
+ # "base_currency": "BTC",
793
+ # "quote_currency": "USDT",
794
+ # "base_min_size": "0.000010000000000000000000000000",
795
+ # "base_max_size": "100000000.000000000000000000000000000000",
796
+ # "price_min_precision": -1,
797
+ # "price_max_precision": 2,
798
+ # "quote_increment": "0.00001", # Api docs says "The minimum order quantity is also the minimum order quantity increment", however I think they mistakenly use the term 'order quantity'
799
+ # "expiration": "NA",
800
+ # "min_buy_amount": "5.000000000000000000000000000000",
801
+ # "min_sell_amount": "5.000000000000000000000000000000",
802
+ # "trade_status": "trading"
803
+ # },
804
+ # ]
805
+ # }
806
+ # }
807
+ #
808
+ data = self.safe_value(response, 'data', {})
809
+ symbols = self.safe_value(data, 'symbols', [])
810
+ result = []
811
+ for i in range(0, len(symbols)):
812
+ market = symbols[i]
813
+ id = self.safe_string(market, 'symbol')
814
+ numericId = self.safe_integer(market, 'symbol_id')
815
+ baseId = self.safe_string(market, 'base_currency')
816
+ quoteId = self.safe_string(market, 'quote_currency')
817
+ base = self.safe_currency_code(baseId)
818
+ quote = self.safe_currency_code(quoteId)
819
+ symbol = base + '/' + quote
820
+ minBuyCost = self.safe_string(market, 'min_buy_amount')
821
+ minSellCost = self.safe_string(market, 'min_sell_amount')
822
+ minCost = Precise.string_max(minBuyCost, minSellCost)
823
+ baseMinSize = self.safe_number(market, 'base_min_size')
824
+ result.append({
825
+ 'id': id,
826
+ 'numericId': numericId,
827
+ 'symbol': symbol,
828
+ 'base': base,
829
+ 'quote': quote,
830
+ 'settle': None,
831
+ 'baseId': baseId,
832
+ 'quoteId': quoteId,
833
+ 'settleId': None,
834
+ 'type': 'spot',
835
+ 'spot': True,
836
+ 'margin': False,
837
+ 'swap': False,
838
+ 'future': False,
839
+ 'option': False,
840
+ 'active': True,
841
+ 'contract': False,
842
+ 'linear': None,
843
+ 'inverse': None,
844
+ 'contractSize': None,
845
+ 'expiry': None,
846
+ 'expiryDatetime': None,
847
+ 'strike': None,
848
+ 'optionType': None,
849
+ 'precision': {
850
+ 'amount': baseMinSize,
851
+ 'price': self.parse_number(self.parse_precision(self.safe_string(market, 'price_max_precision'))),
852
+ },
853
+ 'limits': {
854
+ 'leverage': {
855
+ 'min': None,
856
+ 'max': None,
857
+ },
858
+ 'amount': {
859
+ 'min': baseMinSize,
860
+ 'max': self.safe_number(market, 'base_max_size'),
861
+ },
862
+ 'price': {
863
+ 'min': None,
864
+ 'max': None,
865
+ },
866
+ 'cost': {
867
+ 'min': self.parse_number(minCost),
868
+ 'max': None,
869
+ },
870
+ },
871
+ 'created': None,
872
+ 'info': market,
873
+ })
874
+ return result
875
+
876
+ async def fetch_contract_markets(self, params={}):
877
+ response = await self.publicGetContractPublicDetails(params)
878
+ #
879
+ # {
880
+ # "code": 1000,
881
+ # "message": "Ok",
882
+ # "trace": "9b92a999-9463-4c96-91a4-93ad1cad0d72",
883
+ # "data": {
884
+ # "symbols": [{
885
+ # "symbol": "BTCUSDT",
886
+ # "product_type": 1,
887
+ # "open_timestamp": 1594080000,
888
+ # "expire_timestamp": 0,
889
+ # "settle_timestamp": 0,
890
+ # "base_currency": "BTC",
891
+ # "quote_currency": "USDT",
892
+ # "last_price": "23920",
893
+ # "volume_24h": "18969368",
894
+ # "turnover_24h": "458933659.7858",
895
+ # "index_price": "23945.25191635",
896
+ # "index_name": "BTCUSDT",
897
+ # "contract_size": "0.001",
898
+ # "min_leverage": "1",
899
+ # "max_leverage": "100",
900
+ # "price_precision": "0.1",
901
+ # "vol_precision": "1",
902
+ # "max_volume": "500000",
903
+ # "min_volume": "1"
904
+ # },
905
+ # ...
906
+ # ]
907
+ # }
908
+ # }
909
+ #
910
+ data = self.safe_value(response, 'data', {})
911
+ symbols = self.safe_value(data, 'symbols', [])
912
+ result = []
913
+ for i in range(0, len(symbols)):
914
+ market = symbols[i]
915
+ id = self.safe_string(market, 'symbol')
916
+ baseId = self.safe_string(market, 'base_currency')
917
+ quoteId = self.safe_string(market, 'quote_currency')
918
+ base = self.safe_currency_code(baseId)
919
+ quote = self.safe_currency_code(quoteId)
920
+ settleId = 'USDT' # self is bitmart's ID for usdt
921
+ settle = self.safe_currency_code(settleId)
922
+ symbol = base + '/' + quote + ':' + settle
923
+ productType = self.safe_integer(market, 'product_type')
924
+ isSwap = (productType == 1)
925
+ isFutures = (productType == 2)
926
+ expiry = self.safe_integer(market, 'expire_timestamp')
927
+ if not isFutures and (expiry == 0):
928
+ expiry = None
929
+ result.append({
930
+ 'id': id,
931
+ 'numericId': None,
932
+ 'symbol': symbol,
933
+ 'base': base,
934
+ 'quote': quote,
935
+ 'settle': settle,
936
+ 'baseId': baseId,
937
+ 'quoteId': quoteId,
938
+ 'settleId': settleId,
939
+ 'type': 'swap' if isSwap else 'future',
940
+ 'spot': False,
941
+ 'margin': False,
942
+ 'swap': isSwap,
943
+ 'future': isFutures,
944
+ 'option': False,
945
+ 'active': True,
946
+ 'contract': True,
947
+ 'linear': True,
948
+ 'inverse': False,
949
+ 'contractSize': self.safe_number(market, 'contract_size'),
950
+ 'expiry': expiry,
951
+ 'expiryDatetime': self.iso8601(expiry),
952
+ 'strike': None,
953
+ 'optionType': None,
954
+ 'precision': {
955
+ 'amount': self.safe_number(market, 'vol_precision'),
956
+ 'price': self.safe_number(market, 'price_precision'),
957
+ },
958
+ 'limits': {
959
+ 'leverage': {
960
+ 'min': self.safe_number(market, 'min_leverage'),
961
+ 'max': self.safe_number(market, 'max_leverage'),
962
+ },
963
+ 'amount': {
964
+ 'min': self.safe_number(market, 'min_volume'),
965
+ 'max': self.safe_number(market, 'max_volume'),
966
+ },
967
+ 'price': {
968
+ 'min': None,
969
+ 'max': None,
970
+ },
971
+ 'cost': {
972
+ 'min': None,
973
+ 'max': None,
974
+ },
975
+ },
976
+ 'created': self.safe_integer(market, 'open_timestamp'),
977
+ 'info': market,
978
+ })
979
+ return result
980
+
981
+ async def fetch_markets(self, params={}) -> List[Market]:
982
+ """
983
+ retrieves data on all markets for bitmart
984
+ :param dict [params]: extra parameters specific to the exchange API endpoint
985
+ :returns dict[]: an array of objects representing market data
986
+ """
987
+ spot = await self.fetch_spot_markets(params)
988
+ contract = await self.fetch_contract_markets(params)
989
+ return self.array_concat(spot, contract)
990
+
991
+ async def fetch_currencies(self, params={}) -> Currencies:
992
+ """
993
+ fetches all available currencies on an exchange
994
+ :param dict [params]: extra parameters specific to the exchange API endpoint
995
+ :returns dict: an associative dictionary of currencies
996
+ """
997
+ response = await self.publicGetSpotV1Currencies(params)
998
+ #
999
+ # {
1000
+ # "message":"OK",
1001
+ # "code":1000,
1002
+ # "trace":"8c768b3c-025f-413f-bec5-6d6411d46883",
1003
+ # "data":{
1004
+ # "currencies":[
1005
+ # {"currency":"MATIC","name":"Matic Network","withdraw_enabled":true,"deposit_enabled":true},
1006
+ # {"currency":"KTN","name":"Kasoutuuka News","withdraw_enabled":true,"deposit_enabled":false},
1007
+ # {"currency":"BRT","name":"Berith","withdraw_enabled":true,"deposit_enabled":true},
1008
+ # ]
1009
+ # }
1010
+ # }
1011
+ #
1012
+ data = self.safe_value(response, 'data', {})
1013
+ currencies = self.safe_value(data, 'currencies', [])
1014
+ result: dict = {}
1015
+ for i in range(0, len(currencies)):
1016
+ currency = currencies[i]
1017
+ id = self.safe_string(currency, 'id')
1018
+ code = self.safe_currency_code(id)
1019
+ name = self.safe_string(currency, 'name')
1020
+ withdrawEnabled = self.safe_value(currency, 'withdraw_enabled')
1021
+ depositEnabled = self.safe_value(currency, 'deposit_enabled')
1022
+ active = withdrawEnabled and depositEnabled
1023
+ result[code] = {
1024
+ 'id': id,
1025
+ 'code': code,
1026
+ 'name': name,
1027
+ 'info': currency, # the original payload
1028
+ 'active': active,
1029
+ 'deposit': depositEnabled,
1030
+ 'withdraw': withdrawEnabled,
1031
+ 'fee': None,
1032
+ 'precision': None,
1033
+ 'limits': {
1034
+ 'amount': {'min': None, 'max': None},
1035
+ 'withdraw': {'min': None, 'max': None},
1036
+ },
1037
+ }
1038
+ return result
1039
+
1040
+ async def fetch_transaction_fee(self, code: str, params={}):
1041
+ """
1042
+ * @deprecated
1043
+ please use fetchDepositWithdrawFee instead
1044
+ :param str code: unified currency code
1045
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1046
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
1047
+ """
1048
+ await self.load_markets()
1049
+ currency = self.currency(code)
1050
+ request: dict = {
1051
+ 'currency': currency['id'],
1052
+ }
1053
+ response = await self.privateGetAccountV1WithdrawCharge(self.extend(request, params))
1054
+ #
1055
+ # {
1056
+ # "message": "OK",
1057
+ # "code": "1000",
1058
+ # "trace": "3ecc0adf-91bd-4de7-aca1-886c1122f54f",
1059
+ # "data": {
1060
+ # "today_available_withdraw_BTC": "100.0000",
1061
+ # "min_withdraw": "0.005",
1062
+ # "withdraw_precision": "8",
1063
+ # "withdraw_fee": "0.000500000000000000000000000000"
1064
+ # }
1065
+ # }
1066
+ #
1067
+ data = response['data']
1068
+ withdrawFees: dict = {}
1069
+ withdrawFees[code] = self.safe_number(data, 'withdraw_fee')
1070
+ return {
1071
+ 'info': response,
1072
+ 'withdraw': withdrawFees,
1073
+ 'deposit': {},
1074
+ }
1075
+
1076
+ def parse_deposit_withdraw_fee(self, fee, currency: Currency = None):
1077
+ #
1078
+ # {
1079
+ # "today_available_withdraw_BTC": "100.0000",
1080
+ # "min_withdraw": "0.005",
1081
+ # "withdraw_precision": "8",
1082
+ # "withdraw_fee": "0.000500000000000000000000000000"
1083
+ # }
1084
+ #
1085
+ return {
1086
+ 'info': fee,
1087
+ 'withdraw': {
1088
+ 'fee': self.safe_number(fee, 'withdraw_fee'),
1089
+ 'percentage': None,
1090
+ },
1091
+ 'deposit': {
1092
+ 'fee': None,
1093
+ 'percentage': None,
1094
+ },
1095
+ 'networks': {},
1096
+ }
1097
+
1098
+ async def fetch_deposit_withdraw_fee(self, code: str, params={}):
1099
+ """
1100
+ fetch the fee for deposits and withdrawals
1101
+ :param str code: unified currency code
1102
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1103
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
1104
+ """
1105
+ await self.load_markets()
1106
+ currency = self.currency(code)
1107
+ request: dict = {
1108
+ 'currency': currency['id'],
1109
+ }
1110
+ response = await self.privateGetAccountV1WithdrawCharge(self.extend(request, params))
1111
+ #
1112
+ # {
1113
+ # "message": "OK",
1114
+ # "code": "1000",
1115
+ # "trace": "3ecc0adf-91bd-4de7-aca1-886c1122f54f",
1116
+ # "data": {
1117
+ # "today_available_withdraw_BTC": "100.0000",
1118
+ # "min_withdraw": "0.005",
1119
+ # "withdraw_precision": "8",
1120
+ # "withdraw_fee": "0.000500000000000000000000000000"
1121
+ # }
1122
+ # }
1123
+ #
1124
+ data = response['data']
1125
+ return self.parse_deposit_withdraw_fee(data)
1126
+
1127
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1128
+ #
1129
+ # spot(REST) fetchTickers
1130
+ #
1131
+ # {
1132
+ # 'result': [
1133
+ # "AFIN_USDT", # symbol
1134
+ # "0.001047", # last
1135
+ # "11110", # v_24h
1136
+ # "11.632170", # qv_24h
1137
+ # "0.001048", # open_24h
1138
+ # "0.001048", # high_24h
1139
+ # "0.001047", # low_24h
1140
+ # "-0.00095", # price_change_24h
1141
+ # "0.001029", # bid_px
1142
+ # "5555", # bid_sz
1143
+ # "0.001041", # ask_px
1144
+ # "5297", # ask_sz
1145
+ # "1717122550482" # timestamp
1146
+ # ]
1147
+ # }
1148
+ #
1149
+ # spot(REST) fetchTicker
1150
+ #
1151
+ # {
1152
+ # "symbol": "BTC_USDT",
1153
+ # "last": "68500.00",
1154
+ # "v_24h": "10491.65490",
1155
+ # "qv_24h": "717178990.42",
1156
+ # "open_24h": "68149.75",
1157
+ # "high_24h": "69499.99",
1158
+ # "low_24h": "67132.40",
1159
+ # "fluctuation": "0.00514",
1160
+ # "bid_px": "68500",
1161
+ # "bid_sz": "0.00162",
1162
+ # "ask_px": "68500.01",
1163
+ # "ask_sz": "0.01722",
1164
+ # "ts": "1717131391671"
1165
+ # }
1166
+ #
1167
+ # spot(WS)
1168
+ #
1169
+ # {
1170
+ # "symbol":"BTC_USDT",
1171
+ # "last_price":"146.24",
1172
+ # "open_24h":"147.17",
1173
+ # "high_24h":"147.48",
1174
+ # "low_24h":"143.88",
1175
+ # "base_volume_24h":"117387.58", # NOT base, but quote currencynot !!
1176
+ # "s_t": 1610936002
1177
+ # }
1178
+ #
1179
+ # swap
1180
+ #
1181
+ # {
1182
+ # "contract_symbol":"DOGEUSDT",
1183
+ # "last_price":"0.130340",
1184
+ # "index_price":"0.13048245",
1185
+ # "last_funding_rate":"0.00002287",
1186
+ # "price_change_percent_24h":"-2.074",
1187
+ # "volume_24h":"113705028.59482228",
1188
+ # "url":"https://futures.bitmart.com/en?symbol=DOGEUSDT",
1189
+ # "high_price":"0.134520",
1190
+ # "low_price":"0.128570",
1191
+ # "legal_coin_price":"0.1302699"
1192
+ # }
1193
+ #
1194
+ result = self.safe_list(ticker, 'result', [])
1195
+ average = self.safe_string_2(ticker, 'avg_price', 'index_price')
1196
+ marketId = self.safe_string_2(ticker, 'symbol', 'contract_symbol')
1197
+ timestamp = self.safe_integer_2(ticker, 'timestamp', 'ts')
1198
+ last = self.safe_string_2(ticker, 'last_price', 'last')
1199
+ percentage = self.safe_string(ticker, 'price_change_percent_24h')
1200
+ change = self.safe_string(ticker, 'fluctuation')
1201
+ high = self.safe_string_2(ticker, 'high_24h', 'high_price')
1202
+ low = self.safe_string_2(ticker, 'low_24h', 'low_price')
1203
+ bid = self.safe_string_2(ticker, 'best_bid', 'bid_px')
1204
+ bidVolume = self.safe_string_2(ticker, 'best_bid_size', 'bid_sz')
1205
+ ask = self.safe_string_2(ticker, 'best_ask', 'ask_px')
1206
+ askVolume = self.safe_string_2(ticker, 'best_ask_size', 'ask_sz')
1207
+ open = self.safe_string(ticker, 'open_24h')
1208
+ baseVolume = self.safe_string_2(ticker, 'base_volume_24h', 'v_24h')
1209
+ quoteVolume = self.safe_string_lower_2(ticker, 'quote_volume_24h', 'qv_24h')
1210
+ listMarketId = self.safe_string(result, 0)
1211
+ if listMarketId is not None:
1212
+ marketId = listMarketId
1213
+ timestamp = self.safe_integer(result, 12)
1214
+ high = self.safe_string(result, 5)
1215
+ low = self.safe_string(result, 6)
1216
+ bid = self.safe_string(result, 8)
1217
+ bidVolume = self.safe_string(result, 9)
1218
+ ask = self.safe_string(result, 10)
1219
+ askVolume = self.safe_string(result, 11)
1220
+ open = self.safe_string(result, 4)
1221
+ last = self.safe_string(result, 1)
1222
+ change = self.safe_string(result, 7)
1223
+ baseVolume = self.safe_string(result, 2)
1224
+ quoteVolume = self.safe_string_lower(result, 3)
1225
+ market = self.safe_market(marketId, market)
1226
+ symbol = market['symbol']
1227
+ if timestamp is None:
1228
+ # ticker from WS has a different field(in seconds)
1229
+ timestamp = self.safe_integer_product(ticker, 's_t', 1000)
1230
+ if percentage is None:
1231
+ percentage = Precise.string_mul(change, '100')
1232
+ if quoteVolume is None:
1233
+ if baseVolume is None:
1234
+ # self is swap
1235
+ quoteVolume = self.safe_string(ticker, 'volume_24h', quoteVolume)
1236
+ else:
1237
+ # self is a ticker from websockets
1238
+ # contrary to name and documentation, base_volume_24h is actually the quote volume
1239
+ quoteVolume = baseVolume
1240
+ baseVolume = None
1241
+ return self.safe_ticker({
1242
+ 'symbol': symbol,
1243
+ 'timestamp': timestamp,
1244
+ 'datetime': self.iso8601(timestamp),
1245
+ 'high': high,
1246
+ 'low': low,
1247
+ 'bid': bid,
1248
+ 'bidVolume': bidVolume,
1249
+ 'ask': ask,
1250
+ 'askVolume': askVolume,
1251
+ 'vwap': None,
1252
+ 'open': open,
1253
+ 'close': last,
1254
+ 'last': last,
1255
+ 'previousClose': None,
1256
+ 'change': change,
1257
+ 'percentage': percentage,
1258
+ 'average': average,
1259
+ 'baseVolume': baseVolume,
1260
+ 'quoteVolume': quoteVolume,
1261
+ 'info': ticker,
1262
+ }, market)
1263
+
1264
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1265
+ """
1266
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1267
+ :see: https://developer-pro.bitmart.com/en/spot/#get-ticker-of-a-trading-pair-v3
1268
+ :param str symbol: unified symbol of the market to fetch the ticker for
1269
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1270
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1271
+ """
1272
+ await self.load_markets()
1273
+ market = self.market(symbol)
1274
+ request: dict = {}
1275
+ response = None
1276
+ if market['swap']:
1277
+ request['contract_symbol'] = market['id']
1278
+ response = await self.publicGetContractV1Tickers(self.extend(request, params))
1279
+ #
1280
+ # {
1281
+ # "message":"OK",
1282
+ # "code":1000,
1283
+ # "trace":"4a0ebceb-d3f7-45a3-8feb-f61e230e24cd",
1284
+ # "data":{
1285
+ # "tickers":[
1286
+ # {
1287
+ # "contract_symbol":"DOGEUSDT",
1288
+ # "last_price":"0.130180",
1289
+ # "index_price":"0.13028635",
1290
+ # "last_funding_rate":"0.00002025",
1291
+ # "price_change_percent_24h":"-2.326",
1292
+ # "volume_24h":"116789313.01797258",
1293
+ # "url":"https://futures.bitmart.com/en?symbol=DOGEUSDT",
1294
+ # "high_price":"0.134520",
1295
+ # "low_price":"0.128570",
1296
+ # "legal_coin_price":"0.13017401"
1297
+ # }
1298
+ # ]
1299
+ # }
1300
+ # }
1301
+ #
1302
+ elif market['spot']:
1303
+ request['symbol'] = market['id']
1304
+ response = await self.publicGetSpotQuotationV3Ticker(self.extend(request, params))
1305
+ #
1306
+ # {
1307
+ # "code": 1000,
1308
+ # "trace": "f2194c2c202d2.99.1717535",
1309
+ # "message": "success",
1310
+ # "data": {
1311
+ # "symbol": "BTC_USDT",
1312
+ # "last": "68500.00",
1313
+ # "v_24h": "10491.65490",
1314
+ # "qv_24h": "717178990.42",
1315
+ # "open_24h": "68149.75",
1316
+ # "high_24h": "69499.99",
1317
+ # "low_24h": "67132.40",
1318
+ # "fluctuation": "0.00514",
1319
+ # "bid_px": "68500",
1320
+ # "bid_sz": "0.00162",
1321
+ # "ask_px": "68500.01",
1322
+ # "ask_sz": "0.01722",
1323
+ # "ts": "1717131391671"
1324
+ # }
1325
+ # }
1326
+ #
1327
+ else:
1328
+ raise NotSupported(self.id + ' fetchTicker() does not support ' + market['type'] + ' markets, only spot and swap markets are accepted')
1329
+ # fails in naming for contract tickers 'contract_symbol'
1330
+ tickersById = None
1331
+ tickers = []
1332
+ ticker: dict = {}
1333
+ if market['spot']:
1334
+ ticker = self.safe_dict(response, 'data', {})
1335
+ else:
1336
+ data = self.safe_dict(response, 'data', {})
1337
+ tickers = self.safe_list(data, 'tickers', [])
1338
+ tickersById = self.index_by(tickers, 'contract_symbol')
1339
+ ticker = self.safe_dict(tickersById, market['id'])
1340
+ return self.parse_ticker(ticker, market)
1341
+
1342
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1343
+ """
1344
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1345
+ :see: https://developer-pro.bitmart.com/en/spot/#get-ticker-of-all-pairs-v3
1346
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1347
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1348
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1349
+ """
1350
+ await self.load_markets()
1351
+ symbols = self.market_symbols(symbols)
1352
+ type = None
1353
+ market = None
1354
+ if symbols is not None:
1355
+ symbol = self.safe_value(symbols, 0)
1356
+ market = self.market(symbol)
1357
+ type, params = self.handle_market_type_and_params('fetchTickers', market, params)
1358
+ response = None
1359
+ if type == 'spot':
1360
+ response = await self.publicGetSpotQuotationV3Tickers(params)
1361
+ #
1362
+ # {
1363
+ # "code": 1000,
1364
+ # "trace": "17c5e5d9ac49f9b71efca2bed55f1a.105.171225637482393",
1365
+ # "message": "success",
1366
+ # "data": [
1367
+ # [
1368
+ # "AFIN_USDT",
1369
+ # "0.001047",
1370
+ # "11110",
1371
+ # "11.632170",
1372
+ # "0.001048",
1373
+ # "0.001048",
1374
+ # "0.001047",
1375
+ # "-0.00095",
1376
+ # "0.001029",
1377
+ # "5555",
1378
+ # "0.001041",
1379
+ # "5297",
1380
+ # "1717122550482"
1381
+ # ],
1382
+ # ]
1383
+ # }
1384
+ #
1385
+ elif type == 'swap':
1386
+ response = await self.publicGetContractV1Tickers(params)
1387
+ #
1388
+ # {
1389
+ # "message": "OK",
1390
+ # "code": 1000,
1391
+ # "trace": "c1dec681c24ea5d.105.171712565",
1392
+ # "data": {
1393
+ # "tickers": [
1394
+ # {
1395
+ # "contract_symbol": "SNTUSDT",
1396
+ # "last_price": "0.0366600",
1397
+ # "index_price": "0.03587373",
1398
+ # "last_funding_rate": "0.00005000",
1399
+ # "price_change_percent_24h": "-2.629",
1400
+ # "volume_24h": "10102540.19909109848",
1401
+ # "url": "https://futures.bitmart.com/en?symbol=SNTUSDT",
1402
+ # "high_price": "0.0405600",
1403
+ # "low_price": "0.0355000",
1404
+ # "legal_coin_price": "0.03666697"
1405
+ # },
1406
+ # ]
1407
+ # }
1408
+ # }
1409
+ #
1410
+ else:
1411
+ raise NotSupported(self.id + ' fetchTickers() does not support ' + type + ' markets, only spot and swap markets are accepted')
1412
+ tickers = []
1413
+ if type == 'spot':
1414
+ tickers = self.safe_list(response, 'data', [])
1415
+ else:
1416
+ data = self.safe_dict(response, 'data', {})
1417
+ tickers = self.safe_list(data, 'tickers', [])
1418
+ result: dict = {}
1419
+ for i in range(0, len(tickers)):
1420
+ ticker: dict = {}
1421
+ if type == 'spot':
1422
+ ticker = self.parse_ticker({'result': tickers[i]})
1423
+ else:
1424
+ ticker = self.parse_ticker(tickers[i])
1425
+ symbol = ticker['symbol']
1426
+ result[symbol] = ticker
1427
+ return self.filter_by_array_tickers(result, 'symbol', symbols)
1428
+
1429
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1430
+ """
1431
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1432
+ :see: https://developer-pro.bitmart.com/en/spot/#get-depth-v3
1433
+ :see: https://developer-pro.bitmart.com/en/futures/#get-market-depth
1434
+ :param str symbol: unified symbol of the market to fetch the order book for
1435
+ :param int [limit]: the maximum amount of order book entries to return
1436
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1437
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1438
+ """
1439
+ await self.load_markets()
1440
+ market = self.market(symbol)
1441
+ request: dict = {
1442
+ 'symbol': market['id'],
1443
+ }
1444
+ response = None
1445
+ if market['spot']:
1446
+ if limit is not None:
1447
+ request['limit'] = limit # default 35, max 50
1448
+ response = await self.publicGetSpotQuotationV3Books(self.extend(request, params))
1449
+ elif market['swap']:
1450
+ response = await self.publicGetContractPublicDepth(self.extend(request, params))
1451
+ else:
1452
+ raise NotSupported(self.id + ' fetchOrderBook() does not support ' + market['type'] + ' markets, only spot and swap markets are accepted')
1453
+ #
1454
+ # spot
1455
+ #
1456
+ # {
1457
+ # "code": 1000,
1458
+ # "message": "success",
1459
+ # "data": {
1460
+ # "ts": "1695264191808",
1461
+ # "symbol": "BTC_USDT",
1462
+ # "asks": [
1463
+ # ["26942.57","0.06492"],
1464
+ # ["26942.73","0.05447"],
1465
+ # ["26943.00","0.07154"]
1466
+ # ],
1467
+ # "bids": [
1468
+ # ["26942.45","0.00074"],
1469
+ # ["26941.53","0.00371"],
1470
+ # ["26940.94","0.08992"]
1471
+ # ]
1472
+ # },
1473
+ # "trace": "430a7f69581d4258a8e4b424dfb10782.73.16952341919017619"
1474
+ # }
1475
+ #
1476
+ # swap
1477
+ #
1478
+ # {
1479
+ # "code": 1000,
1480
+ # "message": "Ok",
1481
+ # "data": {
1482
+ # "asks": [
1483
+ # ["26938.3","3499","3499"],
1484
+ # ["26938.5","14702","18201"],
1485
+ # ["26938.6","20457","38658"]
1486
+ # ],
1487
+ # "bids": [
1488
+ # ["26938.2","20","20"],
1489
+ # ["26937.9","1913","1933"],
1490
+ # ["26937.8","2588","4521"]
1491
+ # ],
1492
+ # "timestamp": 1695264383999,
1493
+ # "symbol": "BTCUSDT"
1494
+ # },
1495
+ # "trace": "4cad855074664097ac6ba5258c47305d.72.16952643834721135"
1496
+ # }
1497
+ #
1498
+ data = self.safe_value(response, 'data', {})
1499
+ timestamp = self.safe_integer_2(data, 'ts', 'timestamp')
1500
+ return self.parse_order_book(data, market['symbol'], timestamp)
1501
+
1502
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
1503
+ #
1504
+ # public fetchTrades spot( amount = count * price )
1505
+ #
1506
+ # [
1507
+ # "BTC_USDT", # symbol
1508
+ # "1717212457302", # timestamp
1509
+ # "67643.11", # price
1510
+ # "0.00106", # size
1511
+ # "sell" # side
1512
+ # ]
1513
+ #
1514
+ # spot: fetchMyTrades
1515
+ #
1516
+ # {
1517
+ # "tradeId":"182342999769370687",
1518
+ # "orderId":"183270218784142990",
1519
+ # "clientOrderId":"183270218784142990",
1520
+ # "symbol":"ADA_USDT",
1521
+ # "side":"buy",
1522
+ # "orderMode":"spot",
1523
+ # "type":"market",
1524
+ # "price":"0.245948",
1525
+ # "size":"20.71",
1526
+ # "notional":"5.09358308",
1527
+ # "fee":"0.00509358",
1528
+ # "feeCoinName":"USDT",
1529
+ # "tradeRole":"taker",
1530
+ # "createTime":1695658457836,
1531
+ # }
1532
+ #
1533
+ # swap: fetchMyTrades
1534
+ #
1535
+ # {
1536
+ # "order_id": "230930336848609",
1537
+ # "trade_id": "6212604014",
1538
+ # "symbol": "BTCUSDT",
1539
+ # "side": 3,
1540
+ # "price": "26910.4",
1541
+ # "vol": "1",
1542
+ # "exec_type": "Taker",
1543
+ # "profit": False,
1544
+ # "create_time": 1695961596692,
1545
+ # "realised_profit": "-0.0003",
1546
+ # "paid_fees": "0.01614624"
1547
+ # }
1548
+ #
1549
+ # ws swap
1550
+ #
1551
+ # {
1552
+ # 'fee': '-0.000044502',
1553
+ # 'feeCcy': 'USDT',
1554
+ # 'fillPrice': '74.17',
1555
+ # 'fillQty': '1',
1556
+ # 'lastTradeID': 6802340762
1557
+ # }
1558
+ #
1559
+ timestamp = self.safe_integer_n(trade, ['createTime', 'create_time', 1])
1560
+ isPublic = self.safe_string(trade, 0)
1561
+ isPublicTrade = (isPublic is not None)
1562
+ amount = None
1563
+ cost = None
1564
+ type = None
1565
+ side = None
1566
+ if isPublicTrade:
1567
+ amount = self.safe_string_2(trade, 'count', 3)
1568
+ cost = self.safe_string(trade, 'amount')
1569
+ side = self.safe_string_2(trade, 'type', 4)
1570
+ else:
1571
+ amount = self.safe_string_n(trade, ['size', 'vol', 'fillQty'])
1572
+ cost = self.safe_string(trade, 'notional')
1573
+ type = self.safe_string(trade, 'type')
1574
+ side = self.parse_order_side(self.safe_string(trade, 'side'))
1575
+ marketId = self.safe_string_2(trade, 'symbol', 0)
1576
+ market = self.safe_market(marketId, market)
1577
+ feeCostString = self.safe_string_2(trade, 'fee', 'paid_fees')
1578
+ fee = None
1579
+ if feeCostString is not None:
1580
+ feeCurrencyId = self.safe_string(trade, 'feeCoinName')
1581
+ feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
1582
+ if feeCurrencyCode is None:
1583
+ feeCurrencyCode = market['base'] if (side == 'buy') else market['quote']
1584
+ fee = {
1585
+ 'cost': feeCostString,
1586
+ 'currency': feeCurrencyCode,
1587
+ }
1588
+ return self.safe_trade({
1589
+ 'info': trade,
1590
+ 'id': self.safe_string_n(trade, ['tradeId', 'trade_id', 'lastTradeID']),
1591
+ 'order': self.safe_string_2(trade, 'orderId', 'order_id'),
1592
+ 'timestamp': timestamp,
1593
+ 'datetime': self.iso8601(timestamp),
1594
+ 'symbol': market['symbol'],
1595
+ 'type': type,
1596
+ 'side': side,
1597
+ 'price': self.safe_string_n(trade, ['price', 'fillPrice', 2]),
1598
+ 'amount': amount,
1599
+ 'cost': cost,
1600
+ 'takerOrMaker': self.safe_string_lower_2(trade, 'tradeRole', 'exec_type'),
1601
+ 'fee': fee,
1602
+ }, market)
1603
+
1604
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
1605
+ """
1606
+ get a list of the most recent trades for a particular symbol
1607
+ :see: https://developer-pro.bitmart.com/en/spot/#get-recent-trades-v3
1608
+ :param str symbol: unified symbol of the market to fetch trades for
1609
+ :param int [since]: timestamp in ms of the earliest trade to fetch
1610
+ :param int [limit]: the maximum number of trades to fetch
1611
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1612
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
1613
+ """
1614
+ await self.load_markets()
1615
+ market = self.market(symbol)
1616
+ if not market['spot']:
1617
+ raise NotSupported(self.id + ' fetchTrades() does not support ' + market['type'] + ' orders, only spot orders are accepted')
1618
+ request: dict = {
1619
+ 'symbol': market['id'],
1620
+ }
1621
+ if limit is not None:
1622
+ request['limit'] = limit
1623
+ response = await self.publicGetSpotQuotationV3Trades(self.extend(request, params))
1624
+ #
1625
+ # {
1626
+ # "code": 1000,
1627
+ # "trace": "58031f9a5bd.111.17117",
1628
+ # "message": "success",
1629
+ # "data": [
1630
+ # [
1631
+ # "BTC_USDT",
1632
+ # "1717212457302",
1633
+ # "67643.11",
1634
+ # "0.00106",
1635
+ # "sell"
1636
+ # ],
1637
+ # ]
1638
+ # }
1639
+ #
1640
+ data = self.safe_list(response, 'data', [])
1641
+ return self.parse_trades(data, market, since, limit)
1642
+
1643
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
1644
+ #
1645
+ # spot
1646
+ # [
1647
+ # "1699512060", # timestamp
1648
+ # "36746.49", # open
1649
+ # "36758.71", # high
1650
+ # "36736.13", # low
1651
+ # "36755.99", # close
1652
+ # "2.83965", # base volume
1653
+ # "104353.57" # quote volume
1654
+ # ]
1655
+ #
1656
+ # swap
1657
+ # {
1658
+ # "low_price": "20090.3",
1659
+ # "high_price": "20095.5",
1660
+ # "open_price": "20092.6",
1661
+ # "close_price": "20091.4",
1662
+ # "volume": "8748",
1663
+ # "timestamp": 1665002281
1664
+ # }
1665
+ #
1666
+ # ws
1667
+ # [
1668
+ # 1631056350, # timestamp
1669
+ # "46532.83", # open
1670
+ # "46555.71", # high
1671
+ # "46511.41", # low
1672
+ # "46555.71", # close
1673
+ # "0.25", # volume
1674
+ # ]
1675
+ #
1676
+ # ws swap
1677
+ # {
1678
+ # "symbol":"BTCUSDT",
1679
+ # "o":"146.24",
1680
+ # "h":"146.24",
1681
+ # "l":"146.24",
1682
+ # "c":"146.24",
1683
+ # "v":"146"
1684
+ # }
1685
+ #
1686
+ if isinstance(ohlcv, list):
1687
+ return [
1688
+ self.safe_timestamp(ohlcv, 0),
1689
+ self.safe_number(ohlcv, 1),
1690
+ self.safe_number(ohlcv, 2),
1691
+ self.safe_number(ohlcv, 3),
1692
+ self.safe_number(ohlcv, 4),
1693
+ self.safe_number(ohlcv, 5),
1694
+ ]
1695
+ else:
1696
+ return [
1697
+ self.safe_timestamp_2(ohlcv, 'timestamp', 'ts'),
1698
+ self.safe_number_2(ohlcv, 'open_price', 'o'),
1699
+ self.safe_number_2(ohlcv, 'high_price', 'h'),
1700
+ self.safe_number_2(ohlcv, 'low_price', 'l'),
1701
+ self.safe_number_2(ohlcv, 'close_price', 'c'),
1702
+ self.safe_number_2(ohlcv, 'volume', 'v'),
1703
+ ]
1704
+
1705
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
1706
+ """
1707
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
1708
+ :see: https://developer-pro.bitmart.com/en/spot/#get-history-k-line-v3
1709
+ :see: https://developer-pro.bitmart.com/en/futures/#get-k-line
1710
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
1711
+ :param str timeframe: the length of time each candle represents
1712
+ :param int [since]: timestamp in ms of the earliest candle to fetch
1713
+ :param int [limit]: the maximum amount of candles to fetch
1714
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1715
+ :param int [params.until]: timestamp of the latest candle in ms
1716
+ :param boolean [params.paginate]: *spot only* default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1717
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
1718
+ """
1719
+ await self.load_markets()
1720
+ paginate = False
1721
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate', False)
1722
+ if paginate:
1723
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 200)
1724
+ market = self.market(symbol)
1725
+ duration = self.parse_timeframe(timeframe)
1726
+ parsedTimeframe = self.safe_integer(self.timeframes, timeframe)
1727
+ request: dict = {
1728
+ 'symbol': market['id'],
1729
+ }
1730
+ if parsedTimeframe is not None:
1731
+ request['step'] = parsedTimeframe
1732
+ else:
1733
+ request['step'] = timeframe
1734
+ if market['spot']:
1735
+ request, params = self.handle_until_option('before', request, params, 0.001)
1736
+ if limit is not None:
1737
+ request['limit'] = limit
1738
+ if since is not None:
1739
+ request['after'] = self.parse_to_int((since / 1000)) - 1
1740
+ else:
1741
+ maxLimit = 1200
1742
+ if limit is None:
1743
+ limit = maxLimit
1744
+ limit = min(maxLimit, limit)
1745
+ now = self.parse_to_int(self.milliseconds() / 1000)
1746
+ if since is None:
1747
+ start = now - limit * duration
1748
+ request['start_time'] = start
1749
+ request['end_time'] = now
1750
+ else:
1751
+ start = self.parse_to_int((since / 1000)) - 1
1752
+ end = self.sum(start, limit * duration)
1753
+ request['start_time'] = start
1754
+ request['end_time'] = min(end, now)
1755
+ request, params = self.handle_until_option('end_time', request, params, 0.001)
1756
+ response = None
1757
+ if market['swap']:
1758
+ response = await self.publicGetContractPublicKline(self.extend(request, params))
1759
+ else:
1760
+ response = await self.publicGetSpotQuotationV3Klines(self.extend(request, params))
1761
+ #
1762
+ # spot
1763
+ #
1764
+ # {
1765
+ # "code": 1000,
1766
+ # "message": "success",
1767
+ # "data": [
1768
+ # ["1699512060","36746.49","36758.71","36736.13","36755.99","2.83965","104353.57"],
1769
+ # ["1699512120","36756.00","36758.70","36737.14","36737.63","1.96070","72047.10"],
1770
+ # ["1699512180","36737.63","36740.45","36737.62","36740.44","0.63194","23217.62"]
1771
+ # ],
1772
+ # "trace": "6591fc7b508845359d5fa442e3b3a4fb.72.16995122398750695"
1773
+ # }
1774
+ #
1775
+ # swap
1776
+ #
1777
+ # {
1778
+ # "code": 1000,
1779
+ # "message": "Ok",
1780
+ # "data": [
1781
+ # {
1782
+ # "low_price": "20090.3",
1783
+ # "high_price": "20095.5",
1784
+ # "open_price": "20092.6",
1785
+ # "close_price": "20091.4",
1786
+ # "volume": "8748",
1787
+ # "timestamp": 1665002281
1788
+ # },
1789
+ # ...
1790
+ # ],
1791
+ # "trace": "96c989db-e0f5-46f5-bba6-60cfcbde699b"
1792
+ # }
1793
+ #
1794
+ ohlcv = self.safe_list(response, 'data', [])
1795
+ return self.parse_ohlcvs(ohlcv, market, timeframe, since, limit)
1796
+
1797
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1798
+ """
1799
+ :see: https://developer-pro.bitmart.com/en/spot/#account-trade-list-v4-signed
1800
+ :see: https://developer-pro.bitmart.com/en/futures/#get-order-trade-keyed
1801
+ fetch all trades made by the user
1802
+ :param str symbol: unified market symbol
1803
+ :param int [since]: the earliest time in ms to fetch trades for
1804
+ :param int [limit]: the maximum number of trades structures to retrieve
1805
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1806
+ :param int [params.until]: the latest time in ms to fetch trades for
1807
+ :param boolean [params.marginMode]: *spot* whether to fetch trades for margin orders or spot orders, defaults to spot orders(only isolated margin orders are supported)
1808
+ :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1809
+ """
1810
+ await self.load_markets()
1811
+ market = None
1812
+ request: dict = {}
1813
+ if symbol is not None:
1814
+ market = self.market(symbol)
1815
+ request['symbol'] = market['id']
1816
+ type = None
1817
+ response = None
1818
+ type, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
1819
+ until = self.safe_integer_n(params, ['until', 'endTime', 'end_time'])
1820
+ params = self.omit(params, ['until'])
1821
+ if type == 'spot':
1822
+ marginMode = None
1823
+ marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
1824
+ if marginMode == 'isolated':
1825
+ request['orderMode'] = 'iso_margin'
1826
+ options = self.safe_value(self.options, 'fetchMyTrades', {})
1827
+ defaultLimit = self.safe_integer(options, 'limit', 200)
1828
+ if limit is None:
1829
+ limit = defaultLimit
1830
+ request['limit'] = limit
1831
+ if since is not None:
1832
+ request['startTime'] = since
1833
+ if until is not None:
1834
+ request['endTime'] = until
1835
+ response = await self.privatePostSpotV4QueryTrades(self.extend(request, params))
1836
+ elif type == 'swap':
1837
+ if symbol is None:
1838
+ raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
1839
+ if since is not None:
1840
+ request['start_time'] = since
1841
+ if until is not None:
1842
+ request['end_time'] = until
1843
+ response = await self.privateGetContractPrivateTrades(self.extend(request, params))
1844
+ else:
1845
+ raise NotSupported(self.id + ' fetchMyTrades() does not support ' + type + ' orders, only spot and swap orders are accepted')
1846
+ #
1847
+ # spot
1848
+ #
1849
+ # {
1850
+ # "code":1000,
1851
+ # "message":"success",
1852
+ # "data":[
1853
+ # {
1854
+ # "tradeId":"182342999769370687",
1855
+ # "orderId":"183270218784142990",
1856
+ # "clientOrderId":"183270218784142990",
1857
+ # "symbol":"ADA_USDT",
1858
+ # "side":"buy",
1859
+ # "orderMode":"spot",
1860
+ # "type":"market",
1861
+ # "price":"0.245948",
1862
+ # "size":"20.71",
1863
+ # "notional":"5.09358308",
1864
+ # "fee":"0.00509358",
1865
+ # "feeCoinName":"USDT",
1866
+ # "tradeRole":"taker",
1867
+ # "createTime":1695658457836,
1868
+ # "updateTime":1695658457836
1869
+ # }
1870
+ # ],
1871
+ # "trace":"fbaee9e0e2f5442fba5b3262fc86b0ac.65.16956593456523085"
1872
+ # }
1873
+ #
1874
+ # swap
1875
+ #
1876
+ # {
1877
+ # "code": 1000,
1878
+ # "message": "Ok",
1879
+ # "data": [
1880
+ # {
1881
+ # "order_id": "230930336848609",
1882
+ # "trade_id": "6212604014",
1883
+ # "symbol": "BTCUSDT",
1884
+ # "side": 3,
1885
+ # "price": "26910.4",
1886
+ # "vol": "1",
1887
+ # "exec_type": "Taker",
1888
+ # "profit": False,
1889
+ # "create_time": 1695961596692,
1890
+ # "realised_profit": "-0.0003",
1891
+ # "paid_fees": "0.01614624"
1892
+ # },
1893
+ # ],
1894
+ # "trace": "4cad855074634097ac6ba5257c47305d.62.16959616054873723"
1895
+ # }
1896
+ #
1897
+ data = self.safe_list(response, 'data', [])
1898
+ return self.parse_trades(data, market, since, limit)
1899
+
1900
+ async def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1901
+ """
1902
+ :see: https://developer-pro.bitmart.com/en/spot/#order-trade-list-v4-signed
1903
+ fetch all the trades made from a single order
1904
+ :param str id: order id
1905
+ :param str symbol: unified market symbol
1906
+ :param int [since]: the earliest time in ms to fetch trades for
1907
+ :param int [limit]: the maximum number of trades to retrieve
1908
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1909
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
1910
+ """
1911
+ await self.load_markets()
1912
+ request: dict = {
1913
+ 'orderId': id,
1914
+ }
1915
+ response = await self.privatePostSpotV4QueryOrderTrades(self.extend(request, params))
1916
+ data = self.safe_list(response, 'data', [])
1917
+ return self.parse_trades(data, None, since, limit)
1918
+
1919
+ def custom_parse_balance(self, response, marketType) -> Balances:
1920
+ data = self.safe_value(response, 'data', {})
1921
+ wallet = None
1922
+ if marketType == 'swap':
1923
+ wallet = self.safe_value(response, 'data', [])
1924
+ elif marketType == 'margin':
1925
+ wallet = self.safe_value(data, 'symbols', [])
1926
+ else:
1927
+ wallet = self.safe_value(data, 'wallet', [])
1928
+ result = {'info': response}
1929
+ if marketType == 'margin':
1930
+ for i in range(0, len(wallet)):
1931
+ entry = wallet[i]
1932
+ marketId = self.safe_string(entry, 'symbol')
1933
+ symbol = self.safe_symbol(marketId, None, '_')
1934
+ base = self.safe_value(entry, 'base', {})
1935
+ quote = self.safe_value(entry, 'quote', {})
1936
+ baseCode = self.safe_currency_code(self.safe_string(base, 'currency'))
1937
+ quoteCode = self.safe_currency_code(self.safe_string(quote, 'currency'))
1938
+ subResult: dict = {}
1939
+ subResult[baseCode] = self.parse_balance_helper(base)
1940
+ subResult[quoteCode] = self.parse_balance_helper(quote)
1941
+ result[symbol] = self.safe_balance(subResult)
1942
+ return result
1943
+ else:
1944
+ for i in range(0, len(wallet)):
1945
+ balance = wallet[i]
1946
+ currencyId = self.safe_string_2(balance, 'id', 'currency')
1947
+ currencyId = self.safe_string(balance, 'coin_code', currencyId)
1948
+ code = self.safe_currency_code(currencyId)
1949
+ account = self.account()
1950
+ account['free'] = self.safe_string_2(balance, 'available', 'available_balance')
1951
+ account['used'] = self.safe_string_2(balance, 'frozen', 'frozen_balance')
1952
+ result[code] = account
1953
+ return self.safe_balance(result)
1954
+
1955
+ def parse_balance_helper(self, entry):
1956
+ account = self.account()
1957
+ account['used'] = self.safe_string(entry, 'frozen')
1958
+ account['free'] = self.safe_string(entry, 'available')
1959
+ account['total'] = self.safe_string(entry, 'total_asset')
1960
+ debt = self.safe_string(entry, 'borrow_unpaid')
1961
+ interest = self.safe_string(entry, 'interest_unpaid')
1962
+ account['debt'] = Precise.string_add(debt, interest)
1963
+ return account
1964
+
1965
+ async def fetch_balance(self, params={}) -> Balances:
1966
+ """
1967
+ query for balance and get the amount of funds available for trading or funds locked in orders
1968
+ :see: https://developer-pro.bitmart.com/en/spot/#get-spot-wallet-balance
1969
+ :see: https://developer-pro.bitmart.com/en/futures/#get-contract-assets-detail
1970
+ :see: https://developer-pro.bitmart.com/en/spot/#get-account-balance
1971
+ :see: https://developer-pro.bitmart.com/en/spot/#get-margin-account-details-isolated
1972
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1973
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1974
+ """
1975
+ await self.load_markets()
1976
+ marketType = None
1977
+ marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
1978
+ marginMode = self.safe_string(params, 'marginMode')
1979
+ isMargin = self.safe_bool(params, 'margin', False)
1980
+ params = self.omit(params, ['margin', 'marginMode'])
1981
+ if marginMode is not None or isMargin:
1982
+ marketType = 'margin'
1983
+ response = None
1984
+ if marketType == 'spot':
1985
+ response = await self.privateGetSpotV1Wallet(params)
1986
+ elif marketType == 'swap':
1987
+ response = await self.privateGetContractPrivateAssetsDetail(params)
1988
+ elif marketType == 'account':
1989
+ response = await self.privateGetAccountV1Wallet(params)
1990
+ elif marketType == 'margin':
1991
+ response = await self.privateGetSpotV1MarginIsolatedAccount(params)
1992
+ else:
1993
+ raise NotSupported(self.id + ' fetchBalance() does not support ' + marketType + ' markets, only spot, swap and account and margin markets are accepted')
1994
+ #
1995
+ # spot
1996
+ #
1997
+ # {
1998
+ # "message":"OK",
1999
+ # "code":1000,
2000
+ # "trace":"39069916-72f9-44c7-acde-2ad5afd21cad",
2001
+ # "data":{
2002
+ # "wallet":[
2003
+ # {"id":"BTC","name":"Bitcoin","available":"0.00000062","frozen":"0.00000000"},
2004
+ # {"id":"ETH","name":"Ethereum","available":"0.00002277","frozen":"0.00000000"},
2005
+ # {"id":"BMX","name":"BitMart Token","available":"0.00000000","frozen":"0.00000000"}
2006
+ # ]
2007
+ # }
2008
+ # }
2009
+ #
2010
+ # account
2011
+ #
2012
+ # {
2013
+ # "message":"OK",
2014
+ # "code":1000,
2015
+ # "trace":"5c3b7fc7-93b2-49ef-bb59-7fdc56915b59",
2016
+ # "data":{
2017
+ # "wallet":[
2018
+ # {"currency":"BTC","name":"Bitcoin","available":"0.00000062","frozen":"0.00000000"},
2019
+ # {"currency":"ETH","name":"Ethereum","available":"0.00002277","frozen":"0.00000000"}
2020
+ # ]
2021
+ # }
2022
+ # }
2023
+ #
2024
+ # swap
2025
+ #
2026
+ # {
2027
+ # "code": 1000,
2028
+ # "message": "Ok",
2029
+ # "data": [
2030
+ # {
2031
+ # "currency": "USDT",
2032
+ # "available_balance": "0",
2033
+ # "frozen_balance": "0",
2034
+ # "unrealized": "0",
2035
+ # "equity": "0",
2036
+ # "position_deposit": "0"
2037
+ # },
2038
+ # ...
2039
+ # ],
2040
+ # "trace": "f9da3a39-cf45-42e7-914d-294f565dfc33"
2041
+ # }
2042
+ #
2043
+ # margin
2044
+ #
2045
+ # {
2046
+ # "message": "OK",
2047
+ # "code": 1000,
2048
+ # "trace": "61dd6ab265c04064b72d8bc9b205f741.71.16701055600915302",
2049
+ # "data": {
2050
+ # "symbols": [
2051
+ # {
2052
+ # "symbol": "BTC_USDT",
2053
+ # "risk_rate": "999.00",
2054
+ # "risk_level": "1",
2055
+ # "buy_enabled": False,
2056
+ # "sell_enabled": False,
2057
+ # "liquidate_price": null,
2058
+ # "liquidate_rate": "1.15",
2059
+ # "base": {
2060
+ # "currency": "BTC",
2061
+ # "borrow_enabled": True,
2062
+ # "borrowed": "0.00000000",
2063
+ # "available": "0.00000000",
2064
+ # "frozen": "0.00000000",
2065
+ # "net_asset": "0.00000000",
2066
+ # "net_assetBTC": "0.00000000",
2067
+ # "total_asset": "0.00000000",
2068
+ # "borrow_unpaid": "0.00000000",
2069
+ # "interest_unpaid": "0.00000000"
2070
+ # },
2071
+ # "quote": {
2072
+ # "currency": "USDT",
2073
+ # "borrow_enabled": True,
2074
+ # "borrowed": "0.00000000",
2075
+ # "available": "20.00000000",
2076
+ # "frozen": "0.00000000",
2077
+ # "net_asset": "20.00000000",
2078
+ # "net_assetBTC": "0.00118008",
2079
+ # "total_asset": "20.00000000",
2080
+ # "borrow_unpaid": "0.00000000",
2081
+ # "interest_unpaid": "0.00000000"
2082
+ # }
2083
+ # }
2084
+ # ]
2085
+ # }
2086
+ # }
2087
+ #
2088
+ return self.custom_parse_balance(response, marketType)
2089
+
2090
+ def parse_trading_fee(self, fee: dict, market: Market = None) -> TradingFeeInterface:
2091
+ #
2092
+ # {
2093
+ # "symbol": "ETH_USDT",
2094
+ # "taker_fee_rate": "0.0025",
2095
+ # "maker_fee_rate": "0.0025"
2096
+ # }
2097
+ #
2098
+ marketId = self.safe_string(fee, 'symbol')
2099
+ symbol = self.safe_symbol(marketId)
2100
+ return {
2101
+ 'info': fee,
2102
+ 'symbol': symbol,
2103
+ 'maker': self.safe_number(fee, 'maker_fee_rate'),
2104
+ 'taker': self.safe_number(fee, 'taker_fee_rate'),
2105
+ 'percentage': None,
2106
+ 'tierBased': None,
2107
+ }
2108
+
2109
+ async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
2110
+ """
2111
+ fetch the trading fees for a market
2112
+ :param str symbol: unified market symbol
2113
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2114
+ :returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
2115
+ """
2116
+ await self.load_markets()
2117
+ market = self.market(symbol)
2118
+ if not market['spot']:
2119
+ raise NotSupported(self.id + ' fetchTradingFee() does not support ' + market['type'] + ' orders, only spot orders are accepted')
2120
+ request: dict = {
2121
+ 'symbol': market['id'],
2122
+ }
2123
+ response = await self.privateGetSpotV1TradeFee(self.extend(request, params))
2124
+ #
2125
+ # {
2126
+ # "message": "OK",
2127
+ # "code": "1000",
2128
+ # "trace": "5a6f1e40-37fe-4849-a494-03279fadcc62",
2129
+ # "data": {
2130
+ # "symbol": "ETH_USDT",
2131
+ # "taker_fee_rate": "0.0025",
2132
+ # "maker_fee_rate": "0.0025"
2133
+ # }
2134
+ # }
2135
+ #
2136
+ data = self.safe_value(response, 'data')
2137
+ return self.parse_trading_fee(data)
2138
+
2139
+ def parse_order(self, order: dict, market: Market = None) -> Order:
2140
+ #
2141
+ # createOrder
2142
+ #
2143
+ # {
2144
+ # "order_id": 2707217580
2145
+ # }
2146
+ #
2147
+ # swap
2148
+ # "data": {
2149
+ # "order_id": 231116359426639,
2150
+ # "price": "market price"
2151
+ # },
2152
+ #
2153
+ # cancelOrder
2154
+ #
2155
+ # "2707217580" # order id
2156
+ #
2157
+ # spot fetchOrder, fetchOrdersByStatus, fetchOpenOrders, fetchClosedOrders
2158
+ #
2159
+ # {
2160
+ # "order_id":1736871726781,
2161
+ # "symbol":"BTC_USDT",
2162
+ # "create_time":1591096004000,
2163
+ # "side":"sell",
2164
+ # "type":"market", # limit, market, limit_maker, ioc
2165
+ # "price":"0.00",
2166
+ # "price_avg":"0.00",
2167
+ # "size":"0.02000",
2168
+ # "notional":"0.00000000",
2169
+ # "filled_notional":"0.00000000",
2170
+ # "filled_size":"0.00000",
2171
+ # "status":"8"
2172
+ # }
2173
+ #
2174
+ # spot v4
2175
+ # {
2176
+ # "orderId" : "118100034543076010",
2177
+ # "clientOrderId" : "118100034543076010",
2178
+ # "symbol" : "BTC_USDT",
2179
+ # "side" : "buy",
2180
+ # "orderMode" : "spot",
2181
+ # "type" : "limit",
2182
+ # "state" : "filled",
2183
+ # "price" : "48800.00",
2184
+ # "priceAvg" : "39999.00",
2185
+ # "size" : "0.10000",
2186
+ # "filledSize" : "0.10000",
2187
+ # "notional" : "4880.00000000",
2188
+ # "filledNotional" : "3999.90000000",
2189
+ # "createTime" : 1681701557927,
2190
+ # "updateTime" : 1681701559408
2191
+ # }
2192
+ #
2193
+ # swap: fetchOrder, fetchOpenOrders, fetchClosedOrders
2194
+ #
2195
+ # {
2196
+ # "order_id": "230935812485489",
2197
+ # "client_order_id": "",
2198
+ # "price": "24000",
2199
+ # "size": "1",
2200
+ # "symbol": "BTCUSDT",
2201
+ # "state": 2,
2202
+ # "side": 1,
2203
+ # "type": "limit",
2204
+ # "leverage": "10",
2205
+ # "open_type": "isolated",
2206
+ # "deal_avg_price": "0",
2207
+ # "deal_size": "0",
2208
+ # "create_time": 1695702258629,
2209
+ # "update_time": 1695702258642,
2210
+ # "activation_price_type": 0,
2211
+ # "activation_price": "",
2212
+ # "callback_rate": ""
2213
+ # }
2214
+ #
2215
+ id = None
2216
+ if isinstance(order, str):
2217
+ id = order
2218
+ order = {}
2219
+ id = self.safe_string_2(order, 'order_id', 'orderId', id)
2220
+ timestamp = self.safe_integer_2(order, 'create_time', 'createTime')
2221
+ marketId = self.safe_string(order, 'symbol')
2222
+ symbol = self.safe_symbol(marketId, market)
2223
+ market = self.safe_market(symbol, market)
2224
+ orderType = self.safe_string(market, 'type', 'spot')
2225
+ type = self.safe_string(order, 'type')
2226
+ timeInForce = None
2227
+ postOnly = None
2228
+ if type == 'limit_maker':
2229
+ type = 'limit'
2230
+ postOnly = True
2231
+ timeInForce = 'PO'
2232
+ if type == 'ioc':
2233
+ type = 'limit'
2234
+ timeInForce = 'IOC'
2235
+ priceString = self.safe_string(order, 'price')
2236
+ if priceString == 'market price':
2237
+ priceString = None
2238
+ trailingActivationPrice = self.safe_number(order, 'activation_price')
2239
+ return self.safe_order({
2240
+ 'id': id,
2241
+ 'clientOrderId': self.safe_string(order, 'client_order_id'),
2242
+ 'info': order,
2243
+ 'timestamp': timestamp,
2244
+ 'datetime': self.iso8601(timestamp),
2245
+ 'lastTradeTimestamp': self.safe_integer(order, 'update_time'),
2246
+ 'symbol': symbol,
2247
+ 'type': type,
2248
+ 'timeInForce': timeInForce,
2249
+ 'postOnly': postOnly,
2250
+ 'side': self.parse_order_side(self.safe_string(order, 'side')),
2251
+ 'price': self.omit_zero(priceString),
2252
+ 'stopPrice': trailingActivationPrice,
2253
+ 'triggerPrice': trailingActivationPrice,
2254
+ 'amount': self.omit_zero(self.safe_string(order, 'size')),
2255
+ 'cost': self.safe_string_2(order, 'filled_notional', 'filledNotional'),
2256
+ 'average': self.safe_string_n(order, ['price_avg', 'priceAvg', 'deal_avg_price']),
2257
+ 'filled': self.safe_string_n(order, ['filled_size', 'filledSize', 'deal_size']),
2258
+ 'remaining': None,
2259
+ 'status': self.parse_order_status_by_type(orderType, self.safe_string_2(order, 'status', 'state')),
2260
+ 'fee': None,
2261
+ 'trades': None,
2262
+ }, market)
2263
+
2264
+ def parse_order_side(self, side):
2265
+ sides: dict = {
2266
+ '1': 'buy',
2267
+ '2': 'buy',
2268
+ '3': 'sell',
2269
+ '4': 'sell',
2270
+ }
2271
+ return self.safe_string(sides, side, side)
2272
+
2273
+ def parse_order_status_by_type(self, type, status):
2274
+ statusesByType: dict = {
2275
+ 'spot': {
2276
+ '1': 'rejected', # Order failure
2277
+ '2': 'open', # Placing order
2278
+ '3': 'rejected', # Order failure, Freeze failure
2279
+ '4': 'open', # Order success, Pending for fulfilment
2280
+ '5': 'open', # Partially filled
2281
+ '6': 'closed', # Fully filled
2282
+ '7': 'canceled', # Canceling
2283
+ '8': 'canceled', # Canceled
2284
+ 'new': 'open',
2285
+ 'partially_filled': 'open',
2286
+ 'filled': 'closed',
2287
+ 'partially_canceled': 'canceled',
2288
+ },
2289
+ 'swap': {
2290
+ '1': 'open', # Submitting
2291
+ '2': 'open', # Commissioned
2292
+ '4': 'closed', # Completed
2293
+ },
2294
+ }
2295
+ statuses = self.safe_value(statusesByType, type, {})
2296
+ return self.safe_string(statuses, status, status)
2297
+
2298
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
2299
+ """
2300
+ create a market buy order by providing the symbol and cost
2301
+ :see: https://developer-pro.bitmart.com/en/spot/#new-order-v2-signed
2302
+ :param str symbol: unified symbol of the market to create an order in
2303
+ :param float cost: how much you want to trade in units of the quote currency
2304
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2305
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2306
+ """
2307
+ await self.load_markets()
2308
+ market = self.market(symbol)
2309
+ if not market['spot']:
2310
+ raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
2311
+ params['createMarketBuyOrderRequiresPrice'] = False
2312
+ return await self.create_order(symbol, 'market', 'buy', cost, None, params)
2313
+
2314
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2315
+ """
2316
+ create a trade order
2317
+ :see: https://developer-pro.bitmart.com/en/spot/#new-order-v2-signed
2318
+ :see: https://developer-pro.bitmart.com/en/spot/#place-margin-order
2319
+ :see: https://developer-pro.bitmart.com/en/futures/#submit-order-signed
2320
+ :see: https://developer-pro.bitmart.com/en/futures/#submit-plan-order-signed
2321
+ :param str symbol: unified symbol of the market to create an order in
2322
+ :param str type: 'market', 'limit' or 'trailing' for swap markets only
2323
+ :param str side: 'buy' or 'sell'
2324
+ :param float amount: how much of currency you want to trade in units of base currency
2325
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
2326
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2327
+ :param str [params.marginMode]: 'cross' or 'isolated'
2328
+ :param str [params.leverage]: *swap only* leverage level
2329
+ :param str [params.clientOrderId]: client order id of the order
2330
+ :param boolean [params.reduceOnly]: *swap only* reduce only
2331
+ :param boolean [params.postOnly]: make sure the order is posted to the order book and not matched immediately
2332
+ :param str [params.triggerPrice]: *swap only* the price to trigger a stop order
2333
+ :param int [params.price_type]: *swap only* 1: last price, 2: fair price, default is 1
2334
+ :param int [params.price_way]: *swap only* 1: price way long, 2: price way short
2335
+ :param int [params.activation_price_type]: *swap trailing order only* 1: last price, 2: fair price, default is 1
2336
+ :param str [params.trailingPercent]: *swap only* the percent to trail away from the current market price, min 0.1 max 5
2337
+ :param str [params.trailingTriggerPrice]: *swap only* the price to trigger a trailing order, default uses the price argument
2338
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2339
+ """
2340
+ await self.load_markets()
2341
+ market = self.market(symbol)
2342
+ result = self.handle_margin_mode_and_params('createOrder', params)
2343
+ marginMode = self.safe_string(result, 0)
2344
+ triggerPrice = self.safe_string_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
2345
+ isTriggerOrder = triggerPrice is not None
2346
+ response = None
2347
+ if market['spot']:
2348
+ spotRequest = self.create_spot_order_request(symbol, type, side, amount, price, params)
2349
+ if marginMode == 'isolated':
2350
+ response = await self.privatePostSpotV1MarginSubmitOrder(spotRequest)
2351
+ else:
2352
+ response = await self.privatePostSpotV2SubmitOrder(spotRequest)
2353
+ else:
2354
+ swapRequest = self.create_swap_order_request(symbol, type, side, amount, price, params)
2355
+ if isTriggerOrder:
2356
+ response = await self.privatePostContractPrivateSubmitPlanOrder(swapRequest)
2357
+ else:
2358
+ response = await self.privatePostContractPrivateSubmitOrder(swapRequest)
2359
+ #
2360
+ # spot and margin
2361
+ #
2362
+ # {
2363
+ # "code": 1000,
2364
+ # "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
2365
+ # "message": "OK",
2366
+ # "data": {
2367
+ # "order_id": 2707217580
2368
+ # }
2369
+ # }
2370
+ #
2371
+ # swap
2372
+ # {"code":1000,"message":"Ok","data":{"order_id":231116359426639,"price":"market price"},"trace":"7f9c94e10f9d4513bc08a7bfc2a5559a.62.16996369620521911"}
2373
+ #
2374
+ data = self.safe_value(response, 'data', {})
2375
+ order = self.parse_order(data, market)
2376
+ order['type'] = type
2377
+ order['side'] = side
2378
+ order['amount'] = amount
2379
+ order['price'] = price
2380
+ return order
2381
+
2382
+ async def create_orders(self, orders: List[OrderRequest], params={}):
2383
+ """
2384
+ create a list of trade orders
2385
+ :see: https://developer-pro.bitmart.com/en/spot/#new-batch-order-v4-signed
2386
+ :param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
2387
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2388
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2389
+ """
2390
+ await self.load_markets()
2391
+ ordersRequests = []
2392
+ symbol = None
2393
+ market = None
2394
+ for i in range(0, len(orders)):
2395
+ rawOrder = orders[i]
2396
+ marketId = self.safe_string(rawOrder, 'symbol')
2397
+ market = self.market(marketId)
2398
+ if not market['spot']:
2399
+ raise NotSupported(self.id + ' createOrders() supports spot orders only')
2400
+ if symbol is None:
2401
+ symbol = marketId
2402
+ else:
2403
+ if symbol != marketId:
2404
+ raise BadRequest(self.id + ' createOrders() requires all orders to have the same symbol')
2405
+ type = self.safe_string(rawOrder, 'type')
2406
+ side = self.safe_string(rawOrder, 'side')
2407
+ amount = self.safe_value(rawOrder, 'amount')
2408
+ price = self.safe_value(rawOrder, 'price')
2409
+ orderParams = self.safe_dict(rawOrder, 'params', {})
2410
+ orderRequest = self.create_spot_order_request(marketId, type, side, amount, price, orderParams)
2411
+ orderRequest = self.omit(orderRequest, ['symbol']) # not needed because it goes in the outter object
2412
+ ordersRequests.append(orderRequest)
2413
+ request: dict = {
2414
+ 'symbol': market['id'],
2415
+ 'orderParams': ordersRequests,
2416
+ }
2417
+ response = await self.privatePostSpotV4BatchOrders(request)
2418
+ #
2419
+ # {
2420
+ # "message": "OK",
2421
+ # "code": 1000,
2422
+ # "trace": "5fc697fb817a4b5396284786a9b2609a.263.17022620476480263",
2423
+ # "data": {
2424
+ # "code": 0,
2425
+ # "msg": "success",
2426
+ # "data": {
2427
+ # "orderIds": [
2428
+ # "212751308355553320"
2429
+ # ]
2430
+ # }
2431
+ # }
2432
+ # }
2433
+ #
2434
+ data = self.safe_dict(response, 'data', {})
2435
+ innderData = self.safe_dict(data, 'data', {})
2436
+ orderIds = self.safe_list(innderData, 'orderIds', [])
2437
+ parsedOrders = []
2438
+ for i in range(0, len(orderIds)):
2439
+ orderId = orderIds[i]
2440
+ order = self.safe_order({'id': orderId}, market)
2441
+ parsedOrders.append(order)
2442
+ return parsedOrders
2443
+
2444
+ def create_swap_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2445
+ """
2446
+ * @ignore
2447
+ create a trade order
2448
+ :see: https://developer-pro.bitmart.com/en/futures/#submit-order-signed
2449
+ :see: https://developer-pro.bitmart.com/en/futures/#submit-plan-order-signed
2450
+ :param str symbol: unified symbol of the market to create an order in
2451
+ :param str type: 'market', 'limit' or 'trailing'
2452
+ :param str side: 'buy' or 'sell'
2453
+ :param float amount: how much of currency you want to trade in units of base currency
2454
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
2455
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2456
+ :param int [params.leverage]: leverage level
2457
+ :param boolean [params.reduceOnly]: *swap only* reduce only
2458
+ :param str [params.marginMode]: 'cross' or 'isolated', default is 'cross'
2459
+ :param str [params.clientOrderId]: client order id of the order
2460
+ :param str [params.triggerPrice]: *swap only* the price to trigger a stop order
2461
+ :param int [params.price_type]: *swap only* 1: last price, 2: fair price, default is 1
2462
+ :param int [params.price_way]: *swap only* 1: price way long, 2: price way short
2463
+ :param int [params.activation_price_type]: *swap trailing order only* 1: last price, 2: fair price, default is 1
2464
+ :param str [params.trailingPercent]: *swap only* the percent to trail away from the current market price, min 0.1 max 5
2465
+ :param str [params.trailingTriggerPrice]: *swap only* the price to trigger a trailing order, default uses the price argument
2466
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2467
+ """
2468
+ market = self.market(symbol)
2469
+ request: dict = {
2470
+ 'symbol': market['id'],
2471
+ 'type': type,
2472
+ 'size': int(self.amount_to_precision(symbol, amount)),
2473
+ }
2474
+ timeInForce = self.safe_string(params, 'timeInForce')
2475
+ mode = self.safe_integer(params, 'mode') # only for swap
2476
+ isMarketOrder = type == 'market'
2477
+ postOnly = None
2478
+ reduceOnly = self.safe_value(params, 'reduceOnly')
2479
+ isExchangeSpecificPo = (mode == 4)
2480
+ postOnly, params = self.handle_post_only(isMarketOrder, isExchangeSpecificPo, params)
2481
+ ioc = ((timeInForce == 'IOC') or (mode == 3))
2482
+ isLimitOrder = (type == 'limit') or postOnly or ioc
2483
+ if timeInForce == 'GTC':
2484
+ request['mode'] = 1
2485
+ elif timeInForce == 'FOK':
2486
+ request['mode'] = 2
2487
+ elif timeInForce == 'IOC':
2488
+ request['mode'] = 3
2489
+ if postOnly:
2490
+ request['mode'] = 4
2491
+ triggerPrice = self.safe_string_n(params, ['triggerPrice', 'stopPrice', 'trigger_price'])
2492
+ isTriggerOrder = triggerPrice is not None
2493
+ trailingTriggerPrice = self.safe_string_2(params, 'trailingTriggerPrice', 'activation_price', self.number_to_string(price))
2494
+ trailingPercent = self.safe_string_2(params, 'trailingPercent', 'callback_rate')
2495
+ isTrailingPercentOrder = trailingPercent is not None
2496
+ if isLimitOrder:
2497
+ request['price'] = self.price_to_precision(symbol, price)
2498
+ elif type == 'trailing' or isTrailingPercentOrder:
2499
+ request['callback_rate'] = trailingPercent
2500
+ request['activation_price'] = self.price_to_precision(symbol, trailingTriggerPrice)
2501
+ request['activation_price_type'] = self.safe_integer(params, 'activation_price_type', 1)
2502
+ if isTriggerOrder:
2503
+ request['executive_price'] = self.price_to_precision(symbol, price)
2504
+ request['trigger_price'] = self.price_to_precision(symbol, triggerPrice)
2505
+ request['price_type'] = self.safe_integer(params, 'price_type', 1)
2506
+ if side == 'buy':
2507
+ if reduceOnly:
2508
+ request['price_way'] = 2
2509
+ else:
2510
+ request['price_way'] = 1
2511
+ elif side == 'sell':
2512
+ if reduceOnly:
2513
+ request['price_way'] = 1
2514
+ else:
2515
+ request['price_way'] = 2
2516
+ if side == 'buy':
2517
+ if reduceOnly:
2518
+ request['side'] = 2 # buy close short
2519
+ else:
2520
+ request['side'] = 1 # buy open long
2521
+ elif side == 'sell':
2522
+ if reduceOnly:
2523
+ request['side'] = 3 # sell close long
2524
+ else:
2525
+ request['side'] = 4 # sell open short
2526
+ marginMode = None
2527
+ marginMode, params = self.handle_margin_mode_and_params('createOrder', params, 'cross')
2528
+ request['open_type'] = marginMode
2529
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2530
+ if clientOrderId is not None:
2531
+ params = self.omit(params, 'clientOrderId')
2532
+ request['client_order_id'] = clientOrderId
2533
+ leverage = self.safe_integer(params, 'leverage', 1)
2534
+ params = self.omit(params, ['timeInForce', 'postOnly', 'reduceOnly', 'leverage', 'trailingTriggerPrice', 'trailingPercent', 'triggerPrice', 'stopPrice'])
2535
+ request['leverage'] = self.number_to_string(leverage)
2536
+ return self.extend(request, params)
2537
+
2538
+ def create_spot_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
2539
+ """
2540
+ * @ignore
2541
+ create a spot order request
2542
+ :see: https://developer-pro.bitmart.com/en/spot/#place-spot-order
2543
+ :see: https://developer-pro.bitmart.com/en/spot/#place-margin-order
2544
+ :param str symbol: unified symbol of the market to create an order in
2545
+ :param str type: 'market' or 'limit'
2546
+ :param str side: 'buy' or 'sell'
2547
+ :param float amount: how much of currency you want to trade in units of base currency
2548
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
2549
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2550
+ :param str [params.marginMode]: 'cross' or 'isolated'
2551
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2552
+ """
2553
+ market = self.market(symbol)
2554
+ request: dict = {
2555
+ 'symbol': market['id'],
2556
+ 'side': side,
2557
+ 'type': type,
2558
+ }
2559
+ timeInForce = self.safe_string(params, 'timeInForce')
2560
+ if timeInForce == 'FOK':
2561
+ raise InvalidOrder(self.id + ' createOrder() only accepts timeInForce parameter values of IOC or PO')
2562
+ mode = self.safe_integer(params, 'mode') # only for swap
2563
+ isMarketOrder = type == 'market'
2564
+ postOnly = None
2565
+ isExchangeSpecificPo = (type == 'limit_maker') or (mode == 4)
2566
+ postOnly, params = self.handle_post_only(isMarketOrder, isExchangeSpecificPo, params)
2567
+ params = self.omit(params, ['timeInForce', 'postOnly'])
2568
+ ioc = ((timeInForce == 'IOC') or (type == 'ioc'))
2569
+ isLimitOrder = (type == 'limit') or postOnly or ioc
2570
+ # method = 'privatePostSpotV2SubmitOrder'
2571
+ if isLimitOrder:
2572
+ request['size'] = self.amount_to_precision(symbol, amount)
2573
+ request['price'] = self.price_to_precision(symbol, price)
2574
+ elif isMarketOrder:
2575
+ # for market buy it requires the amount of quote currency to spend
2576
+ if side == 'buy':
2577
+ notional = self.safe_string_2(params, 'cost', 'notional')
2578
+ params = self.omit(params, 'cost')
2579
+ createMarketBuyOrderRequiresPrice = True
2580
+ createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
2581
+ if createMarketBuyOrderRequiresPrice:
2582
+ if (price is None) and (notional is None):
2583
+ raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend in the amount argument or in the "notional" extra parameter(the exchange-specific behaviour)')
2584
+ else:
2585
+ amountString = self.number_to_string(amount)
2586
+ priceString = self.number_to_string(price)
2587
+ notional = Precise.string_mul(amountString, priceString)
2588
+ else:
2589
+ notional = self.number_to_string(amount) if (notional is None) else notional
2590
+ request['notional'] = self.decimal_to_precision(notional, TRUNCATE, market['precision']['price'], self.precisionMode)
2591
+ elif side == 'sell':
2592
+ request['size'] = self.amount_to_precision(symbol, amount)
2593
+ if postOnly:
2594
+ request['type'] = 'limit_maker'
2595
+ if ioc:
2596
+ request['type'] = 'ioc'
2597
+ clientOrderId = self.safe_string(params, 'clientOrderId')
2598
+ if clientOrderId is not None:
2599
+ params = self.omit(params, 'clientOrderId')
2600
+ request['client_order_id'] = clientOrderId
2601
+ return self.extend(request, params)
2602
+
2603
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
2604
+ """
2605
+ cancels an open order
2606
+ :see: https://developer-pro.bitmart.com/en/futures/#cancel-order-signed
2607
+ :see: https://developer-pro.bitmart.com/en/spot/#cancel-order-v3-signed
2608
+ :see: https://developer-pro.bitmart.com/en/futures/#cancel-plan-order-signed
2609
+ :see: https://developer-pro.bitmart.com/en/futures/#cancel-plan-order-signed
2610
+ :param str id: order id
2611
+ :param str symbol: unified symbol of the market the order was made in
2612
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2613
+ :param str [params.clientOrderId]: *spot only* the client order id of the order to cancel
2614
+ :param boolean [params.stop]: *swap only* whether the order is a stop order
2615
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2616
+ """
2617
+ if symbol is None:
2618
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
2619
+ await self.load_markets()
2620
+ market = self.market(symbol)
2621
+ request: dict = {
2622
+ 'symbol': market['id'],
2623
+ }
2624
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'client_order_id')
2625
+ if clientOrderId is not None:
2626
+ request['client_order_id'] = clientOrderId
2627
+ else:
2628
+ request['order_id'] = str(id)
2629
+ params = self.omit(params, ['clientOrderId'])
2630
+ response = None
2631
+ if market['spot']:
2632
+ response = await self.privatePostSpotV3CancelOrder(self.extend(request, params))
2633
+ else:
2634
+ stop = self.safe_value_2(params, 'stop', 'trigger')
2635
+ params = self.omit(params, ['stop', 'trigger'])
2636
+ if not stop:
2637
+ response = await self.privatePostContractPrivateCancelOrder(self.extend(request, params))
2638
+ else:
2639
+ response = await self.privatePostContractPrivateCancelPlanOrder(self.extend(request, params))
2640
+ # swap
2641
+ # {"code":1000,"message":"Ok","trace":"7f9c94e10f9d4513bc08a7bfc2a5559a.55.16959817848001851"}
2642
+ #
2643
+ # spot
2644
+ #
2645
+ # {
2646
+ # "code": 1000,
2647
+ # "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
2648
+ # "message": "OK",
2649
+ # "data": {
2650
+ # "result": True
2651
+ # }
2652
+ # }
2653
+ #
2654
+ # spot alternative
2655
+ #
2656
+ # {
2657
+ # "code": 1000,
2658
+ # "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
2659
+ # "message": "OK",
2660
+ # "data": True
2661
+ # }
2662
+ #
2663
+ if market['swap']:
2664
+ return response
2665
+ data = self.safe_value(response, 'data')
2666
+ if data is True:
2667
+ return self.safe_order({'id': id}, market)
2668
+ succeeded = self.safe_value(data, 'succeed')
2669
+ if succeeded is not None:
2670
+ id = self.safe_string(succeeded, 0)
2671
+ if id is None:
2672
+ raise InvalidOrder(self.id + ' cancelOrder() failed to cancel ' + symbol + ' order id ' + id)
2673
+ else:
2674
+ result = self.safe_value(data, 'result')
2675
+ if not result:
2676
+ raise InvalidOrder(self.id + ' cancelOrder() ' + symbol + ' order id ' + id + ' is filled or canceled')
2677
+ order = self.safe_order({'id': id, 'symbol': market['symbol'], 'info': {}}, market)
2678
+ return order
2679
+
2680
+ async def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
2681
+ """
2682
+ cancel multiple orders
2683
+ :see: https://developer-pro.bitmart.com/en/spot/#cancel-batch-order-v4-signed
2684
+ :param str[] ids: order ids
2685
+ :param str symbol: unified symbol of the market the order was made in
2686
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2687
+ :param str[] [params.clientOrderIds]: client order ids
2688
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2689
+ """
2690
+ if symbol is None:
2691
+ raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
2692
+ await self.load_markets()
2693
+ market = self.market(symbol)
2694
+ if not market['spot']:
2695
+ raise NotSupported(self.id + ' cancelOrders() does not support ' + market['type'] + ' orders, only spot orders are accepted')
2696
+ clientOrderIds = self.safe_list(params, 'clientOrderIds')
2697
+ params = self.omit(params, ['clientOrderIds'])
2698
+ request: dict = {
2699
+ 'symbol': market['id'],
2700
+ }
2701
+ if clientOrderIds is not None:
2702
+ request['clientOrderIds'] = clientOrderIds
2703
+ else:
2704
+ request['orderIds'] = ids
2705
+ response = await self.privatePostSpotV4CancelOrders(self.extend(request, params))
2706
+ #
2707
+ # {
2708
+ # "message": "OK",
2709
+ # "code": 1000,
2710
+ # "trace": "c4edbce860164203954f7c3c81d60fc6.309.17022669632770001",
2711
+ # "data": {
2712
+ # "successIds": [
2713
+ # "213055379155243012"
2714
+ # ],
2715
+ # "failIds": [],
2716
+ # "totalCount": 1,
2717
+ # "successCount": 1,
2718
+ # "failedCount": 0
2719
+ # }
2720
+ # }
2721
+ #
2722
+ data = self.safe_dict(response, 'data', {})
2723
+ allOrders = []
2724
+ successIds = self.safe_list(data, 'successIds', [])
2725
+ for i in range(0, len(successIds)):
2726
+ id = successIds[i]
2727
+ allOrders.append(self.safe_order({'id': id, 'status': 'canceled'}, market))
2728
+ failIds = self.safe_list(data, 'failIds', [])
2729
+ for i in range(0, len(failIds)):
2730
+ id = failIds[i]
2731
+ allOrders.append(self.safe_order({'id': id, 'status': 'failed'}, market))
2732
+ return allOrders
2733
+
2734
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
2735
+ """
2736
+ cancel all open orders in a market
2737
+ :see: https://developer-pro.bitmart.com/en/spot/#cancel-all-orders
2738
+ :see: https://developer-pro.bitmart.com/en/futures/#cancel-all-orders-signed
2739
+ :param str symbol: unified market symbol of the market to cancel orders in
2740
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2741
+ :param str [params.side]: *spot only* 'buy' or 'sell'
2742
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2743
+ """
2744
+ await self.load_markets()
2745
+ request: dict = {}
2746
+ market = None
2747
+ if symbol is not None:
2748
+ market = self.market(symbol)
2749
+ request['symbol'] = market['id']
2750
+ response = None
2751
+ type = None
2752
+ type, params = self.handle_market_type_and_params('cancelAllOrders', market, params)
2753
+ if type == 'spot':
2754
+ response = await self.privatePostSpotV1CancelOrders(self.extend(request, params))
2755
+ elif type == 'swap':
2756
+ if symbol is None:
2757
+ raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
2758
+ response = await self.privatePostContractPrivateCancelOrders(self.extend(request, params))
2759
+ #
2760
+ # spot
2761
+ #
2762
+ # {
2763
+ # "code": 1000,
2764
+ # "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
2765
+ # "message": "OK",
2766
+ # "data": {}
2767
+ # }
2768
+ #
2769
+ # swap
2770
+ #
2771
+ # {
2772
+ # "code": 1000,
2773
+ # "message": "Ok",
2774
+ # "trace": "7f9c94e10f9d4513bc08a7bfc2a5559a.70.16954131323145323"
2775
+ # }
2776
+ #
2777
+ return response
2778
+
2779
+ async def fetch_orders_by_status(self, status, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2780
+ if symbol is None:
2781
+ raise ArgumentsRequired(self.id + ' fetchOrdersByStatus() requires a symbol argument')
2782
+ await self.load_markets()
2783
+ market = self.market(symbol)
2784
+ if not market['spot']:
2785
+ raise NotSupported(self.id + ' fetchOrdersByStatus() does not support ' + market['type'] + ' orders, only spot orders are accepted')
2786
+ request: dict = {
2787
+ 'symbol': market['id'],
2788
+ 'offset': 1, # max offset * limit < 500
2789
+ 'N': 100, # max limit is 100
2790
+ }
2791
+ if status == 'open':
2792
+ request['status'] = 9
2793
+ elif status == 'closed':
2794
+ request['status'] = 6
2795
+ elif status == 'canceled':
2796
+ request['status'] = 8
2797
+ else:
2798
+ request['status'] = status
2799
+ response = await self.privateGetSpotV3Orders(self.extend(request, params))
2800
+ #
2801
+ # spot
2802
+ #
2803
+ # {
2804
+ # "message":"OK",
2805
+ # "code":1000,
2806
+ # "trace":"70e7d427-7436-4fb8-8cdd-97e1f5eadbe9",
2807
+ # "data":{
2808
+ # "current_page":1,
2809
+ # "orders":[
2810
+ # {
2811
+ # "order_id":2147601241,
2812
+ # "symbol":"BTC_USDT",
2813
+ # "create_time":1591099963000,
2814
+ # "side":"sell",
2815
+ # "type":"limit",
2816
+ # "price":"9000.00",
2817
+ # "price_avg":"0.00",
2818
+ # "size":"1.00000",
2819
+ # "notional":"9000.00000000",
2820
+ # "filled_notional":"0.00000000",
2821
+ # "filled_size":"0.00000",
2822
+ # "status":"4"
2823
+ # }
2824
+ # ]
2825
+ # }
2826
+ # }
2827
+ #
2828
+ data = self.safe_value(response, 'data', {})
2829
+ orders = self.safe_list(data, 'orders', [])
2830
+ return self.parse_orders(orders, market, since, limit)
2831
+
2832
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2833
+ """
2834
+ :see: https://developer-pro.bitmart.com/en/spot/#current-open-orders-v4-signed
2835
+ :see: https://developer-pro.bitmart.com/en/futures/#get-all-open-orders-keyed
2836
+ :see: https://developer-pro.bitmart.com/en/futures/#get-all-current-plan-orders-keyed
2837
+ fetch all unfilled currently open orders
2838
+ :param str symbol: unified market symbol
2839
+ :param int [since]: the earliest time in ms to fetch open orders for
2840
+ :param int [limit]: the maximum number of open order structures to retrieve
2841
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2842
+ :param boolean [params.marginMode]: *spot* whether to fetch trades for margin orders or spot orders, defaults to spot orders(only isolated margin orders are supported)
2843
+ :param int [params.until]: *spot* the latest time in ms to fetch orders for
2844
+ :param str [params.type]: *swap* order type, 'limit' or 'market'
2845
+ :param str [params.order_state]: *swap* the order state, 'all' or 'partially_filled', default is 'all'
2846
+ :param str [params.orderType]: *swap only* 'limit', 'market', or 'trailing'
2847
+ :param boolean [params.trailing]: *swap only* set to True if you want to fetch trailing orders
2848
+ :param boolean [params.trigger]: *swap only* set to True if you want to fetch trigger orders
2849
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2850
+ """
2851
+ await self.load_markets()
2852
+ market = None
2853
+ request: dict = {}
2854
+ if symbol is not None:
2855
+ market = self.market(symbol)
2856
+ request['symbol'] = market['id']
2857
+ if limit is not None:
2858
+ request['limit'] = limit
2859
+ type = None
2860
+ response = None
2861
+ type, params = self.handle_market_type_and_params('fetchOpenOrders', market, params)
2862
+ if type == 'spot':
2863
+ marginMode = None
2864
+ marginMode, params = self.handle_margin_mode_and_params('fetchOpenOrders', params)
2865
+ if marginMode == 'isolated':
2866
+ request['orderMode'] = 'iso_margin'
2867
+ if since is not None:
2868
+ request['startTime'] = since
2869
+ until = self.safe_integer_2(params, 'until', 'endTime')
2870
+ if until is not None:
2871
+ params = self.omit(params, ['endTime'])
2872
+ request['endTime'] = until
2873
+ response = await self.privatePostSpotV4QueryOpenOrders(self.extend(request, params))
2874
+ elif type == 'swap':
2875
+ isStop = self.safe_value_2(params, 'stop', 'trigger')
2876
+ params = self.omit(params, ['stop', 'trigger'])
2877
+ if isStop:
2878
+ response = await self.privateGetContractPrivateCurrentPlanOrder(self.extend(request, params))
2879
+ else:
2880
+ trailing = self.safe_bool(params, 'trailing', False)
2881
+ orderType = self.safe_string(params, 'orderType')
2882
+ params = self.omit(params, ['orderType', 'trailing'])
2883
+ if trailing:
2884
+ orderType = 'trailing'
2885
+ if orderType is not None:
2886
+ request['type'] = orderType
2887
+ response = await self.privateGetContractPrivateGetOpenOrders(self.extend(request, params))
2888
+ else:
2889
+ raise NotSupported(self.id + ' fetchOpenOrders() does not support ' + type + ' orders, only spot and swap orders are accepted')
2890
+ #
2891
+ # spot
2892
+ #
2893
+ # {
2894
+ # "code": 1000,
2895
+ # "message": "success",
2896
+ # "data": [
2897
+ # {
2898
+ # "orderId": "183299373022163211",
2899
+ # "clientOrderId": "183299373022163211",
2900
+ # "symbol": "BTC_USDT",
2901
+ # "side": "buy",
2902
+ # "orderMode": "spot",
2903
+ # "type": "limit",
2904
+ # "state": "new",
2905
+ # "price": "25000.00",
2906
+ # "priceAvg": "0.00",
2907
+ # "size": "0.00020",
2908
+ # "filledSize": "0.00000",
2909
+ # "notional": "5.00000000",
2910
+ # "filledNotional": "0.00000000",
2911
+ # "createTime": 1695703703338,
2912
+ # "updateTime": 1695703703359
2913
+ # }
2914
+ # ],
2915
+ # "trace": "15f11d48e3234c81a2e786cr2e7a38e6.71.16957022303515933"
2916
+ # }
2917
+ #
2918
+ # swap
2919
+ #
2920
+ # {
2921
+ # "code": 1000,
2922
+ # "message": "Ok",
2923
+ # "data": [
2924
+ # {
2925
+ # "order_id": "230935812485489",
2926
+ # "client_order_id": "",
2927
+ # "price": "24000",
2928
+ # "size": "1",
2929
+ # "symbol": "BTCUSDT",
2930
+ # "state": 2,
2931
+ # "side": 1,
2932
+ # "type": "limit",
2933
+ # "leverage": "10",
2934
+ # "open_type": "isolated",
2935
+ # "deal_avg_price": "0",
2936
+ # "deal_size": "0",
2937
+ # "create_time": 1695702258629,
2938
+ # "update_time": 1695702258642
2939
+ # }
2940
+ # ],
2941
+ # "trace": "7f9d94g10f9d4513bc08a7rfc3a5559a.71.16957022303515933"
2942
+ # }
2943
+ #
2944
+ data = self.safe_list(response, 'data', [])
2945
+ return self.parse_orders(data, market, since, limit)
2946
+
2947
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2948
+ """
2949
+ :see: https://developer-pro.bitmart.com/en/spot/#account-orders-v4-signed
2950
+ :see: https://developer-pro.bitmart.com/en/futures/#get-order-history-keyed
2951
+ fetches information on multiple closed orders made by the user
2952
+ :param str symbol: unified market symbol of the market orders were made in
2953
+ :param int [since]: the earliest time in ms to fetch orders for
2954
+ :param int [limit]: the maximum number of order structures to retrieve
2955
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2956
+ :param int [params.until]: timestamp in ms of the latest entry
2957
+ :param str [params.marginMode]: *spot only* 'cross' or 'isolated', for margin trading
2958
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2959
+ """
2960
+ await self.load_markets()
2961
+ market = None
2962
+ request: dict = {}
2963
+ if symbol is not None:
2964
+ market = self.market(symbol)
2965
+ request['symbol'] = market['id']
2966
+ type = None
2967
+ type, params = self.handle_market_type_and_params('fetchClosedOrders', market, params)
2968
+ if type != 'spot':
2969
+ if symbol is None:
2970
+ raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
2971
+ marginMode = None
2972
+ marginMode, params = self.handle_margin_mode_and_params('fetchClosedOrders', params)
2973
+ if marginMode == 'isolated':
2974
+ request['orderMode'] = 'iso_margin'
2975
+ startTimeKey = 'startTime' if (type == 'spot') else 'start_time'
2976
+ if since is not None:
2977
+ request[startTimeKey] = since
2978
+ endTimeKey = 'endTime' if (type == 'spot') else 'end_time'
2979
+ until = self.safe_integer_2(params, 'until', endTimeKey)
2980
+ if until is not None:
2981
+ params = self.omit(params, ['until'])
2982
+ request[endTimeKey] = until
2983
+ response = None
2984
+ if type == 'spot':
2985
+ response = await self.privatePostSpotV4QueryHistoryOrders(self.extend(request, params))
2986
+ else:
2987
+ response = await self.privateGetContractPrivateOrderHistory(self.extend(request, params))
2988
+ data = self.safe_list(response, 'data', [])
2989
+ return self.parse_orders(data, market, since, limit)
2990
+
2991
+ async def fetch_canceled_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
2992
+ """
2993
+ fetches information on multiple canceled orders made by the user
2994
+ :param str symbol: unified market symbol of the market orders were made in
2995
+ :param int [since]: timestamp in ms of the earliest order, default is None
2996
+ :param int [limit]: max number of orders to return, default is None
2997
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2998
+ :returns dict: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2999
+ """
3000
+ return await self.fetch_orders_by_status('canceled', symbol, since, limit, params)
3001
+
3002
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
3003
+ """
3004
+ fetches information on an order made by the user
3005
+ :see: https://developer-pro.bitmart.com/en/spot/#query-order-by-id-v4-signed
3006
+ :see: https://developer-pro.bitmart.com/en/spot/#query-order-by-clientorderid-v4-signed
3007
+ :see: https://developer-pro.bitmart.com/en/futures/#get-order-detail-keyed
3008
+ :param str id: the id of the order
3009
+ :param str symbol: unified symbol of the market the order was made in
3010
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3011
+ :param str [params.clientOrderId]: *spot* fetch the order by client order id instead of order id
3012
+ :param str [params.orderType]: *swap only* 'limit', 'market', 'liquidate', 'bankruptcy', 'adl' or 'trailing'
3013
+ :param boolean [params.trailing]: *swap only* set to True if you want to fetch a trailing order
3014
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3015
+ """
3016
+ await self.load_markets()
3017
+ request: dict = {}
3018
+ type = None
3019
+ market = None
3020
+ response = None
3021
+ if symbol is not None:
3022
+ market = self.market(symbol)
3023
+ type, params = self.handle_market_type_and_params('fetchOrder', market, params)
3024
+ if type == 'spot':
3025
+ clientOrderId = self.safe_string(params, 'clientOrderId')
3026
+ if not clientOrderId:
3027
+ request['orderId'] = id
3028
+ if clientOrderId is not None:
3029
+ response = await self.privatePostSpotV4QueryClientOrder(self.extend(request, params))
3030
+ else:
3031
+ response = await self.privatePostSpotV4QueryOrder(self.extend(request, params))
3032
+ elif type == 'swap':
3033
+ if symbol is None:
3034
+ raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
3035
+ trailing = self.safe_bool(params, 'trailing', False)
3036
+ orderType = self.safe_string(params, 'orderType')
3037
+ params = self.omit(params, ['orderType', 'trailing'])
3038
+ if trailing:
3039
+ orderType = 'trailing'
3040
+ if orderType is not None:
3041
+ request['type'] = orderType
3042
+ request['symbol'] = market['id']
3043
+ request['order_id'] = id
3044
+ response = await self.privateGetContractPrivateOrder(self.extend(request, params))
3045
+ #
3046
+ # spot
3047
+ #
3048
+ # {
3049
+ # "code": 1000,
3050
+ # "message": "success",
3051
+ # "data": {
3052
+ # "orderId": "183347420821295423",
3053
+ # "clientOrderId": "183347420821295423",
3054
+ # "symbol": "BTC_USDT",
3055
+ # "side": "buy",
3056
+ # "orderMode": "spot",
3057
+ # "type": "limit",
3058
+ # "state": "new",
3059
+ # "price": "24000.00",
3060
+ # "priceAvg": "0.00",
3061
+ # "size": "0.00022",
3062
+ # "filledSize": "0.00000",
3063
+ # "notional": "5.28000000",
3064
+ # "filledNotional": "0.00000000",
3065
+ # "createTime": 1695783014734,
3066
+ # "updateTime": 1695783014762
3067
+ # },
3068
+ # "trace": "ce3e6422c8b44d5fag855348a68693ed.63.14957831547451715"
3069
+ # }
3070
+ #
3071
+ # swap
3072
+ #
3073
+ # {
3074
+ # "code": 1000,
3075
+ # "message": "Ok",
3076
+ # "data": {
3077
+ # "order_id": "230927283405028",
3078
+ # "client_order_id": "",
3079
+ # "price": "23000",
3080
+ # "size": "1",
3081
+ # "symbol": "BTCUSDT",
3082
+ # "state": 2,
3083
+ # "side": 1,
3084
+ # "type": "limit",
3085
+ # "leverage": "10",
3086
+ # "open_type": "isolated",
3087
+ # "deal_avg_price": "0",
3088
+ # "deal_size": "0",
3089
+ # "create_time": 1695783433600,
3090
+ # "update_time": 1695783433613
3091
+ # },
3092
+ # "trace": "4cad855075664097af6ba5257c47605d.63.14957831547451715"
3093
+ # }
3094
+ #
3095
+ data = self.safe_dict(response, 'data', {})
3096
+ return self.parse_order(data, market)
3097
+
3098
+ async def fetch_deposit_address(self, code: str, params={}):
3099
+ """
3100
+ fetch the deposit address for a currency associated with self account
3101
+ :see: https://developer-pro.bitmart.com/en/spot/#deposit-address-keyed
3102
+ :param str code: unified currency code
3103
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3104
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
3105
+ """
3106
+ await self.load_markets()
3107
+ currency = self.currency(code)
3108
+ request: dict = {
3109
+ 'currency': currency['id'],
3110
+ }
3111
+ if code == 'USDT':
3112
+ defaultNetworks = self.safe_value(self.options, 'defaultNetworks')
3113
+ defaultNetwork = self.safe_string_upper(defaultNetworks, code)
3114
+ networks = self.safe_value(self.options, 'networks', {})
3115
+ networkInner = self.safe_string_upper(params, 'network', defaultNetwork) # self line allows the user to specify either ERC20 or ETH
3116
+ networkInner = self.safe_string(networks, networkInner, networkInner) # handle ERC20>ETH alias
3117
+ if networkInner is not None:
3118
+ request['currency'] = request['currency'] + '-' + networkInner # when network the currency need to be changed to currency + '-' + network https://developer-pro.bitmart.com/en/account/withdraw_apply.html on the end of page
3119
+ params = self.omit(params, 'network')
3120
+ response = await self.privateGetAccountV1DepositAddress(self.extend(request, params))
3121
+ #
3122
+ # {
3123
+ # "message": "OK",
3124
+ # "code": 1000,
3125
+ # "trace": "0e6edd79-f77f-4251-abe5-83ba75d06c1a",
3126
+ # "data": {
3127
+ # currency: 'ETH',
3128
+ # chain: 'Ethereum',
3129
+ # address: '0x99B5EEc2C520f86F0F62F05820d28D05D36EccCf',
3130
+ # address_memo: ''
3131
+ # }
3132
+ # }
3133
+ #
3134
+ data = self.safe_dict(response, 'data', {})
3135
+ return self.parse_deposit_address(data, currency)
3136
+
3137
+ def parse_deposit_address(self, depositAddress, currency=None):
3138
+ #
3139
+ # {
3140
+ # currency: 'ETH',
3141
+ # chain: 'Ethereum',
3142
+ # address: '0x99B5EEc2C520f86F0F62F05820d28D05D36EccCf',
3143
+ # address_memo: ''
3144
+ # }
3145
+ #
3146
+ currencyId = self.safe_string(depositAddress, 'currency')
3147
+ address = self.safe_string(depositAddress, 'address')
3148
+ chain = self.safe_string(depositAddress, 'chain')
3149
+ network = None
3150
+ currency = self.safe_currency(currencyId, currency)
3151
+ if chain is not None:
3152
+ parts = chain.split('-')
3153
+ partsLength = len(parts)
3154
+ networkId = self.safe_string(parts, partsLength - 1)
3155
+ network = self.safe_network_code(networkId, currency)
3156
+ self.check_address(address)
3157
+ return {
3158
+ 'info': depositAddress,
3159
+ 'currency': self.safe_string(currency, 'code'),
3160
+ 'address': address,
3161
+ 'tag': self.safe_string(depositAddress, 'address_memo'),
3162
+ 'network': network,
3163
+ }
3164
+
3165
+ def safe_network_code(self, networkId, currency=None):
3166
+ name = self.safe_string(currency, 'name')
3167
+ if networkId == name:
3168
+ code = self.safe_string(currency, 'code')
3169
+ return code
3170
+ return self.network_id_to_code(networkId)
3171
+
3172
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
3173
+ """
3174
+ make a withdrawal
3175
+ :param str code: unified currency code
3176
+ :param float amount: the amount to withdraw
3177
+ :param str address: the address to withdraw to
3178
+ :param str tag:
3179
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3180
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
3181
+ """
3182
+ tag, params = self.handle_withdraw_tag_and_params(tag, params)
3183
+ self.check_address(address)
3184
+ await self.load_markets()
3185
+ currency = self.currency(code)
3186
+ request: dict = {
3187
+ 'currency': currency['id'],
3188
+ 'amount': amount,
3189
+ 'destination': 'To Digital Address', # To Digital Address, To Binance, To OKEX
3190
+ 'address': address,
3191
+ }
3192
+ if tag is not None:
3193
+ request['address_memo'] = tag
3194
+ if code == 'USDT':
3195
+ defaultNetworks = self.safe_value(self.options, 'defaultNetworks')
3196
+ defaultNetwork = self.safe_string_upper(defaultNetworks, code)
3197
+ networks = self.safe_value(self.options, 'networks', {})
3198
+ network = self.safe_string_upper(params, 'network', defaultNetwork) # self line allows the user to specify either ERC20 or ETH
3199
+ network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
3200
+ if network is not None:
3201
+ request['currency'] = request['currency'] + '-' + network # when network the currency need to be changed to currency + '-' + network https://developer-pro.bitmart.com/en/account/withdraw_apply.html on the end of page
3202
+ params = self.omit(params, 'network')
3203
+ response = await self.privatePostAccountV1WithdrawApply(self.extend(request, params))
3204
+ #
3205
+ # {
3206
+ # "code": 1000,
3207
+ # "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
3208
+ # "message": "OK",
3209
+ # "data": {
3210
+ # "withdraw_id": "121212"
3211
+ # }
3212
+ # }
3213
+ #
3214
+ data = self.safe_value(response, 'data')
3215
+ transaction = self.parse_transaction(data, currency)
3216
+ return self.extend(transaction, {
3217
+ 'code': code,
3218
+ 'address': address,
3219
+ 'tag': tag,
3220
+ })
3221
+
3222
+ async def fetch_transactions_by_type(self, type, code: Str = None, since: Int = None, limit: Int = None, params={}):
3223
+ await self.load_markets()
3224
+ if limit is None:
3225
+ limit = 50 # max 50
3226
+ request: dict = {
3227
+ 'operation_type': type, # deposit or withdraw
3228
+ 'offset': 1,
3229
+ 'N': limit,
3230
+ }
3231
+ currency = None
3232
+ if code is not None:
3233
+ currency = self.currency(code)
3234
+ request['currency'] = currency['id']
3235
+ if code == 'USDT':
3236
+ defaultNetworks = self.safe_value(self.options, 'defaultNetworks')
3237
+ defaultNetwork = self.safe_string_upper(defaultNetworks, code)
3238
+ networks = self.safe_value(self.options, 'networks', {})
3239
+ network = self.safe_string_upper(params, 'network', defaultNetwork) # self line allows the user to specify either ERC20 or ETH
3240
+ network = self.safe_string(networks, network, network) # handle ERC20>ETH alias
3241
+ if network is not None:
3242
+ request['currency'] += '-' + network # when network the currency need to be changed to currency + '-' + network https://developer-pro.bitmart.com/en/account/withdraw_apply.html on the end of page
3243
+ currency['code'] = request['currency'] # update currency code to filter
3244
+ params = self.omit(params, 'network')
3245
+ response = await self.privateGetAccountV2DepositWithdrawHistory(self.extend(request, params))
3246
+ #
3247
+ # {
3248
+ # "message":"OK",
3249
+ # "code":1000,
3250
+ # "trace":"142bf92a-fc50-4689-92b6-590886f90b97",
3251
+ # "data":{
3252
+ # "records":[
3253
+ # {
3254
+ # "withdraw_id":"1679952",
3255
+ # "deposit_id":"",
3256
+ # "operation_type":"withdraw",
3257
+ # "currency":"BMX",
3258
+ # "apply_time":1588867374000,
3259
+ # "arrival_amount":"59.000000000000",
3260
+ # "fee":"1.000000000000",
3261
+ # "status":0,
3262
+ # "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
3263
+ # "address_memo":"",
3264
+ # "tx_id":""
3265
+ # },
3266
+ # ]
3267
+ # }
3268
+ # }
3269
+ #
3270
+ data = self.safe_value(response, 'data', {})
3271
+ records = self.safe_list(data, 'records', [])
3272
+ return self.parse_transactions(records, currency, since, limit)
3273
+
3274
+ async def fetch_deposit(self, id: str, code: Str = None, params={}):
3275
+ """
3276
+ fetch information on a deposit
3277
+ :param str id: deposit id
3278
+ :param str code: not used by bitmart fetchDeposit()
3279
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3280
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
3281
+ """
3282
+ await self.load_markets()
3283
+ request: dict = {
3284
+ 'id': id,
3285
+ }
3286
+ response = await self.privateGetAccountV1DepositWithdrawDetail(self.extend(request, params))
3287
+ #
3288
+ # {
3289
+ # "message":"OK",
3290
+ # "code":1000,
3291
+ # "trace":"f7f74924-14da-42a6-b7f2-d3799dd9a612",
3292
+ # "data":{
3293
+ # "record":{
3294
+ # "withdraw_id":"",
3295
+ # "deposit_id":"1679952",
3296
+ # "operation_type":"deposit",
3297
+ # "currency":"BMX",
3298
+ # "apply_time":1588867374000,
3299
+ # "arrival_amount":"59.000000000000",
3300
+ # "fee":"1.000000000000",
3301
+ # "status":0,
3302
+ # "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
3303
+ # "address_memo":"",
3304
+ # "tx_id":""
3305
+ # }
3306
+ # }
3307
+ # }
3308
+ #
3309
+ data = self.safe_value(response, 'data', {})
3310
+ record = self.safe_dict(data, 'record', {})
3311
+ return self.parse_transaction(record)
3312
+
3313
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3314
+ """
3315
+ fetch all deposits made to an account
3316
+ :param str code: unified currency code
3317
+ :param int [since]: the earliest time in ms to fetch deposits for
3318
+ :param int [limit]: the maximum number of deposits structures to retrieve
3319
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3320
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3321
+ """
3322
+ return await self.fetch_transactions_by_type('deposit', code, since, limit, params)
3323
+
3324
+ async def fetch_withdrawal(self, id: str, code: Str = None, params={}):
3325
+ """
3326
+ fetch data on a currency withdrawal via the withdrawal id
3327
+ :param str id: withdrawal id
3328
+ :param str code: not used by bitmart.fetchWithdrawal
3329
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3330
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
3331
+ """
3332
+ await self.load_markets()
3333
+ request: dict = {
3334
+ 'id': id,
3335
+ }
3336
+ response = await self.privateGetAccountV1DepositWithdrawDetail(self.extend(request, params))
3337
+ #
3338
+ # {
3339
+ # "message":"OK",
3340
+ # "code":1000,
3341
+ # "trace":"f7f74924-14da-42a6-b7f2-d3799dd9a612",
3342
+ # "data":{
3343
+ # "record":{
3344
+ # "withdraw_id":"1679952",
3345
+ # "deposit_id":"",
3346
+ # "operation_type":"withdraw",
3347
+ # "currency":"BMX",
3348
+ # "apply_time":1588867374000,
3349
+ # "arrival_amount":"59.000000000000",
3350
+ # "fee":"1.000000000000",
3351
+ # "status":0,
3352
+ # "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
3353
+ # "address_memo":"",
3354
+ # "tx_id":""
3355
+ # }
3356
+ # }
3357
+ # }
3358
+ #
3359
+ data = self.safe_value(response, 'data', {})
3360
+ record = self.safe_dict(data, 'record', {})
3361
+ return self.parse_transaction(record)
3362
+
3363
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3364
+ """
3365
+ fetch all withdrawals made from an account
3366
+ :param str code: unified currency code
3367
+ :param int [since]: the earliest time in ms to fetch withdrawals for
3368
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
3369
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3370
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3371
+ """
3372
+ return await self.fetch_transactions_by_type('withdraw', code, since, limit, params)
3373
+
3374
+ def parse_transaction_status(self, status: Str):
3375
+ statuses: dict = {
3376
+ '0': 'pending', # Create
3377
+ '1': 'pending', # Submitted, waiting for withdrawal
3378
+ '2': 'pending', # Processing
3379
+ '3': 'ok', # Success
3380
+ '4': 'canceled', # Cancel
3381
+ '5': 'failed', # Fail
3382
+ }
3383
+ return self.safe_string(statuses, status, status)
3384
+
3385
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
3386
+ #
3387
+ # withdraw
3388
+ #
3389
+ # {
3390
+ # "withdraw_id": "121212"
3391
+ # }
3392
+ #
3393
+ # fetchDeposits, fetchWithdrawals, fetchWithdrawal
3394
+ #
3395
+ # {
3396
+ # "withdraw_id":"1679952",
3397
+ # "deposit_id":"",
3398
+ # "operation_type":"withdraw",
3399
+ # "currency":"BMX",
3400
+ # "apply_time":1588867374000,
3401
+ # "arrival_amount":"59.000000000000",
3402
+ # "fee":"1.000000000000",
3403
+ # "status":0,
3404
+ # "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
3405
+ # "address_memo":"",
3406
+ # "tx_id":""
3407
+ # }
3408
+ #
3409
+ id = None
3410
+ withdrawId = self.safe_string(transaction, 'withdraw_id')
3411
+ depositId = self.safe_string(transaction, 'deposit_id')
3412
+ type = None
3413
+ if (withdrawId is not None) and (withdrawId != ''):
3414
+ type = 'withdraw'
3415
+ id = withdrawId
3416
+ elif (depositId is not None) and (depositId != ''):
3417
+ type = 'deposit'
3418
+ id = depositId
3419
+ amount = self.safe_number(transaction, 'arrival_amount')
3420
+ timestamp = self.safe_integer(transaction, 'apply_time')
3421
+ currencyId = self.safe_string(transaction, 'currency')
3422
+ code = self.safe_currency_code(currencyId, currency)
3423
+ status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
3424
+ feeCost = self.safe_number(transaction, 'fee')
3425
+ fee = None
3426
+ if feeCost is not None:
3427
+ fee = {
3428
+ 'cost': feeCost,
3429
+ 'currency': code,
3430
+ }
3431
+ txid = self.safe_string(transaction, 'tx_id')
3432
+ address = self.safe_string(transaction, 'address')
3433
+ tag = self.safe_string(transaction, 'address_memo')
3434
+ return {
3435
+ 'info': transaction,
3436
+ 'id': id,
3437
+ 'currency': code,
3438
+ 'amount': amount,
3439
+ 'network': None,
3440
+ 'address': address,
3441
+ 'addressFrom': None,
3442
+ 'addressTo': None,
3443
+ 'tag': tag,
3444
+ 'tagFrom': None,
3445
+ 'tagTo': None,
3446
+ 'status': status,
3447
+ 'type': type,
3448
+ 'updated': None,
3449
+ 'txid': txid,
3450
+ 'internal': None,
3451
+ 'comment': None,
3452
+ 'timestamp': timestamp if (timestamp != 0) else None,
3453
+ 'datetime': self.iso8601(timestamp) if (timestamp != 0) else None,
3454
+ 'fee': fee,
3455
+ }
3456
+
3457
+ async def repay_isolated_margin(self, symbol: str, code: str, amount, params={}):
3458
+ """
3459
+ repay borrowed margin and interest
3460
+ :see: https://developer-pro.bitmart.com/en/spot/#margin-repay-isolated
3461
+ :param str symbol: unified market symbol
3462
+ :param str code: unified currency code of the currency to repay
3463
+ :param str amount: the amount to repay
3464
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3465
+ :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
3466
+ """
3467
+ await self.load_markets()
3468
+ market = self.market(symbol)
3469
+ currency = self.currency(code)
3470
+ request: dict = {
3471
+ 'symbol': market['id'],
3472
+ 'currency': currency['id'],
3473
+ 'amount': self.currency_to_precision(code, amount),
3474
+ }
3475
+ response = await self.privatePostSpotV1MarginIsolatedRepay(self.extend(request, params))
3476
+ #
3477
+ # {
3478
+ # "message": "OK",
3479
+ # "code": 1000,
3480
+ # "trace": "b0a60b4c-e986-4b54-a190-8f7c05ddf685",
3481
+ # "data": {
3482
+ # "repay_id": "2afcc16d99bd4707818c5a355dc89bed"
3483
+ # }
3484
+ # }
3485
+ #
3486
+ data = self.safe_value(response, 'data', {})
3487
+ transaction = self.parse_margin_loan(data, currency)
3488
+ return self.extend(transaction, {
3489
+ 'amount': amount,
3490
+ 'symbol': symbol,
3491
+ })
3492
+
3493
+ async def borrow_isolated_margin(self, symbol: str, code: str, amount: float, params={}):
3494
+ """
3495
+ create a loan to borrow margin
3496
+ :see: https://developer-pro.bitmart.com/en/spot/#margin-borrow-isolated
3497
+ :param str symbol: unified market symbol
3498
+ :param str code: unified currency code of the currency to borrow
3499
+ :param str amount: the amount to borrow
3500
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3501
+ :returns dict: a `margin loan structure <https://docs.ccxt.com/#/?id=margin-loan-structure>`
3502
+ """
3503
+ await self.load_markets()
3504
+ market = self.market(symbol)
3505
+ currency = self.currency(code)
3506
+ request: dict = {
3507
+ 'symbol': market['id'],
3508
+ 'currency': currency['id'],
3509
+ 'amount': self.currency_to_precision(code, amount),
3510
+ }
3511
+ response = await self.privatePostSpotV1MarginIsolatedBorrow(self.extend(request, params))
3512
+ #
3513
+ # {
3514
+ # "message": "OK",
3515
+ # "code": 1000,
3516
+ # "trace": "e6fda683-181e-4e78-ac9c-b27c4c8ba035",
3517
+ # "data": {
3518
+ # "borrow_id": "629a7177a4ed4cf09869c6a4343b788c"
3519
+ # }
3520
+ # }
3521
+ #
3522
+ data = self.safe_value(response, 'data', {})
3523
+ transaction = self.parse_margin_loan(data, currency)
3524
+ return self.extend(transaction, {
3525
+ 'amount': amount,
3526
+ 'symbol': symbol,
3527
+ })
3528
+
3529
+ def parse_margin_loan(self, info, currency: Currency = None):
3530
+ #
3531
+ # borrowMargin
3532
+ #
3533
+ # {
3534
+ # "borrow_id": "629a7177a4ed4cf09869c6a4343b788c",
3535
+ # }
3536
+ #
3537
+ # repayMargin
3538
+ #
3539
+ # {
3540
+ # "repay_id": "2afcc16d99bd4707818c5a355dc89bed",
3541
+ # }
3542
+ #
3543
+ return {
3544
+ 'id': self.safe_string_2(info, 'borrow_id', 'repay_id'),
3545
+ 'currency': self.safe_currency_code(None, currency),
3546
+ 'amount': None,
3547
+ 'symbol': None,
3548
+ 'timestamp': None,
3549
+ 'datetime': None,
3550
+ 'info': info,
3551
+ }
3552
+
3553
+ async def fetch_isolated_borrow_rate(self, symbol: str, params={}) -> IsolatedBorrowRate:
3554
+ """
3555
+ fetch the rate of interest to borrow a currency for margin trading
3556
+ :see: https://developer-pro.bitmart.com/en/spot/#get-trading-pair-borrowing-rate-and-amount-keyed
3557
+ :param str symbol: unified symbol of the market to fetch the borrow rate for
3558
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3559
+ :returns dict: an `isolated borrow rate structure <https://github.com/ccxt/ccxt/wiki/Manual#isolated-borrow-rate-structure>`
3560
+ """
3561
+ await self.load_markets()
3562
+ market = self.market(symbol)
3563
+ request: dict = {
3564
+ 'symbol': market['id'],
3565
+ }
3566
+ response = await self.privateGetSpotV1MarginIsolatedPairs(self.extend(request, params))
3567
+ #
3568
+ # {
3569
+ # "message": "OK",
3570
+ # "code": 1000,
3571
+ # "trace": "0985a130-a5ae-4fc1-863f-4704e214f585",
3572
+ # "data": {
3573
+ # "symbols": [
3574
+ # {
3575
+ # "symbol": "BTC_USDT",
3576
+ # "max_leverage": "5",
3577
+ # "symbol_enabled": True,
3578
+ # "base": {
3579
+ # "currency": "BTC",
3580
+ # "daily_interest": "0.00055000",
3581
+ # "hourly_interest": "0.00002291",
3582
+ # "max_borrow_amount": "2.00000000",
3583
+ # "min_borrow_amount": "0.00000001",
3584
+ # "borrowable_amount": "0.00670810"
3585
+ # },
3586
+ # "quote": {
3587
+ # "currency": "USDT",
3588
+ # "daily_interest": "0.00055000",
3589
+ # "hourly_interest": "0.00002291",
3590
+ # "max_borrow_amount": "50000.00000000",
3591
+ # "min_borrow_amount": "0.00000001",
3592
+ # "borrowable_amount": "135.12575038"
3593
+ # }
3594
+ # }
3595
+ # ]
3596
+ # }
3597
+ # }
3598
+ #
3599
+ data = self.safe_value(response, 'data', {})
3600
+ symbols = self.safe_value(data, 'symbols', [])
3601
+ borrowRate = self.safe_value(symbols, 0)
3602
+ return self.parse_isolated_borrow_rate(borrowRate, market)
3603
+
3604
+ def parse_isolated_borrow_rate(self, info, market: Market = None) -> IsolatedBorrowRate:
3605
+ #
3606
+ # {
3607
+ # "symbol": "BTC_USDT",
3608
+ # "max_leverage": "5",
3609
+ # "symbol_enabled": True,
3610
+ # "base": {
3611
+ # "currency": "BTC",
3612
+ # "daily_interest": "0.00055000",
3613
+ # "hourly_interest": "0.00002291",
3614
+ # "max_borrow_amount": "2.00000000",
3615
+ # "min_borrow_amount": "0.00000001",
3616
+ # "borrowable_amount": "0.00670810"
3617
+ # },
3618
+ # "quote": {
3619
+ # "currency": "USDT",
3620
+ # "daily_interest": "0.00055000",
3621
+ # "hourly_interest": "0.00002291",
3622
+ # "max_borrow_amount": "50000.00000000",
3623
+ # "min_borrow_amount": "0.00000001",
3624
+ # "borrowable_amount": "135.12575038"
3625
+ # }
3626
+ # }
3627
+ #
3628
+ marketId = self.safe_string(info, 'symbol')
3629
+ symbol = self.safe_symbol(marketId, market)
3630
+ baseData = self.safe_value(info, 'base', {})
3631
+ quoteData = self.safe_value(info, 'quote', {})
3632
+ baseId = self.safe_string(baseData, 'currency')
3633
+ quoteId = self.safe_string(quoteData, 'currency')
3634
+ return {
3635
+ 'symbol': symbol,
3636
+ 'base': self.safe_currency_code(baseId),
3637
+ 'baseRate': self.safe_number(baseData, 'hourly_interest'),
3638
+ 'quote': self.safe_currency_code(quoteId),
3639
+ 'quoteRate': self.safe_number(quoteData, 'hourly_interest'),
3640
+ 'period': 3600000, # 1-Hour
3641
+ 'timestamp': None,
3642
+ 'datetime': None,
3643
+ 'info': info,
3644
+ }
3645
+
3646
+ async def fetch_isolated_borrow_rates(self, params={}) -> IsolatedBorrowRates:
3647
+ """
3648
+ fetch the borrow interest rates of all currencies, currently only works for isolated margin
3649
+ :see: https://developer-pro.bitmart.com/en/spot/#get-trading-pair-borrowing-rate-and-amount-keyed
3650
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3651
+ :returns dict: a list of `isolated borrow rate structures <https://docs.ccxt.com/#/?id=isolated-borrow-rate-structure>`
3652
+ """
3653
+ await self.load_markets()
3654
+ response = await self.privateGetSpotV1MarginIsolatedPairs(params)
3655
+ #
3656
+ # {
3657
+ # "message": "OK",
3658
+ # "code": 1000,
3659
+ # "trace": "0985a130-a5ae-4fc1-863f-4704e214f585",
3660
+ # "data": {
3661
+ # "symbols": [
3662
+ # {
3663
+ # "symbol": "BTC_USDT",
3664
+ # "max_leverage": "5",
3665
+ # "symbol_enabled": True,
3666
+ # "base": {
3667
+ # "currency": "BTC",
3668
+ # "daily_interest": "0.00055000",
3669
+ # "hourly_interest": "0.00002291",
3670
+ # "max_borrow_amount": "2.00000000",
3671
+ # "min_borrow_amount": "0.00000001",
3672
+ # "borrowable_amount": "0.00670810"
3673
+ # },
3674
+ # "quote": {
3675
+ # "currency": "USDT",
3676
+ # "daily_interest": "0.00055000",
3677
+ # "hourly_interest": "0.00002291",
3678
+ # "max_borrow_amount": "50000.00000000",
3679
+ # "min_borrow_amount": "0.00000001",
3680
+ # "borrowable_amount": "135.12575038"
3681
+ # }
3682
+ # }
3683
+ # ]
3684
+ # }
3685
+ # }
3686
+ #
3687
+ data = self.safe_value(response, 'data', {})
3688
+ symbols = self.safe_value(data, 'symbols', [])
3689
+ return self.parse_isolated_borrow_rates(symbols)
3690
+
3691
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
3692
+ """
3693
+ transfer currency internally between wallets on the same account, currently only supports transfer between spot and margin
3694
+ :see: https://developer-pro.bitmart.com/en/spot/#margin-asset-transfer-signed
3695
+ :see: https://developer-pro.bitmart.com/en/futures/#transfer-signed
3696
+ :param str code: unified currency code
3697
+ :param float amount: amount to transfer
3698
+ :param str fromAccount: account to transfer from
3699
+ :param str toAccount: account to transfer to
3700
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3701
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
3702
+ """
3703
+ await self.load_markets()
3704
+ currency = self.currency(code)
3705
+ amountToPrecision = self.currency_to_precision(code, amount)
3706
+ request: dict = {
3707
+ 'amount': amountToPrecision,
3708
+ 'currency': currency['id'],
3709
+ }
3710
+ fromId = self.convert_type_to_account(fromAccount)
3711
+ toId = self.convert_type_to_account(toAccount)
3712
+ if fromAccount == 'spot':
3713
+ if toAccount == 'margin':
3714
+ request['side'] = 'in'
3715
+ request['symbol'] = toId
3716
+ elif toAccount == 'swap':
3717
+ request['type'] = 'spot_to_contract'
3718
+ elif toAccount == 'spot':
3719
+ if fromAccount == 'margin':
3720
+ request['side'] = 'out'
3721
+ request['symbol'] = fromId
3722
+ elif fromAccount == 'swap':
3723
+ request['type'] = 'contract_to_spot'
3724
+ else:
3725
+ raise ArgumentsRequired(self.id + ' transfer() requires either fromAccount or toAccount to be spot')
3726
+ response = None
3727
+ if (fromAccount == 'margin') or (toAccount == 'margin'):
3728
+ response = await self.privatePostSpotV1MarginIsolatedTransfer(self.extend(request, params))
3729
+ elif (fromAccount == 'swap') or (toAccount == 'swap'):
3730
+ response = await self.privatePostAccountV1TransferContract(self.extend(request, params))
3731
+ #
3732
+ # margin
3733
+ #
3734
+ # {
3735
+ # "message": "OK",
3736
+ # "code": 1000,
3737
+ # "trace": "b26cecec-ef5a-47d9-9531-2bd3911d3d55",
3738
+ # "data": {
3739
+ # "transfer_id": "ca90d97a621e47d49774f19af6b029f5"
3740
+ # }
3741
+ # }
3742
+ #
3743
+ # swap
3744
+ #
3745
+ # {
3746
+ # "message": "OK",
3747
+ # "code": 1000,
3748
+ # "trace": "4cad858074667097ac6ba5257c57305d.68.16953302431189455",
3749
+ # "data": {
3750
+ # "currency": "USDT",
3751
+ # "amount": "5"
3752
+ # }
3753
+ # }
3754
+ #
3755
+ data = self.safe_value(response, 'data', {})
3756
+ return self.extend(self.parse_transfer(data, currency), {
3757
+ 'status': self.parse_transfer_status(self.safe_string_2(response, 'code', 'message')),
3758
+ })
3759
+
3760
+ def parse_transfer_status(self, status: Str) -> Str:
3761
+ statuses: dict = {
3762
+ '1000': 'ok',
3763
+ 'OK': 'ok',
3764
+ 'FINISHED': 'ok',
3765
+ }
3766
+ return self.safe_string(statuses, status, status)
3767
+
3768
+ def parse_transfer_to_account(self, type):
3769
+ types: dict = {
3770
+ 'contract_to_spot': 'spot',
3771
+ 'spot_to_contract': 'swap',
3772
+ }
3773
+ return self.safe_string(types, type, type)
3774
+
3775
+ def parse_transfer_from_account(self, type):
3776
+ types: dict = {
3777
+ 'contract_to_spot': 'swap',
3778
+ 'spot_to_contract': 'spot',
3779
+ }
3780
+ return self.safe_string(types, type, type)
3781
+
3782
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
3783
+ #
3784
+ # margin
3785
+ #
3786
+ # {
3787
+ # "transfer_id": "ca90d97a621e47d49774f19af6b029f5"
3788
+ # }
3789
+ #
3790
+ # swap
3791
+ #
3792
+ # {
3793
+ # "currency": "USDT",
3794
+ # "amount": "5"
3795
+ # }
3796
+ #
3797
+ # fetchTransfers
3798
+ #
3799
+ # {
3800
+ # "transfer_id": "902463535961567232",
3801
+ # "currency": "USDT",
3802
+ # "amount": "5",
3803
+ # "type": "contract_to_spot",
3804
+ # "state": "FINISHED",
3805
+ # "timestamp": 1695330539565
3806
+ # }
3807
+ #
3808
+ currencyId = self.safe_string(transfer, 'currency')
3809
+ timestamp = self.safe_integer(transfer, 'timestamp')
3810
+ return {
3811
+ 'id': self.safe_string(transfer, 'transfer_id'),
3812
+ 'timestamp': timestamp,
3813
+ 'datetime': self.iso8601(timestamp),
3814
+ 'currency': self.safe_currency_code(currencyId, currency),
3815
+ 'amount': self.safe_number(transfer, 'amount'),
3816
+ 'fromAccount': self.parse_transfer_from_account(self.safe_string(transfer, 'type')),
3817
+ 'toAccount': self.parse_transfer_to_account(self.safe_string(transfer, 'type')),
3818
+ 'status': self.parse_transfer_status(self.safe_string(transfer, 'state')),
3819
+ }
3820
+
3821
+ async def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> TransferEntries:
3822
+ """
3823
+ fetch a history of internal transfers made on an account, only transfers between spot and swap are supported
3824
+ :see: https://developer-pro.bitmart.com/en/futures/#get-transfer-list-signed
3825
+ :param str code: unified currency code of the currency transferred
3826
+ :param int [since]: the earliest time in ms to fetch transfers for
3827
+ :param int [limit]: the maximum number of transfer structures to retrieve
3828
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3829
+ :param int [params.page]: the required number of pages, default is 1, max is 1000
3830
+ :param int [params.until]: the latest time in ms to fetch transfers for
3831
+ :returns dict[]: a list of `transfer structures <https://docs.ccxt.com/#/?id=transfer-structure>`
3832
+ """
3833
+ await self.load_markets()
3834
+ if limit is None:
3835
+ limit = 10
3836
+ request: dict = {
3837
+ 'page': self.safe_integer(params, 'page', 1), # default is 1, max is 1000
3838
+ 'limit': limit, # default is 10, max is 100
3839
+ }
3840
+ currency = None
3841
+ if code is not None:
3842
+ currency = self.currency(code)
3843
+ request['currency'] = currency['id']
3844
+ if since is not None:
3845
+ request['time_start'] = since
3846
+ if limit is not None:
3847
+ request['limit'] = limit
3848
+ until = self.safe_integer(params, 'until') # unified in milliseconds
3849
+ endTime = self.safe_integer(params, 'time_end', until) # exchange-specific in milliseconds
3850
+ params = self.omit(params, ['until'])
3851
+ if endTime is not None:
3852
+ request['time_end'] = endTime
3853
+ response = await self.privatePostAccountV1TransferContractList(self.extend(request, params))
3854
+ #
3855
+ # {
3856
+ # "message": "OK",
3857
+ # "code": 1000,
3858
+ # "trace": "7f9d93e10f9g4513bc08a7btc2a5559a.69.16953325693032193",
3859
+ # "data": {
3860
+ # "records": [
3861
+ # {
3862
+ # "transfer_id": "902463535961567232",
3863
+ # "currency": "USDT",
3864
+ # "amount": "5",
3865
+ # "type": "contract_to_spot",
3866
+ # "state": "FINISHED",
3867
+ # "timestamp": 1695330539565
3868
+ # },
3869
+ # ]
3870
+ # }
3871
+ # }
3872
+ #
3873
+ data = self.safe_value(response, 'data', {})
3874
+ records = self.safe_list(data, 'records', [])
3875
+ return self.parse_transfers(records, currency, since, limit)
3876
+
3877
+ async def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3878
+ """
3879
+ fetch the interest owed by the user for borrowing currency for margin trading
3880
+ :see: https://developer-pro.bitmart.com/en/spot/#get-borrow-record-isolated
3881
+ :param str code: unified currency code
3882
+ :param str symbol: unified market symbol when fetch interest in isolated markets
3883
+ :param int [since]: the earliest time in ms to fetch borrrow interest for
3884
+ :param int [limit]: the maximum number of structures to retrieve
3885
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3886
+ :returns dict[]: a list of `borrow interest structures <https://docs.ccxt.com/#/?id=borrow-interest-structure>`
3887
+ """
3888
+ if symbol is None:
3889
+ raise ArgumentsRequired(self.id + ' fetchBorrowInterest() requires a symbol argument')
3890
+ await self.load_markets()
3891
+ market = self.market(symbol)
3892
+ request: dict = {
3893
+ 'symbol': market['id'],
3894
+ }
3895
+ if limit is not None:
3896
+ request['N'] = limit
3897
+ if since is not None:
3898
+ request['start_time'] = since
3899
+ response = await self.privateGetSpotV1MarginIsolatedBorrowRecord(self.extend(request, params))
3900
+ #
3901
+ # {
3902
+ # "message": "OK",
3903
+ # "code": 1000,
3904
+ # "trace": "8ea27a2a-4aba-49fa-961d-43a0137b0ef3",
3905
+ # "data": {
3906
+ # "records": [
3907
+ # {
3908
+ # "borrow_id": "1659045283903rNvJnuRTJNL5J53n",
3909
+ # "symbol": "BTC_USDT",
3910
+ # "currency": "USDT",
3911
+ # "borrow_amount": "100.00000000",
3912
+ # "daily_interest": "0.00055000",
3913
+ # "hourly_interest": "0.00002291",
3914
+ # "interest_amount": "0.00229166",
3915
+ # "create_time": 1659045284000
3916
+ # },
3917
+ # ]
3918
+ # }
3919
+ # }
3920
+ #
3921
+ data = self.safe_value(response, 'data', {})
3922
+ rows = self.safe_value(data, 'records', [])
3923
+ interest = self.parse_borrow_interests(rows, market)
3924
+ return self.filter_by_currency_since_limit(interest, code, since, limit)
3925
+
3926
+ def parse_borrow_interest(self, info: dict, market: Market = None):
3927
+ #
3928
+ # {
3929
+ # "borrow_id": "1657664327844Lk5eJJugXmdHHZoe",
3930
+ # "symbol": "BTC_USDT",
3931
+ # "currency": "USDT",
3932
+ # "borrow_amount": "20.00000000",
3933
+ # "daily_interest": "0.00055000",
3934
+ # "hourly_interest": "0.00002291",
3935
+ # "interest_amount": "0.00045833",
3936
+ # "create_time": 1657664329000
3937
+ # }
3938
+ #
3939
+ marketId = self.safe_string(info, 'symbol')
3940
+ market = self.safe_market(marketId, market)
3941
+ timestamp = self.safe_integer(info, 'create_time')
3942
+ return {
3943
+ 'symbol': self.safe_string(market, 'symbol'),
3944
+ 'marginMode': 'isolated',
3945
+ 'currency': self.safe_currency_code(self.safe_string(info, 'currency')),
3946
+ 'interest': self.safe_number(info, 'interest_amount'),
3947
+ 'interestRate': self.safe_number(info, 'hourly_interest'),
3948
+ 'amountBorrowed': self.safe_number(info, 'borrow_amount'),
3949
+ 'timestamp': timestamp, # borrow creation time
3950
+ 'datetime': self.iso8601(timestamp),
3951
+ 'info': info,
3952
+ }
3953
+
3954
+ async def fetch_open_interest(self, symbol: str, params={}):
3955
+ """
3956
+ Retrieves the open interest of a currency
3957
+ :see: https://developer-pro.bitmart.com/en/futures/#get-futures-openinterest
3958
+ :param str symbol: Unified CCXT market symbol
3959
+ :param dict [params]: exchange specific parameters
3960
+ :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
3961
+ """
3962
+ await self.load_markets()
3963
+ market = self.market(symbol)
3964
+ if not market['contract']:
3965
+ raise BadRequest(self.id + ' fetchOpenInterest() supports contract markets only')
3966
+ request: dict = {
3967
+ 'symbol': market['id'],
3968
+ }
3969
+ response = await self.publicGetContractPublicOpenInterest(self.extend(request, params))
3970
+ #
3971
+ # {
3972
+ # "code": 1000,
3973
+ # "message": "Ok",
3974
+ # "data": {
3975
+ # "timestamp": 1694657502415,
3976
+ # "symbol": "BTCUSDT",
3977
+ # "open_interest": "265231.721368593081729069",
3978
+ # "open_interest_value": "7006353.83988919"
3979
+ # },
3980
+ # "trace": "7f9c94e10f9d4513bc08a7bfc2a5559a.72.16946575108274991"
3981
+ # }
3982
+ #
3983
+ data = self.safe_dict(response, 'data', {})
3984
+ return self.parse_open_interest(data, market)
3985
+
3986
+ def parse_open_interest(self, interest, market: Market = None):
3987
+ #
3988
+ # {
3989
+ # "timestamp": 1694657502415,
3990
+ # "symbol": "BTCUSDT",
3991
+ # "open_interest": "265231.721368593081729069",
3992
+ # "open_interest_value": "7006353.83988919"
3993
+ # }
3994
+ #
3995
+ timestamp = self.safe_integer(interest, 'timestamp')
3996
+ id = self.safe_string(interest, 'symbol')
3997
+ return self.safe_open_interest({
3998
+ 'symbol': self.safe_symbol(id, market),
3999
+ 'openInterestAmount': self.safe_number(interest, 'open_interest'),
4000
+ 'openInterestValue': self.safe_number(interest, 'open_interest_value'),
4001
+ 'timestamp': timestamp,
4002
+ 'datetime': self.iso8601(timestamp),
4003
+ 'info': interest,
4004
+ }, market)
4005
+
4006
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
4007
+ """
4008
+ set the level of leverage for a market
4009
+ :see: https://developer-pro.bitmart.com/en/futures/#submit-leverage-signed
4010
+ :param float leverage: the rate of leverage
4011
+ :param str symbol: unified market symbol
4012
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4013
+ :param str [params.marginMode]: 'isolated' or 'cross'
4014
+ :returns dict: response from the exchange
4015
+ """
4016
+ if symbol is None:
4017
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
4018
+ marginMode = None
4019
+ marginMode, params = self.handle_margin_mode_and_params('setLeverage', params)
4020
+ self.check_required_argument('setLeverage', marginMode, 'marginMode', ['isolated', 'cross'])
4021
+ await self.load_markets()
4022
+ market = self.market(symbol)
4023
+ if not market['swap']:
4024
+ raise BadSymbol(self.id + ' setLeverage() supports swap contracts only')
4025
+ request: dict = {
4026
+ 'symbol': market['id'],
4027
+ 'leverage': str(leverage),
4028
+ 'open_type': marginMode,
4029
+ }
4030
+ return await self.privatePostContractPrivateSubmitLeverage(self.extend(request, params))
4031
+
4032
+ async def fetch_funding_rate(self, symbol: str, params={}):
4033
+ """
4034
+ fetch the current funding rate
4035
+ :see: https://developer-pro.bitmart.com/en/futures/#get-current-funding-rate
4036
+ :param str symbol: unified market symbol
4037
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4038
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
4039
+ """
4040
+ await self.load_markets()
4041
+ market = self.market(symbol)
4042
+ if not market['swap']:
4043
+ raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
4044
+ request: dict = {
4045
+ 'symbol': market['id'],
4046
+ }
4047
+ response = await self.publicGetContractPublicFundingRate(self.extend(request, params))
4048
+ #
4049
+ # {
4050
+ # "code": 1000,
4051
+ # "message": "Ok",
4052
+ # "data": {
4053
+ # "timestamp": 1695184410697,
4054
+ # "symbol": "BTCUSDT",
4055
+ # "rate_value": "-0.00002614",
4056
+ # "expected_rate": "-0.00002"
4057
+ # },
4058
+ # "trace": "4cad855074654097ac7ba5257c47305d.54.16951844206655589"
4059
+ # }
4060
+ #
4061
+ data = self.safe_value(response, 'data', {})
4062
+ return self.parse_funding_rate(data, market)
4063
+
4064
+ def parse_funding_rate(self, contract, market: Market = None):
4065
+ #
4066
+ # {
4067
+ # "timestamp": 1695184410697,
4068
+ # "symbol": "BTCUSDT",
4069
+ # "rate_value": "-0.00002614",
4070
+ # "expected_rate": "-0.00002"
4071
+ # }
4072
+ #
4073
+ marketId = self.safe_string(contract, 'symbol')
4074
+ timestamp = self.safe_integer(contract, 'timestamp')
4075
+ return {
4076
+ 'info': contract,
4077
+ 'symbol': self.safe_symbol(marketId, market),
4078
+ 'markPrice': None,
4079
+ 'indexPrice': None,
4080
+ 'interestRate': None,
4081
+ 'estimatedSettlePrice': None,
4082
+ 'timestamp': timestamp,
4083
+ 'datetime': self.iso8601(timestamp),
4084
+ 'fundingRate': self.safe_number(contract, 'expected_rate'),
4085
+ 'fundingTimestamp': None,
4086
+ 'fundingDatetime': None,
4087
+ 'nextFundingRate': None,
4088
+ 'nextFundingTimestamp': None,
4089
+ 'nextFundingDatetime': None,
4090
+ 'previousFundingRate': self.safe_number(contract, 'rate_value'),
4091
+ 'previousFundingTimestamp': None,
4092
+ 'previousFundingDatetime': None,
4093
+ }
4094
+
4095
+ async def fetch_position(self, symbol: str, params={}):
4096
+ """
4097
+ fetch data on a single open contract trade position
4098
+ :see: https://developer-pro.bitmart.com/en/futures/#get-current-position-keyed
4099
+ :param str symbol: unified market symbol of the market the position is held in
4100
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4101
+ :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
4102
+ """
4103
+ await self.load_markets()
4104
+ market = self.market(symbol)
4105
+ request: dict = {
4106
+ 'symbol': market['id'],
4107
+ }
4108
+ response = await self.privateGetContractPrivatePosition(self.extend(request, params))
4109
+ #
4110
+ # {
4111
+ # "code": 1000,
4112
+ # "message": "Ok",
4113
+ # "data": [
4114
+ # {
4115
+ # "symbol": "BTCUSDT",
4116
+ # "leverage": "10",
4117
+ # "timestamp": 1696392515269,
4118
+ # "current_fee": "0.0014250028",
4119
+ # "open_timestamp": 1696392256998,
4120
+ # "current_value": "27.4039",
4121
+ # "mark_price": "27.4039",
4122
+ # "position_value": "27.4079",
4123
+ # "position_cross": "3.75723474",
4124
+ # "maintenance_margin": "0.1370395",
4125
+ # "close_vol": "0",
4126
+ # "close_avg_price": "0",
4127
+ # "open_avg_price": "27407.9",
4128
+ # "entry_price": "27407.9",
4129
+ # "current_amount": "1",
4130
+ # "unrealized_value": "-0.004",
4131
+ # "realized_value": "-0.01644474",
4132
+ # "position_type": 1
4133
+ # }
4134
+ # ],
4135
+ # "trace":"4cad855074664097ac5ba5257c47305d.67.16963925142065945"
4136
+ # }
4137
+ #
4138
+ data = self.safe_value(response, 'data', [])
4139
+ first = self.safe_dict(data, 0, {})
4140
+ return self.parse_position(first, market)
4141
+
4142
+ async def fetch_positions(self, symbols: Strings = None, params={}):
4143
+ """
4144
+ fetch all open contract positions
4145
+ :see: https://developer-pro.bitmart.com/en/futures/#get-current-position-keyed
4146
+ :param str[]|None symbols: list of unified market symbols
4147
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4148
+ :returns dict[]: a list of `position structures <https://docs.ccxt.com/#/?id=position-structure>`
4149
+ """
4150
+ await self.load_markets()
4151
+ market = None
4152
+ symbolsLength = None
4153
+ if symbols is not None:
4154
+ symbolsLength = len(symbols)
4155
+ first = self.safe_string(symbols, 0)
4156
+ market = self.market(first)
4157
+ request: dict = {}
4158
+ if symbolsLength == 1:
4159
+ # only supports symbols or sending one symbol
4160
+ request['symbol'] = market['id']
4161
+ response = await self.privateGetContractPrivatePosition(self.extend(request, params))
4162
+ #
4163
+ # {
4164
+ # "code": 1000,
4165
+ # "message": "Ok",
4166
+ # "data": [
4167
+ # {
4168
+ # "symbol": "BTCUSDT",
4169
+ # "leverage": "10",
4170
+ # "timestamp": 1696392515269,
4171
+ # "current_fee": "0.0014250028",
4172
+ # "open_timestamp": 1696392256998,
4173
+ # "current_value": "27.4039",
4174
+ # "mark_price": "27.4039",
4175
+ # "position_value": "27.4079",
4176
+ # "position_cross": "3.75723474",
4177
+ # "maintenance_margin": "0.1370395",
4178
+ # "close_vol": "0",
4179
+ # "close_avg_price": "0",
4180
+ # "open_avg_price": "27407.9",
4181
+ # "entry_price": "27407.9",
4182
+ # "current_amount": "1",
4183
+ # "unrealized_value": "-0.004",
4184
+ # "realized_value": "-0.01644474",
4185
+ # "position_type": 1
4186
+ # },
4187
+ # ],
4188
+ # "trace":"4cad855074664097ac5ba5257c47305d.67.16963925142065945"
4189
+ # }
4190
+ #
4191
+ positions = self.safe_value(response, 'data', [])
4192
+ result = []
4193
+ for i in range(0, len(positions)):
4194
+ result.append(self.parse_position(positions[i]))
4195
+ symbols = self.market_symbols(symbols)
4196
+ return self.filter_by_array_positions(result, 'symbol', symbols, False)
4197
+
4198
+ def parse_position(self, position: dict, market: Market = None):
4199
+ #
4200
+ # {
4201
+ # "symbol": "BTCUSDT",
4202
+ # "leverage": "10",
4203
+ # "timestamp": 1696392515269,
4204
+ # "current_fee": "0.0014250028",
4205
+ # "open_timestamp": 1696392256998,
4206
+ # "current_value": "27.4039",
4207
+ # "mark_price": "27.4039",
4208
+ # "position_value": "27.4079",
4209
+ # "position_cross": "3.75723474",
4210
+ # "maintenance_margin": "0.1370395",
4211
+ # "close_vol": "0",
4212
+ # "close_avg_price": "0",
4213
+ # "open_avg_price": "27407.9",
4214
+ # "entry_price": "27407.9",
4215
+ # "current_amount": "1",
4216
+ # "unrealized_value": "-0.004",
4217
+ # "realized_value": "-0.01644474",
4218
+ # "position_type": 1
4219
+ # }
4220
+ #
4221
+ marketId = self.safe_string(position, 'symbol')
4222
+ market = self.safe_market(marketId, market)
4223
+ symbol = market['symbol']
4224
+ timestamp = self.safe_integer(position, 'timestamp')
4225
+ side = self.safe_integer(position, 'position_type')
4226
+ maintenanceMargin = self.safe_string(position, 'maintenance_margin')
4227
+ notional = self.safe_string(position, 'current_value')
4228
+ collateral = self.safe_string(position, 'position_cross')
4229
+ maintenanceMarginPercentage = Precise.string_div(maintenanceMargin, notional)
4230
+ marginRatio = Precise.string_div(maintenanceMargin, collateral)
4231
+ return self.safe_position({
4232
+ 'info': position,
4233
+ 'id': None,
4234
+ 'symbol': symbol,
4235
+ 'timestamp': timestamp,
4236
+ 'datetime': self.iso8601(timestamp),
4237
+ 'lastUpdateTimestamp': None,
4238
+ 'hedged': None,
4239
+ 'side': 'long' if (side == 1) else 'short',
4240
+ 'contracts': self.safe_number(position, 'current_amount'),
4241
+ 'contractSize': self.safe_number(market, 'contractSize'),
4242
+ 'entryPrice': self.safe_number(position, 'entry_price'),
4243
+ 'markPrice': self.safe_number(position, 'mark_price'),
4244
+ 'lastPrice': None,
4245
+ 'notional': self.parse_number(notional),
4246
+ 'leverage': self.safe_number(position, 'leverage'),
4247
+ 'collateral': self.parse_number(collateral),
4248
+ 'initialMargin': None,
4249
+ 'initialMarginPercentage': None,
4250
+ 'maintenanceMargin': self.parse_number(maintenanceMargin),
4251
+ 'maintenanceMarginPercentage': self.parse_number(maintenanceMarginPercentage),
4252
+ 'unrealizedPnl': self.safe_number(position, 'unrealized_value'),
4253
+ 'realizedPnl': self.safe_number(position, 'realized_value'),
4254
+ 'liquidationPrice': None,
4255
+ 'marginMode': None,
4256
+ 'percentage': None,
4257
+ 'marginRatio': self.parse_number(marginRatio),
4258
+ 'stopLossPrice': None,
4259
+ 'takeProfitPrice': None,
4260
+ })
4261
+
4262
+ async def fetch_my_liquidations(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
4263
+ """
4264
+ retrieves the users liquidated positions
4265
+ :see: https://developer-pro.bitmart.com/en/futures/#get-order-history-keyed
4266
+ :param str symbol: unified CCXT market symbol
4267
+ :param int [since]: the earliest time in ms to fetch liquidations for
4268
+ :param int [limit]: the maximum number of liquidation structures to retrieve
4269
+ :param dict [params]: exchange specific parameters for the bitmart api endpoint
4270
+ :param int [params.until]: timestamp in ms of the latest liquidation
4271
+ :returns dict: an array of `liquidation structures <https://docs.ccxt.com/#/?id=liquidation-structure>`
4272
+ """
4273
+ if symbol is None:
4274
+ raise ArgumentsRequired(self.id + ' fetchMyLiquidations() requires a symbol argument')
4275
+ await self.load_markets()
4276
+ market = self.market(symbol)
4277
+ if not market['swap']:
4278
+ raise NotSupported(self.id + ' fetchMyLiquidations() supports swap markets only')
4279
+ request: dict = {
4280
+ 'symbol': market['id'],
4281
+ }
4282
+ if since is not None:
4283
+ request['start_time'] = since
4284
+ request, params = self.handle_until_option('end_time', request, params)
4285
+ response = await self.privateGetContractPrivateOrderHistory(self.extend(request, params))
4286
+ #
4287
+ # {
4288
+ # "code": 1000,
4289
+ # "message": "Ok",
4290
+ # "data": [
4291
+ # {
4292
+ # "order_id": "231007865458273",
4293
+ # "client_order_id": "",
4294
+ # "price": "27407.9",
4295
+ # "size": "1",
4296
+ # "symbol": "BTCUSDT",
4297
+ # "state": 4,
4298
+ # "side": 3,
4299
+ # "type": "liquidate",
4300
+ # "leverage": "10",
4301
+ # "open_type": "isolated",
4302
+ # "deal_avg_price": "27422.6",
4303
+ # "deal_size": "1",
4304
+ # "create_time": 1696405864011,
4305
+ # "update_time": 1696405864045
4306
+ # },
4307
+ # ],
4308
+ # "trace": "4cad855074664097ac6ba4257c47305d.71.16965658195443021"
4309
+ # }
4310
+ #
4311
+ data = self.safe_value(response, 'data', [])
4312
+ result = []
4313
+ for i in range(0, len(data)):
4314
+ entry = data[i]
4315
+ checkLiquidation = self.safe_string(entry, 'type')
4316
+ if checkLiquidation == 'liquidate':
4317
+ result.append(entry)
4318
+ return self.parse_liquidations(result, market, since, limit)
4319
+
4320
+ def parse_liquidation(self, liquidation, market: Market = None):
4321
+ #
4322
+ # {
4323
+ # "order_id": "231007865458273",
4324
+ # "client_order_id": "",
4325
+ # "price": "27407.9",
4326
+ # "size": "1",
4327
+ # "symbol": "BTCUSDT",
4328
+ # "state": 4,
4329
+ # "side": 3,
4330
+ # "type": "market",
4331
+ # "leverage": "10",
4332
+ # "open_type": "isolated",
4333
+ # "deal_avg_price": "27422.6",
4334
+ # "deal_size": "1",
4335
+ # "create_time": 1696405864011,
4336
+ # "update_time": 1696405864045
4337
+ # }
4338
+ #
4339
+ marketId = self.safe_string(liquidation, 'symbol')
4340
+ timestamp = self.safe_integer(liquidation, 'update_time')
4341
+ contractsString = self.safe_string(liquidation, 'deal_size')
4342
+ contractSizeString = self.safe_string(market, 'contractSize')
4343
+ priceString = self.safe_string(liquidation, 'deal_avg_price')
4344
+ baseValueString = Precise.string_mul(contractsString, contractSizeString)
4345
+ quoteValueString = Precise.string_mul(baseValueString, priceString)
4346
+ return self.safe_liquidation({
4347
+ 'info': liquidation,
4348
+ 'symbol': self.safe_symbol(marketId, market),
4349
+ 'contracts': self.parse_number(contractsString),
4350
+ 'contractSize': self.parse_number(contractSizeString),
4351
+ 'price': self.parse_number(priceString),
4352
+ 'baseValue': self.parse_number(baseValueString),
4353
+ 'quoteValue': self.parse_number(quoteValueString),
4354
+ 'timestamp': timestamp,
4355
+ 'datetime': self.iso8601(timestamp),
4356
+ })
4357
+
4358
+ def nonce(self):
4359
+ return self.milliseconds()
4360
+
4361
+ def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
4362
+ baseUrl = self.implode_hostname(self.urls['api']['rest'])
4363
+ url = baseUrl + '/' + self.implode_params(path, params)
4364
+ query = self.omit(params, self.extract_params(path))
4365
+ queryString = ''
4366
+ getOrDelete = (method == 'GET') or (method == 'DELETE')
4367
+ if getOrDelete:
4368
+ if query:
4369
+ queryString = self.urlencode(query)
4370
+ url += '?' + queryString
4371
+ if api == 'private':
4372
+ self.check_required_credentials()
4373
+ timestamp = str(self.milliseconds())
4374
+ brokerId = self.safe_string(self.options, 'brokerId', 'CCXTxBitmart000')
4375
+ headers = {
4376
+ 'X-BM-KEY': self.apiKey,
4377
+ 'X-BM-TIMESTAMP': timestamp,
4378
+ 'X-BM-BROKER-ID': brokerId,
4379
+ 'Content-Type': 'application/json',
4380
+ }
4381
+ if not getOrDelete:
4382
+ body = self.json(query)
4383
+ queryString = body
4384
+ auth = timestamp + '#' + self.uid + '#' + queryString
4385
+ signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256)
4386
+ headers['X-BM-SIGN'] = signature
4387
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
4388
+
4389
+ def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
4390
+ if response is None:
4391
+ return None
4392
+ #
4393
+ # spot
4394
+ #
4395
+ # {"message":"Bad Request [to is empty]","code":50000,"trace":"f9d46e1b-4edb-4d07-a06e-4895fb2fc8fc","data":{}}
4396
+ # {"message":"Bad Request [from is empty]","code":50000,"trace":"579986f7-c93a-4559-926b-06ba9fa79d76","data":{}}
4397
+ # {"message":"Kline size over 500","code":50004,"trace":"d625caa8-e8ca-4bd2-b77c-958776965819","data":{}}
4398
+ # {"message":"Balance not enough","code":50020,"trace":"7c709d6a-3292-462c-98c5-32362540aeef","data":{}}
4399
+ #
4400
+ # contract
4401
+ #
4402
+ # {"errno":"OK","message":"INVALID_PARAMETER","code":49998,"trace":"eb5ebb54-23cd-4de2-9064-e090b6c3b2e3","data":null}
4403
+ #
4404
+ message = self.safe_string_lower(response, 'message')
4405
+ isErrorMessage = (message is not None) and (message != 'ok') and (message != 'success')
4406
+ errorCode = self.safe_string(response, 'code')
4407
+ isErrorCode = (errorCode is not None) and (errorCode != '1000')
4408
+ if isErrorCode or isErrorMessage:
4409
+ feedback = self.id + ' ' + body
4410
+ self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
4411
+ self.throw_broadly_matched_exception(self.exceptions['broad'], errorCode, feedback)
4412
+ self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
4413
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
4414
+ raise ExchangeError(feedback) # unknown message
4415
+ return None