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