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

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