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,4325 @@
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.bingx import ImplicitAPI
8
+ import asyncio
9
+ import hashlib
10
+ import numbers
11
+ from ccxt.base.types import Balances, Currencies, Currency, Int, Leverage, MarginMode, MarginModification, Market, Num, Order, OrderBook, OrderRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade, Transaction, TransferEntry, TransferEntries
12
+ from typing import List
13
+ from ccxt.base.errors import ExchangeError
14
+ from ccxt.base.errors import AuthenticationError
15
+ from ccxt.base.errors import PermissionDenied
16
+ from ccxt.base.errors import AccountSuspended
17
+ from ccxt.base.errors import ArgumentsRequired
18
+ from ccxt.base.errors import BadRequest
19
+ from ccxt.base.errors import BadSymbol
20
+ from ccxt.base.errors import InsufficientFunds
21
+ from ccxt.base.errors import OrderNotFound
22
+ from ccxt.base.errors import NotSupported
23
+ from ccxt.base.errors import OperationFailed
24
+ from ccxt.base.errors import DDoSProtection
25
+ from ccxt.base.decimal_to_precision import TICK_SIZE
26
+ from ccxt.base.precise import Precise
27
+
28
+
29
+ class bingx(Exchange, ImplicitAPI):
30
+
31
+ def describe(self):
32
+ return self.deep_extend(super(bingx, self).describe(), {
33
+ 'id': 'bingx',
34
+ 'name': 'BingX',
35
+ 'countries': ['US'], # North America, Canada, the EU, Hong Kong and Taiwan
36
+ 'rateLimit': 100,
37
+ 'version': 'v1',
38
+ 'certified': True,
39
+ 'pro': True,
40
+ 'has': {
41
+ 'CORS': None,
42
+ 'spot': True,
43
+ 'margin': False,
44
+ 'swap': True,
45
+ 'future': False,
46
+ 'option': False,
47
+ 'addMargin': True,
48
+ 'cancelAllOrders': True,
49
+ 'cancelAllOrdersAfter': True,
50
+ 'cancelOrder': True,
51
+ 'cancelOrders': True,
52
+ 'closeAllPositions': True,
53
+ 'closePosition': True,
54
+ 'createMarketBuyOrderWithCost': True,
55
+ 'createMarketOrderWithCost': True,
56
+ 'createMarketSellOrderWithCost': True,
57
+ 'createOrder': True,
58
+ 'createOrders': True,
59
+ 'createOrderWithTakeProfitAndStopLoss': True,
60
+ 'createStopLossOrder': True,
61
+ 'createTakeProfitOrder': True,
62
+ 'createTrailingAmountOrder': True,
63
+ 'createTrailingPercentOrder': True,
64
+ 'createTriggerOrder': True,
65
+ 'fetchBalance': True,
66
+ 'fetchClosedOrders': True,
67
+ 'fetchCurrencies': True,
68
+ 'fetchDepositAddress': True,
69
+ 'fetchDepositAddressesByNetwork': True,
70
+ 'fetchDeposits': True,
71
+ 'fetchDepositWithdrawFee': 'emulated',
72
+ 'fetchDepositWithdrawFees': True,
73
+ 'fetchFundingRate': True,
74
+ 'fetchFundingRateHistory': True,
75
+ 'fetchFundingRates': True,
76
+ 'fetchLeverage': True,
77
+ 'fetchLiquidations': False,
78
+ 'fetchMarginAdjustmentHistory': False,
79
+ 'fetchMarginMode': True,
80
+ 'fetchMarkets': True,
81
+ 'fetchMarkOHLCV': True,
82
+ 'fetchMyLiquidations': True,
83
+ 'fetchOHLCV': True,
84
+ 'fetchOpenInterest': True,
85
+ 'fetchOpenOrders': True,
86
+ 'fetchOrder': True,
87
+ 'fetchOrderBook': True,
88
+ 'fetchOrders': True,
89
+ 'fetchPositionHistory': False,
90
+ 'fetchPositionMode': True,
91
+ 'fetchPositions': True,
92
+ 'fetchPositionsHistory': False,
93
+ 'fetchTicker': True,
94
+ 'fetchTickers': True,
95
+ 'fetchTime': True,
96
+ 'fetchTrades': True,
97
+ 'fetchTransfers': True,
98
+ 'fetchWithdrawals': True,
99
+ 'reduceMargin': True,
100
+ 'sandbox': True,
101
+ 'setLeverage': True,
102
+ 'setMargin': True,
103
+ 'setMarginMode': True,
104
+ 'setPositionMode': True,
105
+ 'transfer': True,
106
+ },
107
+ 'hostname': 'bingx.com',
108
+ 'urls': {
109
+ 'logo': 'https://github-production-user-asset-6210df.s3.amazonaws.com/1294454/253675376-6983b72e-4999-4549-b177-33b374c195e3.jpg',
110
+ 'api': {
111
+ 'spot': 'https://open-api.{hostname}/openApi',
112
+ 'swap': 'https://open-api.{hostname}/openApi',
113
+ 'contract': 'https://open-api.{hostname}/openApi',
114
+ 'wallets': 'https://open-api.{hostname}/openApi',
115
+ 'user': 'https://open-api.{hostname}/openApi',
116
+ 'subAccount': 'https://open-api.{hostname}/openApi',
117
+ 'account': 'https://open-api.{hostname}/openApi',
118
+ 'copyTrading': 'https://open-api.{hostname}/openApi',
119
+ },
120
+ 'test': {
121
+ 'swap': 'https://open-api-vst.{hostname}/openApi', # only swap is really "test" but since the API keys are the same, we want to keep all the functionalities when the user enables the sandboxmode
122
+ },
123
+ 'www': 'https://bingx.com/',
124
+ 'doc': 'https://bingx-api.github.io/docs/',
125
+ 'referral': 'https://bingx.com/invite/OHETOM',
126
+ },
127
+ 'fees': {
128
+ 'tierBased': True,
129
+ 'spot': {
130
+ 'feeSide': 'get',
131
+ 'maker': self.parse_number('0.001'),
132
+ 'taker': self.parse_number('0.001'),
133
+ },
134
+ 'swap': {
135
+ 'feeSide': 'quote',
136
+ 'maker': self.parse_number('0.0002'),
137
+ 'taker': self.parse_number('0.0005'),
138
+ },
139
+ },
140
+ 'requiredCredentials': {
141
+ 'apiKey': True,
142
+ 'secret': True,
143
+ },
144
+ 'api': {
145
+ 'spot': {
146
+ 'v1': {
147
+ 'public': {
148
+ 'get': {
149
+ 'server/time': 1,
150
+ 'common/symbols': 1,
151
+ 'market/trades': 1,
152
+ 'market/depth': 1,
153
+ 'market/kline': 1,
154
+ 'ticker/24hr': 1,
155
+ 'ticker/price': 1,
156
+ 'ticker/bookTicker': 1,
157
+ },
158
+ },
159
+ 'private': {
160
+ 'get': {
161
+ 'trade/query': 1,
162
+ 'trade/openOrders': 1,
163
+ 'trade/historyOrders': 1,
164
+ 'trade/myTrades': 2,
165
+ 'user/commissionRate': 5,
166
+ 'account/balance': 2,
167
+ },
168
+ 'post': {
169
+ 'trade/order': 2,
170
+ 'trade/cancel': 2,
171
+ 'trade/batchOrders': 5,
172
+ 'trade/order/cancelReplace': 5,
173
+ 'trade/cancelOrders': 5,
174
+ 'trade/cancelOpenOrders': 5,
175
+ 'trade/cancelAllAfter': 5,
176
+ },
177
+ },
178
+ },
179
+ 'v2': {
180
+ 'public': {
181
+ 'get': {
182
+ 'market/depth': 1,
183
+ 'market/kline': 1,
184
+ },
185
+ },
186
+ },
187
+ 'v3': {
188
+ 'private': {
189
+ 'get': {
190
+ 'get/asset/transfer': 1,
191
+ 'asset/transfer': 1,
192
+ 'capital/deposit/hisrec': 1,
193
+ 'capital/withdraw/history': 1,
194
+ },
195
+ 'post': {
196
+ 'post/asset/transfer': 5,
197
+ },
198
+ },
199
+ },
200
+ },
201
+ 'swap': {
202
+ 'v1': {
203
+ 'public': {
204
+ 'get': {
205
+ 'ticker/price': 1,
206
+ 'market/historicalTrades': 1,
207
+ },
208
+ },
209
+ 'private': {
210
+ 'get': {
211
+ 'positionSide/dual': 5,
212
+ 'market/markPriceKlines': 1,
213
+ 'trade/batchCancelReplace': 5,
214
+ 'trade/fullOrder': 2,
215
+ },
216
+ 'post': {
217
+ 'trade/cancelReplace': 2,
218
+ 'positionSide/dual': 5,
219
+ 'trade/closePosition': 2,
220
+ },
221
+ },
222
+ },
223
+ 'v2': {
224
+ 'public': {
225
+ 'get': {
226
+ 'server/time': 1,
227
+ 'quote/contracts': 1,
228
+ 'quote/price': 1,
229
+ 'quote/depth': 1,
230
+ 'quote/trades': 1,
231
+ 'quote/premiumIndex': 1,
232
+ 'quote/fundingRate': 1,
233
+ 'quote/klines': 1,
234
+ 'quote/openInterest': 1,
235
+ 'quote/ticker': 1,
236
+ 'quote/bookTicker': 1,
237
+ },
238
+ },
239
+ 'private': {
240
+ 'get': {
241
+ 'user/balance': 2,
242
+ 'user/positions': 2,
243
+ 'user/income': 2,
244
+ 'trade/openOrders': 2,
245
+ 'trade/openOrder': 2,
246
+ 'trade/order': 2,
247
+ 'trade/marginType': 5,
248
+ 'trade/leverage': 2,
249
+ 'trade/forceOrders': 1,
250
+ 'trade/allOrders': 2,
251
+ 'trade/allFillOrders': 2,
252
+ 'user/income/export': 2,
253
+ 'user/commissionRate': 2,
254
+ 'quote/bookTicker': 1,
255
+ },
256
+ 'post': {
257
+ 'trade/order': 2,
258
+ 'trade/batchOrders': 2,
259
+ 'trade/closeAllPositions': 2,
260
+ 'trade/cancelAllAfter': 5,
261
+ 'trade/marginType': 5,
262
+ 'trade/leverage': 5,
263
+ 'trade/positionMargin': 5,
264
+ 'trade/order/test': 2,
265
+ },
266
+ 'delete': {
267
+ 'trade/order': 2,
268
+ 'trade/batchOrders': 2,
269
+ 'trade/allOpenOrders': 2,
270
+ },
271
+ },
272
+ },
273
+ 'v3': {
274
+ 'public': {
275
+ 'get': {
276
+ 'quote/klines': 1,
277
+ },
278
+ },
279
+ },
280
+ },
281
+ 'contract': {
282
+ 'v1': {
283
+ 'private': {
284
+ 'get': {
285
+ 'allPosition': 2,
286
+ 'allOrders': 2,
287
+ 'balance': 2,
288
+ },
289
+ },
290
+ },
291
+ },
292
+ 'wallets': {
293
+ 'v1': {
294
+ 'private': {
295
+ 'get': {
296
+ 'capital/config/getall': 5,
297
+ 'capital/deposit/address': 5,
298
+ 'capital/innerTransfer/records': 1,
299
+ 'capital/subAccount/deposit/address': 5,
300
+ 'capital/deposit/subHisrec': 2,
301
+ 'capital/subAccount/innerTransfer/records': 1,
302
+ 'capital/deposit/riskRecords': 5,
303
+ },
304
+ 'post': {
305
+ 'capital/withdraw/apply': 5,
306
+ 'capital/innerTransfer/apply': 5,
307
+ 'capital/subAccountInnerTransfer/apply': 2,
308
+ 'capital/deposit/createSubAddress': 2,
309
+ },
310
+ },
311
+ },
312
+ },
313
+ 'subAccount': {
314
+ 'v1': {
315
+ 'private': {
316
+ 'get': {
317
+ 'list': 10,
318
+ 'assets': 2,
319
+ },
320
+ 'post': {
321
+ 'create': 10,
322
+ 'apiKey/create': 2,
323
+ 'apiKey/edit': 2,
324
+ 'apiKey/del': 2,
325
+ 'updateStatus': 10,
326
+ },
327
+ },
328
+ },
329
+ },
330
+ 'account': {
331
+ 'v1': {
332
+ 'private': {
333
+ 'get': {
334
+ 'uid': 1,
335
+ 'apiKey/query': 2,
336
+ },
337
+ 'post': {
338
+ 'innerTransfer/authorizeSubAccount': 1,
339
+ },
340
+ },
341
+ },
342
+ },
343
+ 'user': {
344
+ 'auth': {
345
+ 'private': {
346
+ 'post': {
347
+ 'userDataStream': 2,
348
+ },
349
+ 'put': {
350
+ 'userDataStream': 2,
351
+ },
352
+ 'delete': {
353
+ 'userDataStream': 2,
354
+ },
355
+ },
356
+ },
357
+ },
358
+ 'copyTrading': {
359
+ 'v1': {
360
+ 'private': {
361
+ 'get': {
362
+ 'swap/trace/currentTrack': 2,
363
+ },
364
+ 'post': {
365
+ 'swap/trace/closeTrackOrder': 2,
366
+ 'swap/trace/setTPSL': 2,
367
+ 'spot/trader/sellOrder': 10,
368
+ },
369
+ },
370
+ },
371
+ },
372
+ 'api': {
373
+ 'v3': {
374
+ 'private': {
375
+ 'get': {
376
+ 'asset/transfer': 1,
377
+ 'capital/deposit/hisrec': 1,
378
+ 'capital/withdraw/history': 1,
379
+ },
380
+ 'post': {
381
+ 'post/asset/transfer': 1,
382
+ },
383
+ },
384
+ },
385
+ },
386
+ },
387
+ 'timeframes': {
388
+ '1m': '1m',
389
+ '3m': '3m',
390
+ '5m': '5m',
391
+ '15m': '15m',
392
+ '30m': '30m',
393
+ '1h': '1h',
394
+ '2h': '2h',
395
+ '4h': '4h',
396
+ '6h': '6h',
397
+ '12h': '12h',
398
+ '1d': '1d',
399
+ '3d': '3d',
400
+ '1w': '1w',
401
+ '1M': '1M',
402
+ },
403
+ 'precisionMode': TICK_SIZE,
404
+ 'exceptions': {
405
+ 'exact': {
406
+ '400': BadRequest,
407
+ '401': AuthenticationError,
408
+ '403': PermissionDenied,
409
+ '404': BadRequest,
410
+ '429': DDoSProtection,
411
+ '418': PermissionDenied,
412
+ '500': ExchangeError,
413
+ '504': ExchangeError,
414
+ '100001': AuthenticationError,
415
+ '100412': AuthenticationError,
416
+ '100202': InsufficientFunds,
417
+ '100204': BadRequest,
418
+ '100400': BadRequest,
419
+ '100410': OperationFailed, # {"code":100410,"msg":"The current system is busy, please try again later"}
420
+ '100421': BadSymbol, # {"code":100421,"msg":"This pair is currently restricted from API trading","debugMsg":""}
421
+ '100440': ExchangeError,
422
+ '100500': OperationFailed, # {"code":100500,"msg":"The current system is busy, please try again later","debugMsg":""}
423
+ '100503': ExchangeError,
424
+ '80001': BadRequest,
425
+ '80012': InsufficientFunds, # {"code":80012,"msg":"{\"Code\":101253,\"Msg\":\"margin is not enough\"}}
426
+ '80014': BadRequest,
427
+ '80016': OrderNotFound,
428
+ '80017': OrderNotFound,
429
+ '100414': AccountSuspended, # {"code":100414,"msg":"Code: 100414, Msg: risk control check fail,code(1)","debugMsg":""}
430
+ '100419': PermissionDenied, # {"code":100419,"msg":"IP does not match IP whitelist","success":false,"timestamp":1705274099347}
431
+ '100437': BadRequest, # {"code":100437,"msg":"The withdrawal amount is lower than the minimum limit, please re-enter.","timestamp":1689258588845}
432
+ '101204': InsufficientFunds, # {"code":101204,"msg":"","data":{}}
433
+ },
434
+ 'broad': {},
435
+ },
436
+ 'commonCurrencies': {
437
+ 'SNOW': 'Snowman', # Snowman vs SnowSwap conflict
438
+ },
439
+ 'options': {
440
+ 'defaultType': 'spot',
441
+ 'accountsByType': {
442
+ 'spot': 'FUND',
443
+ 'swap': 'PFUTURES',
444
+ 'future': 'SFUTURES',
445
+ },
446
+ 'accountsById': {
447
+ 'FUND': 'spot',
448
+ 'PFUTURES': 'swap',
449
+ 'SFUTURES': 'future',
450
+ },
451
+ 'recvWindow': 5 * 1000, # 5 sec
452
+ 'broker': 'CCXT',
453
+ 'defaultNetworks': {
454
+ 'ETH': 'ETH',
455
+ 'USDT': 'ERC20',
456
+ 'USDC': 'ERC20',
457
+ 'BTC': 'BTC',
458
+ 'LTC': 'LTC',
459
+ },
460
+ },
461
+ })
462
+
463
+ async def fetch_time(self, params={}):
464
+ """
465
+ fetches the current integer timestamp in milliseconds from the bingx server
466
+ :see: https://bingx-api.github.io/docs/#/swapV2/base-info.html#Get%20Server%20Time
467
+ :param dict [params]: extra parameters specific to the exchange API endpoint
468
+ :returns int: the current integer timestamp in milliseconds from the bingx server
469
+ """
470
+ response = await self.swapV2PublicGetServerTime(params)
471
+ #
472
+ # {
473
+ # "code": 0,
474
+ # "msg": "",
475
+ # "data": {
476
+ # "serverTime": 1675319535362
477
+ # }
478
+ # }
479
+ #
480
+ data = self.safe_dict(response, 'data')
481
+ return self.safe_integer(data, 'serverTime')
482
+
483
+ async def fetch_currencies(self, params={}) -> Currencies:
484
+ """
485
+ fetches all available currencies on an exchange
486
+ :see: https://bingx-api.github.io/docs/#/common/account-api.html#All%20Coins
487
+ :param dict [params]: extra parameters specific to the exchange API endpoint
488
+ :returns dict: an associative dictionary of currencies
489
+ """
490
+ if not self.check_required_credentials(False):
491
+ return None
492
+ isSandbox = self.safe_bool(self.options, 'sandboxMode', False)
493
+ if isSandbox:
494
+ return None
495
+ response = await self.walletsV1PrivateGetCapitalConfigGetall(params)
496
+ #
497
+ # {
498
+ # "code": 0,
499
+ # "timestamp": 1688045966616,
500
+ # "data": [
501
+ # {
502
+ # "coin": "BTC",
503
+ # "name": "BTC",
504
+ # "networkList": [
505
+ # {
506
+ # "name": "BTC",
507
+ # "network": "BTC",
508
+ # "isDefault": True,
509
+ # "minConfirm": "2",
510
+ # "withdrawEnable": True,
511
+ # "withdrawFee": "0.00035",
512
+ # "withdrawMax": "1.62842",
513
+ # "withdrawMin": "0.0005"
514
+ # },
515
+ # {
516
+ # "name": "BTC",
517
+ # "network": "BEP20",
518
+ # "isDefault": False,
519
+ # "minConfirm": "15",
520
+ # "withdrawEnable": True,
521
+ # "withdrawFee": "0.00001",
522
+ # "withdrawMax": "1.62734",
523
+ # "withdrawMin": "0.0001"
524
+ # }
525
+ # ]
526
+ # },
527
+ # ...
528
+ # ],
529
+ # }
530
+ #
531
+ data = self.safe_list(response, 'data', [])
532
+ result: dict = {}
533
+ for i in range(0, len(data)):
534
+ entry = data[i]
535
+ currencyId = self.safe_string(entry, 'coin')
536
+ code = self.safe_currency_code(currencyId)
537
+ name = self.safe_string(entry, 'name')
538
+ networkList = self.safe_list(entry, 'networkList')
539
+ networks: dict = {}
540
+ fee = None
541
+ active = None
542
+ withdrawEnabled = None
543
+ defaultLimits: dict = {}
544
+ for j in range(0, len(networkList)):
545
+ rawNetwork = networkList[j]
546
+ network = self.safe_string(rawNetwork, 'network')
547
+ networkCode = self.network_id_to_code(network)
548
+ isDefault = self.safe_bool(rawNetwork, 'isDefault')
549
+ withdrawEnabled = self.safe_bool(rawNetwork, 'withdrawEnable')
550
+ limits: dict = {
551
+ 'amounts': {'min': self.safe_number(rawNetwork, 'withdrawMin'), 'max': self.safe_number(rawNetwork, 'withdrawMax')},
552
+ }
553
+ if isDefault:
554
+ fee = self.safe_number(rawNetwork, 'withdrawFee')
555
+ active = withdrawEnabled
556
+ defaultLimits = limits
557
+ networks[networkCode] = {
558
+ 'info': rawNetwork,
559
+ 'id': network,
560
+ 'network': networkCode,
561
+ 'fee': fee,
562
+ 'active': active,
563
+ 'deposit': None,
564
+ 'withdraw': withdrawEnabled,
565
+ 'precision': None,
566
+ 'limits': limits,
567
+ }
568
+ result[code] = {
569
+ 'info': entry,
570
+ 'code': code,
571
+ 'id': currencyId,
572
+ 'precision': None,
573
+ 'name': name,
574
+ 'active': active,
575
+ 'deposit': None,
576
+ 'withdraw': withdrawEnabled,
577
+ 'networks': networks,
578
+ 'fee': fee,
579
+ 'limits': defaultLimits,
580
+ }
581
+ return result
582
+
583
+ async def fetch_spot_markets(self, params):
584
+ response = await self.spotV1PublicGetCommonSymbols(params)
585
+ #
586
+ # {
587
+ # "code": 0,
588
+ # "msg": "",
589
+ # "debugMsg": "",
590
+ # "data": {
591
+ # "symbols": [
592
+ # {
593
+ # "symbol": "GEAR-USDT",
594
+ # "minQty": 735,
595
+ # "maxQty": 2941177,
596
+ # "minNotional": 5,
597
+ # "maxNotional": 20000,
598
+ # "status": 1,
599
+ # "tickSize": 0.000001,
600
+ # "stepSize": 1
601
+ # },
602
+ # ...
603
+ # ]
604
+ # }
605
+ # }
606
+ #
607
+ data = self.safe_dict(response, 'data')
608
+ markets = self.safe_list(data, 'symbols', [])
609
+ return self.parse_markets(markets)
610
+
611
+ async def fetch_swap_markets(self, params):
612
+ response = await self.swapV2PublicGetQuoteContracts(params)
613
+ #
614
+ # {
615
+ # "code": 0,
616
+ # "msg": "",
617
+ # "data": [
618
+ # {
619
+ # "contractId": "100",
620
+ # "symbol": "BTC-USDT",
621
+ # "size": "0.0001",
622
+ # "quantityPrecision": "4",
623
+ # "pricePrecision": "1",
624
+ # "feeRate": "0.0005",
625
+ # "makerFeeRate": "0.0002",
626
+ # "takerFeeRate": "0.0005",
627
+ # "tradeMinLimit": "0",
628
+ # "tradeMinQuantity": "0.0001",
629
+ # "tradeMinUSDT": "2",
630
+ # "maxLongLeverage": "125",
631
+ # "maxShortLeverage": "125",
632
+ # "currency": "USDT",
633
+ # "asset": "BTC",
634
+ # "status": "1",
635
+ # "apiStateOpen": "true",
636
+ # "apiStateClose": "true",
637
+ # "ensureTrigger": True,
638
+ # "triggerFeeRate": "0.00020000"
639
+ # },
640
+ # ...
641
+ # ]
642
+ # }
643
+ #
644
+ markets = self.safe_list(response, 'data', [])
645
+ return self.parse_markets(markets)
646
+
647
+ def parse_market(self, market: dict) -> Market:
648
+ id = self.safe_string(market, 'symbol')
649
+ symbolParts = id.split('-')
650
+ baseId = symbolParts[0]
651
+ quoteId = symbolParts[1]
652
+ base = self.safe_currency_code(baseId)
653
+ quote = self.safe_currency_code(quoteId)
654
+ currency = self.safe_string(market, 'currency')
655
+ settle = self.safe_currency_code(currency)
656
+ pricePrecision = self.safe_number(market, 'tickSize')
657
+ if pricePrecision is None:
658
+ pricePrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision')))
659
+ quantityPrecision = self.safe_number(market, 'stepSize')
660
+ if quantityPrecision is None:
661
+ quantityPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision')))
662
+ type = 'swap' if (settle is not None) else 'spot'
663
+ spot = type == 'spot'
664
+ swap = type == 'swap'
665
+ symbol = base + '/' + quote
666
+ if settle is not None:
667
+ symbol += ':' + settle
668
+ fees = self.safe_dict(self.fees, type, {})
669
+ contractSize = self.parse_number('1') if (swap) else None
670
+ isActive = self.safe_string(market, 'status') == '1'
671
+ isInverse = None if (spot) else False
672
+ isLinear = None if (spot) else swap
673
+ return self.safe_market_structure({
674
+ 'id': id,
675
+ 'symbol': symbol,
676
+ 'base': base,
677
+ 'quote': quote,
678
+ 'settle': settle,
679
+ 'baseId': baseId,
680
+ 'quoteId': quoteId,
681
+ 'settleId': currency,
682
+ 'type': type,
683
+ 'spot': spot,
684
+ 'margin': False,
685
+ 'swap': swap,
686
+ 'future': False,
687
+ 'option': False,
688
+ 'active': isActive,
689
+ 'contract': swap,
690
+ 'linear': isLinear,
691
+ 'inverse': isInverse,
692
+ 'taker': self.safe_number(fees, 'taker'),
693
+ 'maker': self.safe_number(fees, 'maker'),
694
+ 'feeSide': self.safe_string(fees, 'feeSide'),
695
+ 'contractSize': contractSize,
696
+ 'expiry': None,
697
+ 'expiryDatetime': None,
698
+ 'strike': None,
699
+ 'optionType': None,
700
+ 'precision': {
701
+ 'amount': quantityPrecision,
702
+ 'price': pricePrecision,
703
+ },
704
+ 'limits': {
705
+ 'leverage': {
706
+ 'min': None,
707
+ 'max': self.safe_integer(market, 'maxLongLeverage'),
708
+ },
709
+ 'amount': {
710
+ 'min': self.safe_number_2(market, 'minQty', 'tradeMinQuantity'),
711
+ 'max': self.safe_number(market, 'maxQty'),
712
+ },
713
+ 'price': {
714
+ 'min': None,
715
+ 'max': None,
716
+ },
717
+ 'cost': {
718
+ 'min': self.safe_number_2(market, 'minNotional', 'tradeMinUSDT'),
719
+ 'max': self.safe_number(market, 'maxNotional'),
720
+ },
721
+ },
722
+ 'created': None,
723
+ 'info': market,
724
+ })
725
+
726
+ async def fetch_markets(self, params={}) -> List[Market]:
727
+ """
728
+ retrieves data on all markets for bingx
729
+ :see: https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20Symbols
730
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Contract%20Information
731
+ :param dict [params]: extra parameters specific to the exchange API endpoint
732
+ :returns dict[]: an array of objects representing market data
733
+ """
734
+ requests = [self.fetch_swap_markets(params)]
735
+ isSandbox = self.safe_bool(self.options, 'sandboxMode', False)
736
+ if not isSandbox:
737
+ requests.append(self.fetch_spot_markets(params)) # sandbox is swap only
738
+ promises = await asyncio.gather(*requests)
739
+ spotMarkets = self.safe_list(promises, 0, [])
740
+ swapMarkets = self.safe_list(promises, 1, [])
741
+ return self.array_concat(spotMarkets, swapMarkets)
742
+
743
+ async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
744
+ """
745
+ fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
746
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#K-Line%20Data
747
+ :see: https://bingx-api.github.io/docs/#/spot/market-api.html#Candlestick%20chart%20data
748
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#%20K-Line%20Data
749
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/market-api.html#K-Line%20Data%20-%20Mark%20Price
750
+ :param str symbol: unified symbol of the market to fetch OHLCV data for
751
+ :param str timeframe: the length of time each candle represents
752
+ :param int [since]: timestamp in ms of the earliest candle to fetch
753
+ :param int [limit]: the maximum amount of candles to fetch
754
+ :param dict [params]: extra parameters specific to the exchange API endpoint
755
+ :param int [params.until]: timestamp in ms of the latest candle to fetch
756
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
757
+ :returns int[][]: A list of candles ordered, open, high, low, close, volume
758
+ """
759
+ await self.load_markets()
760
+ paginate = False
761
+ paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate', False)
762
+ if paginate:
763
+ return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 1440)
764
+ market = self.market(symbol)
765
+ request: dict = {
766
+ 'symbol': market['id'],
767
+ }
768
+ request['interval'] = self.safe_string(self.timeframes, timeframe, timeframe)
769
+ if since is not None:
770
+ request['startTime'] = since
771
+ if limit is not None:
772
+ request['limit'] = limit
773
+ until = self.safe_integer_2(params, 'until', 'endTime')
774
+ if until is not None:
775
+ params = self.omit(params, ['until'])
776
+ request['endTime'] = until
777
+ response = None
778
+ if market['spot']:
779
+ response = await self.spotV1PublicGetMarketKline(self.extend(request, params))
780
+ else:
781
+ price = self.safe_string(params, 'price')
782
+ params = self.omit(params, 'price')
783
+ if price == 'mark':
784
+ response = await self.swapV1PrivateGetMarketMarkPriceKlines(self.extend(request, params))
785
+ else:
786
+ response = await self.swapV3PublicGetQuoteKlines(self.extend(request, params))
787
+ #
788
+ # {
789
+ # "code": 0,
790
+ # "msg": "",
791
+ # "data": [
792
+ # {
793
+ # "open": "19396.8",
794
+ # "close": "19394.4",
795
+ # "high": "19397.5",
796
+ # "low": "19385.7",
797
+ # "volume": "110.05",
798
+ # "time": 1666583700000
799
+ # },
800
+ # ...
801
+ # ]
802
+ # }
803
+ #
804
+ # fetchMarkOHLCV
805
+ #
806
+ # {
807
+ # "code": 0,
808
+ # "msg": "",
809
+ # "data": [
810
+ # {
811
+ # "open": "42191.7",
812
+ # "close": "42189.5",
813
+ # "high": "42196.5",
814
+ # "low": "42189.5",
815
+ # "volume": "0.00",
816
+ # "openTime": 1706508840000,
817
+ # "closeTime": 1706508840000
818
+ # }
819
+ # ]
820
+ # }
821
+ #
822
+ ohlcvs = self.safe_value(response, 'data', [])
823
+ if not isinstance(ohlcvs, list):
824
+ ohlcvs = [ohlcvs]
825
+ return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
826
+
827
+ def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
828
+ #
829
+ # {
830
+ # "open": "19394.4",
831
+ # "close": "19379.0",
832
+ # "high": "19394.4",
833
+ # "low": "19368.3",
834
+ # "volume": "167.44",
835
+ # "time": 1666584000000
836
+ # }
837
+ #
838
+ # fetchMarkOHLCV
839
+ #
840
+ # {
841
+ # "open": "42191.7",
842
+ # "close": "42189.5",
843
+ # "high": "42196.5",
844
+ # "low": "42189.5",
845
+ # "volume": "0.00",
846
+ # "openTime": 1706508840000,
847
+ # "closeTime": 1706508840000
848
+ # }
849
+ # spot
850
+ # [
851
+ # 1691402580000,
852
+ # 29093.61,
853
+ # 29093.93,
854
+ # 29087.73,
855
+ # 29093.24,
856
+ # 0.59,
857
+ # 1691402639999,
858
+ # 17221.07
859
+ # ]
860
+ #
861
+ if isinstance(ohlcv, list):
862
+ return [
863
+ self.safe_integer(ohlcv, 0),
864
+ self.safe_number(ohlcv, 1),
865
+ self.safe_number(ohlcv, 2),
866
+ self.safe_number(ohlcv, 3),
867
+ self.safe_number(ohlcv, 4),
868
+ self.safe_number(ohlcv, 5),
869
+ ]
870
+ return [
871
+ self.safe_integer_2(ohlcv, 'time', 'closeTime'),
872
+ self.safe_number(ohlcv, 'open'),
873
+ self.safe_number(ohlcv, 'high'),
874
+ self.safe_number(ohlcv, 'low'),
875
+ self.safe_number(ohlcv, 'close'),
876
+ self.safe_number(ohlcv, 'volume'),
877
+ ]
878
+
879
+ async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
880
+ """
881
+ get the list of most recent trades for a particular symbol
882
+ :see: https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20transaction%20records
883
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#The%20latest%20Trade%20of%20a%20Trading%20Pair
884
+ :param str symbol: unified symbol of the market to fetch trades for
885
+ :param int [since]: timestamp in ms of the earliest trade to fetch
886
+ :param int [limit]: the maximum amount of trades to fetch
887
+ :param dict [params]: extra parameters specific to the exchange API endpoint
888
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
889
+ """
890
+ await self.load_markets()
891
+ market = self.market(symbol)
892
+ request: dict = {
893
+ 'symbol': market['id'],
894
+ }
895
+ if limit is not None:
896
+ request['limit'] = min(limit, 100) # avoid API exception "limit should less than 100"
897
+ response = None
898
+ marketType = None
899
+ marketType, params = self.handle_market_type_and_params('fetchTrades', market, params)
900
+ if marketType == 'spot':
901
+ response = await self.spotV1PublicGetMarketTrades(self.extend(request, params))
902
+ else:
903
+ response = await self.swapV2PublicGetQuoteTrades(self.extend(request, params))
904
+ #
905
+ # spot
906
+ #
907
+ # {
908
+ # "code": 0,
909
+ # "data": [
910
+ # {
911
+ # "id": 43148253,
912
+ # "price": 25714.71,
913
+ # "qty": 1.674571,
914
+ # "time": 1655085975589,
915
+ # "buyerMaker": False
916
+ # }
917
+ # ]
918
+ # }
919
+ #
920
+ # swap
921
+ #
922
+ # {
923
+ # "code":0,
924
+ # "msg":"",
925
+ # "data":[
926
+ # {
927
+ # "time": 1672025549368,
928
+ # "isBuyerMaker": True,
929
+ # "price": "16885.0",
930
+ # "qty": "3.3002",
931
+ # "quoteQty": "55723.87"
932
+ # },
933
+ # ...
934
+ # ]
935
+ # }
936
+ #
937
+ trades = self.safe_list(response, 'data', [])
938
+ return self.parse_trades(trades, market, since, limit)
939
+
940
+ def parse_trade(self, trade: dict, market: Market = None) -> Trade:
941
+ #
942
+ # spot
943
+ # fetchTrades
944
+ #
945
+ # {
946
+ # "id": 43148253,
947
+ # "price": 25714.71,
948
+ # "qty": 1.674571,
949
+ # "time": 1655085975589,
950
+ # "buyerMaker": False
951
+ # }
952
+ #
953
+ # spot
954
+ # fetchMyTrades
955
+ # {
956
+ # "symbol": "LTC-USDT",
957
+ # "id": 36237072,
958
+ # "orderId": 1674069326895775744,
959
+ # "price": "85.891",
960
+ # "qty": "0.0582",
961
+ # "quoteQty": "4.9988562000000005",
962
+ # "commission": -0.00005820000000000001,
963
+ # "commissionAsset": "LTC",
964
+ # "time": 1687964205000,
965
+ # "isBuyer": True,
966
+ # "isMaker": False
967
+ # }
968
+ #
969
+ # swap
970
+ # fetchTrades
971
+ #
972
+ # {
973
+ # "time": 1672025549368,
974
+ # "isBuyerMaker": True,
975
+ # "price": "16885.0",
976
+ # "qty": "3.3002",
977
+ # "quoteQty": "55723.87"
978
+ # }
979
+ #
980
+ # swap
981
+ # fetchMyTrades
982
+ #
983
+ # {
984
+ # "volume": "0.1",
985
+ # "price": "106.75",
986
+ # "amount": "10.6750",
987
+ # "commission": "-0.0053",
988
+ # "currency": "USDT",
989
+ # "orderId": "1676213270274379776",
990
+ # "liquidatedPrice": "0.00",
991
+ # "liquidatedMarginRatio": "0.00",
992
+ # "filledTime": "2023-07-04T20:56:01.000+0800"
993
+ # }
994
+ #
995
+ #
996
+ # ws
997
+ #
998
+ # spot
999
+ #
1000
+ # {
1001
+ # "E": 1690214529432,
1002
+ # "T": 1690214529386,
1003
+ # "e": "trade",
1004
+ # "m": True,
1005
+ # "p": "29110.19",
1006
+ # "q": "0.1868",
1007
+ # "s": "BTC-USDT",
1008
+ # "t": "57903921"
1009
+ # }
1010
+ #
1011
+ # swap
1012
+ #
1013
+ # {
1014
+ # "q": "0.0421",
1015
+ # "p": "29023.5",
1016
+ # "T": 1690221401344,
1017
+ # "m": False,
1018
+ # "s": "BTC-USDT"
1019
+ # }
1020
+ #
1021
+ time = self.safe_integer_n(trade, ['time', 'filledTm', 'T'])
1022
+ datetimeId = self.safe_string(trade, 'filledTm')
1023
+ if datetimeId is not None:
1024
+ time = self.parse8601(datetimeId)
1025
+ if time == 0:
1026
+ time = None
1027
+ cost = self.safe_string(trade, 'quoteQty')
1028
+ # type = 'spot' if (cost is None) else 'swap'; self is not reliable
1029
+ currencyId = self.safe_string_n(trade, ['currency', 'N', 'commissionAsset'])
1030
+ currencyCode = self.safe_currency_code(currencyId)
1031
+ m = self.safe_bool(trade, 'm')
1032
+ marketId = self.safe_string(trade, 's')
1033
+ isBuyerMaker = self.safe_bool_2(trade, 'buyerMaker', 'isBuyerMaker')
1034
+ takeOrMaker = None
1035
+ if (isBuyerMaker is not None) or (m is not None):
1036
+ takeOrMaker = 'maker' if (isBuyerMaker or m) else 'taker'
1037
+ side = self.safe_string_lower_2(trade, 'side', 'S')
1038
+ if side is None:
1039
+ if (isBuyerMaker is not None) or (m is not None):
1040
+ side = 'sell' if (isBuyerMaker or m) else 'buy'
1041
+ takeOrMaker = 'taker'
1042
+ isBuyer = self.safe_bool(trade, 'isBuyer')
1043
+ if isBuyer is not None:
1044
+ side = 'buy' if isBuyer else 'sell'
1045
+ isMaker = self.safe_bool(trade, 'isMaker')
1046
+ if isMaker is not None:
1047
+ takeOrMaker = 'maker' if isMaker else 'taker'
1048
+ amount = self.safe_string_n(trade, ['qty', 'amount', 'q'])
1049
+ if (market is not None) and market['swap'] and ('volume' in trade):
1050
+ # private trade returns num of contracts instead of base currency(as the order-related methods do)
1051
+ contractSize = self.safe_string(market['info'], 'tradeMinQuantity')
1052
+ volume = self.safe_string(trade, 'volume')
1053
+ amount = Precise.string_mul(volume, contractSize)
1054
+ return self.safe_trade({
1055
+ 'id': self.safe_string_n(trade, ['id', 't']),
1056
+ 'info': trade,
1057
+ 'timestamp': time,
1058
+ 'datetime': self.iso8601(time),
1059
+ 'symbol': self.safe_symbol(marketId, market, '-'),
1060
+ 'order': self.safe_string_2(trade, 'orderId', 'i'),
1061
+ 'type': self.safe_string_lower(trade, 'o'),
1062
+ 'side': self.parse_order_side(side),
1063
+ 'takerOrMaker': takeOrMaker,
1064
+ 'price': self.safe_string_2(trade, 'price', 'p'),
1065
+ 'amount': amount,
1066
+ 'cost': cost,
1067
+ 'fee': {
1068
+ 'cost': self.parse_number(Precise.string_abs(self.safe_string_2(trade, 'commission', 'n'))),
1069
+ 'currency': currencyCode,
1070
+ 'rate': None,
1071
+ },
1072
+ }, market)
1073
+
1074
+ async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
1075
+ """
1076
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
1077
+ :see: https://bingx-api.github.io/docs/#/spot/market-api.html#Query%20depth%20information
1078
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Market%20Depth
1079
+ :param str symbol: unified symbol of the market to fetch the order book for
1080
+ :param int [limit]: the maximum amount of order book entries to return
1081
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1082
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
1083
+ """
1084
+ await self.load_markets()
1085
+ market = self.market(symbol)
1086
+ request: dict = {
1087
+ 'symbol': market['id'],
1088
+ }
1089
+ if limit is not None:
1090
+ request['limit'] = limit
1091
+ response = None
1092
+ marketType = None
1093
+ marketType, params = self.handle_market_type_and_params('fetchOrderBook', market, params)
1094
+ if marketType == 'spot':
1095
+ response = await self.spotV1PublicGetMarketDepth(self.extend(request, params))
1096
+ else:
1097
+ response = await self.swapV2PublicGetQuoteDepth(self.extend(request, params))
1098
+ #
1099
+ # spot
1100
+ #
1101
+ # {
1102
+ # "code": 0,
1103
+ # "data": {
1104
+ # "bids": [
1105
+ # [
1106
+ # "26324.73",
1107
+ # "0.37655"
1108
+ # ],
1109
+ # [
1110
+ # "26324.71",
1111
+ # "0.31888"
1112
+ # ],
1113
+ # ],
1114
+ # "asks": [
1115
+ # [
1116
+ # "26340.30",
1117
+ # "6.45221"
1118
+ # ],
1119
+ # [
1120
+ # "26340.15",
1121
+ # "6.73261"
1122
+ # ],
1123
+ # ]}
1124
+ # }
1125
+ #
1126
+ # swap
1127
+ #
1128
+ # {
1129
+ # "code": 0,
1130
+ # "msg": "",
1131
+ # "data": {
1132
+ # "T": 1683914263304,
1133
+ # "bids": [
1134
+ # [
1135
+ # "26300.90000000",
1136
+ # "30408.00000000"
1137
+ # ],
1138
+ # [
1139
+ # "26300.80000000",
1140
+ # "50906.00000000"
1141
+ # ],
1142
+ # ],
1143
+ # "asks": [
1144
+ # [
1145
+ # "26301.00000000",
1146
+ # "43616.00000000"
1147
+ # ],
1148
+ # [
1149
+ # "26301.10000000",
1150
+ # "49402.00000000"
1151
+ # ],
1152
+ # ]}
1153
+ # }
1154
+ #
1155
+ orderbook = self.safe_dict(response, 'data', {})
1156
+ timestamp = self.safe_integer_2(orderbook, 'T', 'ts')
1157
+ return self.parse_order_book(orderbook, market['symbol'], timestamp, 'bids', 'asks', 0, 1)
1158
+
1159
+ async def fetch_funding_rate(self, symbol: str, params={}):
1160
+ """
1161
+ fetch the current funding rate
1162
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Current%20Funding%20Rate
1163
+ :param str symbol: unified market symbol
1164
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1165
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1166
+ """
1167
+ await self.load_markets()
1168
+ market = self.market(symbol)
1169
+ request: dict = {
1170
+ 'symbol': market['id'],
1171
+ }
1172
+ response = await self.swapV2PublicGetQuotePremiumIndex(self.extend(request, params))
1173
+ #
1174
+ # {
1175
+ # "code":0,
1176
+ # "msg":"",
1177
+ # "data":[
1178
+ # {
1179
+ # "symbol": "BTC-USDT",
1180
+ # "markPrice": "16884.5",
1181
+ # "indexPrice": "16886.9",
1182
+ # "lastFundingRate": "0.0001",
1183
+ # "nextFundingTime": 1672041600000
1184
+ # },
1185
+ # ...
1186
+ # ]
1187
+ # }
1188
+ #
1189
+ data = self.safe_list(response, 'data', [])
1190
+ return self.parse_funding_rate(data, market)
1191
+
1192
+ async def fetch_funding_rates(self, symbols: Strings = None, params={}):
1193
+ """
1194
+ fetch the current funding rate
1195
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Current%20Funding%20Rate
1196
+ :param str[] [symbols]: list of unified market symbols
1197
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1198
+ :returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
1199
+ """
1200
+ await self.load_markets()
1201
+ symbols = self.market_symbols(symbols, 'swap', True)
1202
+ response = await self.swapV2PublicGetQuotePremiumIndex(self.extend(params))
1203
+ data = self.safe_list(response, 'data', [])
1204
+ filteredResponse = []
1205
+ for i in range(0, len(data)):
1206
+ item = data[i]
1207
+ marketId = self.safe_string(item, 'symbol')
1208
+ market = self.safe_market(marketId, None, None, 'swap')
1209
+ if (symbols is None) or self.in_array(market['symbol'], symbols):
1210
+ filteredResponse.append(self.parse_funding_rate(item, market))
1211
+ return filteredResponse
1212
+
1213
+ def parse_funding_rate(self, contract, market: Market = None):
1214
+ #
1215
+ # {
1216
+ # "symbol": "BTC-USDT",
1217
+ # "markPrice": "16884.5",
1218
+ # "indexPrice": "16886.9",
1219
+ # "lastFundingRate": "0.0001",
1220
+ # "nextFundingTime": 1672041600000
1221
+ # }
1222
+ #
1223
+ marketId = self.safe_string(contract, 'symbol')
1224
+ nextFundingTimestamp = self.safe_integer(contract, 'nextFundingTime')
1225
+ return {
1226
+ 'info': contract,
1227
+ 'symbol': self.safe_symbol(marketId, market, '-', 'swap'),
1228
+ 'markPrice': self.safe_number(contract, 'markPrice'),
1229
+ 'indexPrice': self.safe_number(contract, 'indexPrice'),
1230
+ 'interestRate': None,
1231
+ 'estimatedSettlePrice': None,
1232
+ 'timestamp': None,
1233
+ 'datetime': None,
1234
+ 'fundingRate': self.safe_number(contract, 'lastFundingRate'),
1235
+ 'fundingTimestamp': None,
1236
+ 'fundingDatetime': None,
1237
+ 'nextFundingRate': None,
1238
+ 'nextFundingTimestamp': nextFundingTimestamp,
1239
+ 'nextFundingDatetime': self.iso8601(nextFundingTimestamp),
1240
+ 'previousFundingRate': None,
1241
+ 'previousFundingTimestamp': None,
1242
+ 'previousFundingDatetime': None,
1243
+ }
1244
+
1245
+ async def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
1246
+ """
1247
+ fetches historical funding rate prices
1248
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Funding%20Rate%20History
1249
+ :param str symbol: unified symbol of the market to fetch the funding rate history for
1250
+ :param int [since]: timestamp in ms of the earliest funding rate to fetch
1251
+ :param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
1252
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1253
+ :param int [params.until]: timestamp in ms of the latest funding rate to fetch
1254
+ :param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
1255
+ :returns dict[]: a list of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>`
1256
+ """
1257
+ if symbol is None:
1258
+ raise ArgumentsRequired(self.id + ' fetchFundingRateHistory() requires a symbol argument')
1259
+ await self.load_markets()
1260
+ paginate = False
1261
+ paginate, params = self.handle_option_and_params(params, 'fetchFundingRateHistory', 'paginate')
1262
+ if paginate:
1263
+ return await self.fetch_paginated_call_deterministic('fetchFundingRateHistory', symbol, since, limit, '8h', params)
1264
+ market = self.market(symbol)
1265
+ request: dict = {
1266
+ 'symbol': market['id'],
1267
+ }
1268
+ if since is not None:
1269
+ request['startTime'] = since
1270
+ if limit is not None:
1271
+ request['limit'] = limit
1272
+ until = self.safe_integer_2(params, 'until', 'startTime')
1273
+ if until is not None:
1274
+ params = self.omit(params, ['until'])
1275
+ request['startTime'] = until
1276
+ response = await self.swapV2PublicGetQuoteFundingRate(self.extend(request, params))
1277
+ #
1278
+ # {
1279
+ # "code":0,
1280
+ # "msg":"",
1281
+ # "data":[
1282
+ # {
1283
+ # "symbol": "BTC-USDT",
1284
+ # "fundingRate": "0.0001",
1285
+ # "fundingTime": 1585684800000
1286
+ # },
1287
+ # ...
1288
+ # ]
1289
+ # }
1290
+ #
1291
+ data = self.safe_list(response, 'data', [])
1292
+ rates = []
1293
+ for i in range(0, len(data)):
1294
+ entry = data[i]
1295
+ marketId = self.safe_string(entry, 'symbol')
1296
+ symbolInner = self.safe_symbol(marketId, market, '-', 'swap')
1297
+ timestamp = self.safe_integer(entry, 'fundingTime')
1298
+ rates.append({
1299
+ 'info': entry,
1300
+ 'symbol': symbolInner,
1301
+ 'fundingRate': self.safe_number(entry, 'fundingRate'),
1302
+ 'timestamp': timestamp,
1303
+ 'datetime': self.iso8601(timestamp),
1304
+ })
1305
+ sorted = self.sort_by(rates, 'timestamp')
1306
+ return self.filter_by_symbol_since_limit(sorted, market['symbol'], since, limit)
1307
+
1308
+ async def fetch_open_interest(self, symbol: str, params={}):
1309
+ """
1310
+ Retrieves the open interest of a currency
1311
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Swap%20Open%20Positions
1312
+ :param str symbol: Unified CCXT market symbol
1313
+ :param dict [params]: exchange specific parameters
1314
+ :returns dict} an open interest structure{@link https://docs.ccxt.com/#/?id=open-interest-structure:
1315
+ """
1316
+ await self.load_markets()
1317
+ market = self.market(symbol)
1318
+ request: dict = {
1319
+ 'symbol': market['id'],
1320
+ }
1321
+ response = await self.swapV2PublicGetQuoteOpenInterest(self.extend(request, params))
1322
+ #
1323
+ # {
1324
+ # "code": 0,
1325
+ # "msg": "",
1326
+ # "data": {
1327
+ # "openInterest": "3289641547.10",
1328
+ # "symbol": "BTC-USDT",
1329
+ # "time": 1672026617364
1330
+ # }
1331
+ # }
1332
+ #
1333
+ data = self.safe_dict(response, 'data', {})
1334
+ return self.parse_open_interest(data, market)
1335
+
1336
+ def parse_open_interest(self, interest, market: Market = None):
1337
+ #
1338
+ # {
1339
+ # "openInterest": "3289641547.10",
1340
+ # "symbol": "BTC-USDT",
1341
+ # "time": 1672026617364
1342
+ # }
1343
+ #
1344
+ timestamp = self.safe_integer(interest, 'time')
1345
+ id = self.safe_string(interest, 'symbol')
1346
+ symbol = self.safe_symbol(id, market, '-', 'swap')
1347
+ openInterest = self.safe_number(interest, 'openInterest')
1348
+ return self.safe_open_interest({
1349
+ 'symbol': symbol,
1350
+ 'baseVolume': None,
1351
+ 'quoteVolume': None, # deprecated
1352
+ 'openInterestAmount': None,
1353
+ 'openInterestValue': openInterest,
1354
+ 'timestamp': timestamp,
1355
+ 'datetime': self.iso8601(timestamp),
1356
+ 'info': interest,
1357
+ }, market)
1358
+
1359
+ async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
1360
+ """
1361
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
1362
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Ticker
1363
+ :see: https://bingx-api.github.io/docs/#/spot/market-api.html#24%E5%B0%8F%E6%97%B6%E4%BB%B7%E6%A0%BC%E5%8F%98%E5%8A%A8%E6%83%85%E5%86%B5
1364
+ :param str symbol: unified symbol of the market to fetch the ticker for
1365
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1366
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
1367
+ """
1368
+ await self.load_markets()
1369
+ market = self.market(symbol)
1370
+ request: dict = {
1371
+ 'symbol': market['id'],
1372
+ }
1373
+ response = None
1374
+ if market['spot']:
1375
+ response = await self.spotV1PublicGetTicker24hr(self.extend(request, params))
1376
+ else:
1377
+ response = await self.swapV2PublicGetQuoteTicker(self.extend(request, params))
1378
+ data = self.safe_list(response, 'data')
1379
+ if data is not None:
1380
+ first = self.safe_dict(data, 0, {})
1381
+ return self.parse_ticker(first, market)
1382
+ dataDict = self.safe_dict(response, 'data', {})
1383
+ return self.parse_ticker(dataDict, market)
1384
+
1385
+ async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
1386
+ """
1387
+ fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
1388
+ :see: https://bingx-api.github.io/docs/#/swapV2/market-api.html#Get%20Ticker
1389
+ :param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
1390
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1391
+ :returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
1392
+ """
1393
+ await self.load_markets()
1394
+ market = None
1395
+ if symbols is not None:
1396
+ symbols = self.market_symbols(symbols)
1397
+ firstSymbol = self.safe_string(symbols, 0)
1398
+ if firstSymbol is not None:
1399
+ market = self.market(firstSymbol)
1400
+ type = None
1401
+ type, params = self.handle_market_type_and_params('fetchTickers', market, params)
1402
+ response = None
1403
+ if type == 'spot':
1404
+ response = await self.spotV1PublicGetTicker24hr(params)
1405
+ else:
1406
+ response = await self.swapV2PublicGetQuoteTicker(params)
1407
+ tickers = self.safe_list(response, 'data')
1408
+ return self.parse_tickers(tickers, symbols)
1409
+
1410
+ def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
1411
+ #
1412
+ # spot
1413
+ # {
1414
+ # "symbol": "BTC-USDT",
1415
+ # "openPrice": "26032.08",
1416
+ # "highPrice": "26178.86",
1417
+ # "lowPrice": "25968.18",
1418
+ # "lastPrice": "26113.60",
1419
+ # "volume": "1161.79",
1420
+ # "quoteVolume": "30288466.44",
1421
+ # "openTime": "1693081020762",
1422
+ # "closeTime": "1693167420762",
1423
+ # added 2023-11-10:
1424
+ # "bidPrice": 16726.0,
1425
+ # "bidQty": 0.05,
1426
+ # "askPrice": 16726.0,
1427
+ # "askQty": 0.05,
1428
+ # }
1429
+ # swap
1430
+ #
1431
+ # {
1432
+ # "symbol": "BTC-USDT",
1433
+ # "priceChange": "52.5",
1434
+ # "priceChangePercent": "0.31%", # they started to add the percent sign in value
1435
+ # "lastPrice": "16880.5",
1436
+ # "lastQty": "2.2238", # only present in swap!
1437
+ # "highPrice": "16897.5",
1438
+ # "lowPrice": "16726.0",
1439
+ # "volume": "245870.1692",
1440
+ # "quoteVolume": "4151395117.73",
1441
+ # "openPrice": "16832.0",
1442
+ # "openTime": 1672026667803,
1443
+ # "closeTime": 1672026648425,
1444
+ # added 2023-11-10:
1445
+ # "bidPrice": 16726.0,
1446
+ # "bidQty": 0.05,
1447
+ # "askPrice": 16726.0,
1448
+ # "askQty": 0.05,
1449
+ # }
1450
+ #
1451
+ marketId = self.safe_string(ticker, 'symbol')
1452
+ lastQty = self.safe_string(ticker, 'lastQty')
1453
+ # in spot markets, lastQty is not present
1454
+ # it's(bad, but) the only way we can check the tickers origin
1455
+ type = 'spot' if (lastQty is None) else 'swap'
1456
+ market = self.safe_market(marketId, market, None, type)
1457
+ symbol = market['symbol']
1458
+ open = self.safe_string(ticker, 'openPrice')
1459
+ high = self.safe_string(ticker, 'highPrice')
1460
+ low = self.safe_string(ticker, 'lowPrice')
1461
+ close = self.safe_string(ticker, 'lastPrice')
1462
+ quoteVolume = self.safe_string(ticker, 'quoteVolume')
1463
+ baseVolume = self.safe_string(ticker, 'volume')
1464
+ percentage = self.safe_string(ticker, 'priceChangePercent')
1465
+ if percentage is not None:
1466
+ percentage = percentage.replace('%', '')
1467
+ change = self.safe_string(ticker, 'priceChange')
1468
+ ts = self.safe_integer(ticker, 'closeTime')
1469
+ datetime = self.iso8601(ts)
1470
+ bid = self.safe_string(ticker, 'bidPrice')
1471
+ bidVolume = self.safe_string(ticker, 'bidQty')
1472
+ ask = self.safe_string(ticker, 'askPrice')
1473
+ askVolume = self.safe_string(ticker, 'askQty')
1474
+ return self.safe_ticker({
1475
+ 'symbol': symbol,
1476
+ 'timestamp': ts,
1477
+ 'datetime': datetime,
1478
+ 'high': high,
1479
+ 'low': low,
1480
+ 'bid': bid,
1481
+ 'bidVolume': bidVolume,
1482
+ 'ask': ask,
1483
+ 'askVolume': askVolume,
1484
+ 'vwap': None,
1485
+ 'open': open,
1486
+ 'close': close,
1487
+ 'last': None,
1488
+ 'previousClose': None,
1489
+ 'change': change,
1490
+ 'percentage': percentage,
1491
+ 'average': None,
1492
+ 'baseVolume': baseVolume,
1493
+ 'quoteVolume': quoteVolume,
1494
+ 'info': ticker,
1495
+ }, market)
1496
+
1497
+ async def fetch_balance(self, params={}) -> Balances:
1498
+ """
1499
+ query for balance and get the amount of funds available for trading or funds locked in orders
1500
+ :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Assets
1501
+ :see: https://bingx-api.github.io/docs/#/swapV2/account-api.html#Get%20Perpetual%20Swap%20Account%20Asset%20Information
1502
+ :see: https://bingx-api.github.io/docs/#/standard/contract-interface.html#Query%20standard%20contract%20balance
1503
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1504
+ :param boolean [params.standard]: whether to fetch standard contract balances
1505
+ :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1506
+ """
1507
+ await self.load_markets()
1508
+ response = None
1509
+ standard = None
1510
+ standard, params = self.handle_option_and_params(params, 'fetchBalance', 'standard', False)
1511
+ marketType, marketTypeQuery = self.handle_market_type_and_params('fetchBalance', None, params)
1512
+ if standard:
1513
+ response = await self.contractV1PrivateGetBalance(marketTypeQuery)
1514
+ elif marketType == 'spot':
1515
+ response = await self.spotV1PrivateGetAccountBalance(marketTypeQuery)
1516
+ else:
1517
+ response = await self.swapV2PrivateGetUserBalance(marketTypeQuery)
1518
+ #
1519
+ # spot
1520
+ #
1521
+ # {
1522
+ # "code": 0,
1523
+ # "msg": "",
1524
+ # "ttl": 1,
1525
+ # "data": {
1526
+ # "balances": [
1527
+ # {
1528
+ # "asset": "USDT",
1529
+ # "free": "16.73971130673954",
1530
+ # "locked": "0"
1531
+ # }
1532
+ # ]
1533
+ # }
1534
+ # }
1535
+ #
1536
+ # swap
1537
+ #
1538
+ # {
1539
+ # "code": 0,
1540
+ # "msg": "",
1541
+ # "data": {
1542
+ # "balance": {
1543
+ # "asset": "USDT",
1544
+ # "balance": "15.6128",
1545
+ # "equity": "15.6128",
1546
+ # "unrealizedProfit": "0.0000",
1547
+ # "realisedProfit": "0.0000",
1548
+ # "availableMargin": "15.6128",
1549
+ # "usedMargin": "0.0000",
1550
+ # "freezedMargin": "0.0000"
1551
+ # }
1552
+ # }
1553
+ # }
1554
+ # standard futures
1555
+ # {
1556
+ # "code":"0",
1557
+ # "timestamp":"1691148990942",
1558
+ # "data":[
1559
+ # {
1560
+ # "asset":"VST",
1561
+ # "balance":"100000.00000000000000000000",
1562
+ # "crossWalletBalance":"100000.00000000000000000000",
1563
+ # "crossUnPnl":"0",
1564
+ # "availableBalance":"100000.00000000000000000000",
1565
+ # "maxWithdrawAmount":"100000.00000000000000000000",
1566
+ # "marginAvailable":false,
1567
+ # "updateTime":"1691148990902"
1568
+ # },
1569
+ # {
1570
+ # "asset":"USDT",
1571
+ # "balance":"0",
1572
+ # "crossWalletBalance":"0",
1573
+ # "crossUnPnl":"0",
1574
+ # "availableBalance":"0",
1575
+ # "maxWithdrawAmount":"0",
1576
+ # "marginAvailable":false,
1577
+ # "updateTime":"1691148990902"
1578
+ # },
1579
+ # ]
1580
+ # }
1581
+ #
1582
+ return self.parse_balance(response)
1583
+
1584
+ def parse_balance(self, response) -> Balances:
1585
+ data = self.safe_value(response, 'data')
1586
+ balances = self.safe_value_2(data, 'balance', 'balances', data)
1587
+ result: dict = {'info': response}
1588
+ if isinstance(balances, list):
1589
+ for i in range(0, len(balances)):
1590
+ balance = balances[i]
1591
+ currencyId = self.safe_string(balance, 'asset')
1592
+ code = self.safe_currency_code(currencyId)
1593
+ account = self.account()
1594
+ account['free'] = self.safe_string_2(balance, 'free', 'availableBalance')
1595
+ account['used'] = self.safe_string(balance, 'locked')
1596
+ account['total'] = self.safe_string(balance, 'balance')
1597
+ result[code] = account
1598
+ else:
1599
+ currencyId = self.safe_string(balances, 'asset')
1600
+ code = self.safe_currency_code(currencyId)
1601
+ account = self.account()
1602
+ account['free'] = self.safe_string(balances, 'availableMargin')
1603
+ account['used'] = self.safe_string(balances, 'usedMargin')
1604
+ result[code] = account
1605
+ return self.safe_balance(result)
1606
+
1607
+ async def fetch_positions(self, symbols: Strings = None, params={}):
1608
+ """
1609
+ fetch all open positions
1610
+ :see: https://bingx-api.github.io/docs/#/swapV2/account-api.html#Perpetual%20Swap%20Positions
1611
+ :see: https://bingx-api.github.io/docs/#/standard/contract-interface.html#Query%20standard%20contract%20balance
1612
+ :param str[]|None symbols: list of unified market symbols
1613
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1614
+ :param boolean [params.standard]: whether to fetch standard contract positions
1615
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1616
+ """
1617
+ await self.load_markets()
1618
+ symbols = self.market_symbols(symbols)
1619
+ standard = None
1620
+ standard, params = self.handle_option_and_params(params, 'fetchPositions', 'standard', False)
1621
+ response = None
1622
+ if standard:
1623
+ response = await self.contractV1PrivateGetAllPosition(params)
1624
+ else:
1625
+ response = await self.swapV2PrivateGetUserPositions(params)
1626
+ #
1627
+ # {
1628
+ # "code": 0,
1629
+ # "msg": "",
1630
+ # "data": [
1631
+ # {
1632
+ # "symbol": "BTC-USDT",
1633
+ # "positionId": "12345678",
1634
+ # "positionSide": "LONG",
1635
+ # "isolated": True,
1636
+ # "positionAmt": "123.33",
1637
+ # "availableAmt": "128.99",
1638
+ # "unrealizedProfit": "1.22",
1639
+ # "realisedProfit": "8.1",
1640
+ # "initialMargin": "123.33",
1641
+ # "avgPrice": "2.2",
1642
+ # "leverage": 10,
1643
+ # }
1644
+ # ]
1645
+ # }
1646
+ #
1647
+ positions = self.safe_list(response, 'data', [])
1648
+ return self.parse_positions(positions, symbols)
1649
+
1650
+ def parse_position(self, position: dict, market: Market = None):
1651
+ #
1652
+ # {
1653
+ # "positionId":"1773122376147623936",
1654
+ # "symbol":"XRP-USDT",
1655
+ # "currency":"USDT",
1656
+ # "positionAmt":"3",
1657
+ # "availableAmt":"3",
1658
+ # "positionSide":"LONG",
1659
+ # "isolated":false,
1660
+ # "avgPrice":"0.6139",
1661
+ # "initialMargin":"0.0897",
1662
+ # "leverage":20,
1663
+ # "unrealizedProfit":"-0.0023",
1664
+ # "realisedProfit":"-0.0009",
1665
+ # "liquidationPrice":0,
1666
+ # "pnlRatio":"-0.0260",
1667
+ # "maxMarginReduction":"",
1668
+ # "riskRate":"",
1669
+ # "markPrice":"",
1670
+ # "positionValue":"",
1671
+ # "onlyOnePosition":false
1672
+ # }
1673
+ #
1674
+ # standard position
1675
+ #
1676
+ # {
1677
+ # "currentPrice": "82.91",
1678
+ # "symbol": "LTC/USDT",
1679
+ # "initialMargin": "5.00000000000000000000",
1680
+ # "unrealizedProfit": "-0.26464500",
1681
+ # "leverage": "20.000000000",
1682
+ # "isolated": True,
1683
+ # "entryPrice": "83.13",
1684
+ # "positionSide": "LONG",
1685
+ # "positionAmt": "1.20365912",
1686
+ # }
1687
+ #
1688
+ marketId = self.safe_string(position, 'symbol', '')
1689
+ marketId = marketId.replace('/', '-') # standard return different format
1690
+ isolated = self.safe_bool(position, 'isolated')
1691
+ marginMode = None
1692
+ if isolated is not None:
1693
+ marginMode = 'isolated' if isolated else 'cross'
1694
+ return self.safe_position({
1695
+ 'info': position,
1696
+ 'id': self.safe_string(position, 'positionId'),
1697
+ 'symbol': self.safe_symbol(marketId, market, '-', 'swap'),
1698
+ 'notional': self.safe_number(position, 'positionValue'),
1699
+ 'marginMode': marginMode,
1700
+ 'liquidationPrice': None,
1701
+ 'entryPrice': self.safe_number_2(position, 'avgPrice', 'entryPrice'),
1702
+ 'unrealizedPnl': self.safe_number(position, 'unrealizedProfit'),
1703
+ 'realizedPnl': self.safe_number(position, 'realisedProfit'),
1704
+ 'percentage': None,
1705
+ 'contracts': self.safe_number(position, 'positionAmt'),
1706
+ 'contractSize': None,
1707
+ 'markPrice': None,
1708
+ 'lastPrice': None,
1709
+ 'side': self.safe_string_lower(position, 'positionSide'),
1710
+ 'hedged': None,
1711
+ 'timestamp': None,
1712
+ 'datetime': None,
1713
+ 'lastUpdateTimestamp': None,
1714
+ 'maintenanceMargin': None,
1715
+ 'maintenanceMarginPercentage': None,
1716
+ 'collateral': None,
1717
+ 'initialMargin': self.safe_number(position, 'initialMargin'),
1718
+ 'initialMarginPercentage': None,
1719
+ 'leverage': self.safe_number(position, 'leverage'),
1720
+ 'marginRatio': None,
1721
+ 'stopLossPrice': None,
1722
+ 'takeProfitPrice': None,
1723
+ })
1724
+
1725
+ async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
1726
+ """
1727
+ create a market order by providing the symbol, side and cost
1728
+ :param str symbol: unified symbol of the market to create an order in
1729
+ :param str side: 'buy' or 'sell'
1730
+ :param float cost: how much you want to trade in units of the quote currency
1731
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1732
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1733
+ """
1734
+ params['quoteOrderQty'] = cost
1735
+ return await self.create_order(symbol, 'market', side, cost, None, params)
1736
+
1737
+ async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
1738
+ """
1739
+ create a market buy order by providing the symbol and cost
1740
+ :param str symbol: unified symbol of the market to create an order in
1741
+ :param float cost: how much you want to trade in units of the quote currency
1742
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1743
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1744
+ """
1745
+ params['quoteOrderQty'] = cost
1746
+ return await self.create_order(symbol, 'market', 'buy', cost, None, params)
1747
+
1748
+ async def create_market_sell_order_with_cost(self, symbol: str, cost: float, params={}):
1749
+ """
1750
+ create a market sell order by providing the symbol and cost
1751
+ :param str symbol: unified symbol of the market to create an order in
1752
+ :param float cost: how much you want to trade in units of the quote currency
1753
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1754
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1755
+ """
1756
+ params['quoteOrderQty'] = cost
1757
+ return await self.create_order(symbol, 'market', 'sell', cost, None, params)
1758
+
1759
+ def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1760
+ """
1761
+ * @ignore
1762
+ helper function to build request
1763
+ :param str symbol: unified symbol of the market to create an order in
1764
+ :param str type: 'market' or 'limit'
1765
+ :param str side: 'buy' or 'sell'
1766
+ :param float amount: how much you want to trade in units of the base currency
1767
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1768
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1769
+ :returns dict: request to be sent to the exchange
1770
+ """
1771
+ market = self.market(symbol)
1772
+ postOnly = None
1773
+ marketType = None
1774
+ marketType, params = self.handle_market_type_and_params('createOrder', market, params)
1775
+ type = type.upper()
1776
+ request: dict = {
1777
+ 'symbol': market['id'],
1778
+ 'type': type,
1779
+ 'side': side.upper(),
1780
+ }
1781
+ isMarketOrder = type == 'MARKET'
1782
+ isSpot = marketType == 'spot'
1783
+ stopLossPrice = self.safe_string(params, 'stopLossPrice')
1784
+ takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
1785
+ triggerPrice = self.safe_string_2(params, 'stopPrice', 'triggerPrice')
1786
+ isTriggerOrder = triggerPrice is not None
1787
+ isStopLossPriceOrder = stopLossPrice is not None
1788
+ isTakeProfitPriceOrder = takeProfitPrice is not None
1789
+ exchangeClientOrderId = 'newClientOrderId' if isSpot else 'clientOrderID'
1790
+ clientOrderId = self.safe_string_2(params, exchangeClientOrderId, 'clientOrderId')
1791
+ if clientOrderId is not None:
1792
+ request[exchangeClientOrderId] = clientOrderId
1793
+ timeInForce = self.safe_string_upper(params, 'timeInForce')
1794
+ postOnly, params = self.handle_post_only(isMarketOrder, timeInForce == 'PostOnly', params)
1795
+ if postOnly or (timeInForce == 'PostOnly'):
1796
+ request['timeInForce'] = 'PostOnly'
1797
+ elif timeInForce == 'IOC':
1798
+ request['timeInForce'] = 'IOC'
1799
+ elif timeInForce == 'GTC':
1800
+ request['timeInForce'] = 'GTC'
1801
+ if isSpot:
1802
+ cost = self.safe_number_2(params, 'cost', 'quoteOrderQty')
1803
+ params = self.omit(params, 'cost')
1804
+ if cost is not None:
1805
+ request['quoteOrderQty'] = self.parse_to_numeric(self.cost_to_precision(symbol, cost))
1806
+ else:
1807
+ if isMarketOrder and (price is not None):
1808
+ # keep the legacy behavior, to avoid breaking the old spot-market-buying code
1809
+ calculatedCost = Precise.string_mul(self.number_to_string(amount), self.number_to_string(price))
1810
+ request['quoteOrderQty'] = self.parse_to_numeric(calculatedCost)
1811
+ else:
1812
+ request['quantity'] = self.parse_to_numeric(self.amount_to_precision(symbol, amount))
1813
+ if not isMarketOrder:
1814
+ request['price'] = self.parse_to_numeric(self.price_to_precision(symbol, price))
1815
+ if triggerPrice is not None:
1816
+ if isMarketOrder and self.safe_string(request, 'quoteOrderQty') is None:
1817
+ raise ArgumentsRequired(self.id + ' createOrder() requires the cost parameter(or the amount + price) for placing spot market-buy trigger orders')
1818
+ request['stopPrice'] = self.price_to_precision(symbol, triggerPrice)
1819
+ if type == 'LIMIT':
1820
+ request['type'] = 'TRIGGER_LIMIT'
1821
+ elif type == 'MARKET':
1822
+ request['type'] = 'TRIGGER_MARKET'
1823
+ elif (stopLossPrice is not None) or (takeProfitPrice is not None):
1824
+ stopTakePrice = stopLossPrice if (stopLossPrice is not None) else takeProfitPrice
1825
+ if type == 'LIMIT':
1826
+ request['type'] = 'TAKE_STOP_LIMIT'
1827
+ elif type == 'MARKET':
1828
+ request['type'] = 'TAKE_STOP_MARKET'
1829
+ request['stopPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, stopTakePrice))
1830
+ else:
1831
+ if timeInForce == 'FOK':
1832
+ request['timeInForce'] = 'FOK'
1833
+ trailingAmount = self.safe_string(params, 'trailingAmount')
1834
+ trailingPercent = self.safe_string_2(params, 'trailingPercent', 'priceRate')
1835
+ trailingType = self.safe_string(params, 'trailingType', 'TRAILING_STOP_MARKET')
1836
+ isTrailingAmountOrder = trailingAmount is not None
1837
+ isTrailingPercentOrder = trailingPercent is not None
1838
+ isTrailing = isTrailingAmountOrder or isTrailingPercentOrder
1839
+ stopLoss = self.safe_value(params, 'stopLoss')
1840
+ takeProfit = self.safe_value(params, 'takeProfit')
1841
+ isStopLoss = stopLoss is not None
1842
+ isTakeProfit = takeProfit is not None
1843
+ if ((type == 'LIMIT') or (type == 'TRIGGER_LIMIT') or (type == 'STOP') or (type == 'TAKE_PROFIT')) and not isTrailing:
1844
+ request['price'] = self.parse_to_numeric(self.price_to_precision(symbol, price))
1845
+ reduceOnly = self.safe_bool(params, 'reduceOnly', False)
1846
+ if isTriggerOrder:
1847
+ request['stopPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, triggerPrice))
1848
+ if isMarketOrder or (type == 'TRIGGER_MARKET'):
1849
+ request['type'] = 'TRIGGER_MARKET'
1850
+ elif (type == 'LIMIT') or (type == 'TRIGGER_LIMIT'):
1851
+ request['type'] = 'TRIGGER_LIMIT'
1852
+ elif isStopLossPriceOrder or isTakeProfitPriceOrder:
1853
+ # This can be used to set the stop loss and take profit, but the position needs to be opened first
1854
+ reduceOnly = True
1855
+ if isStopLossPriceOrder:
1856
+ request['stopPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, stopLossPrice))
1857
+ if isMarketOrder or (type == 'STOP_MARKET'):
1858
+ request['type'] = 'STOP_MARKET'
1859
+ elif (type == 'LIMIT') or (type == 'STOP'):
1860
+ request['type'] = 'STOP'
1861
+ elif isTakeProfitPriceOrder:
1862
+ request['stopPrice'] = self.parse_to_numeric(self.price_to_precision(symbol, takeProfitPrice))
1863
+ if isMarketOrder or (type == 'TAKE_PROFIT_MARKET'):
1864
+ request['type'] = 'TAKE_PROFIT_MARKET'
1865
+ elif (type == 'LIMIT') or (type == 'TAKE_PROFIT'):
1866
+ request['type'] = 'TAKE_PROFIT'
1867
+ elif isTrailing:
1868
+ request['type'] = trailingType
1869
+ if isTrailingAmountOrder:
1870
+ request['price'] = self.parse_to_numeric(trailingAmount)
1871
+ elif isTrailingPercentOrder:
1872
+ requestTrailingPercent = Precise.string_div(trailingPercent, '100')
1873
+ request['priceRate'] = self.parse_to_numeric(requestTrailingPercent)
1874
+ if isStopLoss or isTakeProfit:
1875
+ stringifiedAmount = self.number_to_string(amount)
1876
+ if isStopLoss:
1877
+ slTriggerPrice = self.safe_string_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
1878
+ slWorkingType = self.safe_string(stopLoss, 'workingType', 'MARK_PRICE')
1879
+ slType = self.safe_string(stopLoss, 'type', 'STOP_MARKET')
1880
+ slRequest: dict = {
1881
+ 'stopPrice': self.parse_to_numeric(self.price_to_precision(symbol, slTriggerPrice)),
1882
+ 'workingType': slWorkingType,
1883
+ 'type': slType,
1884
+ }
1885
+ slPrice = self.safe_string(stopLoss, 'price')
1886
+ if slPrice is not None:
1887
+ slRequest['price'] = self.parse_to_numeric(self.price_to_precision(symbol, slPrice))
1888
+ slQuantity = self.safe_string(stopLoss, 'quantity', stringifiedAmount)
1889
+ slRequest['quantity'] = self.parse_to_numeric(self.amount_to_precision(symbol, slQuantity))
1890
+ request['stopLoss'] = self.json(slRequest)
1891
+ if isTakeProfit:
1892
+ tkTriggerPrice = self.safe_string_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
1893
+ tkWorkingType = self.safe_string(takeProfit, 'workingType', 'MARK_PRICE')
1894
+ tpType = self.safe_string(takeProfit, 'type', 'TAKE_PROFIT_MARKET')
1895
+ tpRequest: dict = {
1896
+ 'stopPrice': self.parse_to_numeric(self.price_to_precision(symbol, tkTriggerPrice)),
1897
+ 'workingType': tkWorkingType,
1898
+ 'type': tpType,
1899
+ }
1900
+ slPrice = self.safe_string(takeProfit, 'price')
1901
+ if slPrice is not None:
1902
+ tpRequest['price'] = self.parse_to_numeric(self.price_to_precision(symbol, slPrice))
1903
+ tkQuantity = self.safe_string(takeProfit, 'quantity', stringifiedAmount)
1904
+ tpRequest['quantity'] = self.parse_to_numeric(self.amount_to_precision(symbol, tkQuantity))
1905
+ request['takeProfit'] = self.json(tpRequest)
1906
+ positionSide = None
1907
+ if reduceOnly:
1908
+ positionSide = 'SHORT' if (side == 'buy') else 'LONG'
1909
+ else:
1910
+ positionSide = 'LONG' if (side == 'buy') else 'SHORT'
1911
+ request['positionSide'] = positionSide
1912
+ request['quantity'] = self.parse_to_numeric(self.amount_to_precision(symbol, amount))
1913
+ params = self.omit(params, ['reduceOnly', 'triggerPrice', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingType', 'takeProfit', 'stopLoss', 'clientOrderId'])
1914
+ return self.extend(request, params)
1915
+
1916
+ async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1917
+ """
1918
+ create a trade order
1919
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Trade%20order
1920
+ :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Create%20an%20Order
1921
+ :param str symbol: unified symbol of the market to create an order in
1922
+ :param str type: 'market' or 'limit'
1923
+ :param str side: 'buy' or 'sell'
1924
+ :param float amount: how much you want to trade in units of the base currency
1925
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1926
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1927
+ :param str [params.clientOrderId]: a unique id for the order
1928
+ :param bool [params.postOnly]: True to place a post only order
1929
+ :param str [params.timeInForce]: spot supports 'PO', 'GTC' and 'IOC', swap supports 'PO', 'GTC', 'IOC' and 'FOK'
1930
+ :param bool [params.reduceOnly]: *swap only* True or False whether the order is reduce only
1931
+ :param float [params.triggerPrice]: triggerPrice at which the attached take profit / stop loss order will be triggered
1932
+ :param float [params.stopLossPrice]: stop loss trigger price
1933
+ :param float [params.takeProfitPrice]: take profit trigger price
1934
+ :param float [params.cost]: the quote quantity that can be used alternative for the amount
1935
+ :param float [params.trailingAmount]: *swap only* the quote amount to trail away from the current market price
1936
+ :param float [params.trailingPercent]: *swap only* the percent to trail away from the current market price
1937
+ :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered
1938
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
1939
+ :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
1940
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
1941
+ :param boolean [params.test]: *swap only* whether to use the test endpoint or not, default is False
1942
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1943
+ """
1944
+ await self.load_markets()
1945
+ market = self.market(symbol)
1946
+ test = self.safe_bool(params, 'test', False)
1947
+ params = self.omit(params, 'test')
1948
+ request = self.create_order_request(symbol, type, side, amount, price, params)
1949
+ response = None
1950
+ if market['swap']:
1951
+ if test:
1952
+ response = await self.swapV2PrivatePostTradeOrderTest(request)
1953
+ else:
1954
+ response = await self.swapV2PrivatePostTradeOrder(request)
1955
+ else:
1956
+ response = await self.spotV1PrivatePostTradeOrder(request)
1957
+ #
1958
+ # spot
1959
+ #
1960
+ # {
1961
+ # "code": 0,
1962
+ # "msg": "",
1963
+ # "data": {
1964
+ # "symbol": "XRP-USDT",
1965
+ # "orderId": 1514090846268424192,
1966
+ # "transactTime": 1649822362855,
1967
+ # "price": "0.5",
1968
+ # "origQty": "10",
1969
+ # "executedQty": "0",
1970
+ # "cummulativeQuoteQty": "0",
1971
+ # "status": "PENDING",
1972
+ # "type": "LIMIT",
1973
+ # "side": "BUY"
1974
+ # }
1975
+ # }
1976
+ #
1977
+ # swap
1978
+ #
1979
+ # {
1980
+ # "code": 0,
1981
+ # "msg": "",
1982
+ # "data": {
1983
+ # "order": {
1984
+ # "symbol": "BTC-USDT",
1985
+ # "orderId": 1709036527545438208,
1986
+ # "side": "BUY",
1987
+ # "positionSide": "LONG",
1988
+ # "type": "TRIGGER_LIMIT",
1989
+ # "clientOrderID": "",
1990
+ # "workingType": ""
1991
+ # }
1992
+ # }
1993
+ # }
1994
+ #
1995
+ if isinstance(response, str):
1996
+ # broken api engine : order-ids are too long numbers(i.e. 1742930526912864656)
1997
+ # and json.loadscan not handle them in JS, so we have to use .parseJson
1998
+ # however, when order has an attached SL/TP, their value types need extra parsing
1999
+ response = self.fix_stringified_json_members(response)
2000
+ response = self.parse_json(response)
2001
+ data = self.safe_value(response, 'data', {})
2002
+ order = self.safe_dict(data, 'order', data)
2003
+ return self.parse_order(order, market)
2004
+
2005
+ async def create_orders(self, orders: List[OrderRequest], params={}):
2006
+ """
2007
+ create a list of trade orders
2008
+ :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Batch%20Placing%20Orders
2009
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Bulk%20order
2010
+ :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
2011
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2012
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2013
+ """
2014
+ await self.load_markets()
2015
+ ordersRequests = []
2016
+ symbol = None
2017
+ for i in range(0, len(orders)):
2018
+ rawOrder = orders[i]
2019
+ marketId = self.safe_string(rawOrder, 'symbol')
2020
+ if symbol is None:
2021
+ symbol = marketId
2022
+ else:
2023
+ if symbol != marketId:
2024
+ raise BadRequest(self.id + ' createOrders() requires all orders to have the same symbol')
2025
+ type = self.safe_string(rawOrder, 'type')
2026
+ side = self.safe_string(rawOrder, 'side')
2027
+ amount = self.safe_number(rawOrder, 'amount')
2028
+ price = self.safe_number(rawOrder, 'price')
2029
+ orderParams = self.safe_dict(rawOrder, 'params', {})
2030
+ orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
2031
+ ordersRequests.append(orderRequest)
2032
+ market = self.market(symbol)
2033
+ request: dict = {}
2034
+ response = None
2035
+ if market['swap']:
2036
+ request['batchOrders'] = self.json(ordersRequests)
2037
+ response = await self.swapV2PrivatePostTradeBatchOrders(request)
2038
+ else:
2039
+ request['data'] = self.json(ordersRequests)
2040
+ response = await self.spotV1PrivatePostTradeBatchOrders(request)
2041
+ #
2042
+ # spot
2043
+ #
2044
+ # {
2045
+ # "code": 0,
2046
+ # "msg": "",
2047
+ # "debugMsg": "",
2048
+ # "data": {
2049
+ # "orders": [
2050
+ # {
2051
+ # "symbol": "BTC-USDT",
2052
+ # "orderId": 1720661389564968960,
2053
+ # "transactTime": 1699072618272,
2054
+ # "price": "25000",
2055
+ # "origQty": "0.0002",
2056
+ # "executedQty": "0",
2057
+ # "cummulativeQuoteQty": "0",
2058
+ # "status": "PENDING",
2059
+ # "type": "LIMIT",
2060
+ # "side": "BUY"
2061
+ # },
2062
+ # ]
2063
+ # }
2064
+ # }
2065
+ #
2066
+ # swap
2067
+ #
2068
+ # {
2069
+ # "code": 0,
2070
+ # "msg": "",
2071
+ # "data": {
2072
+ # "orders": [
2073
+ # {
2074
+ # "symbol": "BTC-USDT",
2075
+ # "orderId": 1720657081994006528,
2076
+ # "side": "BUY",
2077
+ # "positionSide": "LONG",
2078
+ # "type": "LIMIT",
2079
+ # "clientOrderID": "",
2080
+ # "workingType": ""
2081
+ # },
2082
+ # ]
2083
+ # }
2084
+ # }
2085
+ #
2086
+ data = self.safe_dict(response, 'data', {})
2087
+ result = self.safe_list(data, 'orders', [])
2088
+ return self.parse_orders(result, market)
2089
+
2090
+ def parse_order_side(self, side):
2091
+ sides: dict = {
2092
+ 'BUY': 'buy',
2093
+ 'SELL': 'sell',
2094
+ 'SHORT': 'sell',
2095
+ 'LONG': 'buy',
2096
+ 'ask': 'sell',
2097
+ 'bid': 'buy',
2098
+ }
2099
+ return self.safe_string(sides, side, side)
2100
+
2101
+ def parse_order_type(self, type: Str):
2102
+ types: dict = {
2103
+ 'trigger_market': 'market',
2104
+ 'trigger_limit': 'limit',
2105
+ 'stop_limit': 'limit',
2106
+ 'stop_market': 'market',
2107
+ 'take_profit_market': 'market',
2108
+ 'stop': 'limit',
2109
+ }
2110
+ return self.safe_string(types, type, type)
2111
+
2112
+ def parse_order(self, order: dict, market: Market = None) -> Order:
2113
+ #
2114
+ # spot
2115
+ # createOrder, createOrders, cancelOrder
2116
+ #
2117
+ # {
2118
+ # "symbol": "XRP-USDT",
2119
+ # "orderId": 1514090846268424192,
2120
+ # "transactTime": 1649822362855,
2121
+ # "price": "0.5",
2122
+ # "origQty": "10",
2123
+ # "executedQty": "0",
2124
+ # "cummulativeQuoteQty": "0",
2125
+ # "status": "PENDING",
2126
+ # "type": "LIMIT",
2127
+ # "side": "BUY"
2128
+ # }
2129
+ #
2130
+ # fetchOrder
2131
+ #
2132
+ # {
2133
+ # "symbol": "ETH-USDT",
2134
+ # "orderId": "1660602123001266176",
2135
+ # "price": "1700",
2136
+ # "origQty": "0.003",
2137
+ # "executedQty": "0",
2138
+ # "cummulativeQuoteQty": "0",
2139
+ # "status": "PENDING",
2140
+ # "type": "LIMIT",
2141
+ # "side": "BUY",
2142
+ # "time": "1684753373276",
2143
+ # "updateTime": "1684753373276",
2144
+ # "origQuoteOrderQty": "0",
2145
+ # "fee": "0",
2146
+ # "feeAsset": "ETH"
2147
+ # }
2148
+ #
2149
+ # fetchOpenOrders, fetchClosedOrders
2150
+ #
2151
+ # {
2152
+ # "symbol": "XRP-USDT",
2153
+ # "orderId": 1514073325788200960,
2154
+ # "price": "0.5",
2155
+ # "StopPrice": "0",
2156
+ # "origQty": "20",
2157
+ # "executedQty": "10",
2158
+ # "cummulativeQuoteQty": "5",
2159
+ # "status": "PENDING",
2160
+ # "type": "LIMIT",
2161
+ # "side": "BUY",
2162
+ # "time": 1649818185647,
2163
+ # "updateTime": 1649818185647,
2164
+ # "origQuoteOrderQty": "0"
2165
+ # "fee": "-0.01"
2166
+ # }
2167
+ #
2168
+ #
2169
+ # swap
2170
+ # createOrder, createOrders
2171
+ #
2172
+ # {
2173
+ # "symbol": "BTC-USDT",
2174
+ # "orderId": 1590973236294713344,
2175
+ # "side": "BUY",
2176
+ # "positionSide": "LONG",
2177
+ # "type": "LIMIT"
2178
+ # }
2179
+ #
2180
+ # fetchOrder, fetchOpenOrders, fetchClosedOrders
2181
+ #
2182
+ # {
2183
+ # "symbol": "BTC-USDT",
2184
+ # "orderId": 1709036527545438208,
2185
+ # "side": "BUY",
2186
+ # "positionSide": "LONG",
2187
+ # "type": "TRIGGER_LIMIT",
2188
+ # "origQty": "0.0010",
2189
+ # "price": "22000.0",
2190
+ # "executedQty": "0.0000",
2191
+ # "avgPrice": "0.0",
2192
+ # "cumQuote": "",
2193
+ # "stopPrice": "23000.0",
2194
+ # "profit": "",
2195
+ # "commission": "",
2196
+ # "status": "NEW",
2197
+ # "time": 1696301035187,
2198
+ # "updateTime": 1696301035187,
2199
+ # "clientOrderId": "",
2200
+ # "leverage": "",
2201
+ # "takeProfit": "",
2202
+ # "stopLoss": "",
2203
+ # "advanceAttr": 0,
2204
+ # "positionID": 0,
2205
+ # "takeProfitEntrustPrice": 0,
2206
+ # "stopLossEntrustPrice": 0,
2207
+ # "orderType": "",
2208
+ # "workingType": "MARK_PRICE"
2209
+ # }
2210
+ # with tp and sl
2211
+ # {
2212
+ # orderId: 1741440894764281900,
2213
+ # symbol: 'LTC-USDT',
2214
+ # positionSide: 'LONG',
2215
+ # side: 'BUY',
2216
+ # type: 'MARKET',
2217
+ # price: 0,
2218
+ # quantity: 1,
2219
+ # stopPrice: 0,
2220
+ # workingType: 'MARK_PRICE',
2221
+ # clientOrderID: '',
2222
+ # timeInForce: 'GTC',
2223
+ # priceRate: 0,
2224
+ # stopLoss: '{"stopPrice":50,"workingType":"MARK_PRICE","type":"STOP_MARKET","quantity":1}',
2225
+ # takeProfit: '{"stopPrice":150,"workingType":"MARK_PRICE","type":"TAKE_PROFIT_MARKET","quantity":1}',
2226
+ # reduceOnly: False
2227
+ # }
2228
+ #
2229
+ # editOrder(swap)
2230
+ #
2231
+ # {
2232
+ # cancelResult: 'true',
2233
+ # cancelMsg: '',
2234
+ # cancelResponse: {
2235
+ # cancelClientOrderId: '',
2236
+ # cancelOrderId: '1755336244265705472',
2237
+ # symbol: 'SOL-USDT',
2238
+ # orderId: '1755336244265705472',
2239
+ # side: 'SELL',
2240
+ # positionSide: 'SHORT',
2241
+ # type: 'LIMIT',
2242
+ # origQty: '1',
2243
+ # price: '100.000',
2244
+ # executedQty: '0',
2245
+ # avgPrice: '0.000',
2246
+ # cumQuote: '0',
2247
+ # stopPrice: '',
2248
+ # profit: '0.0000',
2249
+ # commission: '0.000000',
2250
+ # status: 'PENDING',
2251
+ # time: '1707339747860',
2252
+ # updateTime: '1707339747860',
2253
+ # clientOrderId: '',
2254
+ # leverage: '20X',
2255
+ # workingType: 'MARK_PRICE',
2256
+ # onlyOnePosition: False,
2257
+ # reduceOnly: False
2258
+ # },
2259
+ # replaceResult: 'true',
2260
+ # replaceMsg: '',
2261
+ # newOrderResponse: {
2262
+ # orderId: '1755338440612995072',
2263
+ # symbol: 'SOL-USDT',
2264
+ # positionSide: 'SHORT',
2265
+ # side: 'SELL',
2266
+ # type: 'LIMIT',
2267
+ # price: '99',
2268
+ # quantity: '2',
2269
+ # stopPrice: '0',
2270
+ # workingType: 'MARK_PRICE',
2271
+ # clientOrderID: '',
2272
+ # timeInForce: 'GTC',
2273
+ # priceRate: '0',
2274
+ # stopLoss: '',
2275
+ # takeProfit: '',
2276
+ # reduceOnly: False
2277
+ # }
2278
+ # }
2279
+ #
2280
+ # editOrder(spot)
2281
+ #
2282
+ # {
2283
+ # cancelResult: {code: '0', msg: '', result: True},
2284
+ # openResult: {code: '0', msg: '', result: True},
2285
+ # orderOpenResponse: {
2286
+ # symbol: 'SOL-USDT',
2287
+ # orderId: '1755334007697866752',
2288
+ # transactTime: '1707339214620',
2289
+ # price: '99',
2290
+ # stopPrice: '0',
2291
+ # origQty: '0.2',
2292
+ # executedQty: '0',
2293
+ # cummulativeQuoteQty: '0',
2294
+ # status: 'PENDING',
2295
+ # type: 'LIMIT',
2296
+ # side: 'SELL',
2297
+ # clientOrderID: ''
2298
+ # },
2299
+ # orderCancelResponse: {
2300
+ # symbol: 'SOL-USDT',
2301
+ # orderId: '1755117055251480576',
2302
+ # price: '100',
2303
+ # stopPrice: '0',
2304
+ # origQty: '0.2',
2305
+ # executedQty: '0',
2306
+ # cummulativeQuoteQty: '0',
2307
+ # status: 'CANCELED',
2308
+ # type: 'LIMIT',
2309
+ # side: 'SELL'
2310
+ # }
2311
+ # }
2312
+ # stop loss order
2313
+ # {
2314
+ # "symbol": "ETH-USDT",
2315
+ # "orderId": "1792461744476422144",
2316
+ # "price": "2775.65",
2317
+ # "StopPrice": "2778.42",
2318
+ # "origQty": "0.032359",
2319
+ # "executedQty": "0",
2320
+ # "cummulativeQuoteQty": "0",
2321
+ # "status": "NEW",
2322
+ # "type": "TAKE_STOP_LIMIT",
2323
+ # "side": "SELL",
2324
+ # "time": "1716191156868",
2325
+ # "updateTime": "1716191156868",
2326
+ # "origQuoteOrderQty": "0",
2327
+ # "fee": "0",
2328
+ # "feeAsset": "USDT",
2329
+ # "clientOrderID": ""
2330
+ # }
2331
+ #
2332
+ info = order
2333
+ newOrder = self.safe_dict_2(order, 'newOrderResponse', 'orderOpenResponse')
2334
+ if newOrder is not None:
2335
+ order = newOrder
2336
+ positionSide = self.safe_string_2(order, 'positionSide', 'ps')
2337
+ marketType = 'spot' if (positionSide is None) else 'swap'
2338
+ marketId = self.safe_string_2(order, 'symbol', 's')
2339
+ if market is None:
2340
+ market = self.safe_market(marketId, None, None, marketType)
2341
+ side = self.safe_string_lower_2(order, 'side', 'S')
2342
+ timestamp = self.safe_integer_n(order, ['time', 'transactTime', 'E'])
2343
+ lastTradeTimestamp = self.safe_integer_2(order, 'updateTime', 'T')
2344
+ statusId = self.safe_string_2(order, 'status', 'X')
2345
+ feeCurrencyCode = self.safe_string_2(order, 'feeAsset', 'N')
2346
+ feeCost = self.safe_string_n(order, ['fee', 'commission', 'n'])
2347
+ if (feeCurrencyCode is None):
2348
+ if market['spot']:
2349
+ if side == 'buy':
2350
+ feeCurrencyCode = market['base']
2351
+ else:
2352
+ feeCurrencyCode = market['quote']
2353
+ else:
2354
+ feeCurrencyCode = market['quote']
2355
+ stopLoss = self.safe_value(order, 'stopLoss')
2356
+ stopLossPrice = None
2357
+ if (stopLoss is not None) and (stopLoss != ''):
2358
+ stopLossPrice = self.omit_zero(self.safe_string(stopLoss, 'stopLoss'))
2359
+ if (stopLoss is not None) and ((not isinstance(stopLoss, numbers.Real))) and (stopLoss != ''):
2360
+ # stopLoss: '{"stopPrice":50,"workingType":"MARK_PRICE","type":"STOP_MARKET","quantity":1}',
2361
+ if isinstance(stopLoss, str):
2362
+ stopLoss = self.parse_json(stopLoss)
2363
+ stopLossPrice = self.omit_zero(self.safe_string(stopLoss, 'stopPrice'))
2364
+ takeProfit = self.safe_value(order, 'takeProfit')
2365
+ takeProfitPrice = None
2366
+ if takeProfit is not None and (takeProfit != ''):
2367
+ takeProfitPrice = self.omit_zero(self.safe_string(takeProfit, 'takeProfit'))
2368
+ if (takeProfit is not None) and ((not isinstance(takeProfit, numbers.Real))) and (takeProfit != ''):
2369
+ # takeProfit: '{"stopPrice":150,"workingType":"MARK_PRICE","type":"TAKE_PROFIT_MARKET","quantity":1}',
2370
+ if isinstance(takeProfit, str):
2371
+ takeProfit = self.parse_json(takeProfit)
2372
+ takeProfitPrice = self.omit_zero(self.safe_string(takeProfit, 'stopPrice'))
2373
+ rawType = self.safe_string_lower_2(order, 'type', 'o')
2374
+ stopPrice = self.omit_zero(self.safe_string_2(order, 'StopPrice', 'stopPrice'))
2375
+ triggerPrice = stopPrice
2376
+ if stopPrice is not None:
2377
+ if (rawType.find('stop') > -1) and (stopLossPrice is None):
2378
+ stopLossPrice = stopPrice
2379
+ triggerPrice = None
2380
+ if (rawType.find('take') > -1) and (takeProfitPrice is None):
2381
+ takeProfitPrice = stopPrice
2382
+ triggerPrice = None
2383
+ return self.safe_order({
2384
+ 'info': info,
2385
+ 'id': self.safe_string_2(order, 'orderId', 'i'),
2386
+ 'clientOrderId': self.safe_string_n(order, ['clientOrderID', 'clientOrderId', 'origClientOrderId', 'c']),
2387
+ 'symbol': self.safe_symbol(marketId, market, '-', marketType),
2388
+ 'timestamp': timestamp,
2389
+ 'datetime': self.iso8601(timestamp),
2390
+ 'lastTradeTimestamp': lastTradeTimestamp,
2391
+ 'lastUpdateTimestamp': self.safe_integer(order, 'updateTime'),
2392
+ 'type': self.parse_order_type(rawType),
2393
+ 'timeInForce': self.safe_string(order, 'timeInForce'),
2394
+ 'postOnly': None,
2395
+ 'side': self.parse_order_side(side),
2396
+ 'price': self.safe_string_2(order, 'price', 'p'),
2397
+ 'stopPrice': triggerPrice,
2398
+ 'triggerPrice': triggerPrice,
2399
+ 'stopLossPrice': stopLossPrice,
2400
+ 'takeProfitPrice': takeProfitPrice,
2401
+ 'average': self.safe_string_2(order, 'avgPrice', 'ap'),
2402
+ 'cost': self.safe_string(order, 'cummulativeQuoteQty'),
2403
+ 'amount': self.safe_string_n(order, ['origQty', 'q', 'quantity']),
2404
+ 'filled': self.safe_string_2(order, 'executedQty', 'z'),
2405
+ 'remaining': None,
2406
+ 'status': self.parse_order_status(statusId),
2407
+ 'fee': {
2408
+ 'currency': feeCurrencyCode,
2409
+ 'cost': Precise.string_abs(feeCost),
2410
+ },
2411
+ 'trades': None,
2412
+ 'reduceOnly': self.safe_bool(order, 'reduceOnly'),
2413
+ }, market)
2414
+
2415
+ def parse_order_status(self, status: Str):
2416
+ statuses: dict = {
2417
+ 'NEW': 'open',
2418
+ 'PENDING': 'open',
2419
+ 'PARTIALLY_FILLED': 'open',
2420
+ 'FILLED': 'closed',
2421
+ 'CANCELED': 'canceled',
2422
+ 'CANCELLED': 'canceled',
2423
+ 'FAILED': 'canceled',
2424
+ }
2425
+ return self.safe_string(statuses, status, status)
2426
+
2427
+ async def cancel_order(self, id: str, symbol: Str = None, params={}):
2428
+ """
2429
+ cancels an open order
2430
+ :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Cancel%20an%20Order
2431
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Cancel%20an%20Order
2432
+ :param str id: order id
2433
+ :param str symbol: unified symbol of the market the order was made in
2434
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2435
+ :param str [params.clientOrderId]: a unique id for the order
2436
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2437
+ """
2438
+ if symbol is None:
2439
+ raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
2440
+ await self.load_markets()
2441
+ market = self.market(symbol)
2442
+ request: dict = {
2443
+ 'symbol': market['id'],
2444
+ }
2445
+ clientOrderId = self.safe_string_2(params, 'clientOrderId', 'clientOrderID')
2446
+ params = self.omit(params, ['clientOrderId'])
2447
+ if clientOrderId is not None:
2448
+ request['clientOrderID'] = clientOrderId
2449
+ else:
2450
+ request['orderId'] = id
2451
+ response = None
2452
+ marketType, query = self.handle_market_type_and_params('cancelOrder', market, params)
2453
+ if marketType == 'spot':
2454
+ response = await self.spotV1PrivatePostTradeCancel(self.extend(request, query))
2455
+ else:
2456
+ response = await self.swapV2PrivateDeleteTradeOrder(self.extend(request, query))
2457
+ #
2458
+ # spot
2459
+ #
2460
+ # {
2461
+ # "code": 0,
2462
+ # "msg": "",
2463
+ # "data": {
2464
+ # "symbol": "XRP-USDT",
2465
+ # "orderId": 1514090846268424192,
2466
+ # "price": "0.5",
2467
+ # "origQty": "10",
2468
+ # "executedQty": "0",
2469
+ # "cummulativeQuoteQty": "0",
2470
+ # "status": "CANCELED",
2471
+ # "type": "LIMIT",
2472
+ # "side": "BUY"
2473
+ # }
2474
+ # }
2475
+ #
2476
+ # swap
2477
+ #
2478
+ # {
2479
+ # "code": 0,
2480
+ # "msg": "",
2481
+ # "data": {
2482
+ # "order": {
2483
+ # "symbol": "LINK-USDT",
2484
+ # "orderId": 1597783850786750464,
2485
+ # "side": "BUY",
2486
+ # "positionSide": "LONG",
2487
+ # "type": "TRIGGER_MARKET",
2488
+ # "origQty": "5.0",
2489
+ # "price": "5.0000",
2490
+ # "executedQty": "0.0",
2491
+ # "avgPrice": "0.0000",
2492
+ # "cumQuote": "0",
2493
+ # "stopPrice": "5.0000",
2494
+ # "profit": "",
2495
+ # "commission": "",
2496
+ # "status": "CANCELLED",
2497
+ # "time": 1669776330000,
2498
+ # "updateTime": 1669776330000
2499
+ # }
2500
+ # }
2501
+ # }
2502
+ #
2503
+ data = self.safe_value(response, 'data')
2504
+ first = self.safe_dict(data, 'order', data)
2505
+ return self.parse_order(first, market)
2506
+
2507
+ async def cancel_all_orders(self, symbol: Str = None, params={}):
2508
+ """
2509
+ cancel all open orders
2510
+ :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Cancel%20orders%20by%20symbol
2511
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Cancel%20All%20Orders
2512
+ :param str [symbol]: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
2513
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2514
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2515
+ """
2516
+ if symbol is None:
2517
+ raise ArgumentsRequired(self.id + ' cancelAllOrders() requires a symbol argument')
2518
+ await self.load_markets()
2519
+ market = self.market(symbol)
2520
+ request: dict = {
2521
+ 'symbol': market['id'],
2522
+ }
2523
+ response = None
2524
+ if market['spot']:
2525
+ response = await self.spotV1PrivatePostTradeCancelOpenOrders(self.extend(request, params))
2526
+ #
2527
+ # {
2528
+ # "code": 0,
2529
+ # "msg": "",
2530
+ # "debugMsg": "",
2531
+ # "data": {
2532
+ # "orders": [{
2533
+ # "symbol": "ADA-USDT",
2534
+ # "orderId": 1740659971369992192,
2535
+ # "transactTime": 1703840651730,
2536
+ # "price": 5,
2537
+ # "stopPrice": 0,
2538
+ # "origQty": 10,
2539
+ # "executedQty": 0,
2540
+ # "cummulativeQuoteQty": 0,
2541
+ # "status": "CANCELED",
2542
+ # "type": "LIMIT",
2543
+ # "side": "SELL"
2544
+ # }]
2545
+ # }
2546
+ # }
2547
+ #
2548
+ elif market['swap']:
2549
+ response = await self.swapV2PrivateDeleteTradeAllOpenOrders(self.extend(request, params))
2550
+ #
2551
+ # {
2552
+ # "code": 0,
2553
+ # "msg": "",
2554
+ # "data": {
2555
+ # "success": [
2556
+ # {
2557
+ # "symbol": "LINK-USDT",
2558
+ # "orderId": 1597783835095859200,
2559
+ # "side": "BUY",
2560
+ # "positionSide": "LONG",
2561
+ # "type": "TRIGGER_LIMIT",
2562
+ # "origQty": "5.0",
2563
+ # "price": "9.0000",
2564
+ # "executedQty": "0.0",
2565
+ # "avgPrice": "0.0000",
2566
+ # "cumQuote": "0",
2567
+ # "stopPrice": "9.5000",
2568
+ # "profit": "",
2569
+ # "commission": "",
2570
+ # "status": "NEW",
2571
+ # "time": 1669776326000,
2572
+ # "updateTime": 1669776326000
2573
+ # }
2574
+ # ],
2575
+ # "failed": null
2576
+ # }
2577
+ # }
2578
+ #
2579
+ else:
2580
+ raise BadRequest(self.id + ' cancelAllOrders is only supported for spot and swap markets.')
2581
+ data = self.safe_dict(response, 'data', {})
2582
+ orders = self.safe_list_2(data, 'success', 'orders', [])
2583
+ return self.parse_orders(orders)
2584
+
2585
+ async def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
2586
+ """
2587
+ cancel multiple orders
2588
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Cancel%20a%20Batch%20of%20Orders
2589
+ :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Cancel%20a%20Batch%20of%20Orders
2590
+ :param str[] ids: order ids
2591
+ :param str symbol: unified market symbol, default is None
2592
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2593
+ :param str[] [params.clientOrderIds]: client order ids
2594
+ :returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2595
+ """
2596
+ if symbol is None:
2597
+ raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
2598
+ await self.load_markets()
2599
+ market = self.market(symbol)
2600
+ request: dict = {
2601
+ 'symbol': market['id'],
2602
+ }
2603
+ clientOrderIds = self.safe_value(params, 'clientOrderIds')
2604
+ params = self.omit(params, 'clientOrderIds')
2605
+ idsToParse = ids
2606
+ areClientOrderIds = (clientOrderIds is not None)
2607
+ if areClientOrderIds:
2608
+ idsToParse = clientOrderIds
2609
+ parsedIds = []
2610
+ for i in range(0, len(idsToParse)):
2611
+ id = idsToParse[i]
2612
+ stringId = str(id)
2613
+ parsedIds.append(stringId)
2614
+ response = None
2615
+ if market['spot']:
2616
+ spotReqKey = 'clientOrderIDs' if areClientOrderIds else 'orderIds'
2617
+ request[spotReqKey] = ','.join(parsedIds)
2618
+ response = await self.spotV1PrivatePostTradeCancelOrders(self.extend(request, params))
2619
+ #
2620
+ # {
2621
+ # "code": 0,
2622
+ # "msg": "",
2623
+ # "debugMsg": "",
2624
+ # "data": {
2625
+ # "orders": [
2626
+ # {
2627
+ # "symbol": "SOL-USDT",
2628
+ # "orderId": 1795970045910614016,
2629
+ # "transactTime": 1717027601111,
2630
+ # "price": "180.25",
2631
+ # "stopPrice": "0",
2632
+ # "origQty": "0.03",
2633
+ # "executedQty": "0",
2634
+ # "cummulativeQuoteQty": "0",
2635
+ # "status": "CANCELED",
2636
+ # "type": "LIMIT",
2637
+ # "side": "SELL",
2638
+ # "clientOrderID": ""
2639
+ # },
2640
+ # ...
2641
+ # ]
2642
+ # }
2643
+ # }
2644
+ #
2645
+ else:
2646
+ if areClientOrderIds:
2647
+ request['clientOrderIDList'] = self.json(parsedIds)
2648
+ else:
2649
+ request['orderIdList'] = parsedIds
2650
+ response = await self.swapV2PrivateDeleteTradeBatchOrders(self.extend(request, params))
2651
+ #
2652
+ # {
2653
+ # "code": 0,
2654
+ # "msg": "",
2655
+ # "data": {
2656
+ # "success": [
2657
+ # {
2658
+ # "symbol": "LINK-USDT",
2659
+ # "orderId": 1597783850786750464,
2660
+ # "side": "BUY",
2661
+ # "positionSide": "LONG",
2662
+ # "type": "TRIGGER_MARKET",
2663
+ # "origQty": "5.0",
2664
+ # "price": "5.5710",
2665
+ # "executedQty": "0.0",
2666
+ # "avgPrice": "0.0000",
2667
+ # "cumQuote": "0",
2668
+ # "stopPrice": "5.0000",
2669
+ # "profit": "0.0000",
2670
+ # "commission": "0.000000",
2671
+ # "status": "CANCELLED",
2672
+ # "time": 1669776330000,
2673
+ # "updateTime": 1672370837000
2674
+ # }
2675
+ # ],
2676
+ # "failed": null
2677
+ # }
2678
+ # }
2679
+ #
2680
+ data = self.safe_dict(response, 'data', {})
2681
+ success = self.safe_list_2(data, 'success', 'orders', [])
2682
+ return self.parse_orders(success)
2683
+
2684
+ async def cancel_all_orders_after(self, timeout: Int, params={}):
2685
+ """
2686
+ dead man's switch, cancel all orders after the given timeout
2687
+ :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Cancel%20all%20orders%20in%20countdown
2688
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Cancel%20all%20orders%20in%20countdown
2689
+ :param number timeout: time in milliseconds, 0 represents cancel the timer
2690
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2691
+ :param str [params.type]: spot or swap market
2692
+ :returns dict: the api result
2693
+ """
2694
+ await self.load_markets()
2695
+ isActive = (timeout > 0)
2696
+ request: dict = {
2697
+ 'type': 'ACTIVATE' if (isActive) else 'CLOSE',
2698
+ 'timeOut': (self.parse_to_int(timeout / 1000)) if (isActive) else 0,
2699
+ }
2700
+ response = None
2701
+ type = None
2702
+ type, params = self.handle_market_type_and_params('cancelAllOrdersAfter', None, params)
2703
+ if type == 'spot':
2704
+ response = await self.spotV1PrivatePostTradeCancelAllAfter(self.extend(request, params))
2705
+ elif type == 'swap':
2706
+ response = await self.swapV2PrivatePostTradeCancelAllAfter(self.extend(request, params))
2707
+ else:
2708
+ raise NotSupported(self.id + ' cancelAllOrdersAfter() is not supported for ' + type + ' markets')
2709
+ #
2710
+ # {
2711
+ # code: '0',
2712
+ # msg: '',
2713
+ # data: {
2714
+ # triggerTime: '1712645434',
2715
+ # status: 'ACTIVATED',
2716
+ # note: 'All your perpetual pending orders will be closed automatically at 2024-04-09 06:50:34 UTC(+0),before that you can cancel the timer, or self.extend triggerTime time by self request'
2717
+ # }
2718
+ # }
2719
+ #
2720
+ return response
2721
+
2722
+ async def fetch_order(self, id: str, symbol: Str = None, params={}):
2723
+ """
2724
+ fetches information on an order made by the user
2725
+ :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Orders
2726
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Query%20Order
2727
+ :param str symbol: unified symbol of the market the order was made in
2728
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2729
+ :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2730
+ """
2731
+ if symbol is None:
2732
+ raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
2733
+ await self.load_markets()
2734
+ market = self.market(symbol)
2735
+ request: dict = {
2736
+ 'symbol': market['id'],
2737
+ 'orderId': id,
2738
+ }
2739
+ response = None
2740
+ marketType, query = self.handle_market_type_and_params('fetchOrder', market, params)
2741
+ if marketType == 'spot':
2742
+ response = await self.spotV1PrivateGetTradeQuery(self.extend(request, query))
2743
+ else:
2744
+ response = await self.swapV2PrivateGetTradeOrder(self.extend(request, query))
2745
+ #
2746
+ # spot
2747
+ #
2748
+ # {
2749
+ # "code": 0,
2750
+ # "msg": "",
2751
+ # "data": {
2752
+ # "symbol": "XRP-USDT",
2753
+ # "orderId": 1514087361158316032,
2754
+ # "price": "0.5",
2755
+ # "origQty": "10",
2756
+ # "executedQty": "0",
2757
+ # "cummulativeQuoteQty": "0",
2758
+ # "status": "CANCELED",
2759
+ # "type": "LIMIT",
2760
+ # "side": "BUY",
2761
+ # "time": 1649821532000,
2762
+ # "updateTime": 1649821543000,
2763
+ # "origQuoteOrderQty": "0",
2764
+ # "fee": "0",
2765
+ # "feeAsset": "XRP"
2766
+ # }
2767
+ # }
2768
+ #
2769
+ # swap
2770
+ #
2771
+ # {
2772
+ # "code": 0,
2773
+ # "msg": "",
2774
+ # "data": {
2775
+ # "order": {
2776
+ # "symbol": "BTC-USDT",
2777
+ # "orderId": 1597597642269917184,
2778
+ # "side": "SELL",
2779
+ # "positionSide": "LONG",
2780
+ # "type": "TAKE_PROFIT_MARKET",
2781
+ # "origQty": "1.0000",
2782
+ # "price": "0.0",
2783
+ # "executedQty": "0.0000",
2784
+ # "avgPrice": "0.0",
2785
+ # "cumQuote": "",
2786
+ # "stopPrice": "16494.0",
2787
+ # "profit": "",
2788
+ # "commission": "",
2789
+ # "status": "FILLED",
2790
+ # "time": 1669731935000,
2791
+ # "updateTime": 1669752524000
2792
+ # }
2793
+ # }
2794
+ # }
2795
+ #
2796
+ data = self.safe_value(response, 'data')
2797
+ first = self.safe_dict(data, 'order', data)
2798
+ return self.parse_order(first, market)
2799
+
2800
+ async def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2801
+ """
2802
+ fetches information on multiple orders made by the user
2803
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#User's%20All%20Orders
2804
+ :param str symbol: unified market symbol of the market orders were made in
2805
+ :param int [since]: the earliest time in ms to fetch orders for
2806
+ :param int [limit]: the maximum number of order structures to retrieve
2807
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2808
+ :param int [params.until]: the latest time in ms to fetch entries for
2809
+ :param int [params.orderId]: Only return subsequent orders, and return the latest order by default
2810
+ :returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2811
+ """
2812
+ await self.load_markets()
2813
+ request: dict = {}
2814
+ market = None
2815
+ if symbol is not None:
2816
+ market = self.market(symbol)
2817
+ request['symbol'] = market['id']
2818
+ type = None
2819
+ type, params = self.handle_market_type_and_params('fetchOrders', market, params)
2820
+ if type != 'swap':
2821
+ raise NotSupported(self.id + ' fetchOrders() is only supported for swap markets')
2822
+ if limit is not None:
2823
+ request['limit'] = limit
2824
+ if since is not None:
2825
+ request['startTime'] = since
2826
+ until = self.safe_integer(params, 'until') # unified in milliseconds
2827
+ endTime = self.safe_integer(params, 'endTime', until) # exchange-specific in milliseconds
2828
+ params = self.omit(params, ['endTime', 'until'])
2829
+ if endTime is not None:
2830
+ request['endTime'] = endTime
2831
+ response = await self.swapV1PrivateGetTradeFullOrder(self.extend(request, params))
2832
+ #
2833
+ # {
2834
+ # "code": 0,
2835
+ # "msg": "",
2836
+ # "data": {
2837
+ # "orders": [
2838
+ # {
2839
+ # "symbol": "PYTH-USDT",
2840
+ # "orderId": 1736007506620112100,
2841
+ # "side": "SELL",
2842
+ # "positionSide": "SHORT",
2843
+ # "type": "LIMIT",
2844
+ # "origQty": "33",
2845
+ # "price": "0.3916",
2846
+ # "executedQty": "33",
2847
+ # "avgPrice": "0.3916",
2848
+ # "cumQuote": "13",
2849
+ # "stopPrice": "",
2850
+ # "profit": "0.0000",
2851
+ # "commission": "-0.002585",
2852
+ # "status": "FILLED",
2853
+ # "time": 1702731418000,
2854
+ # "updateTime": 1702731470000,
2855
+ # "clientOrderId": "",
2856
+ # "leverage": "15X",
2857
+ # "takeProfit": {
2858
+ # "type": "TAKE_PROFIT",
2859
+ # "quantity": 0,
2860
+ # "stopPrice": 0,
2861
+ # "price": 0,
2862
+ # "workingType": ""
2863
+ # },
2864
+ # "stopLoss": {
2865
+ # "type": "STOP",
2866
+ # "quantity": 0,
2867
+ # "stopPrice": 0,
2868
+ # "price": 0,
2869
+ # "workingType": ""
2870
+ # },
2871
+ # "advanceAttr": 0,
2872
+ # "positionID": 0,
2873
+ # "takeProfitEntrustPrice": 0,
2874
+ # "stopLossEntrustPrice": 0,
2875
+ # "orderType": "",
2876
+ # "workingType": "MARK_PRICE",
2877
+ # "stopGuaranteed": False,
2878
+ # "triggerOrderId": 1736012449498123500
2879
+ # }
2880
+ # ]
2881
+ # }
2882
+ # }
2883
+ #
2884
+ data = self.safe_dict(response, 'data', {})
2885
+ orders = self.safe_list(data, 'orders', [])
2886
+ return self.parse_orders(orders, market, since, limit)
2887
+
2888
+ async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2889
+ """
2890
+ :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Open%20Orders
2891
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Query%20all%20current%20pending%20orders
2892
+ fetch all unfilled currently open orders
2893
+ :param str symbol: unified market symbol
2894
+ :param int [since]: the earliest time in ms to fetch open orders for
2895
+ :param int [limit]: the maximum number of open order structures to retrieve
2896
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2897
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2898
+ """
2899
+ await self.load_markets()
2900
+ market = None
2901
+ request: dict = {}
2902
+ if symbol is not None:
2903
+ market = self.market(symbol)
2904
+ request['symbol'] = market['id']
2905
+ response = None
2906
+ marketType, query = self.handle_market_type_and_params('fetchOpenOrders', market, params)
2907
+ if marketType == 'spot':
2908
+ response = await self.spotV1PrivateGetTradeOpenOrders(self.extend(request, query))
2909
+ else:
2910
+ response = await self.swapV2PrivateGetTradeOpenOrders(self.extend(request, query))
2911
+ #
2912
+ # spot
2913
+ #
2914
+ # {
2915
+ # "code": 0,
2916
+ # "msg": "",
2917
+ # "data": {
2918
+ # "orders": [
2919
+ # {
2920
+ # "symbol": "XRP-USDT",
2921
+ # "orderId": 1514073325788200960,
2922
+ # "price": "0.5",
2923
+ # "origQty": "20",
2924
+ # "executedQty": "0",
2925
+ # "cummulativeQuoteQty": "0",
2926
+ # "status": "PENDING",
2927
+ # "type": "LIMIT",
2928
+ # "side": "BUY",
2929
+ # "time": 1649818185647,
2930
+ # "updateTime": 1649818185647,
2931
+ # "origQuoteOrderQty": "0"
2932
+ # }
2933
+ # ]
2934
+ # }
2935
+ # }
2936
+ #
2937
+ # swap
2938
+ #
2939
+ # {
2940
+ # "code": 0,
2941
+ # "msg": "",
2942
+ # "data": {
2943
+ # "orders": [
2944
+ # {
2945
+ # "symbol": "LINK-USDT",
2946
+ # "orderId": 1585839271162413056,
2947
+ # "side": "BUY",
2948
+ # "positionSide": "LONG",
2949
+ # "type": "TRIGGER_MARKET",
2950
+ # "origQty": "5.0",
2951
+ # "price": "9",
2952
+ # "executedQty": "0.0",
2953
+ # "avgPrice": "0",
2954
+ # "cumQuote": "0",
2955
+ # "stopPrice": "5",
2956
+ # "profit": "0.0000",
2957
+ # "commission": "0.000000",
2958
+ # "status": "CANCELLED",
2959
+ # "time": 1667631605000,
2960
+ # "updateTime": 1667631605000
2961
+ # },
2962
+ # ]
2963
+ # }
2964
+ # }
2965
+ #
2966
+ data = self.safe_dict(response, 'data', {})
2967
+ orders = self.safe_list(data, 'orders', [])
2968
+ return self.parse_orders(orders, market, since, limit)
2969
+
2970
+ async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
2971
+ """
2972
+ fetches information on multiple closed orders made by the user
2973
+ :see: https://bingx-api.github.io/docs/#/spot/trade-api.html#Query%20Order%20History
2974
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#User's%20Force%20Orders
2975
+ :see: https://bingx-api.github.io/docs/#/standard/contract-interface.html#Historical%20order
2976
+ :param str [symbol]: unified market symbol of the market orders were made in
2977
+ :param int [since]: the earliest time in ms to fetch orders for
2978
+ :param int [limit]: the maximum number of order structures to retrieve
2979
+ :param dict [params]: extra parameters specific to the exchange API endpoint
2980
+ :param int [params.until]: the latest time in ms to fetch orders for
2981
+ :param boolean [params.standard]: whether to fetch standard contract orders
2982
+ :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
2983
+ """
2984
+ if symbol is None:
2985
+ raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
2986
+ await self.load_markets()
2987
+ market = self.market(symbol)
2988
+ request: dict = {
2989
+ 'symbol': market['id'],
2990
+ }
2991
+ response = None
2992
+ standard = None
2993
+ standard, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'standard', False)
2994
+ marketType, query = self.handle_market_type_and_params('fetchClosedOrders', market, params)
2995
+ if standard:
2996
+ response = await self.contractV1PrivateGetAllOrders(self.extend(request, query))
2997
+ elif marketType == 'spot':
2998
+ response = await self.spotV1PrivateGetTradeHistoryOrders(self.extend(request, query))
2999
+ else:
3000
+ response = await self.swapV2PrivateGetTradeAllOrders(self.extend(request, query))
3001
+ #
3002
+ # spot
3003
+ #
3004
+ # {
3005
+ # "code": 0,
3006
+ # "msg": "",
3007
+ # "data": {
3008
+ # "orders": [
3009
+ # {
3010
+ # "symbol": "XRP-USDT",
3011
+ # "orderId": 1514073325788200960,
3012
+ # "price": "0.5",
3013
+ # "origQty": "20",
3014
+ # "executedQty": "0",
3015
+ # "cummulativeQuoteQty": "0",
3016
+ # "status": "PENDING",
3017
+ # "type": "LIMIT",
3018
+ # "side": "BUY",
3019
+ # "time": 1649818185647,
3020
+ # "updateTime": 1649818185647,
3021
+ # "origQuoteOrderQty": "0"
3022
+ # }
3023
+ # ]
3024
+ # }
3025
+ # }
3026
+ #
3027
+ # swap
3028
+ #
3029
+ # {
3030
+ # "code": 0,
3031
+ # "msg": "",
3032
+ # "data": {
3033
+ # "orders": [
3034
+ # {
3035
+ # "symbol": "LINK-USDT",
3036
+ # "orderId": 1585839271162413056,
3037
+ # "side": "BUY",
3038
+ # "positionSide": "LONG",
3039
+ # "type": "TRIGGER_MARKET",
3040
+ # "origQty": "5.0",
3041
+ # "price": "9",
3042
+ # "executedQty": "0.0",
3043
+ # "avgPrice": "0",
3044
+ # "cumQuote": "0",
3045
+ # "stopPrice": "5",
3046
+ # "profit": "0.0000",
3047
+ # "commission": "0.000000",
3048
+ # "status": "CANCELLED",
3049
+ # "time": 1667631605000,
3050
+ # "updateTime": 1667631605000
3051
+ # },
3052
+ # ]
3053
+ # }
3054
+ # }
3055
+ #
3056
+ data = self.safe_value(response, 'data', [])
3057
+ orders = self.safe_list(data, 'orders', [])
3058
+ return self.parse_orders(orders, market, since, limit)
3059
+
3060
+ async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
3061
+ """
3062
+ transfer currency internally between wallets on the same account
3063
+ :see: https://bingx-api.github.io/docs/#/spot/account-api.html#User%20Universal%20Transfer
3064
+ :param str code: unified currency code
3065
+ :param float amount: amount to transfer
3066
+ :param str fromAccount: account to transfer from
3067
+ :param str toAccount: account to transfer to
3068
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3069
+ :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
3070
+ """
3071
+ await self.load_markets()
3072
+ currency = self.currency(code)
3073
+ accountsByType = self.safe_dict(self.options, 'accountsByType', {})
3074
+ fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
3075
+ toId = self.safe_string(accountsByType, toAccount, toAccount)
3076
+ request: dict = {
3077
+ 'asset': currency['id'],
3078
+ 'amount': self.currency_to_precision(code, amount),
3079
+ 'type': fromId + '_' + toId,
3080
+ }
3081
+ response = await self.spotV3PrivateGetGetAssetTransfer(self.extend(request, params))
3082
+ #
3083
+ # {
3084
+ # "tranId":13526853623
3085
+ # }
3086
+ #
3087
+ return {
3088
+ 'info': response,
3089
+ 'id': self.safe_string(response, 'tranId'),
3090
+ 'timestamp': None,
3091
+ 'datetime': None,
3092
+ 'currency': code,
3093
+ 'amount': amount,
3094
+ 'fromAccount': fromAccount,
3095
+ 'toAccount': toAccount,
3096
+ 'status': None,
3097
+ }
3098
+
3099
+ async def fetch_transfers(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> TransferEntries:
3100
+ """
3101
+ fetch a history of internal transfers made on an account
3102
+ :see: https://bingx-api.github.io/docs/#/spot/account-api.html#Query%20User%20Universal%20Transfer%20History%20(USER_DATA)
3103
+ :param str [code]: unified currency code of the currency transferred
3104
+ :param int [since]: the earliest time in ms to fetch transfers for
3105
+ :param int [limit]: the maximum number of transfers structures to retrieve
3106
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3107
+ :returns dict[]: a list of `transfer structures <https://docs.ccxt.com/#/?id=transfer-structure>`
3108
+ """
3109
+ await self.load_markets()
3110
+ currency = None
3111
+ if code is not None:
3112
+ currency = self.currency(code)
3113
+ accountsByType = self.safe_dict(self.options, 'accountsByType', {})
3114
+ fromAccount = self.safe_string(params, 'fromAccount')
3115
+ toAccount = self.safe_string(params, 'toAccount')
3116
+ fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
3117
+ toId = self.safe_string(accountsByType, toAccount, toAccount)
3118
+ if fromId is None or toId is None:
3119
+ raise ExchangeError(self.id + ' fromAccount & toAccount parameter are required')
3120
+ request: dict = {
3121
+ 'type': fromId + '_' + toId,
3122
+ }
3123
+ if since is not None:
3124
+ request['startTime'] = since
3125
+ if limit is not None:
3126
+ request['size'] = limit
3127
+ response = await self.spotV3PrivateGetAssetTransfer(self.extend(request, params))
3128
+ #
3129
+ # {
3130
+ # "total": 3,
3131
+ # "rows": [
3132
+ # {
3133
+ # "asset":"USDT",
3134
+ # "amount":"-100.00000000000000000000",
3135
+ # "type":"FUND_SFUTURES",
3136
+ # "status":"CONFIRMED",
3137
+ # "tranId":1067594500957016069,
3138
+ # "timestamp":1658388859000
3139
+ # },
3140
+ # ]
3141
+ # }
3142
+ #
3143
+ rows = self.safe_list(response, 'rows', [])
3144
+ return self.parse_transfers(rows, currency, since, limit)
3145
+
3146
+ def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
3147
+ tranId = self.safe_string(transfer, 'tranId')
3148
+ timestamp = self.safe_integer(transfer, 'timestamp')
3149
+ currencyCode = self.safe_currency_code(None, currency)
3150
+ status = self.safe_string(transfer, 'status')
3151
+ accountsById = self.safe_dict(self.options, 'accountsById', {})
3152
+ typeId = self.safe_string(transfer, 'type')
3153
+ typeIdSplit = typeId.split('_')
3154
+ fromId = self.safe_string(typeIdSplit, 0)
3155
+ toId = self.safe_string(typeId, 1)
3156
+ fromAccount = self.safe_string(accountsById, fromId, fromId)
3157
+ toAccount = self.safe_string(accountsById, toId, toId)
3158
+ return {
3159
+ 'info': transfer,
3160
+ 'id': tranId,
3161
+ 'timestamp': timestamp,
3162
+ 'datetime': self.iso8601(timestamp),
3163
+ 'currency': currencyCode,
3164
+ 'amount': self.safe_number(transfer, 'amount'),
3165
+ 'fromAccount': fromAccount,
3166
+ 'toAccount': toAccount,
3167
+ 'status': status,
3168
+ }
3169
+
3170
+ async def fetch_deposit_addresses_by_network(self, code: str, params={}):
3171
+ """
3172
+ fetch the deposit addresses for a currency associated with self account
3173
+ :see: https://bingx-api.github.io/docs/#/en-us/common/wallet-api.html#Query%20Main%20Account%20Deposit%20Address
3174
+ :param str code: unified currency code
3175
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3176
+ :returns dict: a dictionary `address structures <https://docs.ccxt.com/#/?id=address-structure>`, indexed by the network
3177
+ """
3178
+ await self.load_markets()
3179
+ currency = self.currency(code)
3180
+ defaultRecvWindow = self.safe_integer(self.options, 'recvWindow')
3181
+ recvWindow = self.safe_integer(self.parse_params, 'recvWindow', defaultRecvWindow)
3182
+ request: dict = {
3183
+ 'coin': currency['id'],
3184
+ 'offset': 0,
3185
+ 'limit': 1000,
3186
+ 'recvWindow': recvWindow,
3187
+ }
3188
+ response = await self.walletsV1PrivateGetCapitalDepositAddress(self.extend(request, params))
3189
+ #
3190
+ # {
3191
+ # "code": "0",
3192
+ # "timestamp": "1695200226859",
3193
+ # "data": {
3194
+ # "data": [
3195
+ # {
3196
+ # "coinId": "799",
3197
+ # "coin": "USDT",
3198
+ # "network": "BEP20",
3199
+ # "address": "6a7eda2817462dabb6493277a2cfe0f5c3f2550b",
3200
+ # "tag": ''
3201
+ # }
3202
+ # ],
3203
+ # "total": "1"
3204
+ # }
3205
+ # }
3206
+ #
3207
+ data = self.safe_list(self.safe_dict(response, 'data'), 'data')
3208
+ parsed = self.parse_deposit_addresses(data, [currency['code']], False)
3209
+ return self.index_by(parsed, 'network')
3210
+
3211
+ async def fetch_deposit_address(self, code: str, params={}):
3212
+ """
3213
+ fetch the deposit address for a currency associated with self account
3214
+ :see: https://bingx-api.github.io/docs/#/en-us/common/wallet-api.html#Query%20Main%20Account%20Deposit%20Address
3215
+ :param str code: unified currency code
3216
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3217
+ :param str [params.network]: The chain of currency. This only apply for multi-chain currency, and there is no need for single chain currency
3218
+ :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
3219
+ """
3220
+ network = self.safe_string(params, 'network')
3221
+ params = self.omit(params, ['network'])
3222
+ addressStructures = await self.fetch_deposit_addresses_by_network(code, params)
3223
+ if network is not None:
3224
+ return self.safe_dict(addressStructures, network)
3225
+ else:
3226
+ options = self.safe_dict(self.options, 'defaultNetworks')
3227
+ defaultNetworkForCurrency = self.safe_string(options, code)
3228
+ if defaultNetworkForCurrency is not None:
3229
+ return self.safe_dict(addressStructures, defaultNetworkForCurrency)
3230
+ else:
3231
+ keys = list(addressStructures.keys())
3232
+ key = self.safe_string(keys, 0)
3233
+ return self.safe_dict(addressStructures, key)
3234
+
3235
+ def parse_deposit_address(self, depositAddress, currency: Currency = None):
3236
+ #
3237
+ # {
3238
+ # "coinId": "799",
3239
+ # "coin": "USDT",
3240
+ # "network": "BEP20",
3241
+ # "address": "6a7eda2817462dabb6493277a2cfe0f5c3f2550b",
3242
+ # "tag": ''
3243
+ # }
3244
+ #
3245
+ address = self.safe_string(depositAddress, 'address')
3246
+ tag = self.safe_string(depositAddress, 'tag')
3247
+ currencyId = self.safe_string(depositAddress, 'coin')
3248
+ currency = self.safe_currency(currencyId, currency)
3249
+ code = currency['code']
3250
+ network = self.safe_string(depositAddress, 'network')
3251
+ self.check_address(address)
3252
+ return {
3253
+ 'currency': code,
3254
+ 'address': address,
3255
+ 'tag': tag,
3256
+ 'network': network,
3257
+ 'info': depositAddress,
3258
+ }
3259
+
3260
+ async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3261
+ """
3262
+ fetch all deposits made to an account
3263
+ :see: https://bingx-api.github.io/docs/#/spot/account-api.html#Deposit%20History(supporting%20network)
3264
+ :param str [code]: unified currency code
3265
+ :param int [since]: the earliest time in ms to fetch deposits for
3266
+ :param int [limit]: the maximum number of deposits structures to retrieve
3267
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3268
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3269
+ """
3270
+ await self.load_markets()
3271
+ request: dict = {
3272
+ }
3273
+ currency = None
3274
+ if code is not None:
3275
+ currency = self.currency(code)
3276
+ request['coin'] = currency['id']
3277
+ if since is not None:
3278
+ request['startTime'] = since
3279
+ if limit is not None:
3280
+ request['limit'] = limit # default 1000
3281
+ response = await self.spotV3PrivateGetCapitalDepositHisrec(self.extend(request, params))
3282
+ #
3283
+ # [
3284
+ # {
3285
+ # "amount":"0.00999800",
3286
+ # "coin":"PAXG",
3287
+ # "network":"ETH",
3288
+ # "status":1,
3289
+ # "address":"0x788cabe9236ce061e5a892e1a59395a81fc8d62c",
3290
+ # "addressTag":"",
3291
+ # "txId":"0xaad4654a3234aa6118af9b4b335f5ae81c360b2394721c019b5d1e75328b09f3",
3292
+ # "insertTime":1599621997000,
3293
+ # "transferType":0,
3294
+ # "unlockConfirm":"12/12", # confirm times for unlocking
3295
+ # "confirmTimes":"12/12"
3296
+ # },
3297
+ # ]
3298
+ #
3299
+ return self.parse_transactions(response, currency, since, limit)
3300
+
3301
+ async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
3302
+ """
3303
+ fetch all withdrawals made from an account
3304
+ :see: https://bingx-api.github.io/docs/#/spot/account-api.html#Withdraw%20History%20(supporting%20network)
3305
+ :param str [code]: unified currency code
3306
+ :param int [since]: the earliest time in ms to fetch withdrawals for
3307
+ :param int [limit]: the maximum number of withdrawals structures to retrieve
3308
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3309
+ :returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
3310
+ """
3311
+ await self.load_markets()
3312
+ request: dict = {
3313
+ }
3314
+ currency = None
3315
+ if code is not None:
3316
+ currency = self.currency(code)
3317
+ request['coin'] = currency['id']
3318
+ if since is not None:
3319
+ request['startTime'] = since
3320
+ if limit is not None:
3321
+ request['limit'] = limit # default 1000
3322
+ response = await self.spotV3PrivateGetCapitalWithdrawHistory(self.extend(request, params))
3323
+ #
3324
+ # [
3325
+ # {
3326
+ # "address": "0x94df8b352de7f46f64b01d3666bf6e936e44ce60",
3327
+ # "amount": "8.91000000",
3328
+ # "applyTime": "2019-10-12 11:12:02",
3329
+ # "coin": "USDT",
3330
+ # "id": "b6ae22b3aa844210a7041aee7589627c",
3331
+ # "withdrawOrderId": "WITHDRAWtest123",
3332
+ # "network": "ETH",
3333
+ # "transferType": 0
3334
+ # "status": 6,
3335
+ # "transactionFee": "0.004",
3336
+ # "confirmNo":3,
3337
+ # "info": "The address is not valid. Please confirm with the recipient",
3338
+ # "txId": "0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268"
3339
+ # },
3340
+ # ]
3341
+ #
3342
+ return self.parse_transactions(response, currency, since, limit)
3343
+
3344
+ def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
3345
+ #
3346
+ # fetchDeposits
3347
+ #
3348
+ # {
3349
+ # "amount":"0.00999800",
3350
+ # "coin":"PAXG",
3351
+ # "network":"ETH",
3352
+ # "status":1,
3353
+ # "address":"0x788cabe9236ce061e5a892e1a59395a81fc8d62c",
3354
+ # "addressTag":"",
3355
+ # "txId":"0xaad4654a3234aa6118af9b4b335f5ae81c360b2394721c019b5d1e75328b09f3",
3356
+ # "insertTime":1599621997000,
3357
+ # "transferType":0,
3358
+ # "unlockConfirm":"12/12", # confirm times for unlocking
3359
+ # "confirmTimes":"12/12"
3360
+ # }
3361
+ #
3362
+ # fetchWithdrawals
3363
+ #
3364
+ # {
3365
+ # "address": "0x94df8b352de7f46f64b01d3666bf6e936e44ce60",
3366
+ # "amount": "8.91000000",
3367
+ # "applyTime": "2019-10-12 11:12:02",
3368
+ # "coin": "USDT",
3369
+ # "id": "b6ae22b3aa844210a7041aee7589627c",
3370
+ # "withdrawOrderId": "WITHDRAWtest123",
3371
+ # "network": "ETH",
3372
+ # "transferType": 0
3373
+ # "status": 6,
3374
+ # "transactionFee": "0.004",
3375
+ # "confirmNo":3,
3376
+ # "info": "The address is not valid. Please confirm with the recipient",
3377
+ # "txId": "0xb5ef8c13b968a406cc62a93a8bd80f9e9a906ef1b3fcf20a2e48573c17659268"
3378
+ # }
3379
+ #
3380
+ # withdraw
3381
+ #
3382
+ # {
3383
+ # "code":0,
3384
+ # "timestamp":1705274263621,
3385
+ # "data":{
3386
+ # "id":"1264246141278773252"
3387
+ # }
3388
+ # }
3389
+ #
3390
+ # parse withdraw-type output first...
3391
+ #
3392
+ data = self.safe_value(transaction, 'data')
3393
+ dataId = None if (data is None) else self.safe_string(data, 'id')
3394
+ id = self.safe_string(transaction, 'id', dataId)
3395
+ address = self.safe_string(transaction, 'address')
3396
+ tag = self.safe_string(transaction, 'addressTag')
3397
+ timestamp = self.safe_integer(transaction, 'insertTime')
3398
+ datetime = self.iso8601(timestamp)
3399
+ if timestamp is None:
3400
+ datetime = self.safe_string(transaction, 'applyTime')
3401
+ timestamp = self.parse8601(datetime)
3402
+ network = self.safe_string(transaction, 'network')
3403
+ currencyId = self.safe_string(transaction, 'coin')
3404
+ code = self.safe_currency_code(currencyId, currency)
3405
+ if (code is not None) and (code != network) and code.find(network) >= 0:
3406
+ if network is not None:
3407
+ code = code.replace(network, '')
3408
+ rawType = self.safe_string(transaction, 'transferType')
3409
+ type = 'deposit' if (rawType == '0') else 'withdrawal'
3410
+ return {
3411
+ 'info': transaction,
3412
+ 'id': id,
3413
+ 'txid': self.safe_string(transaction, 'txId'),
3414
+ 'type': type,
3415
+ 'currency': code,
3416
+ 'network': self.network_id_to_code(network),
3417
+ 'amount': self.safe_number(transaction, 'amount'),
3418
+ 'status': self.parse_transaction_status(self.safe_string(transaction, 'status')),
3419
+ 'timestamp': timestamp,
3420
+ 'datetime': datetime,
3421
+ 'address': address,
3422
+ 'addressFrom': None,
3423
+ 'addressTo': address,
3424
+ 'tag': tag,
3425
+ 'tagFrom': tag,
3426
+ 'tagTo': None,
3427
+ 'updated': None,
3428
+ 'comment': self.safe_string(transaction, 'info'),
3429
+ 'fee': {
3430
+ 'currency': code,
3431
+ 'cost': self.safe_number(transaction, 'transactionFee'),
3432
+ 'rate': None,
3433
+ },
3434
+ 'internal': None,
3435
+ }
3436
+
3437
+ def parse_transaction_status(self, status: str):
3438
+ statuses: dict = {
3439
+ '0': 'pending',
3440
+ '1': 'ok',
3441
+ '10': 'pending',
3442
+ '20': 'rejected',
3443
+ '30': 'ok',
3444
+ '40': 'rejected',
3445
+ '50': 'ok',
3446
+ '60': 'pending',
3447
+ '70': 'rejected',
3448
+ '2': 'pending',
3449
+ '3': 'rejected',
3450
+ '4': 'pending',
3451
+ '5': 'rejected',
3452
+ '6': 'ok',
3453
+ }
3454
+ return self.safe_string(statuses, status, status)
3455
+
3456
+ async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
3457
+ """
3458
+ set margin mode to 'cross' or 'isolated'
3459
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Switch%20Margin%20Mode
3460
+ :param str marginMode: 'cross' or 'isolated'
3461
+ :param str symbol: unified market symbol
3462
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3463
+ :returns dict: response from the exchange
3464
+ """
3465
+ if symbol is None:
3466
+ raise ArgumentsRequired(self.id + ' setMarginMode() requires a symbol argument')
3467
+ await self.load_markets()
3468
+ market = self.market(symbol)
3469
+ if market['type'] != 'swap':
3470
+ raise BadSymbol(self.id + ' setMarginMode() supports swap contracts only')
3471
+ marginMode = marginMode.upper()
3472
+ if marginMode == 'CROSS':
3473
+ marginMode = 'CROSSED'
3474
+ if marginMode != 'ISOLATED' and marginMode != 'CROSSED':
3475
+ raise BadRequest(self.id + ' setMarginMode() marginMode argument should be isolated or cross')
3476
+ request: dict = {
3477
+ 'symbol': market['id'],
3478
+ 'marginType': marginMode,
3479
+ }
3480
+ return await self.swapV2PrivatePostTradeMarginType(self.extend(request, params))
3481
+
3482
+ async def add_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3483
+ request: dict = {
3484
+ 'type': 1,
3485
+ }
3486
+ return await self.set_margin(symbol, amount, self.extend(request, params))
3487
+
3488
+ async def reduce_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3489
+ request: dict = {
3490
+ 'type': 2,
3491
+ }
3492
+ return await self.set_margin(symbol, amount, self.extend(request, params))
3493
+
3494
+ async def set_margin(self, symbol: str, amount: float, params={}) -> MarginModification:
3495
+ """
3496
+ Either adds or reduces margin in an isolated position in order to set the margin to a specific value
3497
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Adjust%20isolated%20margin
3498
+ :param str symbol: unified market symbol of the market to set margin in
3499
+ :param float amount: the amount to set the margin to
3500
+ :param dict [params]: parameters specific to the bingx api endpoint
3501
+ :returns dict: A `margin structure <https://docs.ccxt.com/#/?id=add-margin-structure>`
3502
+ """
3503
+ type = self.safe_integer(params, 'type') # 1 increase margin 2 decrease margin
3504
+ if type is None:
3505
+ raise ArgumentsRequired(self.id + ' setMargin() requires a type parameter either 1(increase margin) or 2(decrease margin)')
3506
+ if not self.in_array(type, [1, 2]):
3507
+ raise ArgumentsRequired(self.id + ' setMargin() requires a type parameter either 1(increase margin) or 2(decrease margin)')
3508
+ await self.load_markets()
3509
+ market = self.market(symbol)
3510
+ request: dict = {
3511
+ 'symbol': market['id'],
3512
+ 'amount': self.amount_to_precision(market['symbol'], amount),
3513
+ 'type': type,
3514
+ }
3515
+ response = await self.swapV2PrivatePostTradePositionMargin(self.extend(request, params))
3516
+ #
3517
+ # {
3518
+ # "code": 0,
3519
+ # "msg": "",
3520
+ # "amount": 1,
3521
+ # "type": 1
3522
+ # }
3523
+ #
3524
+ return self.parse_margin_modification(response, market)
3525
+
3526
+ def parse_margin_modification(self, data: dict, market: Market = None) -> MarginModification:
3527
+ #
3528
+ # {
3529
+ # "code": 0,
3530
+ # "msg": "",
3531
+ # "amount": 1,
3532
+ # "type": 1
3533
+ # }
3534
+ #
3535
+ type = self.safe_string(data, 'type')
3536
+ return {
3537
+ 'info': data,
3538
+ 'symbol': self.safe_string(market, 'symbol'),
3539
+ 'type': 'add' if (type == '1') else 'reduce',
3540
+ 'marginMode': 'isolated',
3541
+ 'amount': self.safe_number(data, 'amount'),
3542
+ 'total': self.safe_number(data, 'margin'),
3543
+ 'code': self.safe_string(market, 'settle'),
3544
+ 'status': None,
3545
+ 'timestamp': None,
3546
+ 'datetime': None,
3547
+ }
3548
+
3549
+ async def fetch_leverage(self, symbol: str, params={}) -> Leverage:
3550
+ """
3551
+ fetch the set leverage for a market
3552
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Query%20Leverage
3553
+ :param str symbol: unified market symbol
3554
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3555
+ :returns dict: a `leverage structure <https://docs.ccxt.com/#/?id=leverage-structure>`
3556
+ """
3557
+ await self.load_markets()
3558
+ market = self.market(symbol)
3559
+ request: dict = {
3560
+ 'symbol': market['id'],
3561
+ }
3562
+ response = await self.swapV2PrivateGetTradeLeverage(self.extend(request, params))
3563
+ #
3564
+ # {
3565
+ # "code": 0,
3566
+ # "msg": "",
3567
+ # "data": {
3568
+ # "longLeverage": 6,
3569
+ # "shortLeverage": 6
3570
+ # }
3571
+ # }
3572
+ #
3573
+ data = self.safe_dict(response, 'data', {})
3574
+ return self.parse_leverage(data, market)
3575
+
3576
+ def parse_leverage(self, leverage: dict, market: Market = None) -> Leverage:
3577
+ marketId = self.safe_string(leverage, 'symbol')
3578
+ return {
3579
+ 'info': leverage,
3580
+ 'symbol': self.safe_symbol(marketId, market),
3581
+ 'marginMode': None,
3582
+ 'longLeverage': self.safe_integer(leverage, 'longLeverage'),
3583
+ 'shortLeverage': self.safe_integer(leverage, 'shortLeverage'),
3584
+ }
3585
+
3586
+ async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
3587
+ """
3588
+ set the level of leverage for a market
3589
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Switch%20Leverage
3590
+ :param float leverage: the rate of leverage
3591
+ :param str symbol: unified market symbol
3592
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3593
+ :param str [params.side]: hedged: ['long' or 'short']. one way: ['both']
3594
+ :returns dict: response from the exchange
3595
+ """
3596
+ if symbol is None:
3597
+ raise ArgumentsRequired(self.id + ' setLeverage() requires a symbol argument')
3598
+ side = self.safe_string_upper(params, 'side')
3599
+ self.check_required_argument('setLeverage', side, 'side', ['LONG', 'SHORT', 'BOTH'])
3600
+ await self.load_markets()
3601
+ market = self.market(symbol)
3602
+ request: dict = {
3603
+ 'symbol': market['id'],
3604
+ 'side': side,
3605
+ 'leverage': leverage,
3606
+ }
3607
+ #
3608
+ # {
3609
+ # "code": 0,
3610
+ # "msg": "",
3611
+ # "data": {
3612
+ # "leverage": 6,
3613
+ # "symbol": "BTC-USDT"
3614
+ # }
3615
+ # }
3616
+ #
3617
+ return await self.swapV2PrivatePostTradeLeverage(self.extend(request, params))
3618
+
3619
+ async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3620
+ """
3621
+ fetch all trades made by the user
3622
+ :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Query%20Order%20History
3623
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#Query%20historical%20transaction%20orders
3624
+ :param str [symbol]: unified market symbol
3625
+ :param int [since]: the earliest time in ms to fetch trades for
3626
+ :param int [limit]: the maximum number of trades structures to retrieve
3627
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3628
+ :param int [params.until]: timestamp in ms for the ending date filter, default is None
3629
+ :param str params['trandingUnit']: COIN(directly represent assets such and ETH) or CONT(represents the number of contract sheets)
3630
+ :returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
3631
+ """
3632
+ if symbol is None:
3633
+ raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
3634
+ await self.load_markets()
3635
+ market = self.market(symbol)
3636
+ now = self.milliseconds()
3637
+ response = None
3638
+ request: dict = {
3639
+ 'symbol': market['id'],
3640
+ }
3641
+ if since is not None:
3642
+ startTimeReq = 'startTime' if market['spot'] else 'startTs'
3643
+ request[startTimeReq] = since
3644
+ elif market['swap']:
3645
+ request['startTs'] = now - 7776000000 # 90 days
3646
+ until = self.safe_integer(params, 'until')
3647
+ params = self.omit(params, 'until')
3648
+ if until is not None:
3649
+ endTimeReq = 'endTime' if market['spot'] else 'endTs'
3650
+ request[endTimeReq] = until
3651
+ elif market['swap']:
3652
+ request['endTs'] = now
3653
+ fills = None
3654
+ if market['spot']:
3655
+ response = await self.spotV1PrivateGetTradeMyTrades(self.extend(request, params))
3656
+ data = self.safe_dict(response, 'data', {})
3657
+ fills = self.safe_list(data, 'fills', [])
3658
+ #
3659
+ # {
3660
+ # "code": 0,
3661
+ # "msg": "",
3662
+ # "debugMsg": "",
3663
+ # "data": {
3664
+ # "fills": [
3665
+ # {
3666
+ # "symbol": "LTC-USDT",
3667
+ # "id": 36237072,
3668
+ # "orderId": 1674069326895775744,
3669
+ # "price": "85.891",
3670
+ # "qty": "0.0582",
3671
+ # "quoteQty": "4.9988562000000005",
3672
+ # "commission": -0.00005820000000000001,
3673
+ # "commissionAsset": "LTC",
3674
+ # "time": 1687964205000,
3675
+ # "isBuyer": True,
3676
+ # "isMaker": False
3677
+ # }
3678
+ # ]
3679
+ # }
3680
+ # }
3681
+ #
3682
+ else:
3683
+ tradingUnit = self.safe_string_upper(params, 'tradingUnit', 'CONT')
3684
+ params = self.omit(params, 'tradingUnit')
3685
+ request['tradingUnit'] = tradingUnit
3686
+ response = await self.swapV2PrivateGetTradeAllFillOrders(self.extend(request, params))
3687
+ data = self.safe_dict(response, 'data', {})
3688
+ fills = self.safe_list(data, 'fill_orders', [])
3689
+ #
3690
+ # {
3691
+ # "code": "0",
3692
+ # "msg": '',
3693
+ # "data": {fill_orders: [
3694
+ # {
3695
+ # "volume": "0.1",
3696
+ # "price": "106.75",
3697
+ # "amount": "10.6750",
3698
+ # "commission": "-0.0053",
3699
+ # "currency": "USDT",
3700
+ # "orderId": "1676213270274379776",
3701
+ # "liquidatedPrice": "0.00",
3702
+ # "liquidatedMarginRatio": "0.00",
3703
+ # "filledTime": "2023-07-04T20:56:01.000+0800"
3704
+ # }
3705
+ # ]
3706
+ # }
3707
+ # }
3708
+ #
3709
+ return self.parse_trades(fills, market, since, limit, params)
3710
+
3711
+ def parse_deposit_withdraw_fee(self, fee, currency: Currency = None):
3712
+ #
3713
+ # {
3714
+ # "coin": "BTC",
3715
+ # "name": "BTC",
3716
+ # "networkList": [
3717
+ # {
3718
+ # "name": "BTC",
3719
+ # "network": "BTC",
3720
+ # "isDefault": True,
3721
+ # "minConfirm": "2",
3722
+ # "withdrawEnable": True,
3723
+ # "withdrawFee": "0.00035",
3724
+ # "withdrawMax": "1.62842",
3725
+ # "withdrawMin": "0.0005"
3726
+ # },
3727
+ # {
3728
+ # "name": "BTC",
3729
+ # "network": "BEP20",
3730
+ # "isDefault": False,
3731
+ # "minConfirm": "15",
3732
+ # "withdrawEnable": True,
3733
+ # "withdrawFee": "0.00001",
3734
+ # "withdrawMax": "1.62734",
3735
+ # "withdrawMin": "0.0001"
3736
+ # }
3737
+ # ]
3738
+ # }
3739
+ #
3740
+ networkList = self.safe_list(fee, 'networkList', [])
3741
+ networkListLength = len(networkList)
3742
+ result: dict = {
3743
+ 'info': fee,
3744
+ 'withdraw': {
3745
+ 'fee': None,
3746
+ 'percentage': None,
3747
+ },
3748
+ 'deposit': {
3749
+ 'fee': None,
3750
+ 'percentage': None,
3751
+ },
3752
+ 'networks': {},
3753
+ }
3754
+ if networkListLength != 0:
3755
+ for i in range(0, networkListLength):
3756
+ network = networkList[i]
3757
+ networkId = self.safe_string(network, 'network')
3758
+ isDefault = self.safe_bool(network, 'isDefault')
3759
+ currencyCode = self.safe_string(currency, 'code')
3760
+ networkCode = self.network_id_to_code(networkId, currencyCode)
3761
+ result['networks'][networkCode] = {
3762
+ 'deposit': {'fee': None, 'percentage': None},
3763
+ 'withdraw': {'fee': self.safe_number(network, 'withdrawFee'), 'percentage': False},
3764
+ }
3765
+ if isDefault:
3766
+ result['withdraw']['fee'] = self.safe_number(network, 'withdrawFee')
3767
+ result['withdraw']['percentage'] = False
3768
+ return result
3769
+
3770
+ async def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
3771
+ """
3772
+ fetch deposit and withdraw fees
3773
+ :see: https://bingx-api.github.io/docs/#/common/account-api.html#All%20Coins'%20Information
3774
+ :param str[]|None codes: list of unified currency codes
3775
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3776
+ :returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
3777
+ """
3778
+ await self.load_markets()
3779
+ response = await self.walletsV1PrivateGetCapitalConfigGetall(params)
3780
+ coins = self.safe_list(response, 'data')
3781
+ return self.parse_deposit_withdraw_fees(coins, codes, 'coin')
3782
+
3783
+ async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
3784
+ """
3785
+ make a withdrawal
3786
+ :see: https://bingx-api.github.io/docs/#/common/account-api.html#Withdraw
3787
+ :param str code: unified currency code
3788
+ :param float amount: the amount to withdraw
3789
+ :param str address: the address to withdraw to
3790
+ :param str [tag]:
3791
+ :param dict [params]: extra parameters specific to the exchange API endpoint
3792
+ :param int [params.walletType]: 1 fund account, 2 standard account, 3 perpetual account
3793
+ :returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
3794
+ """
3795
+ await self.load_markets()
3796
+ currency = self.currency(code)
3797
+ walletType = self.safe_integer(params, 'walletType')
3798
+ if walletType is None:
3799
+ walletType = 1
3800
+ if not self.in_array(walletType, [1, 2, 3]):
3801
+ raise BadRequest(self.id + ' withdraw() requires either 1 fund account, 2 standard futures account, 3 perpetual account for walletType')
3802
+ request: dict = {
3803
+ 'coin': currency['id'],
3804
+ 'address': address,
3805
+ 'amount': self.number_to_string(amount),
3806
+ 'walletType': walletType,
3807
+ }
3808
+ network = self.safe_string_upper(params, 'network')
3809
+ if network is not None:
3810
+ request['network'] = self.network_code_to_id(network)
3811
+ params = self.omit(params, ['walletType', 'network'])
3812
+ response = await self.walletsV1PrivatePostCapitalWithdrawApply(self.extend(request, params))
3813
+ data = self.safe_value(response, 'data')
3814
+ # {
3815
+ # "code":0,
3816
+ # "timestamp":1689258953651,
3817
+ # "data":{
3818
+ # "id":"1197073063359000577"
3819
+ # }
3820
+ # }
3821
+ return self.parse_transaction(data)
3822
+
3823
+ def parse_params(self, params):
3824
+ sortedParams = self.keysort(params)
3825
+ keys = list(sortedParams.keys())
3826
+ for i in range(0, len(keys)):
3827
+ key = keys[i]
3828
+ value = sortedParams[key]
3829
+ if isinstance(value, list):
3830
+ arrStr = '['
3831
+ for j in range(0, len(value)):
3832
+ arrayElement = value[j]
3833
+ if j > 0:
3834
+ arrStr += ','
3835
+ arrStr += str(arrayElement)
3836
+ arrStr += ']'
3837
+ sortedParams[key] = arrStr
3838
+ return sortedParams
3839
+
3840
+ async def fetch_my_liquidations(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
3841
+ """
3842
+ retrieves the users liquidated positions
3843
+ :see: https://bingx-api.github.io/docs/#/swapV2/trade-api.html#User's%20Force%20Orders
3844
+ :param str [symbol]: unified CCXT market symbol
3845
+ :param int [since]: the earliest time in ms to fetch liquidations for
3846
+ :param int [limit]: the maximum number of liquidation structures to retrieve
3847
+ :param dict [params]: exchange specific parameters for the bingx api endpoint
3848
+ :param int [params.until]: timestamp in ms of the latest liquidation
3849
+ :returns dict: an array of `liquidation structures <https://docs.ccxt.com/#/?id=liquidation-structure>`
3850
+ """
3851
+ await self.load_markets()
3852
+ request: dict = {
3853
+ 'autoCloseType': 'LIQUIDATION',
3854
+ }
3855
+ request, params = self.handle_until_option('endTime', request, params)
3856
+ market = None
3857
+ if symbol is not None:
3858
+ market = self.market(symbol)
3859
+ request['symbol'] = market['id']
3860
+ if since is not None:
3861
+ request['startTime'] = since
3862
+ if limit is not None:
3863
+ request['limit'] = limit
3864
+ response = await self.swapV2PrivateGetTradeForceOrders(self.extend(request, params))
3865
+ #
3866
+ # {
3867
+ # "code": 0,
3868
+ # "msg": "",
3869
+ # "data": {
3870
+ # "orders": [
3871
+ # {
3872
+ # "time": "int64",
3873
+ # "symbol": "string",
3874
+ # "side": "string",
3875
+ # "type": "string",
3876
+ # "positionSide": "string",
3877
+ # "cumQuote": "string",
3878
+ # "status": "string",
3879
+ # "stopPrice": "string",
3880
+ # "price": "string",
3881
+ # "origQty": "string",
3882
+ # "avgPrice": "string",
3883
+ # "executedQty": "string",
3884
+ # "orderId": "int64",
3885
+ # "profit": "string",
3886
+ # "commission": "string",
3887
+ # "workingType": "string",
3888
+ # "updateTime": "int64"
3889
+ # },
3890
+ # ]
3891
+ # }
3892
+ # }
3893
+ #
3894
+ data = self.safe_dict(response, 'data', {})
3895
+ liquidations = self.safe_list(data, 'orders', [])
3896
+ return self.parse_liquidations(liquidations, market, since, limit)
3897
+
3898
+ def parse_liquidation(self, liquidation, market: Market = None):
3899
+ #
3900
+ # {
3901
+ # "time": "int64",
3902
+ # "symbol": "string",
3903
+ # "side": "string",
3904
+ # "type": "string",
3905
+ # "positionSide": "string",
3906
+ # "cumQuote": "string",
3907
+ # "status": "string",
3908
+ # "stopPrice": "string",
3909
+ # "price": "string",
3910
+ # "origQty": "string",
3911
+ # "avgPrice": "string",
3912
+ # "executedQty": "string",
3913
+ # "orderId": "int64",
3914
+ # "profit": "string",
3915
+ # "commission": "string",
3916
+ # "workingType": "string",
3917
+ # "updateTime": "int64"
3918
+ # }
3919
+ #
3920
+ marketId = self.safe_string(liquidation, 'symbol')
3921
+ timestamp = self.safe_integer(liquidation, 'time')
3922
+ contractsString = self.safe_string(liquidation, 'executedQty')
3923
+ contractSizeString = self.safe_string(market, 'contractSize')
3924
+ priceString = self.safe_string(liquidation, 'avgPrice')
3925
+ baseValueString = Precise.string_mul(contractsString, contractSizeString)
3926
+ quoteValueString = Precise.string_mul(baseValueString, priceString)
3927
+ return self.safe_liquidation({
3928
+ 'info': liquidation,
3929
+ 'symbol': self.safe_symbol(marketId, market),
3930
+ 'contracts': self.parse_number(contractsString),
3931
+ 'contractSize': self.parse_number(contractSizeString),
3932
+ 'price': self.parse_number(priceString),
3933
+ 'baseValue': self.parse_number(baseValueString),
3934
+ 'quoteValue': self.parse_number(quoteValueString),
3935
+ 'timestamp': timestamp,
3936
+ 'datetime': self.iso8601(timestamp),
3937
+ })
3938
+
3939
+ async def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
3940
+ """
3941
+ closes open positions for a market
3942
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
3943
+ :param str symbol: Unified CCXT market symbol
3944
+ :param str [side]: not used by bingx
3945
+ :param dict [params]: extra parameters specific to the bingx api endpoint
3946
+ :param str|None [params.positionId]: it is recommended to hasattr(self, fill) parameter when closing a position
3947
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3948
+ """
3949
+ await self.load_markets()
3950
+ positionId = self.safe_string(params, 'positionId')
3951
+ params = self.omit(params, 'positionId')
3952
+ response = None
3953
+ if positionId is not None:
3954
+ request: dict = {
3955
+ 'positionId': positionId,
3956
+ }
3957
+ response = await self.swapV1PrivatePostTradeClosePosition(self.extend(request, params))
3958
+ else:
3959
+ market = self.market(symbol)
3960
+ request: dict = {
3961
+ 'symbol': market['id'],
3962
+ }
3963
+ response = await self.swapV2PrivatePostTradeCloseAllPositions(self.extend(request, params))
3964
+ #
3965
+ # swapV1PrivatePostTradeClosePosition
3966
+ #
3967
+ # {
3968
+ # "code": 0,
3969
+ # "msg": "",
3970
+ # "timestamp": 1710992264190,
3971
+ # "data": {
3972
+ # "orderId": 1770656007907930112,
3973
+ # "positionId": "1751667128353910784",
3974
+ # "symbol": "LTC-USDT",
3975
+ # "side": "Ask",
3976
+ # "type": "MARKET",
3977
+ # "positionSide": "Long",
3978
+ # "origQty": "0.2"
3979
+ # }
3980
+ # }
3981
+ #
3982
+ # swapV2PrivatePostTradeCloseAllPositions
3983
+ #
3984
+ # {
3985
+ # "code": 0,
3986
+ # "msg": "",
3987
+ # "data": {
3988
+ # "success": [
3989
+ # 1727686766700486656,
3990
+ # ],
3991
+ # "failed": null
3992
+ # }
3993
+ # }
3994
+ #
3995
+ data = self.safe_dict(response, 'data')
3996
+ return self.parse_order(data)
3997
+
3998
+ async def close_all_positions(self, params={}) -> List[Position]:
3999
+ """
4000
+ closes open positions for a market
4001
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#One-Click%20Close%20All%20Positions
4002
+ :param dict [params]: extra parameters specific to the okx api endpoint
4003
+ :param str [params.recvWindow]: request valid time window value
4004
+ :returns dict[]: `A list of position structures <https://docs.ccxt.com/#/?id=position-structure>`
4005
+ """
4006
+ await self.load_markets()
4007
+ defaultRecvWindow = self.safe_integer(self.options, 'recvWindow')
4008
+ recvWindow = self.safe_integer(self.parse_params, 'recvWindow', defaultRecvWindow)
4009
+ marketType = None
4010
+ marketType, params = self.handle_market_type_and_params('closeAllPositions', None, params)
4011
+ if marketType == 'margin':
4012
+ raise BadRequest(self.id + ' closePositions() cannot be used for ' + marketType + ' markets')
4013
+ request: dict = {
4014
+ 'recvWindow': recvWindow,
4015
+ }
4016
+ response = await self.swapV2PrivatePostTradeCloseAllPositions(self.extend(request, params))
4017
+ #
4018
+ # {
4019
+ # "code": 0,
4020
+ # "msg": "",
4021
+ # "data": {
4022
+ # "success": [
4023
+ # 1727686766700486656,
4024
+ # 1727686767048613888
4025
+ # ],
4026
+ # "failed": null
4027
+ # }
4028
+ # }
4029
+ #
4030
+ data = self.safe_dict(response, 'data', {})
4031
+ success = self.safe_list(data, 'success', [])
4032
+ positions = []
4033
+ for i in range(0, len(success)):
4034
+ position = self.parse_position({'positionId': success[i]})
4035
+ positions.append(position)
4036
+ return positions
4037
+
4038
+ async def fetch_position_mode(self, symbol: Str = None, params={}):
4039
+ """
4040
+ fetchs the position mode, hedged or one way, hedged for binance is set identically for all linear markets or all inverse markets
4041
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Get%20Position%20Mode
4042
+ :param str symbol: unified symbol of the market to fetch the order book for
4043
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4044
+ :returns dict: an object detailing whether the market is in hedged or one-way mode
4045
+ """
4046
+ response = await self.swapV1PrivateGetPositionSideDual(params)
4047
+ #
4048
+ # {
4049
+ # "code": "0",
4050
+ # "msg": "",
4051
+ # "timeStamp": "1709002057516",
4052
+ # "data": {
4053
+ # "dualSidePosition": "false"
4054
+ # }
4055
+ # }
4056
+ #
4057
+ data = self.safe_dict(response, 'data', {})
4058
+ dualSidePosition = self.safe_string(data, 'dualSidePosition')
4059
+ return {
4060
+ 'info': response,
4061
+ 'hedged': (dualSidePosition == 'true'),
4062
+ }
4063
+
4064
+ async def set_position_mode(self, hedged: bool, symbol: Str = None, params={}):
4065
+ """
4066
+ set hedged to True or False for a market
4067
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Set%20Position%20Mode
4068
+ :param bool hedged: set to True to use dualSidePosition
4069
+ :param str symbol: not used by bingx setPositionMode()
4070
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4071
+ :returns dict: response from the exchange
4072
+ """
4073
+ dualSidePosition = None
4074
+ if hedged:
4075
+ dualSidePosition = 'true'
4076
+ else:
4077
+ dualSidePosition = 'false'
4078
+ request: dict = {
4079
+ 'dualSidePosition': dualSidePosition,
4080
+ }
4081
+ #
4082
+ # {
4083
+ # code: '0',
4084
+ # msg: '',
4085
+ # timeStamp: '1703327432734',
4086
+ # data: {dualSidePosition: 'false'}
4087
+ # }
4088
+ #
4089
+ return await self.swapV1PrivatePostPositionSideDual(self.extend(request, params))
4090
+
4091
+ async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
4092
+ """
4093
+ cancels an order and places a new order
4094
+ :see: https://bingx-api.github.io/docs/#/en-us/spot/trade-api.html#Cancel%20order%20and%20place%20a%20new%20order # spot
4095
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Cancel%20an%20order%20and%20then%20Place%20a%20new%20order # swap
4096
+ :param str id: order id
4097
+ :param str symbol: unified symbol of the market to create an order in
4098
+ :param str type: 'market' or 'limit'
4099
+ :param str side: 'buy' or 'sell'
4100
+ :param float amount: how much of the currency you want to trade in units of the base currency
4101
+ :param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
4102
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4103
+ :param str [params.stopPrice]: Trigger price used for TAKE_STOP_LIMIT, TAKE_STOP_MARKET, TRIGGER_LIMIT, TRIGGER_MARKET order types.
4104
+ :param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered
4105
+ :param float [params.takeProfit.triggerPrice]: take profit trigger price
4106
+ :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
4107
+ :param float [params.stopLoss.triggerPrice]: stop loss trigger price
4108
+ *
4109
+ * EXCHANGE SPECIFIC PARAMETERS
4110
+ :param str [params.cancelClientOrderID]: the user-defined id of the order to be canceled, 1-40 characters, different orders cannot use the same clientOrderID, only supports a query range of 2 hours
4111
+ :param str [params.cancelRestrictions]: cancel orders with specified status, NEW: New order, PENDING: Pending order, PARTIALLY_FILLED: Partially filled
4112
+ :param str [params.cancelReplaceMode]: STOP_ON_FAILURE - if the cancel order fails, it will not continue to place a new order, ALLOW_FAILURE - regardless of whether the cancel order succeeds or fails, it will continue to place a new order
4113
+ :param float [params.quoteOrderQty]: order amount
4114
+ :param str [params.newClientOrderId]: custom order id consisting of letters, numbers, and _, 1-40 characters, different orders cannot use the same newClientOrderId.
4115
+ :param str [params.positionSide]: *contract only* position direction, required for single position, for both long and short positions only LONG or SHORT can be chosen, defaults to LONG if empty
4116
+ :param str [params.reduceOnly]: *contract only* True or False, default=false for single position mode. self parameter is not accepted for both long and short positions mode
4117
+ :param float [params.priceRate]: *contract only* for type TRAILING_STOP_Market or TRAILING_TP_SL, Max = 1
4118
+ :param str [params.workingType]: *contract only* StopPrice trigger price types, MARK_PRICE(default), CONTRACT_PRICE, or INDEX_PRICE
4119
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
4120
+ """
4121
+ await self.load_markets()
4122
+ market = self.market(symbol)
4123
+ request = self.create_order_request(symbol, type, side, amount, price, params)
4124
+ request['cancelOrderId'] = id
4125
+ request['cancelReplaceMode'] = 'STOP_ON_FAILURE'
4126
+ response = None
4127
+ if market['swap']:
4128
+ response = await self.swapV1PrivatePostTradeCancelReplace(self.extend(request, params))
4129
+ #
4130
+ # {
4131
+ # code: '0',
4132
+ # msg: '',
4133
+ # data: {
4134
+ # cancelResult: 'true',
4135
+ # cancelMsg: '',
4136
+ # cancelResponse: {
4137
+ # cancelClientOrderId: '',
4138
+ # cancelOrderId: '1755336244265705472',
4139
+ # symbol: 'SOL-USDT',
4140
+ # orderId: '1755336244265705472',
4141
+ # side: 'SELL',
4142
+ # positionSide: 'SHORT',
4143
+ # type: 'LIMIT',
4144
+ # origQty: '1',
4145
+ # price: '100.000',
4146
+ # executedQty: '0',
4147
+ # avgPrice: '0.000',
4148
+ # cumQuote: '0',
4149
+ # stopPrice: '',
4150
+ # profit: '0.0000',
4151
+ # commission: '0.000000',
4152
+ # status: 'PENDING',
4153
+ # time: '1707339747860',
4154
+ # updateTime: '1707339747860',
4155
+ # clientOrderId: '',
4156
+ # leverage: '20X',
4157
+ # workingType: 'MARK_PRICE',
4158
+ # onlyOnePosition: False,
4159
+ # reduceOnly: False
4160
+ # },
4161
+ # replaceResult: 'true',
4162
+ # replaceMsg: '',
4163
+ # newOrderResponse: {
4164
+ # orderId: '1755338440612995072',
4165
+ # symbol: 'SOL-USDT',
4166
+ # positionSide: 'SHORT',
4167
+ # side: 'SELL',
4168
+ # type: 'LIMIT',
4169
+ # price: '99',
4170
+ # quantity: '2',
4171
+ # stopPrice: '0',
4172
+ # workingType: 'MARK_PRICE',
4173
+ # clientOrderID: '',
4174
+ # timeInForce: 'GTC',
4175
+ # priceRate: '0',
4176
+ # stopLoss: '',
4177
+ # takeProfit: '',
4178
+ # reduceOnly: False
4179
+ # }
4180
+ # }
4181
+ # }
4182
+ #
4183
+ else:
4184
+ response = await self.spotV1PrivatePostTradeOrderCancelReplace(self.extend(request, params))
4185
+ #
4186
+ # {
4187
+ # code: '0',
4188
+ # msg: '',
4189
+ # debugMsg: '',
4190
+ # data: {
4191
+ # cancelResult: {code: '0', msg: '', result: True},
4192
+ # openResult: {code: '0', msg: '', result: True},
4193
+ # orderOpenResponse: {
4194
+ # symbol: 'SOL-USDT',
4195
+ # orderId: '1755334007697866752',
4196
+ # transactTime: '1707339214620',
4197
+ # price: '99',
4198
+ # stopPrice: '0',
4199
+ # origQty: '0.2',
4200
+ # executedQty: '0',
4201
+ # cummulativeQuoteQty: '0',
4202
+ # status: 'PENDING',
4203
+ # type: 'LIMIT',
4204
+ # side: 'SELL',
4205
+ # clientOrderID: ''
4206
+ # },
4207
+ # orderCancelResponse: {
4208
+ # symbol: 'SOL-USDT',
4209
+ # orderId: '1755117055251480576',
4210
+ # price: '100',
4211
+ # stopPrice: '0',
4212
+ # origQty: '0.2',
4213
+ # executedQty: '0',
4214
+ # cummulativeQuoteQty: '0',
4215
+ # status: 'CANCELED',
4216
+ # type: 'LIMIT',
4217
+ # side: 'SELL'
4218
+ # }
4219
+ # }
4220
+ # }
4221
+ #
4222
+ data = self.safe_dict(response, 'data')
4223
+ return self.parse_order(data, market)
4224
+
4225
+ async def fetch_margin_mode(self, symbol: str, params={}) -> MarginMode:
4226
+ """
4227
+ fetches the margin mode of the trading pair
4228
+ :see: https://bingx-api.github.io/docs/#/en-us/swapV2/trade-api.html#Query%20Margin%20Mode
4229
+ :param str symbol: unified symbol of the market to fetch the margin mode for
4230
+ :param dict [params]: extra parameters specific to the exchange API endpoint
4231
+ :returns dict: a `margin mode structure <https://docs.ccxt.com/#/?id=margin-mode-structure>`
4232
+ """
4233
+ await self.load_markets()
4234
+ market = self.market(symbol)
4235
+ request: dict = {
4236
+ 'symbol': market['id'],
4237
+ }
4238
+ response = await self.swapV2PrivateGetTradeMarginType(self.extend(request, params))
4239
+ #
4240
+ # {
4241
+ # "code": 0,
4242
+ # "msg": "",
4243
+ # "data": {
4244
+ # "marginType": "CROSSED"
4245
+ # }
4246
+ # }
4247
+ #
4248
+ data = self.safe_dict(response, 'data', {})
4249
+ return self.parse_margin_mode(data, market)
4250
+
4251
+ def parse_margin_mode(self, marginMode: dict, market=None) -> MarginMode:
4252
+ marginType = self.safe_string_lower(marginMode, 'marginType')
4253
+ marginType = 'cross' if (marginType == 'crossed') else marginType
4254
+ return {
4255
+ 'info': marginMode,
4256
+ 'symbol': market['symbol'],
4257
+ 'marginMode': marginType,
4258
+ }
4259
+
4260
+ def sign(self, path, section='public', method='GET', params={}, headers=None, body=None):
4261
+ type = section[0]
4262
+ version = section[1]
4263
+ access = section[2]
4264
+ isSandbox = self.safe_bool(self.options, 'sandboxMode', False)
4265
+ if isSandbox and (type != 'swap'):
4266
+ raise NotSupported(self.id + ' does not have a testnet/sandbox URL for ' + type + ' endpoints')
4267
+ url = self.implode_hostname(self.urls['api'][type])
4268
+ if type == 'spot' and version == 'v3':
4269
+ url += '/api'
4270
+ else:
4271
+ url += '/' + type
4272
+ url += '/' + version + '/'
4273
+ path = self.implode_params(path, params)
4274
+ url += path
4275
+ params = self.omit(params, self.extract_params(path))
4276
+ params = self.keysort(params)
4277
+ if access == 'public':
4278
+ params['timestamp'] = self.nonce()
4279
+ if params:
4280
+ url += '?' + self.urlencode(params)
4281
+ elif access == 'private':
4282
+ self.check_required_credentials()
4283
+ params['timestamp'] = self.nonce()
4284
+ parsedParams = self.parse_params(params)
4285
+ query = self.urlencode(parsedParams)
4286
+ signature = self.hmac(self.encode(self.rawencode(parsedParams)), self.encode(self.secret), hashlib.sha256)
4287
+ if params:
4288
+ query = '?' + query + '&'
4289
+ else:
4290
+ query += '?'
4291
+ query += 'signature=' + signature
4292
+ headers = {
4293
+ 'X-BX-APIKEY': self.apiKey,
4294
+ 'X-SOURCE-KEY': self.safe_string(self.options, 'broker', 'CCXT'),
4295
+ }
4296
+ url += query
4297
+ return {'url': url, 'method': method, 'body': body, 'headers': headers}
4298
+
4299
+ def nonce(self):
4300
+ return self.milliseconds()
4301
+
4302
+ def set_sandbox_mode(self, enable: bool):
4303
+ super(bingx, self).set_sandbox_mode(enable)
4304
+ self.options['sandboxMode'] = enable
4305
+
4306
+ def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
4307
+ if response is None:
4308
+ return None # fallback to default error handler
4309
+ #
4310
+ # {
4311
+ # "code": 80014,
4312
+ # "msg": "Invalid parameters, err:Key: 'GetTickerRequest.Symbol' Error:Field validation for "Symbol" failed on the "len=0|endswith=-USDT" tag",
4313
+ # "data": {
4314
+ # }
4315
+ # }
4316
+ #
4317
+ code = self.safe_string(response, 'code')
4318
+ message = self.safe_string(response, 'msg')
4319
+ if code is not None and code != '0':
4320
+ feedback = self.id + ' ' + body
4321
+ self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
4322
+ self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
4323
+ self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
4324
+ raise ExchangeError(feedback) # unknown message
4325
+ return None