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
ccxt/whitebit.py
ADDED
|
@@ -0,0 +1,2469 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
|
4
|
+
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
|
5
|
+
|
|
6
|
+
from ccxt.base.exchange import Exchange
|
|
7
|
+
from ccxt.abstract.whitebit import ImplicitAPI
|
|
8
|
+
import hashlib
|
|
9
|
+
from ccxt.base.types import Balances, Bool, Currencies, Currency, Int, Market, MarketType, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, Transaction, TransferEntry
|
|
10
|
+
from typing import List
|
|
11
|
+
from ccxt.base.errors import ExchangeError
|
|
12
|
+
from ccxt.base.errors import AuthenticationError
|
|
13
|
+
from ccxt.base.errors import PermissionDenied
|
|
14
|
+
from ccxt.base.errors import ArgumentsRequired
|
|
15
|
+
from ccxt.base.errors import BadRequest
|
|
16
|
+
from ccxt.base.errors import BadSymbol
|
|
17
|
+
from ccxt.base.errors import InsufficientFunds
|
|
18
|
+
from ccxt.base.errors import InvalidOrder
|
|
19
|
+
from ccxt.base.errors import OrderNotFound
|
|
20
|
+
from ccxt.base.errors import NotSupported
|
|
21
|
+
from ccxt.base.errors import DDoSProtection
|
|
22
|
+
from ccxt.base.errors import ExchangeNotAvailable
|
|
23
|
+
from ccxt.base.decimal_to_precision import TICK_SIZE
|
|
24
|
+
from ccxt.base.precise import Precise
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class whitebit(Exchange, ImplicitAPI):
|
|
28
|
+
|
|
29
|
+
def describe(self):
|
|
30
|
+
return self.deep_extend(super(whitebit, self).describe(), {
|
|
31
|
+
'id': 'whitebit',
|
|
32
|
+
'name': 'WhiteBit',
|
|
33
|
+
'version': 'v4',
|
|
34
|
+
'countries': ['EE'],
|
|
35
|
+
'rateLimit': 50,
|
|
36
|
+
'pro': True,
|
|
37
|
+
'has': {
|
|
38
|
+
'CORS': None,
|
|
39
|
+
'spot': True,
|
|
40
|
+
'margin': True,
|
|
41
|
+
'swap': False,
|
|
42
|
+
'future': False,
|
|
43
|
+
'option': False,
|
|
44
|
+
'cancelAllOrders': True,
|
|
45
|
+
'cancelAllOrdersAfter': True,
|
|
46
|
+
'cancelOrder': True,
|
|
47
|
+
'cancelOrders': False,
|
|
48
|
+
'createMarketBuyOrderWithCost': True,
|
|
49
|
+
'createMarketOrderWithCost': False,
|
|
50
|
+
'createMarketSellOrderWithCost': False,
|
|
51
|
+
'createOrder': True,
|
|
52
|
+
'createStopLimitOrder': True,
|
|
53
|
+
'createStopMarketOrder': True,
|
|
54
|
+
'createStopOrder': True,
|
|
55
|
+
'editOrder': False,
|
|
56
|
+
'fetchBalance': True,
|
|
57
|
+
'fetchBorrowRateHistories': False,
|
|
58
|
+
'fetchBorrowRateHistory': False,
|
|
59
|
+
'fetchClosedOrders': True,
|
|
60
|
+
'fetchCrossBorrowRate': False,
|
|
61
|
+
'fetchCrossBorrowRates': False,
|
|
62
|
+
'fetchCurrencies': True,
|
|
63
|
+
'fetchDeposit': True,
|
|
64
|
+
'fetchDepositAddress': True,
|
|
65
|
+
'fetchDeposits': True,
|
|
66
|
+
'fetchDepositsWithdrawals': True,
|
|
67
|
+
'fetchDepositWithdrawFee': 'emulated',
|
|
68
|
+
'fetchDepositWithdrawFees': True,
|
|
69
|
+
'fetchFundingHistory': False,
|
|
70
|
+
'fetchFundingRate': True,
|
|
71
|
+
'fetchFundingRateHistory': False,
|
|
72
|
+
'fetchFundingRates': True,
|
|
73
|
+
'fetchIndexOHLCV': False,
|
|
74
|
+
'fetchIsolatedBorrowRate': False,
|
|
75
|
+
'fetchIsolatedBorrowRates': False,
|
|
76
|
+
'fetchMarginMode': False,
|
|
77
|
+
'fetchMarkets': True,
|
|
78
|
+
'fetchMarkOHLCV': False,
|
|
79
|
+
'fetchMyTrades': True,
|
|
80
|
+
'fetchOHLCV': True,
|
|
81
|
+
'fetchOpenInterestHistory': False,
|
|
82
|
+
'fetchOpenOrders': True,
|
|
83
|
+
'fetchOrderBook': True,
|
|
84
|
+
'fetchOrderTrades': True,
|
|
85
|
+
'fetchPositionMode': False,
|
|
86
|
+
'fetchPremiumIndexOHLCV': False,
|
|
87
|
+
'fetchStatus': True,
|
|
88
|
+
'fetchTicker': True,
|
|
89
|
+
'fetchTickers': True,
|
|
90
|
+
'fetchTime': True,
|
|
91
|
+
'fetchTrades': True,
|
|
92
|
+
'fetchTradingFee': False,
|
|
93
|
+
'fetchTradingFees': True,
|
|
94
|
+
'fetchTransactionFees': True,
|
|
95
|
+
'repayCrossMargin': False,
|
|
96
|
+
'repayIsolatedMargin': False,
|
|
97
|
+
'setLeverage': True,
|
|
98
|
+
'transfer': True,
|
|
99
|
+
'withdraw': True,
|
|
100
|
+
},
|
|
101
|
+
'timeframes': {
|
|
102
|
+
'1m': '1m',
|
|
103
|
+
'3m': '3m',
|
|
104
|
+
'5m': '5m',
|
|
105
|
+
'15m': '15m',
|
|
106
|
+
'30m': '30m',
|
|
107
|
+
'1h': '1h',
|
|
108
|
+
'2h': '2h',
|
|
109
|
+
'4h': '4h',
|
|
110
|
+
'6h': '6h',
|
|
111
|
+
'8h': '8h',
|
|
112
|
+
'12h': '12h',
|
|
113
|
+
'1d': '1d',
|
|
114
|
+
'3d': '3d',
|
|
115
|
+
'1w': '1w',
|
|
116
|
+
'1M': '1M',
|
|
117
|
+
},
|
|
118
|
+
'urls': {
|
|
119
|
+
'logo': 'https://user-images.githubusercontent.com/1294454/66732963-8eb7dd00-ee66-11e9-849b-10d9282bb9e0.jpg',
|
|
120
|
+
'api': {
|
|
121
|
+
'v1': {
|
|
122
|
+
'public': 'https://whitebit.com/api/v1/public',
|
|
123
|
+
'private': 'https://whitebit.com/api/v1',
|
|
124
|
+
},
|
|
125
|
+
'v2': {
|
|
126
|
+
'public': 'https://whitebit.com/api/v2/public',
|
|
127
|
+
},
|
|
128
|
+
'v4': {
|
|
129
|
+
'public': 'https://whitebit.com/api/v4/public',
|
|
130
|
+
'private': 'https://whitebit.com/api/v4',
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
'www': 'https://www.whitebit.com',
|
|
134
|
+
'doc': 'https://github.com/whitebit-exchange/api-docs',
|
|
135
|
+
'fees': 'https://whitebit.com/fee-schedule',
|
|
136
|
+
'referral': 'https://whitebit.com/referral/d9bdf40e-28f2-4b52-b2f9-cd1415d82963',
|
|
137
|
+
},
|
|
138
|
+
'api': {
|
|
139
|
+
'web': {
|
|
140
|
+
'get': [
|
|
141
|
+
'v1/healthcheck',
|
|
142
|
+
],
|
|
143
|
+
},
|
|
144
|
+
'v1': {
|
|
145
|
+
'public': {
|
|
146
|
+
'get': [
|
|
147
|
+
'markets',
|
|
148
|
+
'tickers',
|
|
149
|
+
'ticker',
|
|
150
|
+
'symbols',
|
|
151
|
+
'depth/result',
|
|
152
|
+
'history',
|
|
153
|
+
'kline',
|
|
154
|
+
],
|
|
155
|
+
},
|
|
156
|
+
'private': {
|
|
157
|
+
'post': [
|
|
158
|
+
'account/balance',
|
|
159
|
+
'order/new',
|
|
160
|
+
'order/cancel',
|
|
161
|
+
'orders',
|
|
162
|
+
'account/order_history',
|
|
163
|
+
'account/executed_history',
|
|
164
|
+
'account/executed_history/all',
|
|
165
|
+
'account/order',
|
|
166
|
+
],
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
'v2': {
|
|
170
|
+
'public': {
|
|
171
|
+
'get': [
|
|
172
|
+
'markets',
|
|
173
|
+
'ticker',
|
|
174
|
+
'assets',
|
|
175
|
+
'fee',
|
|
176
|
+
'depth/{market}',
|
|
177
|
+
'trades/{market}',
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
'v4': {
|
|
182
|
+
'public': {
|
|
183
|
+
'get': [
|
|
184
|
+
'assets',
|
|
185
|
+
'collateral/markets',
|
|
186
|
+
'fee',
|
|
187
|
+
'orderbook/{market}',
|
|
188
|
+
'ticker',
|
|
189
|
+
'trades/{market}',
|
|
190
|
+
'time',
|
|
191
|
+
'ping',
|
|
192
|
+
'markets',
|
|
193
|
+
'futures',
|
|
194
|
+
'platform/status',
|
|
195
|
+
],
|
|
196
|
+
},
|
|
197
|
+
'private': {
|
|
198
|
+
'post': [
|
|
199
|
+
'collateral-account/balance',
|
|
200
|
+
'collateral-account/balance-summary',
|
|
201
|
+
'collateral-account/positions/history',
|
|
202
|
+
'collateral-account/leverage',
|
|
203
|
+
'collateral-account/positions/open',
|
|
204
|
+
'collateral-account/summary',
|
|
205
|
+
'main-account/address',
|
|
206
|
+
'main-account/balance',
|
|
207
|
+
'main-account/create-new-address',
|
|
208
|
+
'main-account/codes',
|
|
209
|
+
'main-account/codes/apply',
|
|
210
|
+
'main-account/codes/my',
|
|
211
|
+
'main-account/codes/history',
|
|
212
|
+
'main-account/fiat-deposit-url',
|
|
213
|
+
'main-account/history',
|
|
214
|
+
'main-account/withdraw',
|
|
215
|
+
'main-account/withdraw-pay',
|
|
216
|
+
'main-account/transfer',
|
|
217
|
+
'main-account/smart/plans',
|
|
218
|
+
'main-account/smart/investment',
|
|
219
|
+
'main-account/smart/investment/close',
|
|
220
|
+
'main-account/smart/investments',
|
|
221
|
+
'main-account/fee',
|
|
222
|
+
'main-account/smart/interest-payment-history',
|
|
223
|
+
'trade-account/balance',
|
|
224
|
+
'trade-account/executed-history',
|
|
225
|
+
'trade-account/order',
|
|
226
|
+
'trade-account/order/history',
|
|
227
|
+
'order/collateral/limit',
|
|
228
|
+
'order/collateral/market',
|
|
229
|
+
'order/collateral/stop-limit',
|
|
230
|
+
'order/collateral/trigger-market',
|
|
231
|
+
'order/new',
|
|
232
|
+
'order/market',
|
|
233
|
+
'order/stock_market',
|
|
234
|
+
'order/stop_limit',
|
|
235
|
+
'order/stop_market',
|
|
236
|
+
'order/cancel',
|
|
237
|
+
'order/cancel/all',
|
|
238
|
+
'order/kill-switch',
|
|
239
|
+
'order/kill-switch/status',
|
|
240
|
+
'order/bulk',
|
|
241
|
+
'order/modify',
|
|
242
|
+
'orders',
|
|
243
|
+
'oco-orders',
|
|
244
|
+
'order/collateral/oco',
|
|
245
|
+
'order/oco-cancel',
|
|
246
|
+
'order/oto-cancel',
|
|
247
|
+
'profile/websocket_token',
|
|
248
|
+
'convert/estimate',
|
|
249
|
+
'convert/confirm',
|
|
250
|
+
'convert/history',
|
|
251
|
+
'sub-account/create',
|
|
252
|
+
'sub-account/delete',
|
|
253
|
+
'sub-account/edit',
|
|
254
|
+
'sub-account/list',
|
|
255
|
+
'sub-account/transfer',
|
|
256
|
+
'sub-account/block',
|
|
257
|
+
'sub-account/unblock',
|
|
258
|
+
'sub-account/balances',
|
|
259
|
+
'sub-account/transfer/history',
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
},
|
|
264
|
+
'fees': {
|
|
265
|
+
'trading': {
|
|
266
|
+
'tierBased': False,
|
|
267
|
+
'percentage': True,
|
|
268
|
+
'taker': self.parse_number('0.001'),
|
|
269
|
+
'maker': self.parse_number('0.001'),
|
|
270
|
+
},
|
|
271
|
+
},
|
|
272
|
+
'options': {
|
|
273
|
+
'fiatCurrencies': ['EUR', 'USD', 'RUB', 'UAH'],
|
|
274
|
+
'fetchBalance': {
|
|
275
|
+
'account': 'spot',
|
|
276
|
+
},
|
|
277
|
+
'accountsByType': {
|
|
278
|
+
'funding': 'main',
|
|
279
|
+
'main': 'main',
|
|
280
|
+
'spot': 'spot',
|
|
281
|
+
'margin': 'collateral',
|
|
282
|
+
'trade': 'spot',
|
|
283
|
+
},
|
|
284
|
+
'networksById': {
|
|
285
|
+
'BEP20': 'BSC',
|
|
286
|
+
},
|
|
287
|
+
'defaultType': 'spot',
|
|
288
|
+
'brokerId': 'ccxt',
|
|
289
|
+
},
|
|
290
|
+
'precisionMode': TICK_SIZE,
|
|
291
|
+
'exceptions': {
|
|
292
|
+
'exact': {
|
|
293
|
+
'Unauthorized request.': AuthenticationError, # {"code":10,"message":"Unauthorized request."}
|
|
294
|
+
'The market format is invalid.': BadSymbol, # {"code":0,"message":"Validation failed","errors":{"market":["The market format is invalid."]}}
|
|
295
|
+
'Market is not available': BadSymbol, # {"success":false,"message":{"market":["Market is not available"]},"result":[]}
|
|
296
|
+
'Invalid payload.': BadRequest, # {"code":9,"message":"Invalid payload."}
|
|
297
|
+
'Amount must be greater than 0': InvalidOrder, # {"code":0,"message":"Validation failed","errors":{"amount":["Amount must be greater than 0"]}}
|
|
298
|
+
'Not enough balance.': InsufficientFunds, # {"code":10,"message":"Inner validation failed","errors":{"amount":["Not enough balance."]}}
|
|
299
|
+
'The order id field is required.': InvalidOrder, # {"code":0,"message":"Validation failed","errors":{"orderId":["The order id field is required."]}}
|
|
300
|
+
'Not enough balance': InsufficientFunds, # {"code":0,"message":"Validation failed","errors":{"amount":["Not enough balance"]}}
|
|
301
|
+
'This action is unauthorized.': PermissionDenied, # {"code":0,"message":"This action is unauthorized."}
|
|
302
|
+
'This API Key is not authorized to perform self action.': PermissionDenied, # {"code":4,"message":"This API Key is not authorized to perform self action."}
|
|
303
|
+
'Unexecuted order was not found.': OrderNotFound, # {"code":2,"message":"Inner validation failed","errors":{"order_id":["Unexecuted order was not found."]}}
|
|
304
|
+
'The selected from is invalid.': BadRequest, # {"code":0,"message":"Validation failed","errors":{"from":["The selected from is invalid."]}}
|
|
305
|
+
'503': ExchangeNotAvailable, # {"response":null,"status":503,"errors":{"message":[""]},"notification":null,"warning":null,"_token":null},
|
|
306
|
+
'422': OrderNotFound, # {"response":null,"status":422,"errors":{"orderId":["Finished order id 1295772653 not found on your account"]},"notification":null,"warning":"Finished order id 1295772653 not found on your account","_token":null}
|
|
307
|
+
},
|
|
308
|
+
'broad': {
|
|
309
|
+
'This action is unauthorized': PermissionDenied, # {"code":2,"message":"This action is unauthorized. Enable your key in API settings"}
|
|
310
|
+
'Given amount is less than min amount': InvalidOrder, # {"code":0,"message":"Validation failed","errors":{"amount":["Given amount is less than min amount 200000"],"total":["Total is less than 5.05"]}}
|
|
311
|
+
'Total is less than': InvalidOrder, # {"code":0,"message":"Validation failed","errors":{"amount":["Given amount is less than min amount 200000"],"total":["Total is less than 5.05"]}}
|
|
312
|
+
'fee must be no less than': InvalidOrder, # {"code":0,"message":"Validation failed","errors":{"amount":["Total amount + fee must be no less than 5.05505"]}}
|
|
313
|
+
'Enable your key in API settings': PermissionDenied, # {"code":2,"message":"This action is unauthorized. Enable your key in API settings"}
|
|
314
|
+
'You don\'t have such amount for transfer': InsufficientFunds, # {"code":3,"message":"Inner validation failed","errors":{"amount":["You don't have such amount for transfer(available 0.44523433, in amount: 2)"]}}
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
})
|
|
318
|
+
|
|
319
|
+
def fetch_markets(self, params={}) -> List[Market]:
|
|
320
|
+
"""
|
|
321
|
+
retrieves data on all markets for whitebit
|
|
322
|
+
:see: https://docs.whitebit.com/public/http-v4/#market-info
|
|
323
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
324
|
+
:returns dict[]: an array of objects representing market data
|
|
325
|
+
"""
|
|
326
|
+
markets = self.v4PublicGetMarkets()
|
|
327
|
+
#
|
|
328
|
+
# [
|
|
329
|
+
# {
|
|
330
|
+
# "name": "SON_USD", # Market pair name
|
|
331
|
+
# "stock": "SON", # Ticker of stock currency
|
|
332
|
+
# "money": "USD", # Ticker of money currency
|
|
333
|
+
# "stockPrec": "3", # Stock currency precision
|
|
334
|
+
# "moneyPrec": "2", # Precision of money currency
|
|
335
|
+
# "feePrec": "4", # Fee precision
|
|
336
|
+
# "makerFee": "0.1", # Default maker fee ratio
|
|
337
|
+
# "takerFee": "0.1", # Default taker fee ratio
|
|
338
|
+
# "minAmount": "0.001", # Minimal amount of stock to trade
|
|
339
|
+
# "minTotal": "0.001", # Minimal amount of money to trade
|
|
340
|
+
# "tradesEnabled": True, # Is trading enabled
|
|
341
|
+
# "isCollateral": True, # Is margin trading enabled
|
|
342
|
+
# "type": "spot", # Market type. Possible values: "spot", "futures"
|
|
343
|
+
# "maxTotal": "1000000000" # Maximum total(amount * price) of money to trade
|
|
344
|
+
# },
|
|
345
|
+
# {
|
|
346
|
+
# ...
|
|
347
|
+
# }
|
|
348
|
+
# ]
|
|
349
|
+
#
|
|
350
|
+
return self.parse_markets(markets)
|
|
351
|
+
|
|
352
|
+
def parse_market(self, market: dict) -> Market:
|
|
353
|
+
id = self.safe_string(market, 'name')
|
|
354
|
+
baseId = self.safe_string(market, 'stock')
|
|
355
|
+
quoteId = self.safe_string(market, 'money')
|
|
356
|
+
quoteId = 'USDT' if (quoteId == 'PERP') else quoteId
|
|
357
|
+
base = self.safe_currency_code(baseId)
|
|
358
|
+
quote = self.safe_currency_code(quoteId)
|
|
359
|
+
active = self.safe_value(market, 'tradesEnabled')
|
|
360
|
+
isCollateral = self.safe_value(market, 'isCollateral')
|
|
361
|
+
typeId = self.safe_string(market, 'type')
|
|
362
|
+
type: MarketType
|
|
363
|
+
settle: Str = None
|
|
364
|
+
settleId: Str = None
|
|
365
|
+
symbol = base + '/' + quote
|
|
366
|
+
swap = typeId == 'futures'
|
|
367
|
+
margin = isCollateral and not swap
|
|
368
|
+
contract = False
|
|
369
|
+
amountPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'stockPrec')))
|
|
370
|
+
contractSize = amountPrecision
|
|
371
|
+
linear: Bool = None
|
|
372
|
+
inverse: Bool = None
|
|
373
|
+
if swap:
|
|
374
|
+
settleId = quoteId
|
|
375
|
+
settle = self.safe_currency_code(settleId)
|
|
376
|
+
symbol = symbol + ':' + settle
|
|
377
|
+
type = 'swap'
|
|
378
|
+
contract = True
|
|
379
|
+
linear = True
|
|
380
|
+
inverse = False
|
|
381
|
+
else:
|
|
382
|
+
type = 'spot'
|
|
383
|
+
takerFeeRate = self.safe_string(market, 'takerFee')
|
|
384
|
+
taker = Precise.string_div(takerFeeRate, '100')
|
|
385
|
+
makerFeeRate = self.safe_string(market, 'makerFee')
|
|
386
|
+
maker = Precise.string_div(makerFeeRate, '100')
|
|
387
|
+
return {
|
|
388
|
+
'id': id,
|
|
389
|
+
'symbol': symbol,
|
|
390
|
+
'base': base,
|
|
391
|
+
'quote': quote,
|
|
392
|
+
'settle': settle,
|
|
393
|
+
'baseId': baseId,
|
|
394
|
+
'quoteId': quoteId,
|
|
395
|
+
'settleId': settleId,
|
|
396
|
+
'type': type,
|
|
397
|
+
'spot': not swap,
|
|
398
|
+
'margin': margin,
|
|
399
|
+
'swap': swap,
|
|
400
|
+
'future': False,
|
|
401
|
+
'option': False,
|
|
402
|
+
'active': active,
|
|
403
|
+
'contract': contract,
|
|
404
|
+
'linear': linear,
|
|
405
|
+
'inverse': inverse,
|
|
406
|
+
'taker': self.parse_number(taker),
|
|
407
|
+
'maker': self.parse_number(maker),
|
|
408
|
+
'contractSize': contractSize,
|
|
409
|
+
'expiry': None,
|
|
410
|
+
'expiryDatetime': None,
|
|
411
|
+
'strike': None,
|
|
412
|
+
'optionType': None,
|
|
413
|
+
'precision': {
|
|
414
|
+
'amount': amountPrecision,
|
|
415
|
+
'price': self.parse_number(self.parse_precision(self.safe_string(market, 'moneyPrec'))),
|
|
416
|
+
},
|
|
417
|
+
'limits': {
|
|
418
|
+
'leverage': {
|
|
419
|
+
'min': None,
|
|
420
|
+
'max': None,
|
|
421
|
+
},
|
|
422
|
+
'amount': {
|
|
423
|
+
'min': self.safe_number(market, 'minAmount'),
|
|
424
|
+
'max': None,
|
|
425
|
+
},
|
|
426
|
+
'price': {
|
|
427
|
+
'min': None,
|
|
428
|
+
'max': None,
|
|
429
|
+
},
|
|
430
|
+
'cost': {
|
|
431
|
+
'min': self.safe_number(market, 'minTotal'),
|
|
432
|
+
'max': self.safe_number(market, 'maxTotal'),
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
'created': None,
|
|
436
|
+
'info': market,
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
def fetch_currencies(self, params={}) -> Currencies:
|
|
440
|
+
"""
|
|
441
|
+
fetches all available currencies on an exchange
|
|
442
|
+
:see: https://docs.whitebit.com/public/http-v4/#asset-status-list
|
|
443
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
444
|
+
:returns dict: an associative dictionary of currencies
|
|
445
|
+
"""
|
|
446
|
+
response = self.v4PublicGetAssets(params)
|
|
447
|
+
#
|
|
448
|
+
# "BTC": {
|
|
449
|
+
# "name": "Bitcoin",
|
|
450
|
+
# "unified_cryptoasset_id": 1,
|
|
451
|
+
# "can_withdraw": True,
|
|
452
|
+
# "can_deposit": True,
|
|
453
|
+
# "min_withdraw": "0.001",
|
|
454
|
+
# "max_withdraw": "2",
|
|
455
|
+
# "maker_fee": "0.1",
|
|
456
|
+
# "taker_fee": "0.1",
|
|
457
|
+
# "min_deposit": "0.0001",
|
|
458
|
+
# "max_deposit": "0",
|
|
459
|
+
# },
|
|
460
|
+
#
|
|
461
|
+
ids = list(response.keys())
|
|
462
|
+
result: dict = {}
|
|
463
|
+
for i in range(0, len(ids)):
|
|
464
|
+
id = ids[i]
|
|
465
|
+
currency = response[id]
|
|
466
|
+
# breaks down in Python due to utf8 encoding issues on the exchange side
|
|
467
|
+
# name = self.safe_string(currency, 'name')
|
|
468
|
+
canDeposit = self.safe_bool(currency, 'can_deposit', True)
|
|
469
|
+
canWithdraw = self.safe_bool(currency, 'can_withdraw', True)
|
|
470
|
+
active = canDeposit and canWithdraw
|
|
471
|
+
code = self.safe_currency_code(id)
|
|
472
|
+
result[code] = {
|
|
473
|
+
'id': id,
|
|
474
|
+
'code': code,
|
|
475
|
+
'info': currency, # the original payload
|
|
476
|
+
'name': None, # see the comment above
|
|
477
|
+
'active': active,
|
|
478
|
+
'deposit': canDeposit,
|
|
479
|
+
'withdraw': canWithdraw,
|
|
480
|
+
'fee': None,
|
|
481
|
+
'precision': None,
|
|
482
|
+
'limits': {
|
|
483
|
+
'amount': {
|
|
484
|
+
'min': None,
|
|
485
|
+
'max': None,
|
|
486
|
+
},
|
|
487
|
+
'withdraw': {
|
|
488
|
+
'min': self.safe_number(currency, 'min_withdraw'),
|
|
489
|
+
'max': self.safe_number(currency, 'max_withdraw'),
|
|
490
|
+
},
|
|
491
|
+
},
|
|
492
|
+
}
|
|
493
|
+
return result
|
|
494
|
+
|
|
495
|
+
def fetch_transaction_fees(self, codes: Strings = None, params={}):
|
|
496
|
+
"""
|
|
497
|
+
* @deprecated
|
|
498
|
+
please use fetchDepositWithdrawFees instead
|
|
499
|
+
:see: https://docs.whitebit.com/public/http-v4/#fee
|
|
500
|
+
:param str[]|None codes: not used by fetchTransactionFees()
|
|
501
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
502
|
+
:returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
|
|
503
|
+
"""
|
|
504
|
+
self.load_markets()
|
|
505
|
+
response = self.v4PublicGetFee(params)
|
|
506
|
+
#
|
|
507
|
+
# {
|
|
508
|
+
# "1INCH":{
|
|
509
|
+
# "is_depositable":true,
|
|
510
|
+
# "is_withdrawal":true,
|
|
511
|
+
# "ticker":"1INCH",
|
|
512
|
+
# "name":"1inch",
|
|
513
|
+
# "providers":[
|
|
514
|
+
# ],
|
|
515
|
+
# "withdraw":{
|
|
516
|
+
# "max_amount":"0",
|
|
517
|
+
# "min_amount":"21.5",
|
|
518
|
+
# "fixed":"17.5",
|
|
519
|
+
# "flex":null
|
|
520
|
+
# },
|
|
521
|
+
# "deposit":{
|
|
522
|
+
# "max_amount":"0",
|
|
523
|
+
# "min_amount":"19.5",
|
|
524
|
+
# "fixed":null,
|
|
525
|
+
# "flex":null
|
|
526
|
+
# }
|
|
527
|
+
# },
|
|
528
|
+
# {...}
|
|
529
|
+
# }
|
|
530
|
+
#
|
|
531
|
+
currenciesIds = list(response.keys())
|
|
532
|
+
withdrawFees: dict = {}
|
|
533
|
+
depositFees: dict = {}
|
|
534
|
+
for i in range(0, len(currenciesIds)):
|
|
535
|
+
currency = currenciesIds[i]
|
|
536
|
+
data = response[currency]
|
|
537
|
+
code = self.safe_currency_code(currency)
|
|
538
|
+
withdraw = self.safe_value(data, 'withdraw', {})
|
|
539
|
+
withdrawFees[code] = self.safe_string(withdraw, 'fixed')
|
|
540
|
+
deposit = self.safe_value(data, 'deposit', {})
|
|
541
|
+
depositFees[code] = self.safe_string(deposit, 'fixed')
|
|
542
|
+
return {
|
|
543
|
+
'withdraw': withdrawFees,
|
|
544
|
+
'deposit': depositFees,
|
|
545
|
+
'info': response,
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
def fetch_deposit_withdraw_fees(self, codes: Strings = None, params={}):
|
|
549
|
+
"""
|
|
550
|
+
fetch deposit and withdraw fees
|
|
551
|
+
:see: https://docs.whitebit.com/public/http-v4/#fee
|
|
552
|
+
:param str[]|None codes: not used by fetchDepositWithdrawFees()
|
|
553
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
554
|
+
:returns dict: a list of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>`
|
|
555
|
+
"""
|
|
556
|
+
self.load_markets()
|
|
557
|
+
response = self.v4PublicGetFee(params)
|
|
558
|
+
#
|
|
559
|
+
# {
|
|
560
|
+
# "1INCH": {
|
|
561
|
+
# "is_depositable": True,
|
|
562
|
+
# "is_withdrawal": True,
|
|
563
|
+
# "ticker": "1INCH",
|
|
564
|
+
# "name": "1inch",
|
|
565
|
+
# "providers": [],
|
|
566
|
+
# "withdraw": {
|
|
567
|
+
# "max_amount": "0",
|
|
568
|
+
# "min_amount": "21.5",
|
|
569
|
+
# "fixed": "17.5",
|
|
570
|
+
# "flex": null
|
|
571
|
+
# },
|
|
572
|
+
# "deposit": {
|
|
573
|
+
# "max_amount": "0",
|
|
574
|
+
# "min_amount": "19.5",
|
|
575
|
+
# "fixed": null,
|
|
576
|
+
# "flex": null
|
|
577
|
+
# }
|
|
578
|
+
# },
|
|
579
|
+
# "WBT(ERC20)": {
|
|
580
|
+
# "is_depositable": True,
|
|
581
|
+
# "is_withdrawal": True,
|
|
582
|
+
# "ticker": "WBT",
|
|
583
|
+
# "name": "WhiteBIT Token",
|
|
584
|
+
# "providers": [],
|
|
585
|
+
# "withdraw": {max_amount: "0", min_amount: '0.7', fixed: "0.253", flex: null},
|
|
586
|
+
# "deposit": {max_amount: "0", min_amount: "0.35", fixed: null, flex: null}
|
|
587
|
+
# },
|
|
588
|
+
# "WBT(TRC20)": {
|
|
589
|
+
# "is_depositable": True,
|
|
590
|
+
# "is_withdrawal": True,
|
|
591
|
+
# "ticker": "WBT",
|
|
592
|
+
# "name": "WhiteBIT Token",
|
|
593
|
+
# "providers": [],
|
|
594
|
+
# "withdraw": {max_amount: "0", min_amount: "1.5", fixed: "0.075", flex: null},
|
|
595
|
+
# "deposit": {max_amount: "0", min_amount: "0.75", fixed: null, flex: null}
|
|
596
|
+
# },
|
|
597
|
+
# ...
|
|
598
|
+
# }
|
|
599
|
+
#
|
|
600
|
+
return self.parse_deposit_withdraw_fees(response, codes)
|
|
601
|
+
|
|
602
|
+
def parse_deposit_withdraw_fees(self, response, codes=None, currencyIdKey=None):
|
|
603
|
+
#
|
|
604
|
+
# {
|
|
605
|
+
# "1INCH": {
|
|
606
|
+
# "is_depositable": True,
|
|
607
|
+
# "is_withdrawal": True,
|
|
608
|
+
# "ticker": "1INCH",
|
|
609
|
+
# "name": "1inch",
|
|
610
|
+
# "providers": [],
|
|
611
|
+
# "withdraw": {
|
|
612
|
+
# "max_amount": "0",
|
|
613
|
+
# "min_amount": "21.5",
|
|
614
|
+
# "fixed": "17.5",
|
|
615
|
+
# "flex": null
|
|
616
|
+
# },
|
|
617
|
+
# "deposit": {
|
|
618
|
+
# "max_amount": "0",
|
|
619
|
+
# "min_amount": "19.5",
|
|
620
|
+
# "fixed": null,
|
|
621
|
+
# "flex": null
|
|
622
|
+
# }
|
|
623
|
+
# },
|
|
624
|
+
# "WBT(ERC20)": {
|
|
625
|
+
# "is_depositable": True,
|
|
626
|
+
# "is_withdrawal": True,
|
|
627
|
+
# "ticker": "WBT",
|
|
628
|
+
# "name": "WhiteBIT Token",
|
|
629
|
+
# "providers": [],
|
|
630
|
+
# "withdraw": {max_amount: "0", min_amount: "0.7", fixed: "0.253", flex: null},
|
|
631
|
+
# "deposit": {max_amount: "0", min_amount: "0.35", fixed: null, flex: null}
|
|
632
|
+
# },
|
|
633
|
+
# "WBT(TRC20)": {
|
|
634
|
+
# "is_depositable": True,
|
|
635
|
+
# "is_withdrawal": True,
|
|
636
|
+
# "ticker": "WBT",
|
|
637
|
+
# "name": "WhiteBIT Token",
|
|
638
|
+
# "providers": [],
|
|
639
|
+
# "withdraw": {max_amount: "0", min_amount: "1.5", fixed: "0.075", flex: null},
|
|
640
|
+
# "deposit": {max_amount: "0", min_amount: "0.75", fixed: null, flex: null}
|
|
641
|
+
# },
|
|
642
|
+
# ...
|
|
643
|
+
# }
|
|
644
|
+
#
|
|
645
|
+
depositWithdrawFees: dict = {}
|
|
646
|
+
codes = self.market_codes(codes)
|
|
647
|
+
currencyIds = list(response.keys())
|
|
648
|
+
for i in range(0, len(currencyIds)):
|
|
649
|
+
entry = currencyIds[i]
|
|
650
|
+
splitEntry = entry.split(' ')
|
|
651
|
+
currencyId = splitEntry[0]
|
|
652
|
+
feeInfo = response[entry]
|
|
653
|
+
code = self.safe_currency_code(currencyId)
|
|
654
|
+
if (codes is None) or (self.in_array(code, codes)):
|
|
655
|
+
depositWithdrawFee = self.safe_value(depositWithdrawFees, code)
|
|
656
|
+
if depositWithdrawFee is None:
|
|
657
|
+
depositWithdrawFees[code] = self.deposit_withdraw_fee({})
|
|
658
|
+
depositWithdrawFees[code]['info'][entry] = feeInfo
|
|
659
|
+
networkId = self.safe_string(splitEntry, 1)
|
|
660
|
+
withdraw = self.safe_value(feeInfo, 'withdraw')
|
|
661
|
+
deposit = self.safe_value(feeInfo, 'deposit')
|
|
662
|
+
withdrawFee = self.safe_number(withdraw, 'fixed')
|
|
663
|
+
depositFee = self.safe_number(deposit, 'fixed')
|
|
664
|
+
withdrawResult: dict = {
|
|
665
|
+
'fee': withdrawFee,
|
|
666
|
+
'percentage': False if (withdrawFee is not None) else None,
|
|
667
|
+
}
|
|
668
|
+
depositResult: dict = {
|
|
669
|
+
'fee': depositFee,
|
|
670
|
+
'percentage': False if (depositFee is not None) else None,
|
|
671
|
+
}
|
|
672
|
+
if networkId is not None:
|
|
673
|
+
networkLength = len(networkId)
|
|
674
|
+
networkId = networkId[1:networkLength - 1]
|
|
675
|
+
networkCode = self.network_id_to_code(networkId)
|
|
676
|
+
depositWithdrawFees[code]['networks'][networkCode] = {
|
|
677
|
+
'withdraw': withdrawResult,
|
|
678
|
+
'deposit': depositResult,
|
|
679
|
+
}
|
|
680
|
+
else:
|
|
681
|
+
depositWithdrawFees[code]['withdraw'] = withdrawResult
|
|
682
|
+
depositWithdrawFees[code]['deposit'] = depositResult
|
|
683
|
+
depositWithdrawCodes = list(depositWithdrawFees.keys())
|
|
684
|
+
for i in range(0, len(depositWithdrawCodes)):
|
|
685
|
+
code = depositWithdrawCodes[i]
|
|
686
|
+
currency = self.currency(code)
|
|
687
|
+
depositWithdrawFees[code] = self.assign_default_deposit_withdraw_fees(depositWithdrawFees[code], currency)
|
|
688
|
+
return depositWithdrawFees
|
|
689
|
+
|
|
690
|
+
def fetch_trading_fees(self, params={}) -> TradingFees:
|
|
691
|
+
"""
|
|
692
|
+
fetch the trading fees for multiple markets
|
|
693
|
+
:see: https://docs.whitebit.com/public/http-v4/#asset-status-list
|
|
694
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
695
|
+
:returns dict: a dictionary of `fee structures <https://docs.ccxt.com/#/?id=fee-structure>` indexed by market symbols
|
|
696
|
+
"""
|
|
697
|
+
self.load_markets()
|
|
698
|
+
response = self.v4PublicGetAssets(params)
|
|
699
|
+
#
|
|
700
|
+
# {
|
|
701
|
+
# "1INCH": {
|
|
702
|
+
# "name": "1inch",
|
|
703
|
+
# "unified_cryptoasset_id": "8104",
|
|
704
|
+
# "can_withdraw": True,
|
|
705
|
+
# "can_deposit": True,
|
|
706
|
+
# "min_withdraw": "33",
|
|
707
|
+
# "max_withdraw": "0",
|
|
708
|
+
# "maker_fee": "0.1",
|
|
709
|
+
# "taker_fee": "0.1",
|
|
710
|
+
# "min_deposit": "30",
|
|
711
|
+
# "max_deposit": "0"
|
|
712
|
+
# },
|
|
713
|
+
# ...
|
|
714
|
+
# }
|
|
715
|
+
#
|
|
716
|
+
result: dict = {}
|
|
717
|
+
for i in range(0, len(self.symbols)):
|
|
718
|
+
symbol = self.symbols[i]
|
|
719
|
+
market = self.market(symbol)
|
|
720
|
+
fee = self.safe_value(response, market['baseId'], {})
|
|
721
|
+
makerFee = self.safe_string(fee, 'maker_fee')
|
|
722
|
+
takerFee = self.safe_string(fee, 'taker_fee')
|
|
723
|
+
makerFee = Precise.string_div(makerFee, '100')
|
|
724
|
+
takerFee = Precise.string_div(takerFee, '100')
|
|
725
|
+
result[symbol] = {
|
|
726
|
+
'info': fee,
|
|
727
|
+
'symbol': market['symbol'],
|
|
728
|
+
'percentage': True,
|
|
729
|
+
'tierBased': False,
|
|
730
|
+
'maker': self.parse_number(makerFee),
|
|
731
|
+
'taker': self.parse_number(takerFee),
|
|
732
|
+
}
|
|
733
|
+
return result
|
|
734
|
+
|
|
735
|
+
def fetch_ticker(self, symbol: str, params={}) -> Ticker:
|
|
736
|
+
"""
|
|
737
|
+
fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
738
|
+
:see: https://docs.whitebit.com/public/http-v4/#market-activity
|
|
739
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
740
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
741
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
742
|
+
"""
|
|
743
|
+
self.load_markets()
|
|
744
|
+
market = self.market(symbol)
|
|
745
|
+
request: dict = {
|
|
746
|
+
'market': market['id'],
|
|
747
|
+
}
|
|
748
|
+
response = self.v1PublicGetTicker(self.extend(request, params))
|
|
749
|
+
#
|
|
750
|
+
# {
|
|
751
|
+
# "success":true,
|
|
752
|
+
# "message":"",
|
|
753
|
+
# "result": {
|
|
754
|
+
# "bid":"0.021979",
|
|
755
|
+
# "ask":"0.021996",
|
|
756
|
+
# "open":"0.02182",
|
|
757
|
+
# "high":"0.022039",
|
|
758
|
+
# "low":"0.02161",
|
|
759
|
+
# "last":"0.021987",
|
|
760
|
+
# "volume":"2810.267",
|
|
761
|
+
# "deal":"61.383565474",
|
|
762
|
+
# "change":"0.76",
|
|
763
|
+
# },
|
|
764
|
+
# }
|
|
765
|
+
#
|
|
766
|
+
ticker = self.safe_dict(response, 'result', {})
|
|
767
|
+
return self.parse_ticker(ticker, market)
|
|
768
|
+
|
|
769
|
+
def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
|
|
770
|
+
#
|
|
771
|
+
# FetchTicker(v1)
|
|
772
|
+
#
|
|
773
|
+
# {
|
|
774
|
+
# "bid": "0.021979",
|
|
775
|
+
# "ask": "0.021996",
|
|
776
|
+
# "open": "0.02182",
|
|
777
|
+
# "high": "0.022039",
|
|
778
|
+
# "low": "0.02161",
|
|
779
|
+
# "last": "0.021987",
|
|
780
|
+
# "volume": "2810.267",
|
|
781
|
+
# "deal": "61.383565474",
|
|
782
|
+
# "change": "0.76",
|
|
783
|
+
# }
|
|
784
|
+
#
|
|
785
|
+
# FetchTickers(v4)
|
|
786
|
+
#
|
|
787
|
+
# "BCH_RUB": {
|
|
788
|
+
# "base_id": 1831,
|
|
789
|
+
# "quote_id": 0,
|
|
790
|
+
# "last_price": "32830.21",
|
|
791
|
+
# "quote_volume": "1494659.8024096",
|
|
792
|
+
# "base_volume": "46.1083",
|
|
793
|
+
# "isFrozen": False,
|
|
794
|
+
# "change": "2.12" # in percent
|
|
795
|
+
# }
|
|
796
|
+
#
|
|
797
|
+
market = self.safe_market(None, market)
|
|
798
|
+
last = self.safe_string(ticker, 'last_price')
|
|
799
|
+
return self.safe_ticker({
|
|
800
|
+
'symbol': market['symbol'],
|
|
801
|
+
'timestamp': None,
|
|
802
|
+
'datetime': None,
|
|
803
|
+
'high': self.safe_string(ticker, 'high'),
|
|
804
|
+
'low': self.safe_string(ticker, 'low'),
|
|
805
|
+
'bid': self.safe_string(ticker, 'bid'),
|
|
806
|
+
'bidVolume': None,
|
|
807
|
+
'ask': self.safe_string(ticker, 'ask'),
|
|
808
|
+
'askVolume': None,
|
|
809
|
+
'vwap': None,
|
|
810
|
+
'open': self.safe_string(ticker, 'open'),
|
|
811
|
+
'close': last,
|
|
812
|
+
'last': last,
|
|
813
|
+
'previousClose': None,
|
|
814
|
+
'change': None,
|
|
815
|
+
'percentage': self.safe_string(ticker, 'change'),
|
|
816
|
+
'average': None,
|
|
817
|
+
'baseVolume': self.safe_string_2(ticker, 'base_volume', 'volume'),
|
|
818
|
+
'quoteVolume': self.safe_string_2(ticker, 'quote_volume', 'deal'),
|
|
819
|
+
'info': ticker,
|
|
820
|
+
}, market)
|
|
821
|
+
|
|
822
|
+
def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
823
|
+
"""
|
|
824
|
+
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
825
|
+
:see: https://docs.whitebit.com/public/http-v4/#market-activity
|
|
826
|
+
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
827
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
828
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
829
|
+
"""
|
|
830
|
+
self.load_markets()
|
|
831
|
+
symbols = self.market_symbols(symbols)
|
|
832
|
+
response = self.v4PublicGetTicker(params)
|
|
833
|
+
#
|
|
834
|
+
# "BCH_RUB": {
|
|
835
|
+
# "base_id":1831,
|
|
836
|
+
# "quote_id":0,
|
|
837
|
+
# "last_price":"32830.21",
|
|
838
|
+
# "quote_volume":"1494659.8024096",
|
|
839
|
+
# "base_volume":"46.1083",
|
|
840
|
+
# "isFrozen":false,
|
|
841
|
+
# "change":"2.12"
|
|
842
|
+
# },
|
|
843
|
+
#
|
|
844
|
+
marketIds = list(response.keys())
|
|
845
|
+
result: dict = {}
|
|
846
|
+
for i in range(0, len(marketIds)):
|
|
847
|
+
marketId = marketIds[i]
|
|
848
|
+
market = self.safe_market(marketId)
|
|
849
|
+
ticker = self.parse_ticker(response[marketId], market)
|
|
850
|
+
symbol = ticker['symbol']
|
|
851
|
+
result[symbol] = ticker
|
|
852
|
+
return self.filter_by_array_tickers(result, 'symbol', symbols)
|
|
853
|
+
|
|
854
|
+
def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
|
855
|
+
"""
|
|
856
|
+
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
857
|
+
:see: https://docs.whitebit.com/public/http-v4/#orderbook
|
|
858
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
|
859
|
+
:param int [limit]: the maximum amount of order book entries to return
|
|
860
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
861
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
862
|
+
"""
|
|
863
|
+
self.load_markets()
|
|
864
|
+
market = self.market(symbol)
|
|
865
|
+
request: dict = {
|
|
866
|
+
'market': market['id'],
|
|
867
|
+
}
|
|
868
|
+
if limit is not None:
|
|
869
|
+
request['limit'] = limit # default = 100, maximum = 100
|
|
870
|
+
response = self.v4PublicGetOrderbookMarket(self.extend(request, params))
|
|
871
|
+
#
|
|
872
|
+
# {
|
|
873
|
+
# "timestamp": 1594391413,
|
|
874
|
+
# "asks": [
|
|
875
|
+
# [
|
|
876
|
+
# "9184.41",
|
|
877
|
+
# "0.773162"
|
|
878
|
+
# ],
|
|
879
|
+
# [...]
|
|
880
|
+
# ],
|
|
881
|
+
# "bids": [
|
|
882
|
+
# [
|
|
883
|
+
# "9181.19",
|
|
884
|
+
# "0.010873"
|
|
885
|
+
# ],
|
|
886
|
+
# [...]
|
|
887
|
+
# ]
|
|
888
|
+
# }
|
|
889
|
+
#
|
|
890
|
+
timestamp = self.safe_timestamp(response, 'timestamp')
|
|
891
|
+
return self.parse_order_book(response, symbol, timestamp)
|
|
892
|
+
|
|
893
|
+
def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
894
|
+
"""
|
|
895
|
+
get the list of most recent trades for a particular symbol
|
|
896
|
+
:see: https://docs.whitebit.com/public/http-v4/#recent-trades
|
|
897
|
+
:param str symbol: unified symbol of the market to fetch trades for
|
|
898
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
899
|
+
:param int [limit]: the maximum amount of trades to fetch
|
|
900
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
901
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
902
|
+
"""
|
|
903
|
+
self.load_markets()
|
|
904
|
+
market = self.market(symbol)
|
|
905
|
+
request: dict = {
|
|
906
|
+
'market': market['id'],
|
|
907
|
+
}
|
|
908
|
+
response = self.v4PublicGetTradesMarket(self.extend(request, params))
|
|
909
|
+
#
|
|
910
|
+
# [
|
|
911
|
+
# {
|
|
912
|
+
# "tradeID": 158056419,
|
|
913
|
+
# "price": "9186.13",
|
|
914
|
+
# "quote_volume": "0.0021",
|
|
915
|
+
# "base_volume": "9186.13",
|
|
916
|
+
# "trade_timestamp": 1594391747,
|
|
917
|
+
# "type": "sell"
|
|
918
|
+
# },
|
|
919
|
+
# ],
|
|
920
|
+
#
|
|
921
|
+
return self.parse_trades(response, market, since, limit)
|
|
922
|
+
|
|
923
|
+
def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
924
|
+
"""
|
|
925
|
+
fetch all trades made by the user
|
|
926
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#query-executed-order-history
|
|
927
|
+
:param str symbol: unified symbol of the market to fetch trades for
|
|
928
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
929
|
+
:param int [limit]: the maximum amount of trades to fetch
|
|
930
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
931
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
932
|
+
"""
|
|
933
|
+
self.load_markets()
|
|
934
|
+
market: Market = None
|
|
935
|
+
request: dict = {}
|
|
936
|
+
if symbol is not None:
|
|
937
|
+
market = self.market(symbol)
|
|
938
|
+
request['market'] = market['id']
|
|
939
|
+
response = self.v4PrivatePostTradeAccountExecutedHistory(self.extend(request, params))
|
|
940
|
+
#
|
|
941
|
+
# when no symbol is provided
|
|
942
|
+
#
|
|
943
|
+
# {
|
|
944
|
+
# "USDC_USDT":[
|
|
945
|
+
# {
|
|
946
|
+
# "id":"1343815269",
|
|
947
|
+
# "clientOrderId":"",
|
|
948
|
+
# "time":"1641051917.532965",
|
|
949
|
+
# "side":"sell",
|
|
950
|
+
# "role":"2",
|
|
951
|
+
# "amount":"9.986",
|
|
952
|
+
# "price":"0.9995",
|
|
953
|
+
# "deal":"9.981007",
|
|
954
|
+
# "fee":"0.009981007",
|
|
955
|
+
# "orderId":"58166729555"
|
|
956
|
+
# },
|
|
957
|
+
# ]
|
|
958
|
+
# }
|
|
959
|
+
#
|
|
960
|
+
# when a symbol is provided
|
|
961
|
+
#
|
|
962
|
+
# [
|
|
963
|
+
# {
|
|
964
|
+
# "id": 1343815269,
|
|
965
|
+
# "clientOrderId": '',
|
|
966
|
+
# "time": 1641051917.532965,
|
|
967
|
+
# "side": "sell",
|
|
968
|
+
# "role": 2,
|
|
969
|
+
# "amount": "9.986",
|
|
970
|
+
# "price": "0.9995",
|
|
971
|
+
# "deal": "9.981007",
|
|
972
|
+
# "fee": "0.009981007",
|
|
973
|
+
# "orderId": 58166729555,
|
|
974
|
+
# },
|
|
975
|
+
# ]
|
|
976
|
+
#
|
|
977
|
+
if isinstance(response, list):
|
|
978
|
+
return self.parse_trades(response, market, since, limit)
|
|
979
|
+
else:
|
|
980
|
+
results = []
|
|
981
|
+
keys = list(response.keys())
|
|
982
|
+
for i in range(0, len(keys)):
|
|
983
|
+
marketId = keys[i]
|
|
984
|
+
marketNew = self.safe_market(marketId, None, '_')
|
|
985
|
+
rawTrades = self.safe_value(response, marketId, [])
|
|
986
|
+
parsed = self.parse_trades(rawTrades, marketNew, since, limit)
|
|
987
|
+
results = self.array_concat(results, parsed)
|
|
988
|
+
results = self.sort_by_2(results, 'timestamp', 'id')
|
|
989
|
+
return self.filter_by_since_limit(results, since, limit, 'timestamp')
|
|
990
|
+
|
|
991
|
+
def parse_trade(self, trade: dict, market: Market = None) -> Trade:
|
|
992
|
+
#
|
|
993
|
+
# fetchTradesV4
|
|
994
|
+
#
|
|
995
|
+
# {
|
|
996
|
+
# "tradeID": 158056419,
|
|
997
|
+
# "price": "9186.13",
|
|
998
|
+
# "quote_volume": "0.0021",
|
|
999
|
+
# "base_volume": "9186.13",
|
|
1000
|
+
# "trade_timestamp": 1594391747,
|
|
1001
|
+
# "type": "sell"
|
|
1002
|
+
# }
|
|
1003
|
+
#
|
|
1004
|
+
# orderTrades(v4Private)
|
|
1005
|
+
#
|
|
1006
|
+
# {
|
|
1007
|
+
# "time": 1593342324.613711,
|
|
1008
|
+
# "fee": "0.00000419198",
|
|
1009
|
+
# "price": "0.00000701",
|
|
1010
|
+
# "amount": "598",
|
|
1011
|
+
# "id": 149156519, # trade id
|
|
1012
|
+
# "dealOrderId": 3134995325, # orderId
|
|
1013
|
+
# "clientOrderId": "customId11",
|
|
1014
|
+
# "role": 2, # 1 = maker, 2 = taker
|
|
1015
|
+
# "deal": "0.00419198" # amount in money
|
|
1016
|
+
# }
|
|
1017
|
+
#
|
|
1018
|
+
# fetchMyTrades
|
|
1019
|
+
#
|
|
1020
|
+
# {
|
|
1021
|
+
# "id": 1343815269,
|
|
1022
|
+
# "clientOrderId": '',
|
|
1023
|
+
# "time": 1641051917.532965,
|
|
1024
|
+
# "side": "sell",
|
|
1025
|
+
# "role": 2,
|
|
1026
|
+
# "amount": "9.986",
|
|
1027
|
+
# "price": "0.9995",
|
|
1028
|
+
# "deal": "9.981007",
|
|
1029
|
+
# "fee": "0.009981007",
|
|
1030
|
+
# "orderId": 58166729555,
|
|
1031
|
+
# }
|
|
1032
|
+
#
|
|
1033
|
+
market = self.safe_market(None, market)
|
|
1034
|
+
timestamp = self.safe_timestamp_2(trade, 'time', 'trade_timestamp')
|
|
1035
|
+
orderId = self.safe_string_2(trade, 'dealOrderId', 'orderId')
|
|
1036
|
+
cost = self.safe_string(trade, 'deal')
|
|
1037
|
+
price = self.safe_string(trade, 'price')
|
|
1038
|
+
amount = self.safe_string_2(trade, 'amount', 'quote_volume')
|
|
1039
|
+
id = self.safe_string_2(trade, 'id', 'tradeID')
|
|
1040
|
+
side = self.safe_string_2(trade, 'type', 'side')
|
|
1041
|
+
symbol = market['symbol']
|
|
1042
|
+
role = self.safe_integer(trade, 'role')
|
|
1043
|
+
takerOrMaker: Str = None
|
|
1044
|
+
if role is not None:
|
|
1045
|
+
takerOrMaker = 'maker' if (role == 1) else 'taker'
|
|
1046
|
+
fee = None
|
|
1047
|
+
feeCost = self.safe_string(trade, 'fee')
|
|
1048
|
+
if feeCost is not None:
|
|
1049
|
+
fee = {
|
|
1050
|
+
'cost': feeCost,
|
|
1051
|
+
'currency': market['quote'],
|
|
1052
|
+
}
|
|
1053
|
+
return self.safe_trade({
|
|
1054
|
+
'info': trade,
|
|
1055
|
+
'timestamp': timestamp,
|
|
1056
|
+
'datetime': self.iso8601(timestamp),
|
|
1057
|
+
'symbol': symbol,
|
|
1058
|
+
'id': id,
|
|
1059
|
+
'order': orderId,
|
|
1060
|
+
'type': None,
|
|
1061
|
+
'takerOrMaker': takerOrMaker,
|
|
1062
|
+
'side': side,
|
|
1063
|
+
'price': price,
|
|
1064
|
+
'amount': amount,
|
|
1065
|
+
'cost': cost,
|
|
1066
|
+
'fee': fee,
|
|
1067
|
+
}, market)
|
|
1068
|
+
|
|
1069
|
+
def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
1070
|
+
"""
|
|
1071
|
+
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
1072
|
+
:see: https://docs.whitebit.com/public/http-v1/#kline
|
|
1073
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
1074
|
+
:param str timeframe: the length of time each candle represents
|
|
1075
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
1076
|
+
:param int [limit]: the maximum amount of candles to fetch
|
|
1077
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1078
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
1079
|
+
"""
|
|
1080
|
+
self.load_markets()
|
|
1081
|
+
market = self.market(symbol)
|
|
1082
|
+
request: dict = {
|
|
1083
|
+
'market': market['id'],
|
|
1084
|
+
'interval': self.safe_string(self.timeframes, timeframe, timeframe),
|
|
1085
|
+
}
|
|
1086
|
+
if since is not None:
|
|
1087
|
+
maxLimit = 1440
|
|
1088
|
+
if limit is None:
|
|
1089
|
+
limit = maxLimit
|
|
1090
|
+
limit = min(limit, maxLimit)
|
|
1091
|
+
start = self.parse_to_int(since / 1000)
|
|
1092
|
+
request['start'] = start
|
|
1093
|
+
if limit is not None:
|
|
1094
|
+
request['limit'] = min(limit, 1440)
|
|
1095
|
+
response = self.v1PublicGetKline(self.extend(request, params))
|
|
1096
|
+
#
|
|
1097
|
+
# {
|
|
1098
|
+
# "success":true,
|
|
1099
|
+
# "message":"",
|
|
1100
|
+
# "result":[
|
|
1101
|
+
# [1591488000,"0.025025","0.025025","0.025029","0.025023","6.181","0.154686629"],
|
|
1102
|
+
# [1591488060,"0.025028","0.025033","0.025035","0.025026","8.067","0.201921167"],
|
|
1103
|
+
# [1591488120,"0.025034","0.02505","0.02505","0.025034","20.089","0.503114696"],
|
|
1104
|
+
# ]
|
|
1105
|
+
# }
|
|
1106
|
+
#
|
|
1107
|
+
result = self.safe_list(response, 'result', [])
|
|
1108
|
+
return self.parse_ohlcvs(result, market, timeframe, since, limit)
|
|
1109
|
+
|
|
1110
|
+
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
|
1111
|
+
#
|
|
1112
|
+
# [
|
|
1113
|
+
# 1591488000,
|
|
1114
|
+
# "0.025025",
|
|
1115
|
+
# "0.025025",
|
|
1116
|
+
# "0.025029",
|
|
1117
|
+
# "0.025023",
|
|
1118
|
+
# "6.181",
|
|
1119
|
+
# "0.154686629"
|
|
1120
|
+
# ]
|
|
1121
|
+
#
|
|
1122
|
+
return [
|
|
1123
|
+
self.safe_timestamp(ohlcv, 0), # timestamp
|
|
1124
|
+
self.safe_number(ohlcv, 1), # open
|
|
1125
|
+
self.safe_number(ohlcv, 3), # high
|
|
1126
|
+
self.safe_number(ohlcv, 4), # low
|
|
1127
|
+
self.safe_number(ohlcv, 2), # close
|
|
1128
|
+
self.safe_number(ohlcv, 5), # volume
|
|
1129
|
+
]
|
|
1130
|
+
|
|
1131
|
+
def fetch_status(self, params={}):
|
|
1132
|
+
"""
|
|
1133
|
+
the latest known information on the availability of the exchange API
|
|
1134
|
+
:see: https://docs.whitebit.com/public/http-v4/#server-status
|
|
1135
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1136
|
+
:returns dict: a `status structure <https://docs.ccxt.com/#/?id=exchange-status-structure>`
|
|
1137
|
+
"""
|
|
1138
|
+
response = self.v4PublicGetPing(params)
|
|
1139
|
+
#
|
|
1140
|
+
# [
|
|
1141
|
+
# "pong"
|
|
1142
|
+
# ]
|
|
1143
|
+
#
|
|
1144
|
+
status = self.safe_string(response, 0)
|
|
1145
|
+
return {
|
|
1146
|
+
'status': 'ok' if (status == 'pong') else status,
|
|
1147
|
+
'updated': None,
|
|
1148
|
+
'eta': None,
|
|
1149
|
+
'url': None,
|
|
1150
|
+
'info': response,
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
def fetch_time(self, params={}):
|
|
1154
|
+
"""
|
|
1155
|
+
fetches the current integer timestamp in milliseconds from the exchange server
|
|
1156
|
+
:see: https://docs.whitebit.com/public/http-v4/#server-time
|
|
1157
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1158
|
+
:returns int: the current integer timestamp in milliseconds from the exchange server
|
|
1159
|
+
"""
|
|
1160
|
+
response = self.v4PublicGetTime(params)
|
|
1161
|
+
#
|
|
1162
|
+
# {
|
|
1163
|
+
# "time":1635467280514
|
|
1164
|
+
# }
|
|
1165
|
+
#
|
|
1166
|
+
return self.safe_integer(response, 'time')
|
|
1167
|
+
|
|
1168
|
+
def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
|
|
1169
|
+
"""
|
|
1170
|
+
create a market order by providing the symbol, side and cost
|
|
1171
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1172
|
+
:param str side: 'buy' or 'sell'
|
|
1173
|
+
:param float cost: how much you want to trade in units of the quote currency
|
|
1174
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1175
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1176
|
+
"""
|
|
1177
|
+
params['cost'] = cost
|
|
1178
|
+
# only buy side is supported
|
|
1179
|
+
return self.create_order(symbol, 'market', side, 0, None, params)
|
|
1180
|
+
|
|
1181
|
+
def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}) -> Order:
|
|
1182
|
+
"""
|
|
1183
|
+
create a market buy order by providing the symbol and cost
|
|
1184
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1185
|
+
:param float cost: how much you want to trade in units of the quote currency
|
|
1186
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1187
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1188
|
+
"""
|
|
1189
|
+
return self.create_market_order_with_cost(symbol, 'buy', cost, params)
|
|
1190
|
+
|
|
1191
|
+
def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
1192
|
+
"""
|
|
1193
|
+
create a trade order
|
|
1194
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#create-limit-order
|
|
1195
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#create-market-order
|
|
1196
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#create-buy-stock-market-order
|
|
1197
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#create-stop-limit-order
|
|
1198
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#create-stop-market-order
|
|
1199
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1200
|
+
:param str type: 'market' or 'limit'
|
|
1201
|
+
:param str side: 'buy' or 'sell'
|
|
1202
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
|
1203
|
+
:param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
1204
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1205
|
+
:param float [params.cost]: *market orders only* the cost of the order in units of the base currency
|
|
1206
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1207
|
+
"""
|
|
1208
|
+
self.load_markets()
|
|
1209
|
+
market = self.market(symbol)
|
|
1210
|
+
request: dict = {
|
|
1211
|
+
'market': market['id'],
|
|
1212
|
+
'side': side,
|
|
1213
|
+
}
|
|
1214
|
+
cost = None
|
|
1215
|
+
cost, params = self.handle_param_string(params, 'cost')
|
|
1216
|
+
if cost is not None:
|
|
1217
|
+
if (side != 'buy') or (type != 'market'):
|
|
1218
|
+
raise InvalidOrder(self.id + ' createOrder() cost is only supported for market buy orders')
|
|
1219
|
+
request['amount'] = self.cost_to_precision(symbol, cost)
|
|
1220
|
+
else:
|
|
1221
|
+
request['amount'] = self.amount_to_precision(symbol, amount)
|
|
1222
|
+
clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
|
|
1223
|
+
if clientOrderId is None:
|
|
1224
|
+
brokerId = self.safe_string(self.options, 'brokerId')
|
|
1225
|
+
if brokerId is not None:
|
|
1226
|
+
request['clientOrderId'] = brokerId + self.uuid16()
|
|
1227
|
+
else:
|
|
1228
|
+
request['clientOrderId'] = clientOrderId
|
|
1229
|
+
params = self.omit(params, ['clientOrderId'])
|
|
1230
|
+
marketType = self.safe_string(market, 'type')
|
|
1231
|
+
isLimitOrder = type == 'limit'
|
|
1232
|
+
isMarketOrder = type == 'market'
|
|
1233
|
+
stopPrice = self.safe_number_n(params, ['triggerPrice', 'stopPrice', 'activation_price'])
|
|
1234
|
+
isStopOrder = (stopPrice is not None)
|
|
1235
|
+
postOnly = self.is_post_only(isMarketOrder, False, params)
|
|
1236
|
+
marginMode, query = self.handle_margin_mode_and_params('createOrder', params)
|
|
1237
|
+
if postOnly:
|
|
1238
|
+
request['postOnly'] = True
|
|
1239
|
+
if marginMode is not None and marginMode != 'cross':
|
|
1240
|
+
raise NotSupported(self.id + ' createOrder() is only available for cross margin')
|
|
1241
|
+
params = self.omit(query, ['postOnly', 'triggerPrice', 'stopPrice'])
|
|
1242
|
+
useCollateralEndpoint = marginMode is not None or marketType == 'swap'
|
|
1243
|
+
response = None
|
|
1244
|
+
if isStopOrder:
|
|
1245
|
+
request['activation_price'] = self.price_to_precision(symbol, stopPrice)
|
|
1246
|
+
if isLimitOrder:
|
|
1247
|
+
# stop limit order
|
|
1248
|
+
request['price'] = self.price_to_precision(symbol, price)
|
|
1249
|
+
response = self.v4PrivatePostOrderStopLimit(self.extend(request, params))
|
|
1250
|
+
else:
|
|
1251
|
+
# stop market order
|
|
1252
|
+
if useCollateralEndpoint:
|
|
1253
|
+
response = self.v4PrivatePostOrderCollateralTriggerMarket(self.extend(request, params))
|
|
1254
|
+
else:
|
|
1255
|
+
response = self.v4PrivatePostOrderStopMarket(self.extend(request, params))
|
|
1256
|
+
else:
|
|
1257
|
+
if isLimitOrder:
|
|
1258
|
+
# limit order
|
|
1259
|
+
request['price'] = self.price_to_precision(symbol, price)
|
|
1260
|
+
if useCollateralEndpoint:
|
|
1261
|
+
response = self.v4PrivatePostOrderCollateralLimit(self.extend(request, params))
|
|
1262
|
+
else:
|
|
1263
|
+
response = self.v4PrivatePostOrderNew(self.extend(request, params))
|
|
1264
|
+
else:
|
|
1265
|
+
# market order
|
|
1266
|
+
if useCollateralEndpoint:
|
|
1267
|
+
response = self.v4PrivatePostOrderCollateralMarket(self.extend(request, params))
|
|
1268
|
+
else:
|
|
1269
|
+
if cost is not None:
|
|
1270
|
+
response = self.v4PrivatePostOrderMarket(self.extend(request, params))
|
|
1271
|
+
else:
|
|
1272
|
+
response = self.v4PrivatePostOrderStockMarket(self.extend(request, params))
|
|
1273
|
+
return self.parse_order(response)
|
|
1274
|
+
|
|
1275
|
+
def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
|
|
1276
|
+
"""
|
|
1277
|
+
edit a trade order
|
|
1278
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#modify-order
|
|
1279
|
+
:param str id: cancel order id
|
|
1280
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1281
|
+
:param str type: 'market' or 'limit'
|
|
1282
|
+
:param str side: 'buy' or 'sell'
|
|
1283
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
|
1284
|
+
:param float price: the price at which the order is to be fullfilled, in units of the base currency, ignored in market orders
|
|
1285
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1286
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1287
|
+
"""
|
|
1288
|
+
if id is None:
|
|
1289
|
+
raise ArgumentsRequired(self.id + ' editOrder() requires a id argument')
|
|
1290
|
+
if symbol is None:
|
|
1291
|
+
raise ArgumentsRequired(self.id + ' editOrder() requires a symbol argument')
|
|
1292
|
+
self.load_markets()
|
|
1293
|
+
market = self.market(symbol)
|
|
1294
|
+
request: dict = {
|
|
1295
|
+
'orderId': id,
|
|
1296
|
+
'market': market['id'],
|
|
1297
|
+
}
|
|
1298
|
+
clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
|
|
1299
|
+
if clientOrderId is not None:
|
|
1300
|
+
# Update clientOrderId of the order
|
|
1301
|
+
request['clientOrderId'] = clientOrderId
|
|
1302
|
+
isLimitOrder = type == 'limit'
|
|
1303
|
+
stopPrice = self.safe_number_n(params, ['triggerPrice', 'stopPrice', 'activation_price'])
|
|
1304
|
+
isStopOrder = (stopPrice is not None)
|
|
1305
|
+
params = self.omit(params, ['clOrdId', 'clientOrderId', 'triggerPrice', 'stopPrice'])
|
|
1306
|
+
if isStopOrder:
|
|
1307
|
+
request['activation_price'] = self.price_to_precision(symbol, stopPrice)
|
|
1308
|
+
if isLimitOrder:
|
|
1309
|
+
# stop limit order
|
|
1310
|
+
request['amount'] = self.amount_to_precision(symbol, amount)
|
|
1311
|
+
request['price'] = self.price_to_precision(symbol, price)
|
|
1312
|
+
else:
|
|
1313
|
+
# stop market order
|
|
1314
|
+
if side == 'buy':
|
|
1315
|
+
# Use total parameter instead of amount for modify buy stop market order
|
|
1316
|
+
request['total'] = self.amount_to_precision(symbol, amount)
|
|
1317
|
+
else:
|
|
1318
|
+
request['amount'] = self.amount_to_precision(symbol, amount)
|
|
1319
|
+
else:
|
|
1320
|
+
request['amount'] = self.amount_to_precision(symbol, amount)
|
|
1321
|
+
if isLimitOrder:
|
|
1322
|
+
# limit order
|
|
1323
|
+
request['price'] = self.price_to_precision(symbol, price)
|
|
1324
|
+
response = self.v4PrivatePostOrderModify(self.extend(request, params))
|
|
1325
|
+
return self.parse_order(response)
|
|
1326
|
+
|
|
1327
|
+
def cancel_order(self, id: str, symbol: Str = None, params={}):
|
|
1328
|
+
"""
|
|
1329
|
+
cancels an open order
|
|
1330
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#cancel-order
|
|
1331
|
+
:param str id: order id
|
|
1332
|
+
:param str symbol: unified symbol of the market the order was made in
|
|
1333
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1334
|
+
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1335
|
+
"""
|
|
1336
|
+
if symbol is None:
|
|
1337
|
+
raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
|
|
1338
|
+
self.load_markets()
|
|
1339
|
+
market = self.market(symbol)
|
|
1340
|
+
request: dict = {
|
|
1341
|
+
'market': market['id'],
|
|
1342
|
+
'orderId': int(id),
|
|
1343
|
+
}
|
|
1344
|
+
response = self.v4PrivatePostOrderCancel(self.extend(request, params))
|
|
1345
|
+
#
|
|
1346
|
+
# {
|
|
1347
|
+
# "orderId": 4180284841, # order id
|
|
1348
|
+
# "clientOrderId": "customId11", # custom order identifier; "clientOrderId": "" - if not specified.
|
|
1349
|
+
# "market": "BTC_USDT", # deal market
|
|
1350
|
+
# "side": "buy", # order side
|
|
1351
|
+
# "type": "stop market", # order type
|
|
1352
|
+
# "timestamp": 1595792396.165973, # current timestamp
|
|
1353
|
+
# "dealMoney": "0", # if order finished - amount in money currency that is finished
|
|
1354
|
+
# "dealStock": "0", # if order finished - amount in stock currency that is finished
|
|
1355
|
+
# "amount": "0.001", # amount
|
|
1356
|
+
# "takerFee": "0.001", # maker fee ratio. If the number less than 0.0001 - it will be rounded to zero
|
|
1357
|
+
# "makerFee": "0.001", # maker fee ratio. If the number less than 0.0001 - it will be rounded to zero
|
|
1358
|
+
# "left": "0.001", # if order not finished - rest of the amount that must be finished
|
|
1359
|
+
# "dealFee": "0", # fee in money that you pay if order is finished
|
|
1360
|
+
# "price": "40000", # price if price isset
|
|
1361
|
+
# "activation_price": "40000" # activation price if activation price is set
|
|
1362
|
+
# }
|
|
1363
|
+
#
|
|
1364
|
+
return self.parse_order(response)
|
|
1365
|
+
|
|
1366
|
+
def cancel_all_orders(self, symbol: Str = None, params={}):
|
|
1367
|
+
"""
|
|
1368
|
+
cancel all open orders
|
|
1369
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#cancel-all-orders
|
|
1370
|
+
:param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
|
|
1371
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1372
|
+
:param str [params.type]: market type, ['swap', 'spot']
|
|
1373
|
+
:param boolean [params.isMargin]: cancel all margin orders
|
|
1374
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1375
|
+
"""
|
|
1376
|
+
self.load_markets()
|
|
1377
|
+
market = None
|
|
1378
|
+
request: dict = {}
|
|
1379
|
+
if symbol is not None:
|
|
1380
|
+
market = self.market(symbol)
|
|
1381
|
+
request['market'] = market['id']
|
|
1382
|
+
type = None
|
|
1383
|
+
type, params = self.handle_market_type_and_params('cancelAllOrders', market, params)
|
|
1384
|
+
requestType = []
|
|
1385
|
+
if type == 'spot':
|
|
1386
|
+
isMargin = None
|
|
1387
|
+
isMargin, params = self.handle_option_and_params(params, 'cancelAllOrders', 'isMargin', False)
|
|
1388
|
+
if isMargin:
|
|
1389
|
+
requestType.append('margin')
|
|
1390
|
+
else:
|
|
1391
|
+
requestType.append('spot')
|
|
1392
|
+
elif type == 'swap':
|
|
1393
|
+
requestType.append('futures')
|
|
1394
|
+
else:
|
|
1395
|
+
raise NotSupported(self.id + ' cancelAllOrders() does not support ' + type + ' type')
|
|
1396
|
+
request['type'] = requestType
|
|
1397
|
+
response = self.v4PrivatePostOrderCancelAll(self.extend(request, params))
|
|
1398
|
+
#
|
|
1399
|
+
# []
|
|
1400
|
+
#
|
|
1401
|
+
return self.parse_orders(response, market)
|
|
1402
|
+
|
|
1403
|
+
def cancel_all_orders_after(self, timeout: Int, params={}):
|
|
1404
|
+
"""
|
|
1405
|
+
dead man's switch, cancel all orders after the given timeout
|
|
1406
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#sync-kill-switch-timer
|
|
1407
|
+
:param number timeout: time in milliseconds, 0 represents cancel the timer
|
|
1408
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1409
|
+
:param str [params.types]: Order types value. Example: "spot", "margin", "futures" or None
|
|
1410
|
+
:param str [params.symbol]: symbol unified symbol of the market the order was made in
|
|
1411
|
+
:returns dict: the api result
|
|
1412
|
+
"""
|
|
1413
|
+
self.load_markets()
|
|
1414
|
+
symbol = self.safe_string(params, 'symbol')
|
|
1415
|
+
if symbol is None:
|
|
1416
|
+
raise ArgumentsRequired(self.id + ' cancelAllOrdersAfter() requires a symbol argument in params')
|
|
1417
|
+
market = self.market(symbol)
|
|
1418
|
+
params = self.omit(params, 'symbol')
|
|
1419
|
+
isBiggerThanZero = (timeout > 0)
|
|
1420
|
+
request: dict = {
|
|
1421
|
+
'market': market['id'],
|
|
1422
|
+
# 'timeout': self.number_to_string(timeout / 1000) if (timeout > 0) else null,
|
|
1423
|
+
}
|
|
1424
|
+
if isBiggerThanZero:
|
|
1425
|
+
request['timeout'] = self.number_to_string(timeout / 1000)
|
|
1426
|
+
else:
|
|
1427
|
+
request['timeout'] = 'null'
|
|
1428
|
+
response = self.v4PrivatePostOrderKillSwitch(self.extend(request, params))
|
|
1429
|
+
#
|
|
1430
|
+
# {
|
|
1431
|
+
# "market": "BTC_USDT", # currency market,
|
|
1432
|
+
# "startTime": 1662478154, # now timestamp,
|
|
1433
|
+
# "cancellationTime": 1662478154, # now + timer_value,
|
|
1434
|
+
# "types": ["spot", "margin"]
|
|
1435
|
+
# }
|
|
1436
|
+
#
|
|
1437
|
+
return response
|
|
1438
|
+
|
|
1439
|
+
def parse_balance(self, response) -> Balances:
|
|
1440
|
+
balanceKeys = list(response.keys())
|
|
1441
|
+
result: dict = {}
|
|
1442
|
+
for i in range(0, len(balanceKeys)):
|
|
1443
|
+
id = balanceKeys[i]
|
|
1444
|
+
code = self.safe_currency_code(id)
|
|
1445
|
+
balance = response[id]
|
|
1446
|
+
if isinstance(balance, dict) and balance is not None:
|
|
1447
|
+
account = self.account()
|
|
1448
|
+
account['free'] = self.safe_string_2(balance, 'available', 'main_balance')
|
|
1449
|
+
account['used'] = self.safe_string(balance, 'freeze')
|
|
1450
|
+
account['total'] = self.safe_string(balance, 'main_balance')
|
|
1451
|
+
result[code] = account
|
|
1452
|
+
else:
|
|
1453
|
+
account = self.account()
|
|
1454
|
+
account['total'] = balance
|
|
1455
|
+
result[code] = account
|
|
1456
|
+
return self.safe_balance(result)
|
|
1457
|
+
|
|
1458
|
+
def fetch_balance(self, params={}) -> Balances:
|
|
1459
|
+
"""
|
|
1460
|
+
query for balance and get the amount of funds available for trading or funds locked in orders
|
|
1461
|
+
:see: https://docs.whitebit.com/private/http-main-v4/#main-balance
|
|
1462
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#trading-balance
|
|
1463
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1464
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
|
1465
|
+
"""
|
|
1466
|
+
self.load_markets()
|
|
1467
|
+
marketType = None
|
|
1468
|
+
marketType, params = self.handle_market_type_and_params('fetchBalance', None, params)
|
|
1469
|
+
response = None
|
|
1470
|
+
if marketType == 'swap':
|
|
1471
|
+
response = self.v4PrivatePostCollateralAccountBalance(params)
|
|
1472
|
+
else:
|
|
1473
|
+
options = self.safe_value(self.options, 'fetchBalance', {})
|
|
1474
|
+
defaultAccount = self.safe_string(options, 'account')
|
|
1475
|
+
account = self.safe_string_2(params, 'account', 'type', defaultAccount)
|
|
1476
|
+
params = self.omit(params, ['account', 'type'])
|
|
1477
|
+
if account == 'main' or account == 'funding':
|
|
1478
|
+
response = self.v4PrivatePostMainAccountBalance(params)
|
|
1479
|
+
else:
|
|
1480
|
+
response = self.v4PrivatePostTradeAccountBalance(params)
|
|
1481
|
+
#
|
|
1482
|
+
# main account
|
|
1483
|
+
#
|
|
1484
|
+
# {
|
|
1485
|
+
# "BTC":{"main_balance":"0.0013929494020316"},
|
|
1486
|
+
# "ETH":{"main_balance":"0.001398289308"},
|
|
1487
|
+
# }
|
|
1488
|
+
#
|
|
1489
|
+
# spot trade account
|
|
1490
|
+
#
|
|
1491
|
+
# {
|
|
1492
|
+
# "BTC": {"available": "0.123", "freeze": "1"},
|
|
1493
|
+
# "XMR": {"available": "3013", "freeze": "100"},
|
|
1494
|
+
# }
|
|
1495
|
+
#
|
|
1496
|
+
# swap
|
|
1497
|
+
#
|
|
1498
|
+
# {
|
|
1499
|
+
# "BTC": 1,
|
|
1500
|
+
# "USDT": 1000
|
|
1501
|
+
# }
|
|
1502
|
+
#
|
|
1503
|
+
return self.parse_balance(response)
|
|
1504
|
+
|
|
1505
|
+
def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1506
|
+
"""
|
|
1507
|
+
fetch all unfilled currently open orders
|
|
1508
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#query-unexecutedactive-orders
|
|
1509
|
+
:param str symbol: unified market symbol
|
|
1510
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
|
1511
|
+
:param int [limit]: the maximum number of open order structures to retrieve
|
|
1512
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1513
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1514
|
+
"""
|
|
1515
|
+
if symbol is None:
|
|
1516
|
+
raise ArgumentsRequired(self.id + ' fetchOpenOrders() requires a symbol argument')
|
|
1517
|
+
self.load_markets()
|
|
1518
|
+
market = self.market(symbol)
|
|
1519
|
+
request: dict = {
|
|
1520
|
+
'market': market['id'],
|
|
1521
|
+
}
|
|
1522
|
+
if limit is not None:
|
|
1523
|
+
request['limit'] = min(limit, 100)
|
|
1524
|
+
response = self.v4PrivatePostOrders(self.extend(request, params))
|
|
1525
|
+
#
|
|
1526
|
+
# [
|
|
1527
|
+
# {
|
|
1528
|
+
# "orderId": 3686033640,
|
|
1529
|
+
# "clientOrderId": "customId11",
|
|
1530
|
+
# "market": "BTC_USDT",
|
|
1531
|
+
# "side": "buy",
|
|
1532
|
+
# "type": "limit",
|
|
1533
|
+
# "timestamp": 1594605801.49815, # current timestamp of unexecuted order
|
|
1534
|
+
# "dealMoney": "0", # executed amount in money
|
|
1535
|
+
# "dealStock": "0", # executed amount in stock
|
|
1536
|
+
# "amount": "2.241379", # active order amount
|
|
1537
|
+
# "takerFee": "0.001",
|
|
1538
|
+
# "makerFee": "0.001",
|
|
1539
|
+
# "left": "2.241379", # unexecuted amount in stock
|
|
1540
|
+
# "dealFee": "0", # executed fee by deal
|
|
1541
|
+
# "price": "40000"
|
|
1542
|
+
# },
|
|
1543
|
+
# ]
|
|
1544
|
+
#
|
|
1545
|
+
return self.parse_orders(response, market, since, limit, {'status': 'open'})
|
|
1546
|
+
|
|
1547
|
+
def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1548
|
+
"""
|
|
1549
|
+
fetches information on multiple closed orders made by the user
|
|
1550
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#query-executed-orders
|
|
1551
|
+
:param str symbol: unified market symbol of the market orders were made in
|
|
1552
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
|
1553
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
|
1554
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1555
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1556
|
+
"""
|
|
1557
|
+
self.load_markets()
|
|
1558
|
+
request: dict = {}
|
|
1559
|
+
market = None
|
|
1560
|
+
if symbol is not None:
|
|
1561
|
+
market = self.market(symbol)
|
|
1562
|
+
symbol = market['symbol']
|
|
1563
|
+
request['market'] = market['id']
|
|
1564
|
+
if limit is not None:
|
|
1565
|
+
request['limit'] = min(limit, 100) # default 50 max 100
|
|
1566
|
+
response = self.v4PrivatePostTradeAccountOrderHistory(self.extend(request, params))
|
|
1567
|
+
#
|
|
1568
|
+
# {
|
|
1569
|
+
# "BTC_USDT": [
|
|
1570
|
+
# {
|
|
1571
|
+
# "id": 160305483,
|
|
1572
|
+
# "clientOrderId": "customId11",
|
|
1573
|
+
# "time": 1594667731.724403,
|
|
1574
|
+
# "side": "sell",
|
|
1575
|
+
# "role": 2, # 1 = maker, 2 = taker
|
|
1576
|
+
# "amount": "0.000076",
|
|
1577
|
+
# "price": "9264.21",
|
|
1578
|
+
# "deal": "0.70407996",
|
|
1579
|
+
# "fee": "0.00070407996"
|
|
1580
|
+
# },
|
|
1581
|
+
# ],
|
|
1582
|
+
# }
|
|
1583
|
+
#
|
|
1584
|
+
marketIds = list(response.keys())
|
|
1585
|
+
results = []
|
|
1586
|
+
for i in range(0, len(marketIds)):
|
|
1587
|
+
marketId = marketIds[i]
|
|
1588
|
+
marketNew = self.safe_market(marketId, None, '_')
|
|
1589
|
+
orders = response[marketId]
|
|
1590
|
+
for j in range(0, len(orders)):
|
|
1591
|
+
order = self.parse_order(orders[j], marketNew)
|
|
1592
|
+
results.append(self.extend(order, {'status': 'closed'}))
|
|
1593
|
+
results = self.sort_by(results, 'timestamp')
|
|
1594
|
+
results = self.filter_by_symbol_since_limit(results, symbol, since, limit)
|
|
1595
|
+
return results
|
|
1596
|
+
|
|
1597
|
+
def parse_order_type(self, type: Str):
|
|
1598
|
+
types: dict = {
|
|
1599
|
+
'limit': 'limit',
|
|
1600
|
+
'market': 'market',
|
|
1601
|
+
'stop market': 'market',
|
|
1602
|
+
'stop limit': 'limit',
|
|
1603
|
+
'stock market': 'market',
|
|
1604
|
+
'margin limit': 'limit',
|
|
1605
|
+
'margin market': 'market',
|
|
1606
|
+
}
|
|
1607
|
+
return self.safe_string(types, type, type)
|
|
1608
|
+
|
|
1609
|
+
def parse_order(self, order: dict, market: Market = None) -> Order:
|
|
1610
|
+
#
|
|
1611
|
+
# createOrder, fetchOpenOrders, cancelOrder
|
|
1612
|
+
#
|
|
1613
|
+
# {
|
|
1614
|
+
# "orderId":105687928629,
|
|
1615
|
+
# "clientOrderId":"",
|
|
1616
|
+
# "market":"DOGE_USDT",
|
|
1617
|
+
# "side":"sell",
|
|
1618
|
+
# "type":"stop market",
|
|
1619
|
+
# "timestamp":1659091079.729576,
|
|
1620
|
+
# "dealMoney":"0", # executed amount in quote
|
|
1621
|
+
# "dealStock":"0", # base filled amount
|
|
1622
|
+
# "amount":"100",
|
|
1623
|
+
# "takerFee":"0.001",
|
|
1624
|
+
# "makerFee":"0",
|
|
1625
|
+
# "left":"100",
|
|
1626
|
+
# "price": "40000", # price if price isset
|
|
1627
|
+
# "dealFee":"0",
|
|
1628
|
+
# "activation_price":"0.065" # stop price(if stop limit or stop market)
|
|
1629
|
+
# }
|
|
1630
|
+
#
|
|
1631
|
+
# fetchClosedOrders
|
|
1632
|
+
#
|
|
1633
|
+
# {
|
|
1634
|
+
# "id":105531094719,
|
|
1635
|
+
# "clientOrderId":"",
|
|
1636
|
+
# "ctime":1659045334.550127,
|
|
1637
|
+
# "ftime":1659045334.550127,
|
|
1638
|
+
# "side":"buy",
|
|
1639
|
+
# "amount":"5.9940059", # cost in terms of quote for regular market orders, amount in terms or base for all other order types
|
|
1640
|
+
# "price":"0",
|
|
1641
|
+
# "type":"market",
|
|
1642
|
+
# "takerFee":"0.001",
|
|
1643
|
+
# "makerFee":"0",
|
|
1644
|
+
# "dealFee":"0.0059375815",
|
|
1645
|
+
# "dealStock":"85", # base filled amount
|
|
1646
|
+
# "dealMoney":"5.9375815", # executed amount in quote
|
|
1647
|
+
# }
|
|
1648
|
+
#
|
|
1649
|
+
marketId = self.safe_string(order, 'market')
|
|
1650
|
+
market = self.safe_market(marketId, market, '_')
|
|
1651
|
+
symbol = market['symbol']
|
|
1652
|
+
side = self.safe_string(order, 'side')
|
|
1653
|
+
filled = self.safe_string(order, 'dealStock')
|
|
1654
|
+
remaining = self.safe_string(order, 'left')
|
|
1655
|
+
clientOrderId = self.safe_string(order, 'clientOrderId')
|
|
1656
|
+
if clientOrderId == '':
|
|
1657
|
+
clientOrderId = None
|
|
1658
|
+
price = self.safe_string(order, 'price')
|
|
1659
|
+
stopPrice = self.safe_number(order, 'activation_price')
|
|
1660
|
+
orderId = self.safe_string_2(order, 'orderId', 'id')
|
|
1661
|
+
type = self.safe_string(order, 'type')
|
|
1662
|
+
orderType = self.parse_order_type(type)
|
|
1663
|
+
if orderType == 'market':
|
|
1664
|
+
remaining = None
|
|
1665
|
+
amount = self.safe_string(order, 'amount')
|
|
1666
|
+
cost = self.safe_string(order, 'dealMoney')
|
|
1667
|
+
if (side == 'buy') and ((type == 'market') or (type == 'stop market')):
|
|
1668
|
+
amount = filled
|
|
1669
|
+
dealFee = self.safe_string(order, 'dealFee')
|
|
1670
|
+
fee = None
|
|
1671
|
+
if dealFee is not None:
|
|
1672
|
+
fee = {
|
|
1673
|
+
'cost': self.parse_number(dealFee),
|
|
1674
|
+
'currency': market['quote'],
|
|
1675
|
+
}
|
|
1676
|
+
timestamp = self.safe_timestamp_2(order, 'ctime', 'timestamp')
|
|
1677
|
+
lastTradeTimestamp = self.safe_timestamp(order, 'ftime')
|
|
1678
|
+
return self.safe_order({
|
|
1679
|
+
'info': order,
|
|
1680
|
+
'id': orderId,
|
|
1681
|
+
'symbol': symbol,
|
|
1682
|
+
'clientOrderId': clientOrderId,
|
|
1683
|
+
'timestamp': timestamp,
|
|
1684
|
+
'datetime': self.iso8601(timestamp),
|
|
1685
|
+
'lastTradeTimestamp': lastTradeTimestamp,
|
|
1686
|
+
'timeInForce': None,
|
|
1687
|
+
'postOnly': None,
|
|
1688
|
+
'status': None,
|
|
1689
|
+
'side': side,
|
|
1690
|
+
'price': price,
|
|
1691
|
+
'type': orderType,
|
|
1692
|
+
'stopPrice': stopPrice,
|
|
1693
|
+
'triggerPrice': stopPrice,
|
|
1694
|
+
'amount': amount,
|
|
1695
|
+
'filled': filled,
|
|
1696
|
+
'remaining': remaining,
|
|
1697
|
+
'average': None,
|
|
1698
|
+
'cost': cost,
|
|
1699
|
+
'fee': fee,
|
|
1700
|
+
'trades': None,
|
|
1701
|
+
}, market)
|
|
1702
|
+
|
|
1703
|
+
def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1704
|
+
"""
|
|
1705
|
+
fetch all the trades made from a single order
|
|
1706
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#query-executed-order-deals
|
|
1707
|
+
:param str id: order id
|
|
1708
|
+
:param str symbol: unified market symbol
|
|
1709
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
|
1710
|
+
:param int [limit]: the maximum number of trades to retrieve
|
|
1711
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1712
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
1713
|
+
"""
|
|
1714
|
+
self.load_markets()
|
|
1715
|
+
request: dict = {
|
|
1716
|
+
'orderId': int(id),
|
|
1717
|
+
}
|
|
1718
|
+
market = None
|
|
1719
|
+
if symbol is not None:
|
|
1720
|
+
market = self.market(symbol)
|
|
1721
|
+
request['market'] = market['id']
|
|
1722
|
+
if limit is not None:
|
|
1723
|
+
request['limit'] = min(limit, 100)
|
|
1724
|
+
response = self.v4PrivatePostTradeAccountOrder(self.extend(request, params))
|
|
1725
|
+
#
|
|
1726
|
+
# {
|
|
1727
|
+
# "records": [
|
|
1728
|
+
# {
|
|
1729
|
+
# "time": 1593342324.613711,
|
|
1730
|
+
# "fee": "0.00000419198",
|
|
1731
|
+
# "price": "0.00000701",
|
|
1732
|
+
# "amount": "598",
|
|
1733
|
+
# "id": 149156519, # trade id
|
|
1734
|
+
# "dealOrderId": 3134995325, # orderId
|
|
1735
|
+
# "clientOrderId": "customId11", # empty string if not specified
|
|
1736
|
+
# "role": 2, # 1 = maker, 2 = taker
|
|
1737
|
+
# "deal": "0.00419198"
|
|
1738
|
+
# }
|
|
1739
|
+
# ],
|
|
1740
|
+
# "offset": 0,
|
|
1741
|
+
# "limit": 100
|
|
1742
|
+
# }
|
|
1743
|
+
#
|
|
1744
|
+
data = self.safe_list(response, 'records', [])
|
|
1745
|
+
return self.parse_trades(data, market)
|
|
1746
|
+
|
|
1747
|
+
def fetch_deposit_address(self, code: str, params={}):
|
|
1748
|
+
"""
|
|
1749
|
+
fetch the deposit address for a currency associated with self account
|
|
1750
|
+
:see: https://docs.whitebit.com/private/http-main-v4/#get-fiat-deposit-address
|
|
1751
|
+
:see: https://docs.whitebit.com/private/http-main-v4/#get-cryptocurrency-deposit-address
|
|
1752
|
+
:param str code: unified currency code
|
|
1753
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1754
|
+
:returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
|
|
1755
|
+
"""
|
|
1756
|
+
self.load_markets()
|
|
1757
|
+
currency = self.currency(code)
|
|
1758
|
+
request: dict = {
|
|
1759
|
+
'ticker': currency['id'],
|
|
1760
|
+
}
|
|
1761
|
+
response = None
|
|
1762
|
+
if self.is_fiat(code):
|
|
1763
|
+
provider = self.safe_string(params, 'provider')
|
|
1764
|
+
if provider is None:
|
|
1765
|
+
raise ArgumentsRequired(self.id + ' fetchDepositAddress() requires a provider when the ticker is fiat')
|
|
1766
|
+
request['provider'] = provider
|
|
1767
|
+
amount = self.safe_number(params, 'amount')
|
|
1768
|
+
if amount is None:
|
|
1769
|
+
raise ArgumentsRequired(self.id + ' fetchDepositAddress() requires an amount when the ticker is fiat')
|
|
1770
|
+
request['amount'] = amount
|
|
1771
|
+
uniqueId = self.safe_value(params, 'uniqueId')
|
|
1772
|
+
if uniqueId is None:
|
|
1773
|
+
raise ArgumentsRequired(self.id + ' fetchDepositAddress() requires an uniqueId when the ticker is fiat')
|
|
1774
|
+
response = self.v4PrivatePostMainAccountFiatDepositUrl(self.extend(request, params))
|
|
1775
|
+
else:
|
|
1776
|
+
response = self.v4PrivatePostMainAccountAddress(self.extend(request, params))
|
|
1777
|
+
#
|
|
1778
|
+
# fiat
|
|
1779
|
+
#
|
|
1780
|
+
# {
|
|
1781
|
+
# "url": "https://someaddress.com"
|
|
1782
|
+
# }
|
|
1783
|
+
#
|
|
1784
|
+
# crypto
|
|
1785
|
+
#
|
|
1786
|
+
# {
|
|
1787
|
+
# "account": {
|
|
1788
|
+
# "address": "GDTSOI56XNVAKJNJBLJGRNZIVOCIZJRBIDKTWSCYEYNFAZEMBLN75RMN",
|
|
1789
|
+
# "memo": "48565488244493"
|
|
1790
|
+
# },
|
|
1791
|
+
# "required": {
|
|
1792
|
+
# "fixedFee": "0",
|
|
1793
|
+
# "flexFee": {
|
|
1794
|
+
# "maxFee": "0",
|
|
1795
|
+
# "minFee": "0",
|
|
1796
|
+
# "percent": "0"
|
|
1797
|
+
# },
|
|
1798
|
+
# "maxAmount": "0",
|
|
1799
|
+
# "minAmount": "1"
|
|
1800
|
+
# }
|
|
1801
|
+
# }
|
|
1802
|
+
#
|
|
1803
|
+
url = self.safe_string(response, 'url')
|
|
1804
|
+
account = self.safe_value(response, 'account', {})
|
|
1805
|
+
address = self.safe_string(account, 'address', url)
|
|
1806
|
+
tag = self.safe_string(account, 'memo')
|
|
1807
|
+
self.check_address(address)
|
|
1808
|
+
return {
|
|
1809
|
+
'currency': code,
|
|
1810
|
+
'address': address,
|
|
1811
|
+
'tag': tag,
|
|
1812
|
+
'network': None,
|
|
1813
|
+
'info': response,
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
|
|
1817
|
+
"""
|
|
1818
|
+
set the level of leverage for a market
|
|
1819
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#change-collateral-account-leverage
|
|
1820
|
+
:param float leverage: the rate of leverage
|
|
1821
|
+
:param str symbol: unified market symbol
|
|
1822
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1823
|
+
:returns dict: response from the exchange
|
|
1824
|
+
"""
|
|
1825
|
+
self.load_markets()
|
|
1826
|
+
if symbol is not None:
|
|
1827
|
+
raise NotSupported(self.id + ' setLeverage() does not allow to set per symbol')
|
|
1828
|
+
if (leverage < 1) or (leverage > 20):
|
|
1829
|
+
raise BadRequest(self.id + ' setLeverage() leverage should be between 1 and 20')
|
|
1830
|
+
request: dict = {
|
|
1831
|
+
'leverage': leverage,
|
|
1832
|
+
}
|
|
1833
|
+
return self.v4PrivatePostCollateralAccountLeverage(self.extend(request, params))
|
|
1834
|
+
# {
|
|
1835
|
+
# "leverage": 5
|
|
1836
|
+
# }
|
|
1837
|
+
|
|
1838
|
+
def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
|
1839
|
+
"""
|
|
1840
|
+
transfer currency internally between wallets on the same account
|
|
1841
|
+
:see: https://docs.whitebit.com/private/http-main-v4/#transfer-between-main-and-trade-balances
|
|
1842
|
+
:param str code: unified currency code
|
|
1843
|
+
:param float amount: amount to transfer
|
|
1844
|
+
:param str fromAccount: account to transfer from - main, spot, collateral
|
|
1845
|
+
:param str toAccount: account to transfer to - main, spot, collateral
|
|
1846
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1847
|
+
:returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
|
1848
|
+
"""
|
|
1849
|
+
self.load_markets()
|
|
1850
|
+
currency = self.currency(code)
|
|
1851
|
+
accountsByType = self.safe_value(self.options, 'accountsByType')
|
|
1852
|
+
fromAccountId = self.safe_string(accountsByType, fromAccount, fromAccount)
|
|
1853
|
+
toAccountId = self.safe_string(accountsByType, toAccount, toAccount)
|
|
1854
|
+
amountString = self.currency_to_precision(code, amount)
|
|
1855
|
+
request: dict = {
|
|
1856
|
+
'ticker': currency['id'],
|
|
1857
|
+
'amount': amountString,
|
|
1858
|
+
'from': fromAccountId,
|
|
1859
|
+
'to': toAccountId,
|
|
1860
|
+
}
|
|
1861
|
+
response = self.v4PrivatePostMainAccountTransfer(self.extend(request, params))
|
|
1862
|
+
#
|
|
1863
|
+
# []
|
|
1864
|
+
#
|
|
1865
|
+
return self.parse_transfer(response, currency)
|
|
1866
|
+
|
|
1867
|
+
def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
|
|
1868
|
+
#
|
|
1869
|
+
# []
|
|
1870
|
+
#
|
|
1871
|
+
return {
|
|
1872
|
+
'info': transfer,
|
|
1873
|
+
'id': None,
|
|
1874
|
+
'timestamp': None,
|
|
1875
|
+
'datetime': None,
|
|
1876
|
+
'currency': self.safe_currency_code(None, currency),
|
|
1877
|
+
'amount': None,
|
|
1878
|
+
'fromAccount': None,
|
|
1879
|
+
'toAccount': None,
|
|
1880
|
+
'status': None,
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
|
|
1884
|
+
"""
|
|
1885
|
+
make a withdrawal
|
|
1886
|
+
:see: https://docs.whitebit.com/private/http-main-v4/#create-withdraw-request
|
|
1887
|
+
:param str code: unified currency code
|
|
1888
|
+
:param float amount: the amount to withdraw
|
|
1889
|
+
:param str address: the address to withdraw to
|
|
1890
|
+
:param str tag:
|
|
1891
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1892
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
1893
|
+
"""
|
|
1894
|
+
self.load_markets()
|
|
1895
|
+
currency = self.currency(code) # check if it has canDeposit
|
|
1896
|
+
request: dict = {
|
|
1897
|
+
'ticker': currency['id'],
|
|
1898
|
+
'amount': self.currency_to_precision(code, amount),
|
|
1899
|
+
'address': address,
|
|
1900
|
+
}
|
|
1901
|
+
uniqueId = self.safe_value(params, 'uniqueId')
|
|
1902
|
+
if uniqueId is None:
|
|
1903
|
+
uniqueId = self.uuid22()
|
|
1904
|
+
request['uniqueId'] = uniqueId
|
|
1905
|
+
if tag is not None:
|
|
1906
|
+
request['memo'] = tag
|
|
1907
|
+
if self.is_fiat(code):
|
|
1908
|
+
provider = self.safe_value(params, 'provider')
|
|
1909
|
+
if provider is None:
|
|
1910
|
+
raise ArgumentsRequired(self.id + ' withdraw() requires a provider when the ticker is fiat')
|
|
1911
|
+
request['provider'] = provider
|
|
1912
|
+
response = self.v4PrivatePostMainAccountWithdraw(self.extend(request, params))
|
|
1913
|
+
#
|
|
1914
|
+
# empty array with a success status
|
|
1915
|
+
# go to deposit/withdraw history and check you request status by uniqueId
|
|
1916
|
+
#
|
|
1917
|
+
# []
|
|
1918
|
+
#
|
|
1919
|
+
return self.extend({'id': uniqueId}, self.parse_transaction(response, currency))
|
|
1920
|
+
|
|
1921
|
+
def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
|
|
1922
|
+
#
|
|
1923
|
+
# {
|
|
1924
|
+
# "address": "3ApEASLcrQtZpg1TsssFgYF5V5YQJAKvuE", # deposit address
|
|
1925
|
+
# "uniqueId": null, # unique Id of deposit
|
|
1926
|
+
# "transactionId": "a6d71d69-2b17-4ad8-8b15-2d686c54a1a5",
|
|
1927
|
+
# "createdAt": 1593437922, # timestamp of deposit
|
|
1928
|
+
# "currency": "Bitcoin", # deposit currency
|
|
1929
|
+
# "ticker": "BTC", # deposit currency ticker
|
|
1930
|
+
# "method": 1, # called method 1 - deposit, 2 - withdraw
|
|
1931
|
+
# "amount": "0.0006", # amount of deposit
|
|
1932
|
+
# "description": "", # deposit description
|
|
1933
|
+
# "memo": "", # deposit memo
|
|
1934
|
+
# "fee": "0", # deposit fee
|
|
1935
|
+
# "status": 15, # transactions status
|
|
1936
|
+
# "network": null, # if currency is multinetwork
|
|
1937
|
+
# "transactionHash": "a275a514013e4e0f927fd0d1bed215e7f6f2c4c6ce762836fe135ec22529d886", # deposit transaction hash
|
|
1938
|
+
# "details": {
|
|
1939
|
+
# "partial": { # details about partially successful withdrawals
|
|
1940
|
+
# "requestAmount": "50000", # requested withdrawal amount
|
|
1941
|
+
# "processedAmount": "39000", # processed withdrawal amount
|
|
1942
|
+
# "processedFee": "273", # fee for processed withdrawal amount
|
|
1943
|
+
# "normalizeTransaction": "" # deposit id
|
|
1944
|
+
# }
|
|
1945
|
+
# },
|
|
1946
|
+
# "confirmations": { # if transaction status == 15 you can see self object
|
|
1947
|
+
# "actual": 1, # current block confirmations
|
|
1948
|
+
# "required": 2 # required block confirmation for successful deposit
|
|
1949
|
+
# }
|
|
1950
|
+
# "centralized": False,
|
|
1951
|
+
# }
|
|
1952
|
+
#
|
|
1953
|
+
currency = self.safe_currency(None, currency)
|
|
1954
|
+
address = self.safe_string(transaction, 'address')
|
|
1955
|
+
timestamp = self.safe_timestamp(transaction, 'createdAt')
|
|
1956
|
+
currencyId = self.safe_string(transaction, 'ticker')
|
|
1957
|
+
status = self.safe_string(transaction, 'status')
|
|
1958
|
+
method = self.safe_string(transaction, 'method')
|
|
1959
|
+
return {
|
|
1960
|
+
'id': self.safe_string(transaction, 'uniqueId'),
|
|
1961
|
+
'txid': self.safe_string(transaction, 'transactionId'),
|
|
1962
|
+
'timestamp': timestamp,
|
|
1963
|
+
'datetime': self.iso8601(timestamp),
|
|
1964
|
+
'network': self.safe_string(transaction, 'network'),
|
|
1965
|
+
'addressFrom': address if (method == '1') else None,
|
|
1966
|
+
'address': address,
|
|
1967
|
+
'addressTo': address if (method == '2') else None,
|
|
1968
|
+
'amount': self.safe_number(transaction, 'amount'),
|
|
1969
|
+
'type': 'deposit' if (method == '1') else 'withdrawal',
|
|
1970
|
+
'currency': self.safe_currency_code(currencyId, currency),
|
|
1971
|
+
'status': self.parse_transaction_status(status),
|
|
1972
|
+
'updated': None,
|
|
1973
|
+
'tagFrom': None,
|
|
1974
|
+
'tag': None,
|
|
1975
|
+
'tagTo': None,
|
|
1976
|
+
'comment': self.safe_string(transaction, 'description'),
|
|
1977
|
+
'internal': None,
|
|
1978
|
+
'fee': {
|
|
1979
|
+
'cost': self.safe_number(transaction, 'fee'),
|
|
1980
|
+
'currency': self.safe_currency_code(currencyId, currency),
|
|
1981
|
+
},
|
|
1982
|
+
'info': transaction,
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
def parse_transaction_status(self, status: Str):
|
|
1986
|
+
statuses: dict = {
|
|
1987
|
+
'1': 'pending',
|
|
1988
|
+
'2': 'pending',
|
|
1989
|
+
'3': 'ok',
|
|
1990
|
+
'4': 'canceled',
|
|
1991
|
+
'5': 'pending',
|
|
1992
|
+
'6': 'pending',
|
|
1993
|
+
'7': 'ok',
|
|
1994
|
+
'9': 'canceled',
|
|
1995
|
+
'10': 'pending',
|
|
1996
|
+
'11': 'pending',
|
|
1997
|
+
'12': 'pending',
|
|
1998
|
+
'13': 'pending',
|
|
1999
|
+
'14': 'pending',
|
|
2000
|
+
'15': 'pending',
|
|
2001
|
+
'16': 'pending',
|
|
2002
|
+
'17': 'pending',
|
|
2003
|
+
}
|
|
2004
|
+
return self.safe_string(statuses, status, status)
|
|
2005
|
+
|
|
2006
|
+
def fetch_deposit(self, id: str, code: Str = None, params={}):
|
|
2007
|
+
"""
|
|
2008
|
+
fetch information on a deposit
|
|
2009
|
+
:see: https://docs.whitebit.com/private/http-main-v4/#get-depositwithdraw-history
|
|
2010
|
+
:param str id: deposit id
|
|
2011
|
+
:param str code: not used by whitebit fetchDeposit()
|
|
2012
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2013
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2014
|
+
"""
|
|
2015
|
+
self.load_markets()
|
|
2016
|
+
currency = None
|
|
2017
|
+
request: dict = {
|
|
2018
|
+
'transactionMethod': 1,
|
|
2019
|
+
'uniqueId': id,
|
|
2020
|
+
'limit': 1,
|
|
2021
|
+
'offset': 0,
|
|
2022
|
+
}
|
|
2023
|
+
if code is not None:
|
|
2024
|
+
currency = self.currency(code)
|
|
2025
|
+
request['ticker'] = currency['id']
|
|
2026
|
+
response = self.v4PrivatePostMainAccountHistory(self.extend(request, params))
|
|
2027
|
+
#
|
|
2028
|
+
# {
|
|
2029
|
+
# "limit": 100,
|
|
2030
|
+
# "offset": 0,
|
|
2031
|
+
# "records": [
|
|
2032
|
+
# {
|
|
2033
|
+
# "address": "3ApEASLcrQtZpg1TsssFgYF5V5YQJAKvuE", # deposit address
|
|
2034
|
+
# "uniqueId": null, # unique Id of deposit
|
|
2035
|
+
# "createdAt": 1593437922, # timestamp of deposit
|
|
2036
|
+
# "currency": "Bitcoin", # deposit currency
|
|
2037
|
+
# "ticker": "BTC", # deposit currency ticker
|
|
2038
|
+
# "method": 1, # called method 1 - deposit, 2 - withdraw
|
|
2039
|
+
# "amount": "0.0006", # amount of deposit
|
|
2040
|
+
# "description": "", # deposit description
|
|
2041
|
+
# "memo": "", # deposit memo
|
|
2042
|
+
# "fee": "0", # deposit fee
|
|
2043
|
+
# "status": 15, # transactions status
|
|
2044
|
+
# "network": null, # if currency is multinetwork
|
|
2045
|
+
# "transactionHash": "a275a514013e4e0f927fd0d1bed215e7f6f2c4c6ce762836fe135ec22529d886", # deposit transaction hash
|
|
2046
|
+
# "details": {
|
|
2047
|
+
# "partial": { # details about partially successful withdrawals
|
|
2048
|
+
# "requestAmount": "50000", # requested withdrawal amount
|
|
2049
|
+
# "processedAmount": "39000", # processed withdrawal amount
|
|
2050
|
+
# "processedFee": "273", # fee for processed withdrawal amount
|
|
2051
|
+
# "normalizeTransaction": "" # deposit id
|
|
2052
|
+
# }
|
|
2053
|
+
# },
|
|
2054
|
+
# "confirmations": { # if transaction status == 15 you can see self object
|
|
2055
|
+
# "actual": 1, # current block confirmations
|
|
2056
|
+
# "required": 2 # required block confirmation for successful deposit
|
|
2057
|
+
# }
|
|
2058
|
+
# },
|
|
2059
|
+
# {...},
|
|
2060
|
+
# ],
|
|
2061
|
+
# "total": 300 # total number of transactions, use self for calculating ‘limit’ and ‘offset'
|
|
2062
|
+
# }
|
|
2063
|
+
#
|
|
2064
|
+
records = self.safe_value(response, 'records', [])
|
|
2065
|
+
first = self.safe_dict(records, 0, {})
|
|
2066
|
+
return self.parse_transaction(first, currency)
|
|
2067
|
+
|
|
2068
|
+
def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
|
2069
|
+
"""
|
|
2070
|
+
fetch all deposits made to an account
|
|
2071
|
+
:see: https://docs.whitebit.com/private/http-main-v4/#get-depositwithdraw-history
|
|
2072
|
+
:param str code: unified currency code
|
|
2073
|
+
:param int [since]: the earliest time in ms to fetch deposits for
|
|
2074
|
+
:param int [limit]: the maximum number of deposits structures to retrieve
|
|
2075
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2076
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2077
|
+
"""
|
|
2078
|
+
self.load_markets()
|
|
2079
|
+
currency = None
|
|
2080
|
+
request: dict = {
|
|
2081
|
+
'transactionMethod': 1,
|
|
2082
|
+
'limit': 100,
|
|
2083
|
+
'offset': 0,
|
|
2084
|
+
}
|
|
2085
|
+
if code is not None:
|
|
2086
|
+
currency = self.currency(code)
|
|
2087
|
+
request['ticker'] = currency['id']
|
|
2088
|
+
if limit is not None:
|
|
2089
|
+
request['limit'] = min(limit, 100)
|
|
2090
|
+
response = self.v4PrivatePostMainAccountHistory(self.extend(request, params))
|
|
2091
|
+
#
|
|
2092
|
+
# {
|
|
2093
|
+
# "limit": 100,
|
|
2094
|
+
# "offset": 0,
|
|
2095
|
+
# "records": [
|
|
2096
|
+
# {
|
|
2097
|
+
# "address": "3ApEASLcrQtZpg1TsssFgYF5V5YQJAKvuE", # deposit address
|
|
2098
|
+
# "uniqueId": null, # unique Id of deposit
|
|
2099
|
+
# "createdAt": 1593437922, # timestamp of deposit
|
|
2100
|
+
# "currency": "Bitcoin", # deposit currency
|
|
2101
|
+
# "ticker": "BTC", # deposit currency ticker
|
|
2102
|
+
# "method": 1, # called method 1 - deposit, 2 - withdraw
|
|
2103
|
+
# "amount": "0.0006", # amount of deposit
|
|
2104
|
+
# "description": "", # deposit description
|
|
2105
|
+
# "memo": "", # deposit memo
|
|
2106
|
+
# "fee": "0", # deposit fee
|
|
2107
|
+
# "status": 15, # transactions status
|
|
2108
|
+
# "network": null, # if currency is multinetwork
|
|
2109
|
+
# "transactionHash": "a275a514013e4e0f927fd0d1bed215e7f6f2c4c6ce762836fe135ec22529d886", # deposit transaction hash
|
|
2110
|
+
# "details": {
|
|
2111
|
+
# "partial": { # details about partially successful withdrawals
|
|
2112
|
+
# "requestAmount": "50000", # requested withdrawal amount
|
|
2113
|
+
# "processedAmount": "39000", # processed withdrawal amount
|
|
2114
|
+
# "processedFee": "273", # fee for processed withdrawal amount
|
|
2115
|
+
# "normalizeTransaction": "" # deposit id
|
|
2116
|
+
# }
|
|
2117
|
+
# },
|
|
2118
|
+
# "confirmations": { # if transaction status == 15 you can see self object
|
|
2119
|
+
# "actual": 1, # current block confirmations
|
|
2120
|
+
# "required": 2 # required block confirmation for successful deposit
|
|
2121
|
+
# }
|
|
2122
|
+
# },
|
|
2123
|
+
# {...},
|
|
2124
|
+
# ],
|
|
2125
|
+
# "total": 300 # total number of transactions, use self for calculating ‘limit’ and ‘offset'
|
|
2126
|
+
# }
|
|
2127
|
+
#
|
|
2128
|
+
records = self.safe_list(response, 'records', [])
|
|
2129
|
+
return self.parse_transactions(records, currency, since, limit)
|
|
2130
|
+
|
|
2131
|
+
def fetch_borrow_interest(self, code: Str = None, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
2132
|
+
"""
|
|
2133
|
+
fetch the interest owed by the user for borrowing currency for margin trading
|
|
2134
|
+
:see: https://docs.whitebit.com/private/http-trade-v4/#open-positions
|
|
2135
|
+
:param str code: unified currency code
|
|
2136
|
+
:param str symbol: unified market symbol
|
|
2137
|
+
:param int [since]: the earliest time in ms to fetch borrrow interest for
|
|
2138
|
+
:param int [limit]: the maximum number of structures to retrieve
|
|
2139
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2140
|
+
:returns dict[]: a list of `borrow interest structures <https://docs.ccxt.com/#/?id=borrow-interest-structure>`
|
|
2141
|
+
"""
|
|
2142
|
+
self.load_markets()
|
|
2143
|
+
request: dict = {}
|
|
2144
|
+
market = None
|
|
2145
|
+
if symbol is not None:
|
|
2146
|
+
market = self.market(symbol)
|
|
2147
|
+
request['market'] = market['id']
|
|
2148
|
+
response = self.v4PrivatePostCollateralAccountPositionsOpen(self.extend(request, params))
|
|
2149
|
+
#
|
|
2150
|
+
# [
|
|
2151
|
+
# {
|
|
2152
|
+
# "positionId": 191823,
|
|
2153
|
+
# "market": "BTC_USDT",
|
|
2154
|
+
# "openDate": 1660340344.027163,
|
|
2155
|
+
# "modifyDate": 1660340344.027163,
|
|
2156
|
+
# "amount": "0.003075",
|
|
2157
|
+
# "basePrice": "24149.24512",
|
|
2158
|
+
# "liquidationPrice": "7059.02",
|
|
2159
|
+
# "leverage": "5",
|
|
2160
|
+
# "pnl": "-0.15",
|
|
2161
|
+
# "pnlPercent": "-0.20",
|
|
2162
|
+
# "margin": "14.86",
|
|
2163
|
+
# "freeMargin": "44.99",
|
|
2164
|
+
# "funding": "0",
|
|
2165
|
+
# "unrealizedFunding": "0.0000307828284903",
|
|
2166
|
+
# "liquidationState": null
|
|
2167
|
+
# }
|
|
2168
|
+
# ]
|
|
2169
|
+
#
|
|
2170
|
+
interest = self.parse_borrow_interests(response, market)
|
|
2171
|
+
return self.filter_by_currency_since_limit(interest, code, since, limit)
|
|
2172
|
+
|
|
2173
|
+
def parse_borrow_interest(self, info: dict, market: Market = None):
|
|
2174
|
+
#
|
|
2175
|
+
# {
|
|
2176
|
+
# "positionId": 191823,
|
|
2177
|
+
# "market": "BTC_USDT",
|
|
2178
|
+
# "openDate": 1660340344.027163,
|
|
2179
|
+
# "modifyDate": 1660340344.027163,
|
|
2180
|
+
# "amount": "0.003075",
|
|
2181
|
+
# "basePrice": "24149.24512",
|
|
2182
|
+
# "liquidationPrice": "7059.02",
|
|
2183
|
+
# "leverage": "5",
|
|
2184
|
+
# "pnl": "-0.15",
|
|
2185
|
+
# "pnlPercent": "-0.20",
|
|
2186
|
+
# "margin": "14.86",
|
|
2187
|
+
# "freeMargin": "44.99",
|
|
2188
|
+
# "funding": "0",
|
|
2189
|
+
# "unrealizedFunding": "0.0000307828284903",
|
|
2190
|
+
# "liquidationState": null
|
|
2191
|
+
# }
|
|
2192
|
+
#
|
|
2193
|
+
marketId = self.safe_string(info, 'market')
|
|
2194
|
+
symbol = self.safe_symbol(marketId, market, '_')
|
|
2195
|
+
timestamp = self.safe_timestamp(info, 'modifyDate')
|
|
2196
|
+
return {
|
|
2197
|
+
'symbol': symbol,
|
|
2198
|
+
'marginMode': 'cross',
|
|
2199
|
+
'currency': 'USDT',
|
|
2200
|
+
'interest': self.safe_number(info, 'unrealizedFunding'),
|
|
2201
|
+
'interestRate': 0.00098, # https://whitebit.com/fees
|
|
2202
|
+
'amountBorrowed': self.safe_number(info, 'amount'),
|
|
2203
|
+
'timestamp': timestamp,
|
|
2204
|
+
'datetime': self.iso8601(timestamp),
|
|
2205
|
+
'info': info,
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
def fetch_funding_rate(self, symbol: str, params={}):
|
|
2209
|
+
"""
|
|
2210
|
+
:see: https://docs.whitebit.com/public/http-v4/#available-futures-markets-list
|
|
2211
|
+
fetch the current funding rate
|
|
2212
|
+
:param str symbol: unified market symbol
|
|
2213
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2214
|
+
:returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
|
|
2215
|
+
"""
|
|
2216
|
+
self.load_markets()
|
|
2217
|
+
symbol = self.symbol(symbol)
|
|
2218
|
+
response = self.fetch_funding_rates([symbol], params)
|
|
2219
|
+
return self.safe_value(response, symbol)
|
|
2220
|
+
|
|
2221
|
+
def fetch_funding_rates(self, symbols: Strings = None, params={}):
|
|
2222
|
+
"""
|
|
2223
|
+
:see: https://docs.whitebit.com/public/http-v4/#available-futures-markets-list
|
|
2224
|
+
fetch the funding rate for multiple markets
|
|
2225
|
+
:param str[]|None symbols: list of unified market symbols
|
|
2226
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2227
|
+
:returns dict: a dictionary of `funding rates structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexe by market symbols
|
|
2228
|
+
"""
|
|
2229
|
+
self.load_markets()
|
|
2230
|
+
symbols = self.market_symbols(symbols)
|
|
2231
|
+
response = self.v4PublicGetFutures(params)
|
|
2232
|
+
#
|
|
2233
|
+
# [
|
|
2234
|
+
# {
|
|
2235
|
+
# "name": "BTC_USDT",
|
|
2236
|
+
# "type": "direct",
|
|
2237
|
+
# "quanto_multiplier": "0.0001",
|
|
2238
|
+
# "ref_discount_rate": "0",
|
|
2239
|
+
# "order_price_deviate": "0.5",
|
|
2240
|
+
# "maintenance_rate": "0.005",
|
|
2241
|
+
# "mark_type": "index",
|
|
2242
|
+
# "last_price": "38026",
|
|
2243
|
+
# "mark_price": "37985.6",
|
|
2244
|
+
# "index_price": "37954.92",
|
|
2245
|
+
# "funding_rate_indicative": "0.000219",
|
|
2246
|
+
# "mark_price_round": "0.01",
|
|
2247
|
+
# "funding_offset": 0,
|
|
2248
|
+
# "in_delisting": False,
|
|
2249
|
+
# "risk_limit_base": "1000000",
|
|
2250
|
+
# "interest_rate": "0.0003",
|
|
2251
|
+
# "order_price_round": "0.1",
|
|
2252
|
+
# "order_size_min": 1,
|
|
2253
|
+
# "ref_rebate_rate": "0.2",
|
|
2254
|
+
# "funding_interval": 28800,
|
|
2255
|
+
# "risk_limit_step": "1000000",
|
|
2256
|
+
# "leverage_min": "1",
|
|
2257
|
+
# "leverage_max": "100",
|
|
2258
|
+
# "risk_limit_max": "8000000",
|
|
2259
|
+
# "maker_fee_rate": "-0.00025",
|
|
2260
|
+
# "taker_fee_rate": "0.00075",
|
|
2261
|
+
# "funding_rate": "0.002053",
|
|
2262
|
+
# "order_size_max": 1000000,
|
|
2263
|
+
# "funding_next_apply": 1610035200,
|
|
2264
|
+
# "short_users": 977,
|
|
2265
|
+
# "config_change_time": 1609899548,
|
|
2266
|
+
# "trade_size": 28530850594,
|
|
2267
|
+
# "position_size": 5223816,
|
|
2268
|
+
# "long_users": 455,
|
|
2269
|
+
# "funding_impact_value": "60000",
|
|
2270
|
+
# "orders_limit": 50,
|
|
2271
|
+
# "trade_id": 10851092,
|
|
2272
|
+
# "orderbook_id": 2129638396
|
|
2273
|
+
# }
|
|
2274
|
+
# ]
|
|
2275
|
+
#
|
|
2276
|
+
data = self.safe_value(response, 'result', [])
|
|
2277
|
+
result = self.parse_funding_rates(data)
|
|
2278
|
+
return self.filter_by_array(result, 'symbol', symbols)
|
|
2279
|
+
|
|
2280
|
+
def parse_funding_rate(self, contract, market: Market = None):
|
|
2281
|
+
#
|
|
2282
|
+
# {
|
|
2283
|
+
# "ticker_id":"ADA_PERP",
|
|
2284
|
+
# "stock_currency":"ADA",
|
|
2285
|
+
# "money_currency":"USDT",
|
|
2286
|
+
# "last_price":"0.296708",
|
|
2287
|
+
# "stock_volume":"7982130",
|
|
2288
|
+
# "money_volume":"2345758.29189",
|
|
2289
|
+
# "bid":"0.296608",
|
|
2290
|
+
# "ask":"0.296758",
|
|
2291
|
+
# "high":"0.298338",
|
|
2292
|
+
# "low":"0.290171",
|
|
2293
|
+
# "product_type":"Perpetual",
|
|
2294
|
+
# "open_interest":"46533000",
|
|
2295
|
+
# "index_price":"0.29659",
|
|
2296
|
+
# "index_name":"Cardano",
|
|
2297
|
+
# "index_currency":"ADA",
|
|
2298
|
+
# "funding_rate":"0.0001",
|
|
2299
|
+
# "next_funding_rate_timestamp":"1691193600000",
|
|
2300
|
+
# "brackets":{
|
|
2301
|
+
# "1":"0",
|
|
2302
|
+
# "2":"0",
|
|
2303
|
+
# "3":"0",
|
|
2304
|
+
# "5":"0",
|
|
2305
|
+
# "10":"0",
|
|
2306
|
+
# "20":"0",
|
|
2307
|
+
# "50":"-10000",
|
|
2308
|
+
# "100":"-5000"
|
|
2309
|
+
# },
|
|
2310
|
+
# "max_leverage":"100"
|
|
2311
|
+
# }
|
|
2312
|
+
#
|
|
2313
|
+
marketId = self.safe_string(contract, 'ticker_id')
|
|
2314
|
+
symbol = self.safe_symbol(marketId, market)
|
|
2315
|
+
markPrice = self.safe_number(contract, 'markPrice')
|
|
2316
|
+
indexPrice = self.safe_number(contract, 'indexPrice')
|
|
2317
|
+
interestRate = self.safe_number(contract, 'interestRate')
|
|
2318
|
+
fundingRate = self.safe_number(contract, 'funding_rate')
|
|
2319
|
+
nextFundingTime = self.safe_integer(contract, 'next_funding_rate_timestamp')
|
|
2320
|
+
return {
|
|
2321
|
+
'info': contract,
|
|
2322
|
+
'symbol': symbol,
|
|
2323
|
+
'markPrice': markPrice,
|
|
2324
|
+
'indexPrice': indexPrice,
|
|
2325
|
+
'interestRate': interestRate,
|
|
2326
|
+
'timestamp': None,
|
|
2327
|
+
'datetime': None,
|
|
2328
|
+
'fundingRate': fundingRate,
|
|
2329
|
+
'fundingTimestamp': None,
|
|
2330
|
+
'fundingDatetime': self.iso8601(None),
|
|
2331
|
+
'nextFundingRate': None,
|
|
2332
|
+
'nextFundingTimestamp': nextFundingTime,
|
|
2333
|
+
'nextFundingDatetime': self.iso8601(nextFundingTime),
|
|
2334
|
+
'previousFundingRate': None,
|
|
2335
|
+
'previousFundingTimestamp': None,
|
|
2336
|
+
'previousFundingDatetime': None,
|
|
2337
|
+
}
|
|
2338
|
+
|
|
2339
|
+
def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
|
2340
|
+
"""
|
|
2341
|
+
fetch history of deposits and withdrawals
|
|
2342
|
+
:see: https://github.com/whitebit-exchange/api-docs/blob/main/pages/private/http-main-v4.md#get-depositwithdraw-history
|
|
2343
|
+
:param str [code]: unified currency code for the currency of the deposit/withdrawals, default is None
|
|
2344
|
+
:param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None
|
|
2345
|
+
:param int [limit]: max number of deposit/withdrawals to return, default = 50, Min: 1, Max: 100
|
|
2346
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2347
|
+
*
|
|
2348
|
+
* EXCHANGE SPECIFIC PARAMETERS
|
|
2349
|
+
:param number [params.transactionMethod]: Method. Example: 1 to display deposits / 2 to display withdraws. Do not send self parameter in order to receive both deposits and withdraws.
|
|
2350
|
+
:param str [params.address]: Can be used for filtering transactions by specific address or memo.
|
|
2351
|
+
:param str[] [params.addresses]: Can be used for filtering transactions by specific addresses or memos(max: 20).
|
|
2352
|
+
:param str [params.uniqueId]: Can be used for filtering transactions by specific unique id
|
|
2353
|
+
:param int [params.offset]: If you want the request to return entries starting from a particular line, you can use OFFSET clause to tell it where it should start. Default: 0, Min: 0, Max: 10000
|
|
2354
|
+
:param str[] [params.status]: Can be used for filtering transactions by status codes. Caution: You must use self parameter with appropriate transactionMethod and use valid status codes for self method. You can find them below. Example: "status": [3,7]
|
|
2355
|
+
:returns dict: a list of `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2356
|
+
"""
|
|
2357
|
+
self.load_markets()
|
|
2358
|
+
request: dict = {}
|
|
2359
|
+
currency = None
|
|
2360
|
+
if code is not None:
|
|
2361
|
+
currency = self.currency(code)
|
|
2362
|
+
request['ticker'] = currency['id']
|
|
2363
|
+
if limit is not None:
|
|
2364
|
+
request['limit'] = limit # default 1000
|
|
2365
|
+
response = self.v4PrivatePostMainAccountHistory(self.extend(request, params))
|
|
2366
|
+
#
|
|
2367
|
+
# {
|
|
2368
|
+
# "limit": 100,
|
|
2369
|
+
# "offset": 0,
|
|
2370
|
+
# "records": [
|
|
2371
|
+
# {
|
|
2372
|
+
# "address": "3ApEASLcrQtZpg1TsssFgYF5V5YQJAKvuE", # deposit address
|
|
2373
|
+
# "uniqueId": null, # unique Id of deposit
|
|
2374
|
+
# "createdAt": 1593437922, # timestamp of deposit
|
|
2375
|
+
# "currency": "Bitcoin", # deposit currency
|
|
2376
|
+
# "ticker": "BTC", # deposit currency ticker
|
|
2377
|
+
# "method": 1, # called method 1 - deposit, 2 - withdraw
|
|
2378
|
+
# "amount": "0.0006", # amount of deposit
|
|
2379
|
+
# "description": "", # deposit description
|
|
2380
|
+
# "memo": "", # deposit memo
|
|
2381
|
+
# "fee": "0", # deposit fee
|
|
2382
|
+
# "status": 15, # transactions status
|
|
2383
|
+
# "network": null, # if currency is multinetwork
|
|
2384
|
+
# "transactionHash": "a275a514013e4e0f927fd0d1bed215e7f6f2c4c6ce762836fe135ec22529d886", # deposit transaction hash
|
|
2385
|
+
# "transactionId": "5e112b38-9652-11ed-a1eb-0242ac120002", # transaction id
|
|
2386
|
+
# "details": {
|
|
2387
|
+
# "partial": { # details about partially successful withdrawals
|
|
2388
|
+
# "requestAmount": "50000", # requested withdrawal amount
|
|
2389
|
+
# "processedAmount": "39000", # processed withdrawal amount
|
|
2390
|
+
# "processedFee": "273", # fee for processed withdrawal amount
|
|
2391
|
+
# "normalizeTransaction": "" # deposit id
|
|
2392
|
+
# }
|
|
2393
|
+
# },
|
|
2394
|
+
# "confirmations": { # if transaction status == 15(Pending) you can see self object
|
|
2395
|
+
# "actual": 1, # current block confirmations
|
|
2396
|
+
# "required": 2 # required block confirmation for successful deposit
|
|
2397
|
+
# }
|
|
2398
|
+
# },
|
|
2399
|
+
# {...},
|
|
2400
|
+
# ],
|
|
2401
|
+
# "total": 300 # total number of transactions, use self for calculating ‘limit’ and ‘offset'
|
|
2402
|
+
# }
|
|
2403
|
+
#
|
|
2404
|
+
records = self.safe_list(response, 'records')
|
|
2405
|
+
return self.parse_transactions(records, currency, since, limit)
|
|
2406
|
+
|
|
2407
|
+
def is_fiat(self, currency):
|
|
2408
|
+
fiatCurrencies = self.safe_value(self.options, 'fiatCurrencies', [])
|
|
2409
|
+
return self.in_array(currency, fiatCurrencies)
|
|
2410
|
+
|
|
2411
|
+
def nonce(self):
|
|
2412
|
+
return self.milliseconds()
|
|
2413
|
+
|
|
2414
|
+
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
|
2415
|
+
query = self.omit(params, self.extract_params(path))
|
|
2416
|
+
version = self.safe_value(api, 0)
|
|
2417
|
+
accessibility = self.safe_value(api, 1)
|
|
2418
|
+
pathWithParams = '/' + self.implode_params(path, params)
|
|
2419
|
+
url = self.urls['api'][version][accessibility] + pathWithParams
|
|
2420
|
+
if accessibility == 'public':
|
|
2421
|
+
if query:
|
|
2422
|
+
url += '?' + self.urlencode(query)
|
|
2423
|
+
if accessibility == 'private':
|
|
2424
|
+
self.check_required_credentials()
|
|
2425
|
+
nonce = str(self.nonce())
|
|
2426
|
+
secret = self.encode(self.secret)
|
|
2427
|
+
request = '/' + 'api' + '/' + version + pathWithParams
|
|
2428
|
+
body = self.json(self.extend({'request': request, 'nonce': nonce}, params))
|
|
2429
|
+
payload = self.string_to_base64(body)
|
|
2430
|
+
signature = self.hmac(self.encode(payload), secret, hashlib.sha512)
|
|
2431
|
+
headers = {
|
|
2432
|
+
'Content-Type': 'application/json',
|
|
2433
|
+
'X-TXC-APIKEY': self.apiKey,
|
|
2434
|
+
'X-TXC-PAYLOAD': payload,
|
|
2435
|
+
'X-TXC-SIGNATURE': signature,
|
|
2436
|
+
}
|
|
2437
|
+
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
|
2438
|
+
|
|
2439
|
+
def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
|
|
2440
|
+
if (code == 418) or (code == 429):
|
|
2441
|
+
raise DDoSProtection(self.id + ' ' + str(code) + ' ' + reason + ' ' + body)
|
|
2442
|
+
if code == 404:
|
|
2443
|
+
raise ExchangeError(self.id + ' ' + str(code) + ' endpoint not found')
|
|
2444
|
+
if response is not None:
|
|
2445
|
+
# For cases where we have a meaningful status
|
|
2446
|
+
# {"response":null,"status":422,"errors":{"orderId":["Finished order id 435453454535 not found on your account"]},"notification":null,"warning":"Finished order id 435453454535 not found on your account","_token":null}
|
|
2447
|
+
status = self.safe_string(response, 'status')
|
|
2448
|
+
# {"code":10,"message":"Unauthorized request."}
|
|
2449
|
+
message = self.safe_string(response, 'message')
|
|
2450
|
+
# For these cases where we have a generic code variable error key
|
|
2451
|
+
# {"code":0,"message":"Validation failed","errors":{"amount":["Amount must be greater than 0"]}}
|
|
2452
|
+
codeNew = self.safe_integer(response, 'code')
|
|
2453
|
+
hasErrorStatus = status is not None and status != '200'
|
|
2454
|
+
if hasErrorStatus or codeNew is not None:
|
|
2455
|
+
feedback = self.id + ' ' + body
|
|
2456
|
+
errorInfo = message
|
|
2457
|
+
if hasErrorStatus:
|
|
2458
|
+
errorInfo = status
|
|
2459
|
+
else:
|
|
2460
|
+
errorObject = self.safe_value(response, 'errors')
|
|
2461
|
+
if errorObject is not None:
|
|
2462
|
+
errorKey = list(errorObject.keys())[0]
|
|
2463
|
+
errorMessageArray = self.safe_value(errorObject, errorKey, [])
|
|
2464
|
+
errorMessageLength = len(errorMessageArray)
|
|
2465
|
+
errorInfo = errorMessageArray[0] if (errorMessageLength > 0) else body
|
|
2466
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], errorInfo, feedback)
|
|
2467
|
+
self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
|
|
2468
|
+
raise ExchangeError(feedback)
|
|
2469
|
+
return None
|