ccxt-ir 4.3.46.0.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccxt/__init__.py +358 -0
- ccxt/abantether.py +316 -0
- ccxt/abstract/__init__.py +0 -0
- ccxt/abstract/abantether.py +5 -0
- ccxt/abstract/ace.py +15 -0
- ccxt/abstract/afratether.py +6 -0
- ccxt/abstract/alpaca.py +70 -0
- ccxt/abstract/arzinja.py +5 -0
- ccxt/abstract/arzplus.py +7 -0
- ccxt/abstract/ascendex.py +77 -0
- ccxt/abstract/bequant.py +115 -0
- ccxt/abstract/bigone.py +45 -0
- ccxt/abstract/binance.py +712 -0
- ccxt/abstract/binancecoinm.py +712 -0
- ccxt/abstract/binanceus.py +764 -0
- ccxt/abstract/binanceusdm.py +712 -0
- ccxt/abstract/bingx.py +113 -0
- ccxt/abstract/bit2c.py +27 -0
- ccxt/abstract/bitbank.py +27 -0
- ccxt/abstract/bitbay.py +53 -0
- ccxt/abstract/bitbns.py +40 -0
- ccxt/abstract/bitcoincom.py +115 -0
- ccxt/abstract/bitfinex.py +69 -0
- ccxt/abstract/bitfinex2.py +139 -0
- ccxt/abstract/bitflyer.py +38 -0
- ccxt/abstract/bitget.py +508 -0
- ccxt/abstract/bithumb.py +32 -0
- ccxt/abstract/bitimen.py +7 -0
- ccxt/abstract/bitir.py +7 -0
- ccxt/abstract/bitmart.py +99 -0
- ccxt/abstract/bitmex.py +97 -0
- ccxt/abstract/bitopro.py +29 -0
- ccxt/abstract/bitpanda.py +35 -0
- ccxt/abstract/bitpin.py +7 -0
- ccxt/abstract/bitrue.py +72 -0
- ccxt/abstract/bitso.py +43 -0
- ccxt/abstract/bitstamp.py +258 -0
- ccxt/abstract/bitteam.py +29 -0
- ccxt/abstract/bitvavo.py +27 -0
- ccxt/abstract/bl3p.py +19 -0
- ccxt/abstract/blockchaincom.py +28 -0
- ccxt/abstract/blofin.py +37 -0
- ccxt/abstract/btcalpha.py +18 -0
- ccxt/abstract/btcbox.py +13 -0
- ccxt/abstract/btcmarkets.py +39 -0
- ccxt/abstract/btcturk.py +20 -0
- ccxt/abstract/bybit.py +298 -0
- ccxt/abstract/cex.py +33 -0
- ccxt/abstract/coinbase.py +94 -0
- ccxt/abstract/coinbaseadvanced.py +94 -0
- ccxt/abstract/coinbaseexchange.py +67 -0
- ccxt/abstract/coinbaseinternational.py +39 -0
- ccxt/abstract/coincatch.py +94 -0
- ccxt/abstract/coincheck.py +33 -0
- ccxt/abstract/coinex.py +237 -0
- ccxt/abstract/coinlist.py +54 -0
- ccxt/abstract/coinmate.py +62 -0
- ccxt/abstract/coinmetro.py +34 -0
- ccxt/abstract/coinone.py +67 -0
- ccxt/abstract/coinsph.py +54 -0
- ccxt/abstract/coinspot.py +28 -0
- ccxt/abstract/cryptocom.py +107 -0
- ccxt/abstract/currencycom.py +68 -0
- ccxt/abstract/delta.py +50 -0
- ccxt/abstract/deribit.py +125 -0
- ccxt/abstract/digifinex.py +91 -0
- ccxt/abstract/eterex.py +5 -0
- ccxt/abstract/excoino.py +7 -0
- ccxt/abstract/exir.py +8 -0
- ccxt/abstract/exmo.py +55 -0
- ccxt/abstract/exnovin.py +6 -0
- ccxt/abstract/farhadexchange.py +5 -0
- ccxt/abstract/fmfwio.py +115 -0
- ccxt/abstract/gate.py +265 -0
- ccxt/abstract/gateio.py +265 -0
- ccxt/abstract/gemini.py +58 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/hitbtc.py +115 -0
- ccxt/abstract/hitbtc3.py +115 -0
- ccxt/abstract/hitobit.py +8 -0
- ccxt/abstract/hollaex.py +33 -0
- ccxt/abstract/htx.py +548 -0
- ccxt/abstract/huobi.py +548 -0
- ccxt/abstract/huobijp.py +114 -0
- ccxt/abstract/hyperliquid.py +6 -0
- ccxt/abstract/idex.py +26 -0
- ccxt/abstract/independentreserve.py +37 -0
- ccxt/abstract/indodax.py +26 -0
- ccxt/abstract/jibitex.py +7 -0
- ccxt/abstract/kraken.py +57 -0
- ccxt/abstract/krakenfutures.py +38 -0
- ccxt/abstract/kucoin.py +214 -0
- ccxt/abstract/kucoinfutures.py +233 -0
- ccxt/abstract/kuna.py +182 -0
- ccxt/abstract/latoken.py +56 -0
- ccxt/abstract/lbank.py +61 -0
- ccxt/abstract/luno.py +37 -0
- ccxt/abstract/lykke.py +29 -0
- ccxt/abstract/mercado.py +25 -0
- ccxt/abstract/mexc.py +178 -0
- ccxt/abstract/ndax.py +97 -0
- ccxt/abstract/nobitex.py +7 -0
- ccxt/abstract/novadax.py +29 -0
- ccxt/abstract/oceanex.py +22 -0
- ccxt/abstract/okcoin.py +74 -0
- ccxt/abstract/okexchange.py +8 -0
- ccxt/abstract/okx.py +324 -0
- ccxt/abstract/ompfinex.py +7 -0
- ccxt/abstract/onetrading.py +35 -0
- ccxt/abstract/oxfun.py +34 -0
- ccxt/abstract/p2b.py +22 -0
- ccxt/abstract/paradex.py +40 -0
- ccxt/abstract/paymium.py +28 -0
- ccxt/abstract/phemex.py +115 -0
- ccxt/abstract/poloniex.py +69 -0
- ccxt/abstract/poloniexfutures.py +48 -0
- ccxt/abstract/probit.py +23 -0
- ccxt/abstract/ramzinex.py +7 -0
- ccxt/abstract/sarmayex.py +5 -0
- ccxt/abstract/sarrafex.py +7 -0
- ccxt/abstract/tabdeal.py +7 -0
- ccxt/abstract/tetherland.py +5 -0
- ccxt/abstract/timex.py +62 -0
- ccxt/abstract/tokocrypto.py +37 -0
- ccxt/abstract/tradeogre.py +16 -0
- ccxt/abstract/twox.py +5 -0
- ccxt/abstract/ubitex.py +7 -0
- ccxt/abstract/upbit.py +38 -0
- ccxt/abstract/vertex.py +19 -0
- ccxt/abstract/wallex.py +8 -0
- ccxt/abstract/wavesexchange.py +154 -0
- ccxt/abstract/wazirx.py +30 -0
- ccxt/abstract/whitebit.py +98 -0
- ccxt/abstract/woo.py +83 -0
- ccxt/abstract/woofipro.py +119 -0
- ccxt/abstract/xt.py +152 -0
- ccxt/abstract/yobit.py +16 -0
- ccxt/abstract/zaif.py +38 -0
- ccxt/abstract/zonda.py +53 -0
- ccxt/ace.py +1012 -0
- ccxt/afratether.py +293 -0
- ccxt/alpaca.py +1083 -0
- ccxt/arzinja.py +285 -0
- ccxt/arzplus.py +412 -0
- ccxt/ascendex.py +3330 -0
- ccxt/async_support/__init__.py +337 -0
- ccxt/async_support/abantether.py +316 -0
- ccxt/async_support/ace.py +1012 -0
- ccxt/async_support/afratether.py +293 -0
- ccxt/async_support/alpaca.py +1083 -0
- ccxt/async_support/arzinja.py +285 -0
- ccxt/async_support/arzplus.py +412 -0
- ccxt/async_support/ascendex.py +3330 -0
- ccxt/async_support/base/__init__.py +1 -0
- ccxt/async_support/base/exchange.py +1966 -0
- ccxt/async_support/base/throttler.py +50 -0
- ccxt/async_support/base/ws/__init__.py +38 -0
- ccxt/async_support/base/ws/aiohttp_client.py +125 -0
- ccxt/async_support/base/ws/cache.py +212 -0
- ccxt/async_support/base/ws/client.py +193 -0
- ccxt/async_support/base/ws/fast_client.py +96 -0
- ccxt/async_support/base/ws/functions.py +59 -0
- ccxt/async_support/base/ws/future.py +58 -0
- ccxt/async_support/base/ws/order_book.py +78 -0
- ccxt/async_support/base/ws/order_book_side.py +174 -0
- ccxt/async_support/bequant.py +33 -0
- ccxt/async_support/bigone.py +2113 -0
- ccxt/async_support/binance.py +12234 -0
- ccxt/async_support/binancecoinm.py +45 -0
- ccxt/async_support/binanceus.py +211 -0
- ccxt/async_support/binanceusdm.py +58 -0
- ccxt/async_support/bingx.py +4325 -0
- ccxt/async_support/bit2c.py +866 -0
- ccxt/async_support/bitbank.py +1001 -0
- ccxt/async_support/bitbay.py +17 -0
- ccxt/async_support/bitbns.py +1154 -0
- ccxt/async_support/bitcoincom.py +17 -0
- ccxt/async_support/bitfinex.py +1617 -0
- ccxt/async_support/bitfinex2.py +3552 -0
- ccxt/async_support/bitflyer.py +995 -0
- ccxt/async_support/bitget.py +8273 -0
- ccxt/async_support/bithumb.py +1061 -0
- ccxt/async_support/bitimen.py +401 -0
- ccxt/async_support/bitir.py +490 -0
- ccxt/async_support/bitmart.py +4415 -0
- ccxt/async_support/bitmex.py +2756 -0
- ccxt/async_support/bitopro.py +1630 -0
- ccxt/async_support/bitpanda.py +16 -0
- ccxt/async_support/bitpin.py +454 -0
- ccxt/async_support/bitrue.py +3027 -0
- ccxt/async_support/bitso.py +1670 -0
- ccxt/async_support/bitstamp.py +2203 -0
- ccxt/async_support/bitteam.py +2239 -0
- ccxt/async_support/bitvavo.py +1968 -0
- ccxt/async_support/bl3p.py +485 -0
- ccxt/async_support/blockchaincom.py +1104 -0
- ccxt/async_support/blofin.py +2066 -0
- ccxt/async_support/btcalpha.py +891 -0
- ccxt/async_support/btcbox.py +544 -0
- ccxt/async_support/btcmarkets.py +1221 -0
- ccxt/async_support/btcturk.py +911 -0
- ccxt/async_support/bybit.py +8159 -0
- ccxt/async_support/cex.py +1605 -0
- ccxt/async_support/coinbase.py +4475 -0
- ccxt/async_support/coinbaseadvanced.py +17 -0
- ccxt/async_support/coinbaseexchange.py +1734 -0
- ccxt/async_support/coinbaseinternational.py +1899 -0
- ccxt/async_support/coincatch.py +5069 -0
- ccxt/async_support/coincheck.py +815 -0
- ccxt/async_support/coinex.py +5526 -0
- ccxt/async_support/coinlist.py +2243 -0
- ccxt/async_support/coinmate.py +1067 -0
- ccxt/async_support/coinmetro.py +1797 -0
- ccxt/async_support/coinone.py +1127 -0
- ccxt/async_support/coinsph.py +1850 -0
- ccxt/async_support/coinspot.py +534 -0
- ccxt/async_support/cryptocom.py +2822 -0
- ccxt/async_support/currencycom.py +1950 -0
- ccxt/async_support/delta.py +3376 -0
- ccxt/async_support/deribit.py +3437 -0
- ccxt/async_support/digifinex.py +3960 -0
- ccxt/async_support/eterex.py +286 -0
- ccxt/async_support/excoino.py +399 -0
- ccxt/async_support/exir.py +375 -0
- ccxt/async_support/exmo.py +2462 -0
- ccxt/async_support/exnovin.py +360 -0
- ccxt/async_support/farhadexchange.py +266 -0
- ccxt/async_support/fmfwio.py +34 -0
- ccxt/async_support/gate.py +6976 -0
- ccxt/async_support/gateio.py +16 -0
- ccxt/async_support/gemini.py +1825 -0
- ccxt/async_support/hashkey.py +4150 -0
- ccxt/async_support/hitbtc.py +3423 -0
- ccxt/async_support/hitbtc3.py +16 -0
- ccxt/async_support/hitobit.py +391 -0
- ccxt/async_support/hollaex.py +1813 -0
- ccxt/async_support/htx.py +8506 -0
- ccxt/async_support/huobi.py +16 -0
- ccxt/async_support/huobijp.py +1801 -0
- ccxt/async_support/hyperliquid.py +2431 -0
- ccxt/async_support/idex.py +1766 -0
- ccxt/async_support/independentreserve.py +784 -0
- ccxt/async_support/indodax.py +1247 -0
- ccxt/async_support/jibitex.py +395 -0
- ccxt/async_support/kraken.py +2894 -0
- ccxt/async_support/krakenfutures.py +2601 -0
- ccxt/async_support/kucoin.py +4602 -0
- ccxt/async_support/kucoinfutures.py +2698 -0
- ccxt/async_support/kuna.py +1841 -0
- ccxt/async_support/latoken.py +1664 -0
- ccxt/async_support/lbank.py +2683 -0
- ccxt/async_support/luno.py +1067 -0
- ccxt/async_support/lykke.py +1270 -0
- ccxt/async_support/mercado.py +842 -0
- ccxt/async_support/mexc.py +5369 -0
- ccxt/async_support/ndax.py +2354 -0
- ccxt/async_support/nobitex.py +419 -0
- ccxt/async_support/novadax.py +1484 -0
- ccxt/async_support/oceanex.py +903 -0
- ccxt/async_support/okcoin.py +2936 -0
- ccxt/async_support/okexchange.py +349 -0
- ccxt/async_support/okx.py +7827 -0
- ccxt/async_support/ompfinex.py +472 -0
- ccxt/async_support/onetrading.py +1911 -0
- ccxt/async_support/oxfun.py +2773 -0
- ccxt/async_support/p2b.py +1194 -0
- ccxt/async_support/paradex.py +2015 -0
- ccxt/async_support/paymium.py +564 -0
- ccxt/async_support/phemex.py +4473 -0
- ccxt/async_support/poloniex.py +2232 -0
- ccxt/async_support/poloniexfutures.py +1717 -0
- ccxt/async_support/probit.py +1734 -0
- ccxt/async_support/ramzinex.py +476 -0
- ccxt/async_support/sarmayex.py +357 -0
- ccxt/async_support/sarrafex.py +478 -0
- ccxt/async_support/tabdeal.py +364 -0
- ccxt/async_support/tetherland.py +349 -0
- ccxt/async_support/timex.py +1593 -0
- ccxt/async_support/tokocrypto.py +2405 -0
- ccxt/async_support/tradeogre.py +608 -0
- ccxt/async_support/twox.py +326 -0
- ccxt/async_support/ubitex.py +409 -0
- ccxt/async_support/upbit.py +1833 -0
- ccxt/async_support/vertex.py +2922 -0
- ccxt/async_support/wallex.py +445 -0
- ccxt/async_support/wavesexchange.py +2473 -0
- ccxt/async_support/wazirx.py +1224 -0
- ccxt/async_support/whitebit.py +2469 -0
- ccxt/async_support/woo.py +3114 -0
- ccxt/async_support/woofipro.py +2533 -0
- ccxt/async_support/xt.py +4454 -0
- ccxt/async_support/yobit.py +1283 -0
- ccxt/async_support/zaif.py +725 -0
- ccxt/async_support/zonda.py +1828 -0
- ccxt/base/__init__.py +27 -0
- ccxt/base/decimal_to_precision.py +174 -0
- ccxt/base/errors.py +242 -0
- ccxt/base/exchange.py +5941 -0
- ccxt/base/precise.py +287 -0
- ccxt/base/types.py +502 -0
- ccxt/bequant.py +33 -0
- ccxt/bigone.py +2112 -0
- ccxt/binance.py +12233 -0
- ccxt/binancecoinm.py +45 -0
- ccxt/binanceus.py +211 -0
- ccxt/binanceusdm.py +58 -0
- ccxt/bingx.py +4324 -0
- ccxt/bit2c.py +866 -0
- ccxt/bitbank.py +1001 -0
- ccxt/bitbay.py +17 -0
- ccxt/bitbns.py +1154 -0
- ccxt/bitcoincom.py +17 -0
- ccxt/bitfinex.py +1617 -0
- ccxt/bitfinex2.py +3552 -0
- ccxt/bitflyer.py +995 -0
- ccxt/bitget.py +8272 -0
- ccxt/bithumb.py +1061 -0
- ccxt/bitimen.py +401 -0
- ccxt/bitir.py +490 -0
- ccxt/bitmart.py +4415 -0
- ccxt/bitmex.py +2756 -0
- ccxt/bitopro.py +1630 -0
- ccxt/bitpanda.py +16 -0
- ccxt/bitpin.py +454 -0
- ccxt/bitrue.py +3026 -0
- ccxt/bitso.py +1670 -0
- ccxt/bitstamp.py +2203 -0
- ccxt/bitteam.py +2239 -0
- ccxt/bitvavo.py +1968 -0
- ccxt/bl3p.py +485 -0
- ccxt/blockchaincom.py +1104 -0
- ccxt/blofin.py +2066 -0
- ccxt/btcalpha.py +891 -0
- ccxt/btcbox.py +544 -0
- ccxt/btcmarkets.py +1221 -0
- ccxt/btcturk.py +911 -0
- ccxt/bybit.py +8158 -0
- ccxt/cex.py +1605 -0
- ccxt/coinbase.py +4474 -0
- ccxt/coinbaseadvanced.py +17 -0
- ccxt/coinbaseexchange.py +1734 -0
- ccxt/coinbaseinternational.py +1899 -0
- ccxt/coincatch.py +5069 -0
- ccxt/coincheck.py +815 -0
- ccxt/coinex.py +5525 -0
- ccxt/coinlist.py +2243 -0
- ccxt/coinmate.py +1067 -0
- ccxt/coinmetro.py +1797 -0
- ccxt/coinone.py +1127 -0
- ccxt/coinsph.py +1850 -0
- ccxt/coinspot.py +534 -0
- ccxt/cryptocom.py +2822 -0
- ccxt/currencycom.py +1950 -0
- ccxt/delta.py +3376 -0
- ccxt/deribit.py +3437 -0
- ccxt/digifinex.py +3959 -0
- ccxt/eterex.py +286 -0
- ccxt/excoino.py +399 -0
- ccxt/exir.py +375 -0
- ccxt/exmo.py +2462 -0
- ccxt/exnovin.py +360 -0
- ccxt/farhadexchange.py +266 -0
- ccxt/fmfwio.py +34 -0
- ccxt/gate.py +6975 -0
- ccxt/gateio.py +16 -0
- ccxt/gemini.py +1824 -0
- ccxt/hashkey.py +4150 -0
- ccxt/hitbtc.py +3423 -0
- ccxt/hitbtc3.py +16 -0
- ccxt/hitobit.py +391 -0
- ccxt/hollaex.py +1813 -0
- ccxt/htx.py +8505 -0
- ccxt/huobi.py +16 -0
- ccxt/huobijp.py +1801 -0
- ccxt/hyperliquid.py +2430 -0
- ccxt/idex.py +1766 -0
- ccxt/independentreserve.py +784 -0
- ccxt/indodax.py +1247 -0
- ccxt/jibitex.py +395 -0
- ccxt/kraken.py +2894 -0
- ccxt/krakenfutures.py +2601 -0
- ccxt/kucoin.py +4601 -0
- ccxt/kucoinfutures.py +2698 -0
- ccxt/kuna.py +1841 -0
- ccxt/latoken.py +1664 -0
- ccxt/lbank.py +2682 -0
- ccxt/luno.py +1067 -0
- ccxt/lykke.py +1270 -0
- ccxt/mercado.py +842 -0
- ccxt/mexc.py +5369 -0
- ccxt/ndax.py +2354 -0
- ccxt/nobitex.py +419 -0
- ccxt/novadax.py +1484 -0
- ccxt/oceanex.py +903 -0
- ccxt/okcoin.py +2936 -0
- ccxt/okexchange.py +349 -0
- ccxt/okx.py +7826 -0
- ccxt/ompfinex.py +472 -0
- ccxt/onetrading.py +1911 -0
- ccxt/oxfun.py +2772 -0
- ccxt/p2b.py +1194 -0
- ccxt/paradex.py +2015 -0
- ccxt/paymium.py +564 -0
- ccxt/phemex.py +4473 -0
- ccxt/poloniex.py +2232 -0
- ccxt/poloniexfutures.py +1717 -0
- ccxt/pro/__init__.py +149 -0
- ccxt/pro/alpaca.py +685 -0
- ccxt/pro/ascendex.py +916 -0
- ccxt/pro/bequant.py +38 -0
- ccxt/pro/binance.py +3488 -0
- ccxt/pro/binancecoinm.py +28 -0
- ccxt/pro/binanceus.py +48 -0
- ccxt/pro/binanceusdm.py +31 -0
- ccxt/pro/bingx.py +1264 -0
- ccxt/pro/bitcoincom.py +34 -0
- ccxt/pro/bitfinex.py +621 -0
- ccxt/pro/bitfinex2.py +1083 -0
- ccxt/pro/bitget.py +1692 -0
- ccxt/pro/bithumb.py +368 -0
- ccxt/pro/bitmart.py +1449 -0
- ccxt/pro/bitmex.py +1656 -0
- ccxt/pro/bitopro.py +445 -0
- ccxt/pro/bitpanda.py +15 -0
- ccxt/pro/bitrue.py +447 -0
- ccxt/pro/bitstamp.py +522 -0
- ccxt/pro/bitvavo.py +1270 -0
- ccxt/pro/blockchaincom.py +738 -0
- ccxt/pro/blofin.py +692 -0
- ccxt/pro/bybit.py +2000 -0
- ccxt/pro/cex.py +1440 -0
- ccxt/pro/coinbase.py +678 -0
- ccxt/pro/coinbaseadvanced.py +16 -0
- ccxt/pro/coinbaseexchange.py +895 -0
- ccxt/pro/coinbaseinternational.py +620 -0
- ccxt/pro/coincatch.py +1464 -0
- ccxt/pro/coincheck.py +199 -0
- ccxt/pro/coinex.py +1061 -0
- ccxt/pro/coinone.py +395 -0
- ccxt/pro/cryptocom.py +947 -0
- ccxt/pro/currencycom.py +536 -0
- ccxt/pro/deribit.py +892 -0
- ccxt/pro/exmo.py +629 -0
- ccxt/pro/gate.py +1416 -0
- ccxt/pro/gateio.py +15 -0
- ccxt/pro/gemini.py +865 -0
- ccxt/pro/hashkey.py +802 -0
- ccxt/pro/hitbtc.py +1216 -0
- ccxt/pro/hollaex.py +563 -0
- ccxt/pro/htx.py +2215 -0
- ccxt/pro/huobi.py +15 -0
- ccxt/pro/huobijp.py +570 -0
- ccxt/pro/hyperliquid.py +525 -0
- ccxt/pro/idex.py +672 -0
- ccxt/pro/independentreserve.py +270 -0
- ccxt/pro/kraken.py +1356 -0
- ccxt/pro/krakenfutures.py +1492 -0
- ccxt/pro/kucoin.py +1133 -0
- ccxt/pro/kucoinfutures.py +1081 -0
- ccxt/pro/lbank.py +843 -0
- ccxt/pro/luno.py +303 -0
- ccxt/pro/mexc.py +1122 -0
- ccxt/pro/ndax.py +506 -0
- ccxt/pro/okcoin.py +698 -0
- ccxt/pro/okx.py +1851 -0
- ccxt/pro/onetrading.py +1275 -0
- ccxt/pro/oxfun.py +950 -0
- ccxt/pro/p2b.py +419 -0
- ccxt/pro/paradex.py +352 -0
- ccxt/pro/phemex.py +1441 -0
- ccxt/pro/poloniex.py +1166 -0
- ccxt/pro/poloniexfutures.py +990 -0
- ccxt/pro/probit.py +551 -0
- ccxt/pro/upbit.py +520 -0
- ccxt/pro/vertex.py +943 -0
- ccxt/pro/wazirx.py +749 -0
- ccxt/pro/whitebit.py +864 -0
- ccxt/pro/woo.py +1078 -0
- ccxt/pro/woofipro.py +1183 -0
- ccxt/pro/xt.py +1067 -0
- ccxt/probit.py +1734 -0
- ccxt/ramzinex.py +476 -0
- ccxt/sarmayex.py +357 -0
- ccxt/sarrafex.py +478 -0
- ccxt/static_dependencies/__init__.py +1 -0
- ccxt/static_dependencies/ecdsa/__init__.py +14 -0
- ccxt/static_dependencies/ecdsa/_version.py +520 -0
- ccxt/static_dependencies/ecdsa/curves.py +56 -0
- ccxt/static_dependencies/ecdsa/der.py +221 -0
- ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
- ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
- ccxt/static_dependencies/ecdsa/keys.py +332 -0
- ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
- ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
- ccxt/static_dependencies/ecdsa/util.py +266 -0
- ccxt/static_dependencies/ethereum/__init__.py +7 -0
- ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
- ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
- ccxt/static_dependencies/ethereum/abi/base.py +152 -0
- ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
- ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
- ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
- ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
- ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
- ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
- ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
- ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
- ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
- ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
- ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
- ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
- ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
- ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
- ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
- ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
- ccxt/static_dependencies/ethereum/account/messages.py +263 -0
- ccxt/static_dependencies/ethereum/account/py.typed +0 -0
- ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
- ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
- ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
- ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
- ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
- ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
- ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
- ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
- ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
- ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
- ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
- ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
- ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
- ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
- ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
- ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
- ccxt/static_dependencies/ethereum/utils/address.py +171 -0
- ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
- ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
- ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
- ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
- ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
- ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
- ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
- ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
- ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
- ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
- ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
- ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
- ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
- ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
- ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
- ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
- ccxt/static_dependencies/ethereum/utils/types.py +54 -0
- ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
- ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
- ccxt/static_dependencies/ethereum/utils/units.py +31 -0
- ccxt/static_dependencies/keccak/__init__.py +3 -0
- ccxt/static_dependencies/keccak/keccak.py +197 -0
- ccxt/static_dependencies/lark/__init__.py +38 -0
- ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- ccxt/static_dependencies/lark/ast_utils.py +59 -0
- ccxt/static_dependencies/lark/common.py +86 -0
- ccxt/static_dependencies/lark/exceptions.py +292 -0
- ccxt/static_dependencies/lark/grammar.py +130 -0
- ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- ccxt/static_dependencies/lark/indenter.py +143 -0
- ccxt/static_dependencies/lark/lark.py +658 -0
- ccxt/static_dependencies/lark/lexer.py +678 -0
- ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- ccxt/static_dependencies/lark/reconstruct.py +107 -0
- ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- ccxt/static_dependencies/lark/tree.py +267 -0
- ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- ccxt/static_dependencies/lark/tree_templates.py +180 -0
- ccxt/static_dependencies/lark/utils.py +343 -0
- ccxt/static_dependencies/lark/visitors.py +596 -0
- ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- ccxt/static_dependencies/marshmallow/base.py +65 -0
- ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- ccxt/static_dependencies/marshmallow/types.py +12 -0
- ccxt/static_dependencies/marshmallow/utils.py +378 -0
- ccxt/static_dependencies/marshmallow/validate.py +678 -0
- ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- ccxt/static_dependencies/msgpack/__init__.py +55 -0
- ccxt/static_dependencies/msgpack/exceptions.py +48 -0
- ccxt/static_dependencies/msgpack/ext.py +168 -0
- ccxt/static_dependencies/msgpack/fallback.py +951 -0
- ccxt/static_dependencies/parsimonious/__init__.py +10 -0
- ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
- ccxt/static_dependencies/parsimonious/expressions.py +479 -0
- ccxt/static_dependencies/parsimonious/grammar.py +487 -0
- ccxt/static_dependencies/parsimonious/nodes.py +325 -0
- ccxt/static_dependencies/parsimonious/utils.py +40 -0
- ccxt/static_dependencies/starknet/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- ccxt/static_dependencies/starknet/common.py +15 -0
- ccxt/static_dependencies/starknet/constants.py +39 -0
- ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- ccxt/static_dependencies/starknet/hash/address.py +79 -0
- ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- ccxt/static_dependencies/starkware/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- ccxt/static_dependencies/sympy/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- ccxt/static_dependencies/toolz/__init__.py +26 -0
- ccxt/static_dependencies/toolz/_signatures.py +784 -0
- ccxt/static_dependencies/toolz/_version.py +520 -0
- ccxt/static_dependencies/toolz/compatibility.py +30 -0
- ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
- ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
- ccxt/static_dependencies/toolz/curried/operator.py +22 -0
- ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
- ccxt/static_dependencies/toolz/functoolz.py +1049 -0
- ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
- ccxt/static_dependencies/toolz/recipes.py +46 -0
- ccxt/static_dependencies/toolz/utils.py +9 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/tabdeal.py +364 -0
- ccxt/test/__init__.py +3 -0
- ccxt/test/base/__init__.py +29 -0
- ccxt/test/base/test_account.py +26 -0
- ccxt/test/base/test_balance.py +56 -0
- ccxt/test/base/test_borrow_interest.py +35 -0
- ccxt/test/base/test_borrow_rate.py +32 -0
- ccxt/test/base/test_calculate_fee.py +51 -0
- ccxt/test/base/test_crypto.py +127 -0
- ccxt/test/base/test_currency.py +76 -0
- ccxt/test/base/test_datetime.py +109 -0
- ccxt/test/base/test_decimal_to_precision.py +392 -0
- ccxt/test/base/test_deep_extend.py +68 -0
- ccxt/test/base/test_deposit_withdrawal.py +50 -0
- ccxt/test/base/test_exchange_datetime_functions.py +76 -0
- ccxt/test/base/test_funding_rate_history.py +29 -0
- ccxt/test/base/test_last_price.py +31 -0
- ccxt/test/base/test_ledger_entry.py +45 -0
- ccxt/test/base/test_ledger_item.py +48 -0
- ccxt/test/base/test_leverage_tier.py +33 -0
- ccxt/test/base/test_liquidation.py +50 -0
- ccxt/test/base/test_margin_mode.py +24 -0
- ccxt/test/base/test_margin_modification.py +35 -0
- ccxt/test/base/test_market.py +193 -0
- ccxt/test/base/test_number.py +411 -0
- ccxt/test/base/test_ohlcv.py +33 -0
- ccxt/test/base/test_open_interest.py +32 -0
- ccxt/test/base/test_order.py +64 -0
- ccxt/test/base/test_order_book.py +69 -0
- ccxt/test/base/test_position.py +60 -0
- ccxt/test/base/test_shared_methods.py +353 -0
- ccxt/test/base/test_status.py +24 -0
- ccxt/test/base/test_throttle.py +126 -0
- ccxt/test/base/test_ticker.py +92 -0
- ccxt/test/base/test_trade.py +47 -0
- ccxt/test/base/test_trading_fee.py +26 -0
- ccxt/test/base/test_transaction.py +39 -0
- ccxt/test/test_async.py +1649 -0
- ccxt/test/test_sync.py +1648 -0
- ccxt/test/tests_async.py +1558 -0
- ccxt/test/tests_helpers.py +287 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/tests_sync.py +1555 -0
- ccxt/tetherland.py +349 -0
- ccxt/timex.py +1593 -0
- ccxt/tokocrypto.py +2405 -0
- ccxt/tradeogre.py +608 -0
- ccxt/twox.py +326 -0
- ccxt/ubitex.py +409 -0
- ccxt/upbit.py +1833 -0
- ccxt/vertex.py +2922 -0
- ccxt/wallex.py +445 -0
- ccxt/wavesexchange.py +2472 -0
- ccxt/wazirx.py +1224 -0
- ccxt/whitebit.py +2469 -0
- ccxt/woo.py +3114 -0
- ccxt/woofipro.py +2533 -0
- ccxt/xt.py +4453 -0
- ccxt/yobit.py +1283 -0
- ccxt/zaif.py +725 -0
- ccxt/zonda.py +1828 -0
- ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
- ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
- ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
- ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
- ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,2894 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
|
4
|
+
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
|
5
|
+
|
|
6
|
+
from ccxt.async_support.base.exchange import Exchange
|
|
7
|
+
from ccxt.abstract.kraken import ImplicitAPI
|
|
8
|
+
import hashlib
|
|
9
|
+
from ccxt.base.types import Balances, Currencies, Currency, IndexType, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFeeInterface, 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 AccountSuspended
|
|
15
|
+
from ccxt.base.errors import ArgumentsRequired
|
|
16
|
+
from ccxt.base.errors import BadRequest
|
|
17
|
+
from ccxt.base.errors import BadSymbol
|
|
18
|
+
from ccxt.base.errors import InsufficientFunds
|
|
19
|
+
from ccxt.base.errors import InvalidAddress
|
|
20
|
+
from ccxt.base.errors import InvalidOrder
|
|
21
|
+
from ccxt.base.errors import OrderNotFound
|
|
22
|
+
from ccxt.base.errors import CancelPending
|
|
23
|
+
from ccxt.base.errors import NotSupported
|
|
24
|
+
from ccxt.base.errors import DDoSProtection
|
|
25
|
+
from ccxt.base.errors import RateLimitExceeded
|
|
26
|
+
from ccxt.base.errors import ExchangeNotAvailable
|
|
27
|
+
from ccxt.base.errors import OnMaintenance
|
|
28
|
+
from ccxt.base.errors import InvalidNonce
|
|
29
|
+
from ccxt.base.decimal_to_precision import TRUNCATE
|
|
30
|
+
from ccxt.base.decimal_to_precision import TICK_SIZE
|
|
31
|
+
from ccxt.base.precise import Precise
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class kraken(Exchange, ImplicitAPI):
|
|
35
|
+
|
|
36
|
+
def describe(self):
|
|
37
|
+
return self.deep_extend(super(kraken, self).describe(), {
|
|
38
|
+
'id': 'kraken',
|
|
39
|
+
'name': 'Kraken',
|
|
40
|
+
'countries': ['US'],
|
|
41
|
+
'version': '0',
|
|
42
|
+
# rate-limits: https://support.kraken.com/hc/en-us/articles/206548367-What-are-the-API-rate-limits-#1
|
|
43
|
+
# for public: 1 req/s
|
|
44
|
+
# for private: every second 0.33 weight added to your allowed capacity(some private endpoints need 1 weight, some need 2)
|
|
45
|
+
'rateLimit': 1000,
|
|
46
|
+
'certified': False,
|
|
47
|
+
'pro': True,
|
|
48
|
+
'has': {
|
|
49
|
+
'CORS': None,
|
|
50
|
+
'spot': True,
|
|
51
|
+
'margin': True,
|
|
52
|
+
'swap': False,
|
|
53
|
+
'future': False,
|
|
54
|
+
'option': False,
|
|
55
|
+
'addMargin': False,
|
|
56
|
+
'cancelAllOrders': True,
|
|
57
|
+
'cancelAllOrdersAfter': True,
|
|
58
|
+
'cancelOrder': True,
|
|
59
|
+
'cancelOrders': True,
|
|
60
|
+
'createDepositAddress': True,
|
|
61
|
+
'createMarketBuyOrderWithCost': True,
|
|
62
|
+
'createMarketOrderWithCost': False,
|
|
63
|
+
'createMarketSellOrderWithCost': False,
|
|
64
|
+
'createOrder': True,
|
|
65
|
+
'createStopLimitOrder': True,
|
|
66
|
+
'createStopMarketOrder': True,
|
|
67
|
+
'createStopOrder': True,
|
|
68
|
+
'createTrailingAmountOrder': True,
|
|
69
|
+
'editOrder': True,
|
|
70
|
+
'fetchBalance': True,
|
|
71
|
+
'fetchBorrowInterest': False,
|
|
72
|
+
'fetchBorrowRateHistories': False,
|
|
73
|
+
'fetchBorrowRateHistory': False,
|
|
74
|
+
'fetchClosedOrders': True,
|
|
75
|
+
'fetchCrossBorrowRate': False,
|
|
76
|
+
'fetchCrossBorrowRates': False,
|
|
77
|
+
'fetchCurrencies': True,
|
|
78
|
+
'fetchDepositAddress': True,
|
|
79
|
+
'fetchDeposits': True,
|
|
80
|
+
'fetchFundingHistory': False,
|
|
81
|
+
'fetchFundingRate': False,
|
|
82
|
+
'fetchFundingRateHistory': False,
|
|
83
|
+
'fetchFundingRates': False,
|
|
84
|
+
'fetchIndexOHLCV': False,
|
|
85
|
+
'fetchIsolatedBorrowRate': False,
|
|
86
|
+
'fetchIsolatedBorrowRates': False,
|
|
87
|
+
'fetchLedger': True,
|
|
88
|
+
'fetchLedgerEntry': True,
|
|
89
|
+
'fetchLeverageTiers': False,
|
|
90
|
+
'fetchMarkets': True,
|
|
91
|
+
'fetchMarkOHLCV': False,
|
|
92
|
+
'fetchMyTrades': True,
|
|
93
|
+
'fetchOHLCV': True,
|
|
94
|
+
'fetchOpenInterestHistory': False,
|
|
95
|
+
'fetchOpenOrders': True,
|
|
96
|
+
'fetchOrder': True,
|
|
97
|
+
'fetchOrderBook': True,
|
|
98
|
+
'fetchOrderTrades': 'emulated',
|
|
99
|
+
'fetchPositions': True,
|
|
100
|
+
'fetchPremiumIndexOHLCV': False,
|
|
101
|
+
'fetchTicker': True,
|
|
102
|
+
'fetchTickers': True,
|
|
103
|
+
'fetchTime': True,
|
|
104
|
+
'fetchTrades': True,
|
|
105
|
+
'fetchTradingFee': True,
|
|
106
|
+
'fetchTradingFees': False,
|
|
107
|
+
'fetchWithdrawals': True,
|
|
108
|
+
'setLeverage': False,
|
|
109
|
+
'setMarginMode': False, # Kraken only supports cross margin
|
|
110
|
+
'transfer': True,
|
|
111
|
+
'withdraw': True,
|
|
112
|
+
},
|
|
113
|
+
'timeframes': {
|
|
114
|
+
'1m': 1,
|
|
115
|
+
'5m': 5,
|
|
116
|
+
'15m': 15,
|
|
117
|
+
'30m': 30,
|
|
118
|
+
'1h': 60,
|
|
119
|
+
'4h': 240,
|
|
120
|
+
'1d': 1440,
|
|
121
|
+
'1w': 10080,
|
|
122
|
+
'2w': 21600,
|
|
123
|
+
},
|
|
124
|
+
'urls': {
|
|
125
|
+
'logo': 'https://user-images.githubusercontent.com/51840849/76173629-fc67fb00-61b1-11ea-84fe-f2de582f58a3.jpg',
|
|
126
|
+
'api': {
|
|
127
|
+
'public': 'https://api.kraken.com',
|
|
128
|
+
'private': 'https://api.kraken.com',
|
|
129
|
+
'zendesk': 'https://kraken.zendesk.com/api/v2/help_center/en-us/articles', # use the public zendesk api to receive article bodies and bypass new anti-spam protections
|
|
130
|
+
},
|
|
131
|
+
'www': 'https://www.kraken.com',
|
|
132
|
+
'doc': 'https://docs.kraken.com/rest/',
|
|
133
|
+
'fees': 'https://www.kraken.com/en-us/features/fee-schedule',
|
|
134
|
+
},
|
|
135
|
+
'fees': {
|
|
136
|
+
'trading': {
|
|
137
|
+
'tierBased': True,
|
|
138
|
+
'percentage': True,
|
|
139
|
+
'taker': self.parse_number('0.0026'),
|
|
140
|
+
'maker': self.parse_number('0.0016'),
|
|
141
|
+
'tiers': {
|
|
142
|
+
'taker': [
|
|
143
|
+
[self.parse_number('0'), self.parse_number('0.0026')],
|
|
144
|
+
[self.parse_number('50000'), self.parse_number('0.0024')],
|
|
145
|
+
[self.parse_number('100000'), self.parse_number('0.0022')],
|
|
146
|
+
[self.parse_number('250000'), self.parse_number('0.0020')],
|
|
147
|
+
[self.parse_number('500000'), self.parse_number('0.0018')],
|
|
148
|
+
[self.parse_number('1000000'), self.parse_number('0.0016')],
|
|
149
|
+
[self.parse_number('2500000'), self.parse_number('0.0014')],
|
|
150
|
+
[self.parse_number('5000000'), self.parse_number('0.0012')],
|
|
151
|
+
[self.parse_number('10000000'), self.parse_number('0.0001')],
|
|
152
|
+
],
|
|
153
|
+
'maker': [
|
|
154
|
+
[self.parse_number('0'), self.parse_number('0.0016')],
|
|
155
|
+
[self.parse_number('50000'), self.parse_number('0.0014')],
|
|
156
|
+
[self.parse_number('100000'), self.parse_number('0.0012')],
|
|
157
|
+
[self.parse_number('250000'), self.parse_number('0.0010')],
|
|
158
|
+
[self.parse_number('500000'), self.parse_number('0.0008')],
|
|
159
|
+
[self.parse_number('1000000'), self.parse_number('0.0006')],
|
|
160
|
+
[self.parse_number('2500000'), self.parse_number('0.0004')],
|
|
161
|
+
[self.parse_number('5000000'), self.parse_number('0.0002')],
|
|
162
|
+
[self.parse_number('10000000'), self.parse_number('0.0')],
|
|
163
|
+
],
|
|
164
|
+
},
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
'handleContentTypeApplicationZip': True,
|
|
168
|
+
'api': {
|
|
169
|
+
'zendesk': {
|
|
170
|
+
'get': [
|
|
171
|
+
# we should really refrain from putting fixed fee numbers and stop hardcoding
|
|
172
|
+
# we will be using their web APIs to scrape all numbers from these articles
|
|
173
|
+
'360000292886', # -What-are-the-deposit-fees-
|
|
174
|
+
'201893608', # -What-are-the-withdrawal-fees-
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
'public': {
|
|
178
|
+
'get': {
|
|
179
|
+
# rate-limits explained in comment in the top of self file
|
|
180
|
+
'Assets': 1,
|
|
181
|
+
'AssetPairs': 1,
|
|
182
|
+
'Depth': 1.2,
|
|
183
|
+
'OHLC': 1.2, # 1.2 because 1 triggers too many requests immediately
|
|
184
|
+
'Spread': 1,
|
|
185
|
+
'SystemStatus': 1,
|
|
186
|
+
'Ticker': 1,
|
|
187
|
+
'Time': 1,
|
|
188
|
+
'Trades': 1.2,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
'private': {
|
|
192
|
+
'post': {
|
|
193
|
+
'AddOrder': 0,
|
|
194
|
+
'AddOrderBatch': 0,
|
|
195
|
+
'AddExport': 3,
|
|
196
|
+
'Balance': 3,
|
|
197
|
+
'CancelAll': 3,
|
|
198
|
+
'CancelAllOrdersAfter': 3,
|
|
199
|
+
'CancelOrder': 0,
|
|
200
|
+
'CancelOrderBatch': 0,
|
|
201
|
+
'ClosedOrders': 3,
|
|
202
|
+
'DepositAddresses': 3,
|
|
203
|
+
'DepositMethods': 3,
|
|
204
|
+
'DepositStatus': 3,
|
|
205
|
+
'EditOrder': 0,
|
|
206
|
+
'ExportStatus': 3,
|
|
207
|
+
'GetWebSocketsToken': 3,
|
|
208
|
+
'Ledgers': 6,
|
|
209
|
+
'OpenOrders': 3,
|
|
210
|
+
'OpenPositions': 3,
|
|
211
|
+
'QueryLedgers': 3,
|
|
212
|
+
'QueryOrders': 3,
|
|
213
|
+
'QueryTrades': 3,
|
|
214
|
+
'RetrieveExport': 3,
|
|
215
|
+
'RemoveExport': 3,
|
|
216
|
+
'BalanceEx': 3,
|
|
217
|
+
'TradeBalance': 3,
|
|
218
|
+
'TradesHistory': 6,
|
|
219
|
+
'TradeVolume': 3,
|
|
220
|
+
'Withdraw': 3,
|
|
221
|
+
'WithdrawCancel': 3,
|
|
222
|
+
'WithdrawInfo': 3,
|
|
223
|
+
'WithdrawMethods': 3,
|
|
224
|
+
'WithdrawAddresses': 3,
|
|
225
|
+
'WithdrawStatus': 3,
|
|
226
|
+
'WalletTransfer': 3,
|
|
227
|
+
# sub accounts
|
|
228
|
+
'CreateSubaccount': 3,
|
|
229
|
+
'AccountTransfer': 3,
|
|
230
|
+
# earn
|
|
231
|
+
'Earn/Allocate': 3,
|
|
232
|
+
'Earn/Deallocate': 3,
|
|
233
|
+
'Earn/AllocateStatus': 3,
|
|
234
|
+
'Earn/DeallocateStatus': 3,
|
|
235
|
+
'Earn/Strategies': 3,
|
|
236
|
+
'Earn/Allocations': 3,
|
|
237
|
+
},
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
'commonCurrencies': {
|
|
241
|
+
'LUNA': 'LUNC',
|
|
242
|
+
'LUNA2': 'LUNA',
|
|
243
|
+
'REPV2': 'REP',
|
|
244
|
+
'REP': 'REPV1',
|
|
245
|
+
'UST': 'USTC',
|
|
246
|
+
'XBT': 'BTC',
|
|
247
|
+
'XBT.M': 'BTC.M', # https://support.kraken.com/hc/en-us/articles/360039879471-What-is-Asset-S-and-Asset-M-
|
|
248
|
+
'XDG': 'DOGE',
|
|
249
|
+
},
|
|
250
|
+
'options': {
|
|
251
|
+
'marketsByAltname': {},
|
|
252
|
+
'delistedMarketsById': {},
|
|
253
|
+
# cannot withdraw/deposit these
|
|
254
|
+
'inactiveCurrencies': ['CAD', 'USD', 'JPY', 'GBP'],
|
|
255
|
+
'networks': {
|
|
256
|
+
'ETH': 'ERC20',
|
|
257
|
+
'TRX': 'TRC20',
|
|
258
|
+
},
|
|
259
|
+
'depositMethods': {
|
|
260
|
+
'1INCH': '1inch(1INCH)',
|
|
261
|
+
'AAVE': 'Aave',
|
|
262
|
+
'ADA': 'ADA',
|
|
263
|
+
'ALGO': 'Algorand',
|
|
264
|
+
'ANKR': 'ANKR(ANKR)',
|
|
265
|
+
'ANT': 'Aragon(ANT)',
|
|
266
|
+
'ATOM': 'Cosmos',
|
|
267
|
+
'AXS': 'Axie Infinity Shards(AXS)',
|
|
268
|
+
'BADGER': 'Bager DAO(BADGER)',
|
|
269
|
+
'BAL': 'Balancer(BAL)',
|
|
270
|
+
'BAND': 'Band Protocol(BAND)',
|
|
271
|
+
'BAT': 'BAT',
|
|
272
|
+
'BCH': 'Bitcoin Cash',
|
|
273
|
+
'BNC': 'Bifrost(BNC)',
|
|
274
|
+
'BNT': 'Bancor(BNT)',
|
|
275
|
+
'BTC': 'Bitcoin',
|
|
276
|
+
'CHZ': 'Chiliz(CHZ)',
|
|
277
|
+
'COMP': 'Compound(COMP)',
|
|
278
|
+
'CQT': '\tCovalent Query Token(CQT)',
|
|
279
|
+
'CRV': 'Curve DAO Token(CRV)',
|
|
280
|
+
'CTSI': 'Cartesi(CTSI)',
|
|
281
|
+
'DAI': 'Dai',
|
|
282
|
+
'DASH': 'Dash',
|
|
283
|
+
'DOGE': 'Dogecoin',
|
|
284
|
+
'DOT': 'Polkadot',
|
|
285
|
+
'DYDX': 'dYdX(DYDX)',
|
|
286
|
+
'ENJ': 'Enjin Coin(ENJ)',
|
|
287
|
+
'EOS': 'EOS',
|
|
288
|
+
'ETC': 'Ether Classic(Hex)',
|
|
289
|
+
'ETH': 'Ether(Hex)',
|
|
290
|
+
'EWT': 'Energy Web Token',
|
|
291
|
+
'FEE': 'Kraken Fee Credit',
|
|
292
|
+
'FIL': 'Filecoin',
|
|
293
|
+
'FLOW': 'Flow',
|
|
294
|
+
'GHST': 'Aavegotchi(GHST)',
|
|
295
|
+
'GNO': 'GNO',
|
|
296
|
+
'GRT': 'GRT',
|
|
297
|
+
'ICX': 'Icon',
|
|
298
|
+
'INJ': 'Injective Protocol(INJ)',
|
|
299
|
+
'KAR': 'Karura(KAR)',
|
|
300
|
+
'KAVA': 'Kava',
|
|
301
|
+
'KEEP': 'Keep Token(KEEP)',
|
|
302
|
+
'KNC': 'Kyber Network(KNC)',
|
|
303
|
+
'KSM': 'Kusama',
|
|
304
|
+
'LINK': 'Link',
|
|
305
|
+
'LPT': 'Livepeer Token(LPT)',
|
|
306
|
+
'LRC': 'Loopring(LRC)',
|
|
307
|
+
'LSK': 'Lisk',
|
|
308
|
+
'LTC': 'Litecoin',
|
|
309
|
+
'MANA': 'MANA',
|
|
310
|
+
'MATIC': 'Polygon(MATIC)',
|
|
311
|
+
'MINA': 'Mina', # inspected from webui
|
|
312
|
+
'MIR': 'Mirror Protocol(MIR)',
|
|
313
|
+
'MKR': 'Maker(MKR)',
|
|
314
|
+
'MLN': 'MLN',
|
|
315
|
+
'MOVR': 'Moonriver(MOVR)',
|
|
316
|
+
'NANO': 'NANO',
|
|
317
|
+
'OCEAN': 'OCEAN',
|
|
318
|
+
'OGN': 'Origin Protocol(OGN)',
|
|
319
|
+
'OMG': 'OMG',
|
|
320
|
+
'OXT': 'Orchid(OXT)',
|
|
321
|
+
'OXY': 'Oxygen(OXY)',
|
|
322
|
+
'PAXG': 'PAX(Gold)',
|
|
323
|
+
'PERP': 'Perpetual Protocol(PERP)',
|
|
324
|
+
'PHA': 'Phala(PHA)',
|
|
325
|
+
'QTUM': 'QTUM',
|
|
326
|
+
'RARI': 'Rarible(RARI)',
|
|
327
|
+
'RAY': 'Raydium(RAY)',
|
|
328
|
+
'REN': 'Ren Protocol(REN)',
|
|
329
|
+
'REP': 'REPv2',
|
|
330
|
+
'REPV1': 'REP',
|
|
331
|
+
'SAND': 'The Sandbox(SAND)',
|
|
332
|
+
'SC': 'Siacoin',
|
|
333
|
+
'SDN': 'Shiden(SDN)',
|
|
334
|
+
'SOL': 'Solana', # their deposit method api doesn't work for SOL - was guessed
|
|
335
|
+
'SNX': 'Synthetix Network(SNX)',
|
|
336
|
+
'SRM': 'Serum', # inspected from webui
|
|
337
|
+
'STORJ': 'Storj(STORJ)',
|
|
338
|
+
'SUSHI': 'Sushiswap(SUSHI)',
|
|
339
|
+
'TBTC': 'tBTC',
|
|
340
|
+
'TRX': 'Tron',
|
|
341
|
+
'UNI': 'UNI',
|
|
342
|
+
'USDC': 'USDC',
|
|
343
|
+
'USDT': 'Tether USD(ERC20)',
|
|
344
|
+
'USDT-TRC20': 'Tether USD(TRC20)',
|
|
345
|
+
'WAVES': 'Waves',
|
|
346
|
+
'WBTC': 'Wrapped Bitcoin(WBTC)',
|
|
347
|
+
'XLM': 'Stellar XLM',
|
|
348
|
+
'XMR': 'Monero',
|
|
349
|
+
'XRP': 'Ripple XRP',
|
|
350
|
+
'XTZ': 'XTZ',
|
|
351
|
+
'YFI': 'YFI',
|
|
352
|
+
'ZEC': 'Zcash(Transparent)',
|
|
353
|
+
'ZRX': '0x(ZRX)',
|
|
354
|
+
},
|
|
355
|
+
'withdrawMethods': { # keeping it here because deposit and withdraw return different networks codes
|
|
356
|
+
'Lightning': 'Lightning',
|
|
357
|
+
'Bitcoin': 'BTC',
|
|
358
|
+
'Ripple': 'XRP',
|
|
359
|
+
'Litecoin': 'LTC',
|
|
360
|
+
'Dogecoin': 'DOGE',
|
|
361
|
+
'Stellar': 'XLM',
|
|
362
|
+
'Ethereum': 'ERC20',
|
|
363
|
+
'Arbitrum One': 'Arbitrum',
|
|
364
|
+
'Polygon': 'MATIC',
|
|
365
|
+
'Arbitrum Nova': 'Arbitrum',
|
|
366
|
+
'Optimism': 'Optimism',
|
|
367
|
+
'zkSync Era': 'zkSync',
|
|
368
|
+
'Ethereum Classic': 'ETC',
|
|
369
|
+
'Zcash': 'ZEC',
|
|
370
|
+
'Monero': 'XMR',
|
|
371
|
+
'Tron': 'TRC20',
|
|
372
|
+
'Solana': 'SOL',
|
|
373
|
+
'EOS': 'EOS',
|
|
374
|
+
'Bitcoin Cash': 'BCH',
|
|
375
|
+
'Cardano': 'ADA',
|
|
376
|
+
'Qtum': 'QTUM',
|
|
377
|
+
'Tezos': 'XTZ',
|
|
378
|
+
'Cosmos': 'ATOM',
|
|
379
|
+
'Nano': 'NANO',
|
|
380
|
+
'Siacoin': 'SC',
|
|
381
|
+
'Lisk': 'LSK',
|
|
382
|
+
'Waves': 'WAVES',
|
|
383
|
+
'ICON': 'ICX',
|
|
384
|
+
'Algorand': 'ALGO',
|
|
385
|
+
'Polygon - USDC.e': 'MATIC',
|
|
386
|
+
'Arbitrum One - USDC.e': 'Arbitrum',
|
|
387
|
+
'Polkadot': 'DOT',
|
|
388
|
+
'Kava': 'KAVA',
|
|
389
|
+
'Filecoin': 'FIL',
|
|
390
|
+
'Kusama': 'KSM',
|
|
391
|
+
'Flow': 'FLOW',
|
|
392
|
+
'Energy Web': 'EW',
|
|
393
|
+
'Mina': 'MINA',
|
|
394
|
+
'Centrifuge': 'CFG',
|
|
395
|
+
'Karura': 'KAR',
|
|
396
|
+
'Moonriver': 'MOVR',
|
|
397
|
+
'Shiden': 'SDN',
|
|
398
|
+
'Khala': 'PHA',
|
|
399
|
+
'Bifrost Kusama': 'BNC',
|
|
400
|
+
'Songbird': 'SGB',
|
|
401
|
+
'Terra classic': 'LUNC',
|
|
402
|
+
'KILT': 'KILT',
|
|
403
|
+
'Basilisk': 'BSX',
|
|
404
|
+
'Flare': 'FLR',
|
|
405
|
+
'Avalanche C-Chain': 'AVAX',
|
|
406
|
+
'Kintsugi': 'KINT',
|
|
407
|
+
'Altair': 'AIR',
|
|
408
|
+
'Moonbeam': 'GLMR',
|
|
409
|
+
'Acala': 'ACA',
|
|
410
|
+
'Astar': 'ASTR',
|
|
411
|
+
'Akash': 'AKT',
|
|
412
|
+
'Robonomics': 'XRT',
|
|
413
|
+
'Fantom': 'FTM',
|
|
414
|
+
'Elrond': 'EGLD',
|
|
415
|
+
'THORchain': 'RUNE',
|
|
416
|
+
'Secret': 'SCRT',
|
|
417
|
+
'Near': 'NEAR',
|
|
418
|
+
'Internet Computer Protocol': 'ICP',
|
|
419
|
+
'Picasso': 'PICA',
|
|
420
|
+
'Crust Shadow': 'CSM',
|
|
421
|
+
'Integritee': 'TEER',
|
|
422
|
+
'Parallel Finance': 'PARA',
|
|
423
|
+
'HydraDX': 'HDX',
|
|
424
|
+
'Interlay': 'INTR',
|
|
425
|
+
'Fetch.ai': 'FET',
|
|
426
|
+
'NYM': 'NYM',
|
|
427
|
+
'Terra 2.0': 'LUNA2',
|
|
428
|
+
'Juno': 'JUNO',
|
|
429
|
+
'Nodle': 'NODL',
|
|
430
|
+
'Stacks': 'STX',
|
|
431
|
+
'Ethereum PoW': 'ETHW',
|
|
432
|
+
'Aptos': 'APT',
|
|
433
|
+
'Sui': 'SUI',
|
|
434
|
+
'Genshiro': 'GENS',
|
|
435
|
+
'Aventus': 'AVT',
|
|
436
|
+
'Sei': 'SEI',
|
|
437
|
+
'OriginTrail': 'OTP',
|
|
438
|
+
'Celestia': 'TIA',
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
'precisionMode': TICK_SIZE,
|
|
442
|
+
'exceptions': {
|
|
443
|
+
'EQuery:Invalid asset pair': BadSymbol, # {"error":["EQuery:Invalid asset pair"]}
|
|
444
|
+
'EAPI:Invalid key': AuthenticationError,
|
|
445
|
+
'EFunding:Unknown withdraw key': InvalidAddress, # {"error":["EFunding:Unknown withdraw key"]}
|
|
446
|
+
'EFunding:Invalid amount': InsufficientFunds,
|
|
447
|
+
'EService:Unavailable': ExchangeNotAvailable,
|
|
448
|
+
'EDatabase:Internal error': ExchangeNotAvailable,
|
|
449
|
+
'EService:Busy': ExchangeNotAvailable,
|
|
450
|
+
'EQuery:Unknown asset': BadSymbol, # {"error":["EQuery:Unknown asset"]}
|
|
451
|
+
'EAPI:Rate limit exceeded': DDoSProtection,
|
|
452
|
+
'EOrder:Rate limit exceeded': DDoSProtection,
|
|
453
|
+
'EGeneral:Internal error': ExchangeNotAvailable,
|
|
454
|
+
'EGeneral:Temporary lockout': DDoSProtection,
|
|
455
|
+
'EGeneral:Permission denied': PermissionDenied,
|
|
456
|
+
'EOrder:Unknown order': InvalidOrder,
|
|
457
|
+
'EOrder:Order minimum not met': InvalidOrder,
|
|
458
|
+
'EGeneral:Invalid arguments': BadRequest,
|
|
459
|
+
'ESession:Invalid session': AuthenticationError,
|
|
460
|
+
'EAPI:Invalid nonce': InvalidNonce,
|
|
461
|
+
'EFunding:No funding method': BadRequest, # {"error":"EFunding:No funding method"}
|
|
462
|
+
'EFunding:Unknown asset': BadSymbol, # {"error":["EFunding:Unknown asset"]}
|
|
463
|
+
'EService:Market in post_only mode': OnMaintenance, # {"error":["EService:Market in post_only mode"]}
|
|
464
|
+
'EGeneral:Too many requests': DDoSProtection, # {"error":["EGeneral:Too many requests"]}
|
|
465
|
+
'ETrade:User Locked': AccountSuspended, # {"error":["ETrade:User Locked"]}
|
|
466
|
+
},
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
def fee_to_precision(self, symbol, fee):
|
|
470
|
+
return self.decimal_to_precision(fee, TRUNCATE, self.markets[symbol]['precision']['amount'], self.precisionMode)
|
|
471
|
+
|
|
472
|
+
async def fetch_markets(self, params={}) -> List[Market]:
|
|
473
|
+
"""
|
|
474
|
+
retrieves data on all markets for kraken
|
|
475
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTradableAssetPairs
|
|
476
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
477
|
+
:returns dict[]: an array of objects representing market data
|
|
478
|
+
"""
|
|
479
|
+
response = await self.publicGetAssetPairs(params)
|
|
480
|
+
#
|
|
481
|
+
# {
|
|
482
|
+
# "error": [],
|
|
483
|
+
# "result": {
|
|
484
|
+
# "ADAETH": {
|
|
485
|
+
# "altname": "ADAETH",
|
|
486
|
+
# "wsname": "ADA\/ETH",
|
|
487
|
+
# "aclass_base": "currency",
|
|
488
|
+
# "base": "ADA",
|
|
489
|
+
# "aclass_quote": "currency",
|
|
490
|
+
# "quote": "XETH",
|
|
491
|
+
# "lot": "unit",
|
|
492
|
+
# "pair_decimals": 7,
|
|
493
|
+
# "lot_decimals": 8,
|
|
494
|
+
# "lot_multiplier": 1,
|
|
495
|
+
# "leverage_buy": [],
|
|
496
|
+
# "leverage_sell": [],
|
|
497
|
+
# "fees": [
|
|
498
|
+
# [0, 0.26],
|
|
499
|
+
# [50000, 0.24],
|
|
500
|
+
# [100000, 0.22],
|
|
501
|
+
# [250000, 0.2],
|
|
502
|
+
# [500000, 0.18],
|
|
503
|
+
# [1000000, 0.16],
|
|
504
|
+
# [2500000, 0.14],
|
|
505
|
+
# [5000000, 0.12],
|
|
506
|
+
# [10000000, 0.1]
|
|
507
|
+
# ],
|
|
508
|
+
# "fees_maker": [
|
|
509
|
+
# [0, 0.16],
|
|
510
|
+
# [50000, 0.14],
|
|
511
|
+
# [100000, 0.12],
|
|
512
|
+
# [250000, 0.1],
|
|
513
|
+
# [500000, 0.08],
|
|
514
|
+
# [1000000, 0.06],
|
|
515
|
+
# [2500000, 0.04],
|
|
516
|
+
# [5000000, 0.02],
|
|
517
|
+
# [10000000, 0]
|
|
518
|
+
# ],
|
|
519
|
+
# "fee_volume_currency": "ZUSD",
|
|
520
|
+
# "margin_call": 80,
|
|
521
|
+
# "margin_stop": 40,
|
|
522
|
+
# "ordermin": "1"
|
|
523
|
+
# },
|
|
524
|
+
# }
|
|
525
|
+
# }
|
|
526
|
+
#
|
|
527
|
+
markets = self.safe_value(response, 'result', {})
|
|
528
|
+
keys = list(markets.keys())
|
|
529
|
+
result = []
|
|
530
|
+
for i in range(0, len(keys)):
|
|
531
|
+
id = keys[i]
|
|
532
|
+
market = markets[id]
|
|
533
|
+
baseId = self.safe_string(market, 'base')
|
|
534
|
+
quoteId = self.safe_string(market, 'quote')
|
|
535
|
+
base = self.safe_currency_code(baseId)
|
|
536
|
+
quote = self.safe_currency_code(quoteId)
|
|
537
|
+
darkpool = id.find('.d') >= 0
|
|
538
|
+
altname = self.safe_string(market, 'altname')
|
|
539
|
+
makerFees = self.safe_value(market, 'fees_maker', [])
|
|
540
|
+
firstMakerFee = self.safe_value(makerFees, 0, [])
|
|
541
|
+
firstMakerFeeRate = self.safe_string(firstMakerFee, 1)
|
|
542
|
+
maker = None
|
|
543
|
+
if firstMakerFeeRate is not None:
|
|
544
|
+
maker = self.parse_number(Precise.string_div(firstMakerFeeRate, '100'))
|
|
545
|
+
takerFees = self.safe_value(market, 'fees', [])
|
|
546
|
+
firstTakerFee = self.safe_value(takerFees, 0, [])
|
|
547
|
+
firstTakerFeeRate = self.safe_string(firstTakerFee, 1)
|
|
548
|
+
taker = None
|
|
549
|
+
if firstTakerFeeRate is not None:
|
|
550
|
+
taker = self.parse_number(Precise.string_div(firstTakerFeeRate, '100'))
|
|
551
|
+
leverageBuy = self.safe_value(market, 'leverage_buy', [])
|
|
552
|
+
leverageBuyLength = len(leverageBuy)
|
|
553
|
+
precisionPrice = self.parse_number(self.parse_precision(self.safe_string(market, 'pair_decimals')))
|
|
554
|
+
status = self.safe_string(market, 'status')
|
|
555
|
+
isActive = status == 'online'
|
|
556
|
+
result.append({
|
|
557
|
+
'id': id,
|
|
558
|
+
'wsId': self.safe_string(market, 'wsname'),
|
|
559
|
+
'symbol': altname if darkpool else (base + '/' + quote),
|
|
560
|
+
'base': base,
|
|
561
|
+
'quote': quote,
|
|
562
|
+
'settle': None,
|
|
563
|
+
'baseId': baseId,
|
|
564
|
+
'quoteId': quoteId,
|
|
565
|
+
'settleId': None,
|
|
566
|
+
'darkpool': darkpool,
|
|
567
|
+
'altname': market['altname'],
|
|
568
|
+
'type': 'spot',
|
|
569
|
+
'spot': True,
|
|
570
|
+
'margin': (leverageBuyLength > 0),
|
|
571
|
+
'swap': False,
|
|
572
|
+
'future': False,
|
|
573
|
+
'option': False,
|
|
574
|
+
'active': isActive,
|
|
575
|
+
'contract': False,
|
|
576
|
+
'linear': None,
|
|
577
|
+
'inverse': None,
|
|
578
|
+
'taker': taker,
|
|
579
|
+
'maker': maker,
|
|
580
|
+
'contractSize': None,
|
|
581
|
+
'expiry': None,
|
|
582
|
+
'expiryDatetime': None,
|
|
583
|
+
'strike': None,
|
|
584
|
+
'optionType': None,
|
|
585
|
+
'precision': {
|
|
586
|
+
'amount': self.parse_number(self.parse_precision(self.safe_string(market, 'lot_decimals'))),
|
|
587
|
+
'price': precisionPrice,
|
|
588
|
+
},
|
|
589
|
+
'limits': {
|
|
590
|
+
'leverage': {
|
|
591
|
+
'min': self.parse_number('1'),
|
|
592
|
+
'max': self.safe_number(leverageBuy, leverageBuyLength - 1, 1),
|
|
593
|
+
},
|
|
594
|
+
'amount': {
|
|
595
|
+
'min': self.safe_number(market, 'ordermin'),
|
|
596
|
+
'max': None,
|
|
597
|
+
},
|
|
598
|
+
'price': {
|
|
599
|
+
'min': precisionPrice,
|
|
600
|
+
'max': None,
|
|
601
|
+
},
|
|
602
|
+
'cost': {
|
|
603
|
+
'min': self.safe_number(market, 'costmin'),
|
|
604
|
+
'max': None,
|
|
605
|
+
},
|
|
606
|
+
},
|
|
607
|
+
'created': None,
|
|
608
|
+
'info': market,
|
|
609
|
+
})
|
|
610
|
+
result = self.append_inactive_markets(result)
|
|
611
|
+
self.options['marketsByAltname'] = self.index_by(result, 'altname')
|
|
612
|
+
return result
|
|
613
|
+
|
|
614
|
+
def safe_currency(self, currencyId, currency: Currency = None):
|
|
615
|
+
if currencyId is not None:
|
|
616
|
+
if len(currencyId) > 3:
|
|
617
|
+
if (currencyId.find('X') == 0) or (currencyId.find('Z') == 0):
|
|
618
|
+
if not (currencyId.find('.') > 0):
|
|
619
|
+
currencyId = currencyId[1:]
|
|
620
|
+
return super(kraken, self).safe_currency(currencyId, currency)
|
|
621
|
+
|
|
622
|
+
def append_inactive_markets(self, result):
|
|
623
|
+
# result should be an array to append to
|
|
624
|
+
precision: dict = {
|
|
625
|
+
'amount': self.parse_number('1e-8'),
|
|
626
|
+
'price': self.parse_number('1e-8'),
|
|
627
|
+
}
|
|
628
|
+
costLimits: dict = {'min': None, 'max': None}
|
|
629
|
+
priceLimits: dict = {'min': precision['price'], 'max': None}
|
|
630
|
+
amountLimits: dict = {'min': precision['amount'], 'max': None}
|
|
631
|
+
limits: dict = {'amount': amountLimits, 'price': priceLimits, 'cost': costLimits}
|
|
632
|
+
defaults: dict = {
|
|
633
|
+
'darkpool': False,
|
|
634
|
+
'info': None,
|
|
635
|
+
'maker': None,
|
|
636
|
+
'taker': None,
|
|
637
|
+
'active': False,
|
|
638
|
+
'precision': precision,
|
|
639
|
+
'limits': limits,
|
|
640
|
+
}
|
|
641
|
+
markets = [
|
|
642
|
+
# {'id': 'XXLMZEUR', 'symbol': 'XLM/EUR', 'base': 'XLM', 'quote': 'EUR', 'altname': 'XLMEUR'},
|
|
643
|
+
]
|
|
644
|
+
for i in range(0, len(markets)):
|
|
645
|
+
result.append(self.extend(defaults, markets[i]))
|
|
646
|
+
return result
|
|
647
|
+
|
|
648
|
+
async def fetch_currencies(self, params={}) -> Currencies:
|
|
649
|
+
"""
|
|
650
|
+
fetches all available currencies on an exchange
|
|
651
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getAssetInfo
|
|
652
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
653
|
+
:returns dict: an associative dictionary of currencies
|
|
654
|
+
"""
|
|
655
|
+
response = await self.publicGetAssets(params)
|
|
656
|
+
#
|
|
657
|
+
# {
|
|
658
|
+
# "error": [],
|
|
659
|
+
# "result": {
|
|
660
|
+
# "BCH": {
|
|
661
|
+
# "aclass": "currency",
|
|
662
|
+
# "altname": "BCH",
|
|
663
|
+
# "decimals": 10,
|
|
664
|
+
# "display_decimals": 5
|
|
665
|
+
# "status": "enabled",
|
|
666
|
+
# },
|
|
667
|
+
# ...
|
|
668
|
+
# },
|
|
669
|
+
# }
|
|
670
|
+
#
|
|
671
|
+
currencies = self.safe_value(response, 'result', {})
|
|
672
|
+
ids = list(currencies.keys())
|
|
673
|
+
result: dict = {}
|
|
674
|
+
for i in range(0, len(ids)):
|
|
675
|
+
id = ids[i]
|
|
676
|
+
currency = currencies[id]
|
|
677
|
+
# todo: will need to rethink the fees
|
|
678
|
+
# see: https://support.kraken.com/hc/en-us/articles/201893608-What-are-the-withdrawal-fees-
|
|
679
|
+
# to add support for multiple withdrawal/deposit methods and
|
|
680
|
+
# differentiated fees for each particular method
|
|
681
|
+
code = self.safe_currency_code(id)
|
|
682
|
+
precision = self.parse_number(self.parse_precision(self.safe_string(currency, 'decimals')))
|
|
683
|
+
# assumes all currencies are active except those listed above
|
|
684
|
+
active = self.safe_string(currency, 'status') == 'enabled'
|
|
685
|
+
result[code] = {
|
|
686
|
+
'id': id,
|
|
687
|
+
'code': code,
|
|
688
|
+
'info': currency,
|
|
689
|
+
'name': self.safe_string(currency, 'altname'),
|
|
690
|
+
'active': active,
|
|
691
|
+
'deposit': None,
|
|
692
|
+
'withdraw': None,
|
|
693
|
+
'fee': None,
|
|
694
|
+
'precision': precision,
|
|
695
|
+
'limits': {
|
|
696
|
+
'amount': {
|
|
697
|
+
'min': precision,
|
|
698
|
+
'max': None,
|
|
699
|
+
},
|
|
700
|
+
'withdraw': {
|
|
701
|
+
'min': None,
|
|
702
|
+
'max': None,
|
|
703
|
+
},
|
|
704
|
+
},
|
|
705
|
+
'networks': {},
|
|
706
|
+
}
|
|
707
|
+
return result
|
|
708
|
+
|
|
709
|
+
async def fetch_trading_fee(self, symbol: str, params={}) -> TradingFeeInterface:
|
|
710
|
+
"""
|
|
711
|
+
fetch the trading fees for a market
|
|
712
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeVolume
|
|
713
|
+
:param str symbol: unified market symbol
|
|
714
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
715
|
+
:returns dict: a `fee structure <https://docs.ccxt.com/#/?id=fee-structure>`
|
|
716
|
+
"""
|
|
717
|
+
await self.load_markets()
|
|
718
|
+
market = self.market(symbol)
|
|
719
|
+
request: dict = {
|
|
720
|
+
'pair': market['id'],
|
|
721
|
+
'fee-info': True,
|
|
722
|
+
}
|
|
723
|
+
response = await self.privatePostTradeVolume(self.extend(request, params))
|
|
724
|
+
#
|
|
725
|
+
# {
|
|
726
|
+
# "error": [],
|
|
727
|
+
# "result": {
|
|
728
|
+
# "currency": 'ZUSD',
|
|
729
|
+
# "volume": '0.0000',
|
|
730
|
+
# "fees": {
|
|
731
|
+
# "XXBTZUSD": {
|
|
732
|
+
# "fee": '0.2600',
|
|
733
|
+
# "minfee": '0.1000',
|
|
734
|
+
# "maxfee": '0.2600',
|
|
735
|
+
# "nextfee": '0.2400',
|
|
736
|
+
# "tiervolume": '0.0000',
|
|
737
|
+
# "nextvolume": '50000.0000'
|
|
738
|
+
# }
|
|
739
|
+
# },
|
|
740
|
+
# "fees_maker": {
|
|
741
|
+
# "XXBTZUSD": {
|
|
742
|
+
# "fee": '0.1600',
|
|
743
|
+
# "minfee": '0.0000',
|
|
744
|
+
# "maxfee": '0.1600',
|
|
745
|
+
# "nextfee": '0.1400',
|
|
746
|
+
# "tiervolume": '0.0000',
|
|
747
|
+
# "nextvolume": '50000.0000'
|
|
748
|
+
# }
|
|
749
|
+
# }
|
|
750
|
+
# }
|
|
751
|
+
# }
|
|
752
|
+
#
|
|
753
|
+
result = self.safe_value(response, 'result', {})
|
|
754
|
+
return self.parse_trading_fee(result, market)
|
|
755
|
+
|
|
756
|
+
def parse_trading_fee(self, response, market):
|
|
757
|
+
makerFees = self.safe_value(response, 'fees_maker', {})
|
|
758
|
+
takerFees = self.safe_value(response, 'fees', {})
|
|
759
|
+
symbolMakerFee = self.safe_value(makerFees, market['id'], {})
|
|
760
|
+
symbolTakerFee = self.safe_value(takerFees, market['id'], {})
|
|
761
|
+
return {
|
|
762
|
+
'info': response,
|
|
763
|
+
'symbol': market['symbol'],
|
|
764
|
+
'maker': self.parse_number(Precise.string_div(self.safe_string(symbolMakerFee, 'fee'), '100')),
|
|
765
|
+
'taker': self.parse_number(Precise.string_div(self.safe_string(symbolTakerFee, 'fee'), '100')),
|
|
766
|
+
'percentage': True,
|
|
767
|
+
'tierBased': True,
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
def parse_bid_ask(self, bidask, priceKey: IndexType = 0, amountKey: IndexType = 1, countOrIdKey: IndexType = 2):
|
|
771
|
+
price = self.safe_number(bidask, priceKey)
|
|
772
|
+
amount = self.safe_number(bidask, amountKey)
|
|
773
|
+
timestamp = self.safe_integer(bidask, 2)
|
|
774
|
+
return [price, amount, timestamp]
|
|
775
|
+
|
|
776
|
+
async def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
|
777
|
+
"""
|
|
778
|
+
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
779
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOrderBook
|
|
780
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
|
781
|
+
:param int [limit]: the maximum amount of order book entries to return
|
|
782
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
783
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
784
|
+
"""
|
|
785
|
+
await self.load_markets()
|
|
786
|
+
market = self.market(symbol)
|
|
787
|
+
if market['darkpool']:
|
|
788
|
+
raise ExchangeError(self.id + ' fetchOrderBook() does not provide an order book for darkpool symbol ' + symbol)
|
|
789
|
+
request: dict = {
|
|
790
|
+
'pair': market['id'],
|
|
791
|
+
}
|
|
792
|
+
if limit is not None:
|
|
793
|
+
request['count'] = limit # 100
|
|
794
|
+
response = await self.publicGetDepth(self.extend(request, params))
|
|
795
|
+
#
|
|
796
|
+
# {
|
|
797
|
+
# "error":[],
|
|
798
|
+
# "result":{
|
|
799
|
+
# "XETHXXBT":{
|
|
800
|
+
# "asks":[
|
|
801
|
+
# ["0.023480","4.000",1586321307],
|
|
802
|
+
# ["0.023490","50.095",1586321306],
|
|
803
|
+
# ["0.023500","28.535",1586321302],
|
|
804
|
+
# ],
|
|
805
|
+
# "bids":[
|
|
806
|
+
# ["0.023470","59.580",1586321307],
|
|
807
|
+
# ["0.023460","20.000",1586321301],
|
|
808
|
+
# ["0.023440","67.832",1586321306],
|
|
809
|
+
# ]
|
|
810
|
+
# }
|
|
811
|
+
# }
|
|
812
|
+
# }
|
|
813
|
+
#
|
|
814
|
+
result = self.safe_value(response, 'result', {})
|
|
815
|
+
orderbook = self.safe_value(result, market['id'])
|
|
816
|
+
# sometimes kraken returns wsname instead of market id
|
|
817
|
+
# https://github.com/ccxt/ccxt/issues/8662
|
|
818
|
+
marketInfo = self.safe_value(market, 'info', {})
|
|
819
|
+
wsName = self.safe_value(marketInfo, 'wsname')
|
|
820
|
+
if wsName is not None:
|
|
821
|
+
orderbook = self.safe_value(result, wsName, orderbook)
|
|
822
|
+
return self.parse_order_book(orderbook, symbol)
|
|
823
|
+
|
|
824
|
+
def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
|
|
825
|
+
#
|
|
826
|
+
# {
|
|
827
|
+
# "a":["2432.77000","1","1.000"],
|
|
828
|
+
# "b":["2431.37000","2","2.000"],
|
|
829
|
+
# "c":["2430.58000","0.04408910"],
|
|
830
|
+
# "v":["4147.94474901","8896.96086304"],
|
|
831
|
+
# "p":["2456.22239","2568.63032"],
|
|
832
|
+
# "t":[3907,10056],
|
|
833
|
+
# "l":["2302.18000","2302.18000"],
|
|
834
|
+
# "h":["2621.14000","2860.01000"],
|
|
835
|
+
# "o":"2571.56000"
|
|
836
|
+
# }
|
|
837
|
+
#
|
|
838
|
+
symbol = self.safe_symbol(None, market)
|
|
839
|
+
v = self.safe_value(ticker, 'v', [])
|
|
840
|
+
baseVolume = self.safe_string(v, 1)
|
|
841
|
+
p = self.safe_value(ticker, 'p', [])
|
|
842
|
+
vwap = self.safe_string(p, 1)
|
|
843
|
+
quoteVolume = Precise.string_mul(baseVolume, vwap)
|
|
844
|
+
c = self.safe_value(ticker, 'c', [])
|
|
845
|
+
last = self.safe_string(c, 0)
|
|
846
|
+
high = self.safe_value(ticker, 'h', [])
|
|
847
|
+
low = self.safe_value(ticker, 'l', [])
|
|
848
|
+
bid = self.safe_value(ticker, 'b', [])
|
|
849
|
+
ask = self.safe_value(ticker, 'a', [])
|
|
850
|
+
return self.safe_ticker({
|
|
851
|
+
'symbol': symbol,
|
|
852
|
+
'timestamp': None,
|
|
853
|
+
'datetime': None,
|
|
854
|
+
'high': self.safe_string(high, 1),
|
|
855
|
+
'low': self.safe_string(low, 1),
|
|
856
|
+
'bid': self.safe_string(bid, 0),
|
|
857
|
+
'bidVolume': None,
|
|
858
|
+
'ask': self.safe_string(ask, 0),
|
|
859
|
+
'askVolume': None,
|
|
860
|
+
'vwap': vwap,
|
|
861
|
+
'open': self.safe_string(ticker, 'o'),
|
|
862
|
+
'close': last,
|
|
863
|
+
'last': last,
|
|
864
|
+
'previousClose': None,
|
|
865
|
+
'change': None,
|
|
866
|
+
'percentage': None,
|
|
867
|
+
'average': None,
|
|
868
|
+
'baseVolume': baseVolume,
|
|
869
|
+
'quoteVolume': quoteVolume,
|
|
870
|
+
'info': ticker,
|
|
871
|
+
}, market)
|
|
872
|
+
|
|
873
|
+
async def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
874
|
+
"""
|
|
875
|
+
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
876
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
|
|
877
|
+
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
878
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
879
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
880
|
+
"""
|
|
881
|
+
await self.load_markets()
|
|
882
|
+
request: dict = {}
|
|
883
|
+
if symbols is not None:
|
|
884
|
+
symbols = self.market_symbols(symbols)
|
|
885
|
+
marketIds = []
|
|
886
|
+
for i in range(0, len(symbols)):
|
|
887
|
+
symbol = symbols[i]
|
|
888
|
+
market = self.markets[symbol]
|
|
889
|
+
if market['active'] and not market['darkpool']:
|
|
890
|
+
marketIds.append(market['id'])
|
|
891
|
+
request['pair'] = ','.join(marketIds)
|
|
892
|
+
response = await self.publicGetTicker(self.extend(request, params))
|
|
893
|
+
tickers = response['result']
|
|
894
|
+
ids = list(tickers.keys())
|
|
895
|
+
result: dict = {}
|
|
896
|
+
for i in range(0, len(ids)):
|
|
897
|
+
id = ids[i]
|
|
898
|
+
market = self.safe_market(id)
|
|
899
|
+
symbol = market['symbol']
|
|
900
|
+
ticker = tickers[id]
|
|
901
|
+
result[symbol] = self.parse_ticker(ticker, market)
|
|
902
|
+
return self.filter_by_array_tickers(result, 'symbol', symbols)
|
|
903
|
+
|
|
904
|
+
async def fetch_ticker(self, symbol: str, params={}) -> Ticker:
|
|
905
|
+
"""
|
|
906
|
+
fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
907
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getTickerInformation
|
|
908
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
909
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
910
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
911
|
+
"""
|
|
912
|
+
await self.load_markets()
|
|
913
|
+
darkpool = symbol.find('.d') >= 0
|
|
914
|
+
if darkpool:
|
|
915
|
+
raise ExchangeError(self.id + ' fetchTicker() does not provide a ticker for darkpool symbol ' + symbol)
|
|
916
|
+
market = self.market(symbol)
|
|
917
|
+
request: dict = {
|
|
918
|
+
'pair': market['id'],
|
|
919
|
+
}
|
|
920
|
+
response = await self.publicGetTicker(self.extend(request, params))
|
|
921
|
+
ticker = response['result'][market['id']]
|
|
922
|
+
return self.parse_ticker(ticker, market)
|
|
923
|
+
|
|
924
|
+
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
|
925
|
+
#
|
|
926
|
+
# [
|
|
927
|
+
# 1591475640,
|
|
928
|
+
# "0.02500",
|
|
929
|
+
# "0.02500",
|
|
930
|
+
# "0.02500",
|
|
931
|
+
# "0.02500",
|
|
932
|
+
# "0.02500",
|
|
933
|
+
# "9.12201000",
|
|
934
|
+
# 5
|
|
935
|
+
# ]
|
|
936
|
+
#
|
|
937
|
+
return [
|
|
938
|
+
self.safe_timestamp(ohlcv, 0),
|
|
939
|
+
self.safe_number(ohlcv, 1),
|
|
940
|
+
self.safe_number(ohlcv, 2),
|
|
941
|
+
self.safe_number(ohlcv, 3),
|
|
942
|
+
self.safe_number(ohlcv, 4),
|
|
943
|
+
self.safe_number(ohlcv, 6),
|
|
944
|
+
]
|
|
945
|
+
|
|
946
|
+
async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
947
|
+
"""
|
|
948
|
+
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
949
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getOHLCData
|
|
950
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
951
|
+
:param str timeframe: the length of time each candle represents
|
|
952
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
953
|
+
:param int [limit]: the maximum amount of candles to fetch
|
|
954
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
955
|
+
:param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times. See in the docs all the [availble parameters](https://github.com/ccxt/ccxt/wiki/Manual#pagination-params)
|
|
956
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
957
|
+
"""
|
|
958
|
+
await self.load_markets()
|
|
959
|
+
paginate = False
|
|
960
|
+
paginate, params = self.handle_option_and_params(params, 'fetchOHLCV', 'paginate')
|
|
961
|
+
if paginate:
|
|
962
|
+
return await self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 720)
|
|
963
|
+
market = self.market(symbol)
|
|
964
|
+
parsedTimeframe = self.safe_integer(self.timeframes, timeframe)
|
|
965
|
+
request: dict = {
|
|
966
|
+
'pair': market['id'],
|
|
967
|
+
}
|
|
968
|
+
if parsedTimeframe is not None:
|
|
969
|
+
request['interval'] = parsedTimeframe
|
|
970
|
+
else:
|
|
971
|
+
request['interval'] = timeframe
|
|
972
|
+
if since is not None:
|
|
973
|
+
scaledSince = self.parse_to_int(since / 1000)
|
|
974
|
+
timeFrameInSeconds = parsedTimeframe * 60
|
|
975
|
+
request['since'] = self.number_to_string(scaledSince - timeFrameInSeconds) # expected to be in seconds
|
|
976
|
+
response = await self.publicGetOHLC(self.extend(request, params))
|
|
977
|
+
#
|
|
978
|
+
# {
|
|
979
|
+
# "error":[],
|
|
980
|
+
# "result":{
|
|
981
|
+
# "XETHXXBT":[
|
|
982
|
+
# [1591475580,"0.02499","0.02499","0.02499","0.02499","0.00000","0.00000000",0],
|
|
983
|
+
# [1591475640,"0.02500","0.02500","0.02500","0.02500","0.02500","9.12201000",5],
|
|
984
|
+
# [1591475700,"0.02499","0.02499","0.02499","0.02499","0.02499","1.28681415",2],
|
|
985
|
+
# [1591475760,"0.02499","0.02499","0.02499","0.02499","0.02499","0.08800000",1],
|
|
986
|
+
# ],
|
|
987
|
+
# "last":1591517580
|
|
988
|
+
# }
|
|
989
|
+
# }
|
|
990
|
+
result = self.safe_value(response, 'result', {})
|
|
991
|
+
ohlcvs = self.safe_list(result, market['id'], [])
|
|
992
|
+
return self.parse_ohlcvs(ohlcvs, market, timeframe, since, limit)
|
|
993
|
+
|
|
994
|
+
def parse_ledger_entry_type(self, type):
|
|
995
|
+
types: dict = {
|
|
996
|
+
'trade': 'trade',
|
|
997
|
+
'withdrawal': 'transaction',
|
|
998
|
+
'deposit': 'transaction',
|
|
999
|
+
'transfer': 'transfer',
|
|
1000
|
+
'margin': 'margin',
|
|
1001
|
+
}
|
|
1002
|
+
return self.safe_string(types, type, type)
|
|
1003
|
+
|
|
1004
|
+
def parse_ledger_entry(self, item: dict, currency: Currency = None):
|
|
1005
|
+
#
|
|
1006
|
+
# {
|
|
1007
|
+
# 'LTFK7F-N2CUX-PNY4SX': {
|
|
1008
|
+
# "refid": "TSJTGT-DT7WN-GPPQMJ",
|
|
1009
|
+
# "time": 1520102320.555,
|
|
1010
|
+
# "type": "trade",
|
|
1011
|
+
# "aclass": "currency",
|
|
1012
|
+
# "asset": "XETH",
|
|
1013
|
+
# "amount": "0.1087194600",
|
|
1014
|
+
# "fee": "0.0000000000",
|
|
1015
|
+
# "balance": "0.2855851000"
|
|
1016
|
+
# },
|
|
1017
|
+
# ...
|
|
1018
|
+
# }
|
|
1019
|
+
#
|
|
1020
|
+
id = self.safe_string(item, 'id')
|
|
1021
|
+
direction = None
|
|
1022
|
+
account = None
|
|
1023
|
+
referenceId = self.safe_string(item, 'refid')
|
|
1024
|
+
referenceAccount = None
|
|
1025
|
+
type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
|
|
1026
|
+
code = self.safe_currency_code(self.safe_string(item, 'asset'), currency)
|
|
1027
|
+
amount = self.safe_string(item, 'amount')
|
|
1028
|
+
if Precise.string_lt(amount, '0'):
|
|
1029
|
+
direction = 'out'
|
|
1030
|
+
amount = Precise.string_abs(amount)
|
|
1031
|
+
else:
|
|
1032
|
+
direction = 'in'
|
|
1033
|
+
timestamp = self.safe_timestamp(item, 'time')
|
|
1034
|
+
return {
|
|
1035
|
+
'info': item,
|
|
1036
|
+
'id': id,
|
|
1037
|
+
'direction': direction,
|
|
1038
|
+
'account': account,
|
|
1039
|
+
'referenceId': referenceId,
|
|
1040
|
+
'referenceAccount': referenceAccount,
|
|
1041
|
+
'type': type,
|
|
1042
|
+
'currency': code,
|
|
1043
|
+
'amount': self.parse_number(amount),
|
|
1044
|
+
'before': None,
|
|
1045
|
+
'after': self.safe_number(item, 'balance'),
|
|
1046
|
+
'status': 'ok',
|
|
1047
|
+
'timestamp': timestamp,
|
|
1048
|
+
'datetime': self.iso8601(timestamp),
|
|
1049
|
+
'fee': {
|
|
1050
|
+
'cost': self.safe_number(item, 'fee'),
|
|
1051
|
+
'currency': code,
|
|
1052
|
+
},
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
async def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1056
|
+
"""
|
|
1057
|
+
fetch the history of changes, actions done by the user or operations that altered balance of the user
|
|
1058
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getLedgers
|
|
1059
|
+
:param str code: unified currency code, default is None
|
|
1060
|
+
:param int [since]: timestamp in ms of the earliest ledger entry, default is None
|
|
1061
|
+
:param int [limit]: max number of ledger entrys to return, default is None
|
|
1062
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1063
|
+
:param int [params.until]: timestamp in ms of the latest ledger entry
|
|
1064
|
+
:returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
|
|
1065
|
+
"""
|
|
1066
|
+
# https://www.kraken.com/features/api#get-ledgers-info
|
|
1067
|
+
await self.load_markets()
|
|
1068
|
+
request: dict = {}
|
|
1069
|
+
currency = None
|
|
1070
|
+
if code is not None:
|
|
1071
|
+
currency = self.currency(code)
|
|
1072
|
+
request['asset'] = currency['id']
|
|
1073
|
+
if since is not None:
|
|
1074
|
+
request['start'] = self.parse_to_int(since / 1000)
|
|
1075
|
+
request, params = self.handle_until_option('end', request, params)
|
|
1076
|
+
response = await self.privatePostLedgers(self.extend(request, params))
|
|
1077
|
+
# { error: [],
|
|
1078
|
+
# "result": {ledger: {'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
|
|
1079
|
+
# "time": 1520103488.314,
|
|
1080
|
+
# "type": "withdrawal",
|
|
1081
|
+
# "aclass": "currency",
|
|
1082
|
+
# "asset": "XETH",
|
|
1083
|
+
# "amount": "-0.2805800000",
|
|
1084
|
+
# "fee": "0.0050000000",
|
|
1085
|
+
# "balance": "0.0000051000" },
|
|
1086
|
+
result = self.safe_value(response, 'result', {})
|
|
1087
|
+
ledger = self.safe_value(result, 'ledger', {})
|
|
1088
|
+
keys = list(ledger.keys())
|
|
1089
|
+
items = []
|
|
1090
|
+
for i in range(0, len(keys)):
|
|
1091
|
+
key = keys[i]
|
|
1092
|
+
value = ledger[key]
|
|
1093
|
+
value['id'] = key
|
|
1094
|
+
items.append(value)
|
|
1095
|
+
return self.parse_ledger(items, currency, since, limit)
|
|
1096
|
+
|
|
1097
|
+
async def fetch_ledger_entries_by_ids(self, ids, code: Str = None, params={}):
|
|
1098
|
+
# https://www.kraken.com/features/api#query-ledgers
|
|
1099
|
+
await self.load_markets()
|
|
1100
|
+
ids = ','.join(ids)
|
|
1101
|
+
request = self.extend({
|
|
1102
|
+
'id': ids,
|
|
1103
|
+
}, params)
|
|
1104
|
+
response = await self.privatePostQueryLedgers(request)
|
|
1105
|
+
# { error: [],
|
|
1106
|
+
# "result": {'LPUAIB-TS774-UKHP7X': { refid: "A2B4HBV-L4MDIE-JU4N3N",
|
|
1107
|
+
# "time": 1520103488.314,
|
|
1108
|
+
# "type": "withdrawal",
|
|
1109
|
+
# "aclass": "currency",
|
|
1110
|
+
# "asset": "XETH",
|
|
1111
|
+
# "amount": "-0.2805800000",
|
|
1112
|
+
# "fee": "0.0050000000",
|
|
1113
|
+
# "balance": "0.0000051000" }}}
|
|
1114
|
+
result = response['result']
|
|
1115
|
+
keys = list(result.keys())
|
|
1116
|
+
items = []
|
|
1117
|
+
for i in range(0, len(keys)):
|
|
1118
|
+
key = keys[i]
|
|
1119
|
+
value = result[key]
|
|
1120
|
+
value['id'] = key
|
|
1121
|
+
items.append(value)
|
|
1122
|
+
return self.parse_ledger(items)
|
|
1123
|
+
|
|
1124
|
+
async def fetch_ledger_entry(self, id: str, code: Str = None, params={}):
|
|
1125
|
+
items = await self.fetch_ledger_entries_by_ids([id], code, params)
|
|
1126
|
+
return items[0]
|
|
1127
|
+
|
|
1128
|
+
def parse_trade(self, trade: dict, market: Market = None) -> Trade:
|
|
1129
|
+
#
|
|
1130
|
+
# fetchTrades(public)
|
|
1131
|
+
#
|
|
1132
|
+
# [
|
|
1133
|
+
# "0.032310", # price
|
|
1134
|
+
# "4.28169434", # amount
|
|
1135
|
+
# 1541390792.763, # timestamp
|
|
1136
|
+
# "s", # sell or buy
|
|
1137
|
+
# "l", # limit or market
|
|
1138
|
+
# ""
|
|
1139
|
+
# ]
|
|
1140
|
+
#
|
|
1141
|
+
# fetchOrderTrades(private)
|
|
1142
|
+
#
|
|
1143
|
+
# {
|
|
1144
|
+
# "id": 'TIMIRG-WUNNE-RRJ6GT', # injected from outside
|
|
1145
|
+
# "ordertxid": 'OQRPN2-LRHFY-HIFA7D',
|
|
1146
|
+
# "postxid": 'TKH2SE-M7IF5-CFI7LT',
|
|
1147
|
+
# "pair": 'USDCUSDT',
|
|
1148
|
+
# "time": 1586340086.457,
|
|
1149
|
+
# "type": 'sell',
|
|
1150
|
+
# "ordertype": 'market',
|
|
1151
|
+
# "price": '0.99860000',
|
|
1152
|
+
# "cost": '22.16892001',
|
|
1153
|
+
# "fee": '0.04433784',
|
|
1154
|
+
# "vol": '22.20000000',
|
|
1155
|
+
# "margin": '0.00000000',
|
|
1156
|
+
# "misc": ''
|
|
1157
|
+
# }
|
|
1158
|
+
#
|
|
1159
|
+
timestamp = None
|
|
1160
|
+
side = None
|
|
1161
|
+
type = None
|
|
1162
|
+
price = None
|
|
1163
|
+
amount = None
|
|
1164
|
+
id = None
|
|
1165
|
+
orderId = None
|
|
1166
|
+
fee = None
|
|
1167
|
+
symbol = None
|
|
1168
|
+
if isinstance(trade, list):
|
|
1169
|
+
timestamp = self.safe_timestamp(trade, 2)
|
|
1170
|
+
side = 'sell' if (trade[3] == 's') else 'buy'
|
|
1171
|
+
type = 'limit' if (trade[4] == 'l') else 'market'
|
|
1172
|
+
price = self.safe_string(trade, 0)
|
|
1173
|
+
amount = self.safe_string(trade, 1)
|
|
1174
|
+
tradeLength = len(trade)
|
|
1175
|
+
if tradeLength > 6:
|
|
1176
|
+
id = self.safe_string(trade, 6) # artificially added #1794
|
|
1177
|
+
elif isinstance(trade, str):
|
|
1178
|
+
id = trade
|
|
1179
|
+
elif 'ordertxid' in trade:
|
|
1180
|
+
marketId = self.safe_string(trade, 'pair')
|
|
1181
|
+
foundMarket = self.find_market_by_altname_or_id(marketId)
|
|
1182
|
+
if foundMarket is not None:
|
|
1183
|
+
market = foundMarket
|
|
1184
|
+
elif marketId is not None:
|
|
1185
|
+
# delisted market ids go here
|
|
1186
|
+
market = self.get_delisted_market_by_id(marketId)
|
|
1187
|
+
orderId = self.safe_string(trade, 'ordertxid')
|
|
1188
|
+
id = self.safe_string_2(trade, 'id', 'postxid')
|
|
1189
|
+
timestamp = self.safe_timestamp(trade, 'time')
|
|
1190
|
+
side = self.safe_string(trade, 'type')
|
|
1191
|
+
type = self.safe_string(trade, 'ordertype')
|
|
1192
|
+
price = self.safe_string(trade, 'price')
|
|
1193
|
+
amount = self.safe_string(trade, 'vol')
|
|
1194
|
+
if 'fee' in trade:
|
|
1195
|
+
currency = None
|
|
1196
|
+
if market is not None:
|
|
1197
|
+
currency = market['quote']
|
|
1198
|
+
fee = {
|
|
1199
|
+
'cost': self.safe_string(trade, 'fee'),
|
|
1200
|
+
'currency': currency,
|
|
1201
|
+
}
|
|
1202
|
+
if market is not None:
|
|
1203
|
+
symbol = market['symbol']
|
|
1204
|
+
cost = self.safe_string(trade, 'cost')
|
|
1205
|
+
return self.safe_trade({
|
|
1206
|
+
'id': id,
|
|
1207
|
+
'order': orderId,
|
|
1208
|
+
'info': trade,
|
|
1209
|
+
'timestamp': timestamp,
|
|
1210
|
+
'datetime': self.iso8601(timestamp),
|
|
1211
|
+
'symbol': symbol,
|
|
1212
|
+
'type': type,
|
|
1213
|
+
'side': side,
|
|
1214
|
+
'takerOrMaker': None,
|
|
1215
|
+
'price': price,
|
|
1216
|
+
'amount': amount,
|
|
1217
|
+
'cost': cost,
|
|
1218
|
+
'fee': fee,
|
|
1219
|
+
}, market)
|
|
1220
|
+
|
|
1221
|
+
async def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
1222
|
+
"""
|
|
1223
|
+
get the list of most recent trades for a particular symbol
|
|
1224
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getRecentTrades
|
|
1225
|
+
:param str symbol: unified symbol of the market to fetch trades for
|
|
1226
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
1227
|
+
:param int [limit]: the maximum amount of trades to fetch
|
|
1228
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1229
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
1230
|
+
"""
|
|
1231
|
+
await self.load_markets()
|
|
1232
|
+
market = self.market(symbol)
|
|
1233
|
+
id = market['id']
|
|
1234
|
+
request: dict = {
|
|
1235
|
+
'pair': id,
|
|
1236
|
+
}
|
|
1237
|
+
# https://support.kraken.com/hc/en-us/articles/218198197-How-to-pull-all-trade-data-using-the-Kraken-REST-API
|
|
1238
|
+
# https://github.com/ccxt/ccxt/issues/5677
|
|
1239
|
+
if since is not None:
|
|
1240
|
+
request['since'] = self.number_to_string(self.parse_to_int(since / 1000)) # expected to be in seconds
|
|
1241
|
+
if limit is not None:
|
|
1242
|
+
request['count'] = limit
|
|
1243
|
+
response = await self.publicGetTrades(self.extend(request, params))
|
|
1244
|
+
#
|
|
1245
|
+
# {
|
|
1246
|
+
# "error": [],
|
|
1247
|
+
# "result": {
|
|
1248
|
+
# "XETHXXBT": [
|
|
1249
|
+
# ["0.032310","4.28169434",1541390792.763,"s","l",""]
|
|
1250
|
+
# ],
|
|
1251
|
+
# "last": "1541439421200678657"
|
|
1252
|
+
# }
|
|
1253
|
+
# }
|
|
1254
|
+
#
|
|
1255
|
+
result = response['result']
|
|
1256
|
+
trades = result[id]
|
|
1257
|
+
# trades is a sorted array: last(most recent trade) goes last
|
|
1258
|
+
length = len(trades)
|
|
1259
|
+
if length <= 0:
|
|
1260
|
+
return []
|
|
1261
|
+
lastTrade = trades[length - 1]
|
|
1262
|
+
lastTradeId = self.safe_string(result, 'last')
|
|
1263
|
+
lastTrade.append(lastTradeId)
|
|
1264
|
+
trades[length - 1] = lastTrade
|
|
1265
|
+
return self.parse_trades(trades, market, since, limit)
|
|
1266
|
+
|
|
1267
|
+
def parse_balance(self, response) -> Balances:
|
|
1268
|
+
balances = self.safe_value(response, 'result', {})
|
|
1269
|
+
result: dict = {
|
|
1270
|
+
'info': response,
|
|
1271
|
+
'timestamp': None,
|
|
1272
|
+
'datetime': None,
|
|
1273
|
+
}
|
|
1274
|
+
currencyIds = list(balances.keys())
|
|
1275
|
+
for i in range(0, len(currencyIds)):
|
|
1276
|
+
currencyId = currencyIds[i]
|
|
1277
|
+
code = self.safe_currency_code(currencyId)
|
|
1278
|
+
balance = self.safe_value(balances, currencyId, {})
|
|
1279
|
+
account = self.account()
|
|
1280
|
+
account['used'] = self.safe_string(balance, 'hold_trade')
|
|
1281
|
+
account['total'] = self.safe_string(balance, 'balance')
|
|
1282
|
+
result[code] = account
|
|
1283
|
+
return self.safe_balance(result)
|
|
1284
|
+
|
|
1285
|
+
async def fetch_balance(self, params={}) -> Balances:
|
|
1286
|
+
"""
|
|
1287
|
+
query for balance and get the amount of funds available for trading or funds locked in orders
|
|
1288
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getExtendedBalance
|
|
1289
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1290
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
|
1291
|
+
"""
|
|
1292
|
+
await self.load_markets()
|
|
1293
|
+
response = await self.privatePostBalanceEx(params)
|
|
1294
|
+
#
|
|
1295
|
+
# {
|
|
1296
|
+
# "error": [],
|
|
1297
|
+
# "result": {
|
|
1298
|
+
# "ZUSD": {
|
|
1299
|
+
# "balance": 25435.21,
|
|
1300
|
+
# "hold_trade": 8249.76
|
|
1301
|
+
# },
|
|
1302
|
+
# "XXBT": {
|
|
1303
|
+
# "balance": 1.2435,
|
|
1304
|
+
# "hold_trade": 0.8423
|
|
1305
|
+
# }
|
|
1306
|
+
# }
|
|
1307
|
+
# }
|
|
1308
|
+
#
|
|
1309
|
+
return self.parse_balance(response)
|
|
1310
|
+
|
|
1311
|
+
async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
|
|
1312
|
+
"""
|
|
1313
|
+
create a market order by providing the symbol, side and cost
|
|
1314
|
+
:see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
|
|
1315
|
+
:param str symbol: unified symbol of the market to create an order in(only USD markets are supported)
|
|
1316
|
+
:param str side: 'buy' or 'sell'
|
|
1317
|
+
:param float cost: how much you want to trade in units of the quote currency
|
|
1318
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1319
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1320
|
+
"""
|
|
1321
|
+
await self.load_markets()
|
|
1322
|
+
# only buy orders are supported by the endpoint
|
|
1323
|
+
params['cost'] = cost
|
|
1324
|
+
return await self.create_order(symbol, 'market', side, cost, None, params)
|
|
1325
|
+
|
|
1326
|
+
async def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
|
|
1327
|
+
"""
|
|
1328
|
+
create a market buy order by providing the symbol, side and cost
|
|
1329
|
+
:see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
|
|
1330
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1331
|
+
:param float cost: how much you want to trade in units of the quote currency
|
|
1332
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1333
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1334
|
+
"""
|
|
1335
|
+
await self.load_markets()
|
|
1336
|
+
return await self.create_market_order_with_cost(symbol, 'buy', cost, params)
|
|
1337
|
+
|
|
1338
|
+
async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
1339
|
+
"""
|
|
1340
|
+
:see: https://docs.kraken.com/rest/#tag/Trading/operation/addOrder
|
|
1341
|
+
create a trade order
|
|
1342
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1343
|
+
:param str type: 'market' or 'limit'
|
|
1344
|
+
:param str side: 'buy' or 'sell'
|
|
1345
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
|
1346
|
+
:param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
1347
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1348
|
+
:param bool [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
|
|
1349
|
+
:param bool [params.reduceOnly]: *margin only* indicates if self order is to reduce the size of a position
|
|
1350
|
+
:param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
|
|
1351
|
+
:param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
|
|
1352
|
+
:param str [params.trailingAmount]: *margin only* the quote amount to trail away from the current market price
|
|
1353
|
+
:param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
|
|
1354
|
+
:param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
|
|
1355
|
+
:param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
|
|
1356
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1357
|
+
"""
|
|
1358
|
+
await self.load_markets()
|
|
1359
|
+
market = self.market(symbol)
|
|
1360
|
+
request: dict = {
|
|
1361
|
+
'pair': market['id'],
|
|
1362
|
+
'type': side,
|
|
1363
|
+
'ordertype': type,
|
|
1364
|
+
'volume': self.amount_to_precision(symbol, amount),
|
|
1365
|
+
}
|
|
1366
|
+
orderRequest = self.order_request('createOrder', symbol, type, request, amount, price, params)
|
|
1367
|
+
response = await self.privatePostAddOrder(self.extend(orderRequest[0], orderRequest[1]))
|
|
1368
|
+
#
|
|
1369
|
+
# {
|
|
1370
|
+
# "error": [],
|
|
1371
|
+
# "result": {
|
|
1372
|
+
# "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
|
|
1373
|
+
# "txid": ['OEKVV2-IH52O-TPL6GZ']
|
|
1374
|
+
# }
|
|
1375
|
+
# }
|
|
1376
|
+
#
|
|
1377
|
+
result = self.safe_dict(response, 'result')
|
|
1378
|
+
return self.parse_order(result)
|
|
1379
|
+
|
|
1380
|
+
def find_market_by_altname_or_id(self, id):
|
|
1381
|
+
marketsByAltname = self.safe_value(self.options, 'marketsByAltname', {})
|
|
1382
|
+
if id in marketsByAltname:
|
|
1383
|
+
return marketsByAltname[id]
|
|
1384
|
+
else:
|
|
1385
|
+
return self.safe_market(id)
|
|
1386
|
+
|
|
1387
|
+
def get_delisted_market_by_id(self, id):
|
|
1388
|
+
if id is None:
|
|
1389
|
+
return id
|
|
1390
|
+
market = self.safe_value(self.options['delistedMarketsById'], id)
|
|
1391
|
+
if market is not None:
|
|
1392
|
+
return market
|
|
1393
|
+
baseIdStart = 0
|
|
1394
|
+
baseIdEnd = 3
|
|
1395
|
+
quoteIdStart = 3
|
|
1396
|
+
quoteIdEnd = 6
|
|
1397
|
+
if len(id) == 8:
|
|
1398
|
+
baseIdEnd = 4
|
|
1399
|
+
quoteIdStart = 4
|
|
1400
|
+
quoteIdEnd = 8
|
|
1401
|
+
elif len(id) == 7:
|
|
1402
|
+
baseIdEnd = 4
|
|
1403
|
+
quoteIdStart = 4
|
|
1404
|
+
quoteIdEnd = 7
|
|
1405
|
+
baseId = id[baseIdStart:baseIdEnd]
|
|
1406
|
+
quoteId = id[quoteIdStart:quoteIdEnd]
|
|
1407
|
+
base = self.safe_currency_code(baseId)
|
|
1408
|
+
quote = self.safe_currency_code(quoteId)
|
|
1409
|
+
symbol = base + '/' + quote
|
|
1410
|
+
market = {
|
|
1411
|
+
'symbol': symbol,
|
|
1412
|
+
'base': base,
|
|
1413
|
+
'quote': quote,
|
|
1414
|
+
'baseId': baseId,
|
|
1415
|
+
'quoteId': quoteId,
|
|
1416
|
+
}
|
|
1417
|
+
self.options['delistedMarketsById'][id] = market
|
|
1418
|
+
return market
|
|
1419
|
+
|
|
1420
|
+
def parse_order_status(self, status: Str):
|
|
1421
|
+
statuses: dict = {
|
|
1422
|
+
'pending': 'open', # order pending book entry
|
|
1423
|
+
'open': 'open',
|
|
1424
|
+
'closed': 'closed',
|
|
1425
|
+
'canceled': 'canceled',
|
|
1426
|
+
'expired': 'expired',
|
|
1427
|
+
}
|
|
1428
|
+
return self.safe_string(statuses, status, status)
|
|
1429
|
+
|
|
1430
|
+
def parse_order_type(self, status):
|
|
1431
|
+
statuses: dict = {
|
|
1432
|
+
'take-profit': 'market',
|
|
1433
|
+
'stop-loss-limit': 'limit',
|
|
1434
|
+
'stop-loss': 'market',
|
|
1435
|
+
'take-profit-limit': 'limit',
|
|
1436
|
+
'trailing-stop-limit': 'limit',
|
|
1437
|
+
}
|
|
1438
|
+
return self.safe_string(statuses, status, status)
|
|
1439
|
+
|
|
1440
|
+
def parse_order(self, order: dict, market: Market = None) -> Order:
|
|
1441
|
+
#
|
|
1442
|
+
# createOrder for regular orders
|
|
1443
|
+
#
|
|
1444
|
+
# {
|
|
1445
|
+
# "descr": {order: 'buy 0.02100000 ETHUSDT @ limit 330.00'},
|
|
1446
|
+
# "txid": ['OEKVV2-IH52O-TPL6GZ']
|
|
1447
|
+
# }
|
|
1448
|
+
# {
|
|
1449
|
+
# "txid": ["TX_ID_HERE"],
|
|
1450
|
+
# "descr": {"order":"buy 0.12345678 ETHEUR @ market"},
|
|
1451
|
+
# }
|
|
1452
|
+
#
|
|
1453
|
+
#
|
|
1454
|
+
# createOrder for stop orders
|
|
1455
|
+
#
|
|
1456
|
+
# {
|
|
1457
|
+
# "txid":["OSILNC-VQI5Q-775ZDQ"],
|
|
1458
|
+
# "descr":{"order":"sell 167.28002676 ADAXBT @ stop loss 0.00003280 -> limit 0.00003212"}
|
|
1459
|
+
# }
|
|
1460
|
+
#
|
|
1461
|
+
#
|
|
1462
|
+
# {
|
|
1463
|
+
# "txid":["OVHMJV-BZW2V-6NZFWF"],
|
|
1464
|
+
# "descr":{"order":"sell 0.00100000 ETHUSD @ stop loss 2677.00 -> limit 2577.00 with 5:1 leverage"}
|
|
1465
|
+
# }
|
|
1466
|
+
#
|
|
1467
|
+
# editOrder
|
|
1468
|
+
#
|
|
1469
|
+
# {
|
|
1470
|
+
# "status": "ok",
|
|
1471
|
+
# "txid": "OAW2BO-7RWEK-PZY5UO",
|
|
1472
|
+
# "originaltxid": "OXL6SS-UPNMC-26WBE7",
|
|
1473
|
+
# "volume": "0.00075000",
|
|
1474
|
+
# "price": "13500.0",
|
|
1475
|
+
# "orders_cancelled": 1,
|
|
1476
|
+
# "descr": {
|
|
1477
|
+
# "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
|
|
1478
|
+
# }
|
|
1479
|
+
# }
|
|
1480
|
+
# ws - createOrder
|
|
1481
|
+
# {
|
|
1482
|
+
# "descr": 'sell 0.00010000 XBTUSDT @ market',
|
|
1483
|
+
# "event": 'addOrderStatus',
|
|
1484
|
+
# "reqid": 1,
|
|
1485
|
+
# "status": 'ok',
|
|
1486
|
+
# "txid": 'OAVXZH-XIE54-JCYYDG'
|
|
1487
|
+
# }
|
|
1488
|
+
# ws - editOrder
|
|
1489
|
+
# {
|
|
1490
|
+
# "descr": "order edited price = 9000.00000000",
|
|
1491
|
+
# "event": "editOrderStatus",
|
|
1492
|
+
# "originaltxid": "O65KZW-J4AW3-VFS74A",
|
|
1493
|
+
# "reqid": 3,
|
|
1494
|
+
# "status": "ok",
|
|
1495
|
+
# "txid": "OTI672-HJFAO-XOIPPK"
|
|
1496
|
+
# }
|
|
1497
|
+
#
|
|
1498
|
+
# {
|
|
1499
|
+
# "error": [],
|
|
1500
|
+
# "result": {
|
|
1501
|
+
# "open": {
|
|
1502
|
+
# "OXVPSU-Q726F-L3SDEP": {
|
|
1503
|
+
# "refid": null,
|
|
1504
|
+
# "userref": 0,
|
|
1505
|
+
# "status": "open",
|
|
1506
|
+
# "opentm": 1706893367.4656649,
|
|
1507
|
+
# "starttm": 0,
|
|
1508
|
+
# "expiretm": 0,
|
|
1509
|
+
# "descr": {
|
|
1510
|
+
# "pair": "XRPEUR",
|
|
1511
|
+
# "type": "sell",
|
|
1512
|
+
# "ordertype": "trailing-stop",
|
|
1513
|
+
# "price": "+50.0000%",
|
|
1514
|
+
# "price2": "0",
|
|
1515
|
+
# "leverage": "none",
|
|
1516
|
+
# "order": "sell 10.00000000 XRPEUR @ trailing stop +50.0000%",
|
|
1517
|
+
# "close": ""
|
|
1518
|
+
# },
|
|
1519
|
+
# "vol": "10.00000000",
|
|
1520
|
+
# "vol_exec": "0.00000000",
|
|
1521
|
+
# "cost": "0.00000000",
|
|
1522
|
+
# "fee": "0.00000000",
|
|
1523
|
+
# "price": "0.00000000",
|
|
1524
|
+
# "stopprice": "0.23424000",
|
|
1525
|
+
# "limitprice": "0.46847000",
|
|
1526
|
+
# "misc": "",
|
|
1527
|
+
# "oflags": "fciq",
|
|
1528
|
+
# "trigger": "index"
|
|
1529
|
+
# }
|
|
1530
|
+
# }
|
|
1531
|
+
# }
|
|
1532
|
+
#
|
|
1533
|
+
description = self.safe_dict(order, 'descr', {})
|
|
1534
|
+
orderDescriptionObj = self.safe_dict(order, 'descr') # can be null
|
|
1535
|
+
orderDescription = None
|
|
1536
|
+
if orderDescriptionObj is not None:
|
|
1537
|
+
orderDescription = self.safe_string(orderDescriptionObj, 'order')
|
|
1538
|
+
else:
|
|
1539
|
+
orderDescription = self.safe_string(order, 'descr')
|
|
1540
|
+
side = None
|
|
1541
|
+
type = None
|
|
1542
|
+
marketId = None
|
|
1543
|
+
price = None
|
|
1544
|
+
amount = None
|
|
1545
|
+
stopPrice = None
|
|
1546
|
+
if orderDescription is not None:
|
|
1547
|
+
parts = orderDescription.split(' ')
|
|
1548
|
+
side = self.safe_string(parts, 0)
|
|
1549
|
+
amount = self.safe_string(parts, 1)
|
|
1550
|
+
marketId = self.safe_string(parts, 2)
|
|
1551
|
+
type = self.safe_string(parts, 4)
|
|
1552
|
+
if type == 'stop':
|
|
1553
|
+
stopPrice = self.safe_string(parts, 6)
|
|
1554
|
+
price = self.safe_string(parts, 9)
|
|
1555
|
+
elif type == 'limit':
|
|
1556
|
+
price = self.safe_string(parts, 5)
|
|
1557
|
+
side = self.safe_string(description, 'type', side)
|
|
1558
|
+
type = self.safe_string(description, 'ordertype', type)
|
|
1559
|
+
marketId = self.safe_string(description, 'pair', marketId)
|
|
1560
|
+
foundMarket = self.find_market_by_altname_or_id(marketId)
|
|
1561
|
+
symbol = None
|
|
1562
|
+
if foundMarket is not None:
|
|
1563
|
+
market = foundMarket
|
|
1564
|
+
elif marketId is not None:
|
|
1565
|
+
# delisted market ids go here
|
|
1566
|
+
market = self.get_delisted_market_by_id(marketId)
|
|
1567
|
+
timestamp = self.safe_timestamp(order, 'opentm')
|
|
1568
|
+
amount = self.safe_string(order, 'vol', amount)
|
|
1569
|
+
filled = self.safe_string(order, 'vol_exec')
|
|
1570
|
+
fee = None
|
|
1571
|
+
# kraken truncates the cost in the api response so we will ignore it and calculate it from average & filled
|
|
1572
|
+
# cost = self.safe_string(order, 'cost')
|
|
1573
|
+
price = self.safe_string(description, 'price', price)
|
|
1574
|
+
# when type = trailling stop returns price = '+50.0000%'
|
|
1575
|
+
if (price is not None) and price.endswith('%'):
|
|
1576
|
+
price = None # self is not the price we want
|
|
1577
|
+
if (price is None) or Precise.string_equals(price, '0'):
|
|
1578
|
+
price = self.safe_string(description, 'price2')
|
|
1579
|
+
if (price is None) or Precise.string_equals(price, '0'):
|
|
1580
|
+
price = self.safe_string(order, 'price', price)
|
|
1581
|
+
flags = self.safe_string(order, 'oflags', '')
|
|
1582
|
+
isPostOnly = flags.find('post') > -1
|
|
1583
|
+
average = self.safe_number(order, 'price')
|
|
1584
|
+
if market is not None:
|
|
1585
|
+
symbol = market['symbol']
|
|
1586
|
+
if 'fee' in order:
|
|
1587
|
+
feeCost = self.safe_string(order, 'fee')
|
|
1588
|
+
fee = {
|
|
1589
|
+
'cost': feeCost,
|
|
1590
|
+
'rate': None,
|
|
1591
|
+
}
|
|
1592
|
+
if flags.find('fciq') >= 0:
|
|
1593
|
+
fee['currency'] = market['quote']
|
|
1594
|
+
elif flags.find('fcib') >= 0:
|
|
1595
|
+
fee['currency'] = market['base']
|
|
1596
|
+
status = self.parse_order_status(self.safe_string(order, 'status'))
|
|
1597
|
+
id = self.safe_string_2(order, 'id', 'txid')
|
|
1598
|
+
if (id is None) or (id.startswith('[')):
|
|
1599
|
+
txid = self.safe_list(order, 'txid')
|
|
1600
|
+
id = self.safe_string(txid, 0)
|
|
1601
|
+
clientOrderId = self.safe_string(order, 'userref')
|
|
1602
|
+
rawTrades = self.safe_value(order, 'trades', [])
|
|
1603
|
+
trades = []
|
|
1604
|
+
for i in range(0, len(rawTrades)):
|
|
1605
|
+
rawTrade = rawTrades[i]
|
|
1606
|
+
if isinstance(rawTrade, str):
|
|
1607
|
+
trades.append(self.safe_trade({'id': rawTrade, 'orderId': id, 'symbol': symbol, 'info': {}}))
|
|
1608
|
+
else:
|
|
1609
|
+
trades.append(rawTrade)
|
|
1610
|
+
stopPrice = self.omit_zero(self.safe_string(order, 'stopprice', stopPrice))
|
|
1611
|
+
stopLossPrice = None
|
|
1612
|
+
takeProfitPrice = None
|
|
1613
|
+
if type.startswith('take-profit'):
|
|
1614
|
+
takeProfitPrice = self.safe_string(description, 'price')
|
|
1615
|
+
price = self.omit_zero(self.safe_string(description, 'price2'))
|
|
1616
|
+
elif type.startswith('stop-loss'):
|
|
1617
|
+
stopLossPrice = self.safe_string(description, 'price')
|
|
1618
|
+
price = self.omit_zero(self.safe_string(description, 'price2'))
|
|
1619
|
+
return self.safe_order({
|
|
1620
|
+
'id': id,
|
|
1621
|
+
'clientOrderId': clientOrderId,
|
|
1622
|
+
'info': order,
|
|
1623
|
+
'timestamp': timestamp,
|
|
1624
|
+
'datetime': self.iso8601(timestamp),
|
|
1625
|
+
'lastTradeTimestamp': None,
|
|
1626
|
+
'status': status,
|
|
1627
|
+
'symbol': symbol,
|
|
1628
|
+
'type': self.parse_order_type(type),
|
|
1629
|
+
'timeInForce': None,
|
|
1630
|
+
'postOnly': isPostOnly,
|
|
1631
|
+
'side': side,
|
|
1632
|
+
'price': price,
|
|
1633
|
+
'stopPrice': stopPrice,
|
|
1634
|
+
'triggerPrice': stopPrice,
|
|
1635
|
+
'takeProfitPrice': takeProfitPrice,
|
|
1636
|
+
'stopLossPrice': stopLossPrice,
|
|
1637
|
+
'cost': None,
|
|
1638
|
+
'amount': amount,
|
|
1639
|
+
'filled': filled,
|
|
1640
|
+
'average': average,
|
|
1641
|
+
'remaining': None,
|
|
1642
|
+
'fee': fee,
|
|
1643
|
+
'trades': trades,
|
|
1644
|
+
}, market)
|
|
1645
|
+
|
|
1646
|
+
def order_request(self, method: str, symbol: str, type: str, request: dict, amount: Num, price: Num = None, params={}):
|
|
1647
|
+
clientOrderId = self.safe_string_2(params, 'userref', 'clientOrderId')
|
|
1648
|
+
params = self.omit(params, ['userref', 'clientOrderId'])
|
|
1649
|
+
if clientOrderId is not None:
|
|
1650
|
+
request['userref'] = clientOrderId
|
|
1651
|
+
stopLossTriggerPrice = self.safe_string(params, 'stopLossPrice')
|
|
1652
|
+
takeProfitTriggerPrice = self.safe_string(params, 'takeProfitPrice')
|
|
1653
|
+
isStopLossTriggerOrder = stopLossTriggerPrice is not None
|
|
1654
|
+
isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
|
|
1655
|
+
isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
|
|
1656
|
+
trailingAmount = self.safe_string(params, 'trailingAmount')
|
|
1657
|
+
trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
|
|
1658
|
+
isTrailingAmountOrder = trailingAmount is not None
|
|
1659
|
+
isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
|
|
1660
|
+
isMarketOrder = type == 'market'
|
|
1661
|
+
cost = self.safe_string(params, 'cost')
|
|
1662
|
+
flags = self.safe_string(params, 'oflags')
|
|
1663
|
+
params = self.omit(params, ['cost', 'oflags'])
|
|
1664
|
+
isViqcOrder = (flags is not None) and (flags.find('viqc') > -1) # volume in quote currency
|
|
1665
|
+
if isMarketOrder and (cost is not None or isViqcOrder):
|
|
1666
|
+
if cost is None and (amount is not None):
|
|
1667
|
+
request['volume'] = self.cost_to_precision(symbol, self.number_to_string(amount))
|
|
1668
|
+
else:
|
|
1669
|
+
request['volume'] = self.cost_to_precision(symbol, cost)
|
|
1670
|
+
extendedOflags = flags + ',viqc' if (flags is not None) else 'viqc'
|
|
1671
|
+
request['oflags'] = extendedOflags
|
|
1672
|
+
elif isLimitOrder and not isTrailingAmountOrder:
|
|
1673
|
+
request['price'] = self.price_to_precision(symbol, price)
|
|
1674
|
+
reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
|
|
1675
|
+
if isStopLossOrTakeProfitTrigger:
|
|
1676
|
+
if isStopLossTriggerOrder:
|
|
1677
|
+
request['price'] = self.price_to_precision(symbol, stopLossTriggerPrice)
|
|
1678
|
+
if isLimitOrder:
|
|
1679
|
+
request['ordertype'] = 'stop-loss-limit'
|
|
1680
|
+
else:
|
|
1681
|
+
request['ordertype'] = 'stop-loss'
|
|
1682
|
+
elif isTakeProfitTriggerOrder:
|
|
1683
|
+
request['price'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
|
|
1684
|
+
if isLimitOrder:
|
|
1685
|
+
request['ordertype'] = 'take-profit-limit'
|
|
1686
|
+
else:
|
|
1687
|
+
request['ordertype'] = 'take-profit'
|
|
1688
|
+
if isLimitOrder:
|
|
1689
|
+
request['price2'] = self.price_to_precision(symbol, price)
|
|
1690
|
+
elif isTrailingAmountOrder:
|
|
1691
|
+
trailingActivationPriceType = self.safe_string(params, 'trigger', 'last')
|
|
1692
|
+
trailingAmountString = '+' + trailingAmount
|
|
1693
|
+
request['trigger'] = trailingActivationPriceType
|
|
1694
|
+
if isLimitOrder or (trailingLimitAmount is not None):
|
|
1695
|
+
offset = self.safe_string(params, 'offset', '-')
|
|
1696
|
+
trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount)
|
|
1697
|
+
request['price'] = trailingAmountString
|
|
1698
|
+
request['price2'] = trailingLimitAmountString
|
|
1699
|
+
request['ordertype'] = 'trailing-stop-limit'
|
|
1700
|
+
else:
|
|
1701
|
+
request['price'] = trailingAmountString
|
|
1702
|
+
request['ordertype'] = 'trailing-stop'
|
|
1703
|
+
if reduceOnly:
|
|
1704
|
+
if method == 'createOrderWs':
|
|
1705
|
+
request['reduce_only'] = True # ws request can't have stringified bool
|
|
1706
|
+
else:
|
|
1707
|
+
request['reduce_only'] = 'true' # not using hasattr(self, boolean) case, because the urlencodedNested transforms it into 'True' string
|
|
1708
|
+
close = self.safe_dict(params, 'close')
|
|
1709
|
+
if close is not None:
|
|
1710
|
+
close = self.extend({}, close)
|
|
1711
|
+
closePrice = self.safe_value(close, 'price')
|
|
1712
|
+
if closePrice is not None:
|
|
1713
|
+
close['price'] = self.price_to_precision(symbol, closePrice)
|
|
1714
|
+
closePrice2 = self.safe_value(close, 'price2') # stopPrice
|
|
1715
|
+
if closePrice2 is not None:
|
|
1716
|
+
close['price2'] = self.price_to_precision(symbol, closePrice2)
|
|
1717
|
+
request['close'] = close
|
|
1718
|
+
timeInForce = self.safe_string_2(params, 'timeInForce', 'timeinforce')
|
|
1719
|
+
if timeInForce is not None:
|
|
1720
|
+
request['timeinforce'] = timeInForce
|
|
1721
|
+
isMarket = (type == 'market')
|
|
1722
|
+
postOnly = None
|
|
1723
|
+
postOnly, params = self.handle_post_only(isMarket, False, params)
|
|
1724
|
+
if postOnly:
|
|
1725
|
+
extendedPostFlags = flags + ',post' if (flags is not None) else 'post'
|
|
1726
|
+
request['oflags'] = extendedPostFlags
|
|
1727
|
+
params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingLimitAmount', 'offset'])
|
|
1728
|
+
return [request, params]
|
|
1729
|
+
|
|
1730
|
+
async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
|
|
1731
|
+
"""
|
|
1732
|
+
edit a trade order
|
|
1733
|
+
:see: https://docs.kraken.com/rest/#tag/Trading/operation/editOrder
|
|
1734
|
+
:param str id: order id
|
|
1735
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1736
|
+
:param str type: 'market' or 'limit'
|
|
1737
|
+
:param str side: 'buy' or 'sell'
|
|
1738
|
+
:param float amount: how much of the currency you want to trade in units of the base currency
|
|
1739
|
+
:param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
1740
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1741
|
+
:param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
|
|
1742
|
+
:param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
|
|
1743
|
+
:param str [params.trailingAmount]: *margin only* the quote price away from the current market price
|
|
1744
|
+
:param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
|
|
1745
|
+
:param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
|
|
1746
|
+
:param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
|
|
1747
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1748
|
+
"""
|
|
1749
|
+
await self.load_markets()
|
|
1750
|
+
market = self.market(symbol)
|
|
1751
|
+
if not market['spot']:
|
|
1752
|
+
raise NotSupported(self.id + ' editOrder() does not support ' + market['type'] + ' orders, only spot orders are accepted')
|
|
1753
|
+
request: dict = {
|
|
1754
|
+
'txid': id,
|
|
1755
|
+
'pair': market['id'],
|
|
1756
|
+
}
|
|
1757
|
+
if amount is not None:
|
|
1758
|
+
request['volume'] = self.amount_to_precision(symbol, amount)
|
|
1759
|
+
orderRequest = self.order_request('editOrder', symbol, type, request, amount, price, params)
|
|
1760
|
+
response = await self.privatePostEditOrder(self.extend(orderRequest[0], orderRequest[1]))
|
|
1761
|
+
#
|
|
1762
|
+
# {
|
|
1763
|
+
# "error": [],
|
|
1764
|
+
# "result": {
|
|
1765
|
+
# "status": "ok",
|
|
1766
|
+
# "txid": "OAW2BO-7RWEK-PZY5UO",
|
|
1767
|
+
# "originaltxid": "OXL6SS-UPNMC-26WBE7",
|
|
1768
|
+
# "volume": "0.00075000",
|
|
1769
|
+
# "price": "13500.0",
|
|
1770
|
+
# "orders_cancelled": 1,
|
|
1771
|
+
# "descr": {
|
|
1772
|
+
# "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
|
|
1773
|
+
# }
|
|
1774
|
+
# }
|
|
1775
|
+
# }
|
|
1776
|
+
#
|
|
1777
|
+
data = self.safe_dict(response, 'result', {})
|
|
1778
|
+
return self.parse_order(data, market)
|
|
1779
|
+
|
|
1780
|
+
async def fetch_order(self, id: str, symbol: Str = None, params={}):
|
|
1781
|
+
"""
|
|
1782
|
+
fetches information on an order made by the user
|
|
1783
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOrdersInfo
|
|
1784
|
+
:param str symbol: not used by kraken fetchOrder
|
|
1785
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1786
|
+
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1787
|
+
"""
|
|
1788
|
+
await self.load_markets()
|
|
1789
|
+
clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
|
|
1790
|
+
request: dict = {
|
|
1791
|
+
'trades': True, # whether or not to include trades in output(optional, default False)
|
|
1792
|
+
# 'txid': id, # do not comma separate a list of ids - use fetchOrdersByIds instead
|
|
1793
|
+
# 'userref': 'optional', # restrict results to given user reference id(optional)
|
|
1794
|
+
}
|
|
1795
|
+
query = params
|
|
1796
|
+
if clientOrderId is not None:
|
|
1797
|
+
request['userref'] = clientOrderId
|
|
1798
|
+
query = self.omit(params, ['userref', 'clientOrderId'])
|
|
1799
|
+
else:
|
|
1800
|
+
request['txid'] = id
|
|
1801
|
+
response = await self.privatePostQueryOrders(self.extend(request, query))
|
|
1802
|
+
#
|
|
1803
|
+
# {
|
|
1804
|
+
# "error":[],
|
|
1805
|
+
# "result":{
|
|
1806
|
+
# "OTLAS3-RRHUF-NDWH5A":{
|
|
1807
|
+
# "refid":null,
|
|
1808
|
+
# "userref":null,
|
|
1809
|
+
# "status":"closed",
|
|
1810
|
+
# "reason":null,
|
|
1811
|
+
# "opentm":1586822919.3342,
|
|
1812
|
+
# "closetm":1586822919.365,
|
|
1813
|
+
# "starttm":0,
|
|
1814
|
+
# "expiretm":0,
|
|
1815
|
+
# "descr":{
|
|
1816
|
+
# "pair":"XBTUSDT",
|
|
1817
|
+
# "type":"sell",
|
|
1818
|
+
# "ordertype":"market",
|
|
1819
|
+
# "price":"0",
|
|
1820
|
+
# "price2":"0",
|
|
1821
|
+
# "leverage":"none",
|
|
1822
|
+
# "order":"sell 0.21804000 XBTUSDT @ market",
|
|
1823
|
+
# "close":""
|
|
1824
|
+
# },
|
|
1825
|
+
# "vol":"0.21804000",
|
|
1826
|
+
# "vol_exec":"0.21804000",
|
|
1827
|
+
# "cost":"1493.9",
|
|
1828
|
+
# "fee":"3.8",
|
|
1829
|
+
# "price":"6851.5",
|
|
1830
|
+
# "stopprice":"0.00000",
|
|
1831
|
+
# "limitprice":"0.00000",
|
|
1832
|
+
# "misc":"",
|
|
1833
|
+
# "oflags":"fciq",
|
|
1834
|
+
# "trades":["TT5UC3-GOIRW-6AZZ6R"]
|
|
1835
|
+
# }
|
|
1836
|
+
# }
|
|
1837
|
+
# }
|
|
1838
|
+
#
|
|
1839
|
+
result = self.safe_value(response, 'result', [])
|
|
1840
|
+
if not (id in result):
|
|
1841
|
+
raise OrderNotFound(self.id + ' fetchOrder() could not find order id ' + id)
|
|
1842
|
+
return self.parse_order(self.extend({'id': id}, result[id]))
|
|
1843
|
+
|
|
1844
|
+
async def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1845
|
+
"""
|
|
1846
|
+
fetch all the trades made from a single order
|
|
1847
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradesInfo
|
|
1848
|
+
:param str id: order id
|
|
1849
|
+
:param str symbol: unified market symbol
|
|
1850
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
|
1851
|
+
:param int [limit]: the maximum number of trades to retrieve
|
|
1852
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1853
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
1854
|
+
"""
|
|
1855
|
+
orderTrades = self.safe_value(params, 'trades')
|
|
1856
|
+
tradeIds = []
|
|
1857
|
+
if orderTrades is None:
|
|
1858
|
+
raise ArgumentsRequired(self.id + " fetchOrderTrades() requires a unified order structure in the params argument or a 'trades' param(an array of trade id strings)")
|
|
1859
|
+
else:
|
|
1860
|
+
for i in range(0, len(orderTrades)):
|
|
1861
|
+
orderTrade = orderTrades[i]
|
|
1862
|
+
if isinstance(orderTrade, str):
|
|
1863
|
+
tradeIds.append(orderTrade)
|
|
1864
|
+
else:
|
|
1865
|
+
tradeIds.append(orderTrade['id'])
|
|
1866
|
+
await self.load_markets()
|
|
1867
|
+
if symbol is not None:
|
|
1868
|
+
symbol = self.symbol(symbol)
|
|
1869
|
+
options = self.safe_value(self.options, 'fetchOrderTrades', {})
|
|
1870
|
+
batchSize = self.safe_integer(options, 'batchSize', 20)
|
|
1871
|
+
numTradeIds = len(tradeIds)
|
|
1872
|
+
numBatches = self.parse_to_int(numTradeIds / batchSize)
|
|
1873
|
+
numBatches = self.sum(numBatches, 1)
|
|
1874
|
+
result = []
|
|
1875
|
+
for j in range(0, numBatches):
|
|
1876
|
+
requestIds = []
|
|
1877
|
+
for k in range(0, batchSize):
|
|
1878
|
+
index = self.sum(j * batchSize, k)
|
|
1879
|
+
if index < numTradeIds:
|
|
1880
|
+
requestIds.append(tradeIds[index])
|
|
1881
|
+
request: dict = {
|
|
1882
|
+
'txid': ','.join(requestIds),
|
|
1883
|
+
}
|
|
1884
|
+
response = await self.privatePostQueryTrades(request)
|
|
1885
|
+
#
|
|
1886
|
+
# {
|
|
1887
|
+
# "error": [],
|
|
1888
|
+
# "result": {
|
|
1889
|
+
# 'TIMIRG-WUNNE-RRJ6GT': {
|
|
1890
|
+
# "ordertxid": 'OQRPN2-LRHFY-HIFA7D',
|
|
1891
|
+
# "postxid": 'TKH2SE-M7IF5-CFI7LT',
|
|
1892
|
+
# "pair": 'USDCUSDT',
|
|
1893
|
+
# "time": 1586340086.457,
|
|
1894
|
+
# "type": 'sell',
|
|
1895
|
+
# "ordertype": 'market',
|
|
1896
|
+
# "price": '0.99860000',
|
|
1897
|
+
# "cost": '22.16892001',
|
|
1898
|
+
# "fee": '0.04433784',
|
|
1899
|
+
# "vol": '22.20000000',
|
|
1900
|
+
# "margin": '0.00000000',
|
|
1901
|
+
# "misc": ''
|
|
1902
|
+
# }
|
|
1903
|
+
# }
|
|
1904
|
+
# }
|
|
1905
|
+
#
|
|
1906
|
+
rawTrades = self.safe_value(response, 'result')
|
|
1907
|
+
ids = list(rawTrades.keys())
|
|
1908
|
+
for i in range(0, len(ids)):
|
|
1909
|
+
rawTrades[ids[i]]['id'] = ids[i]
|
|
1910
|
+
trades = self.parse_trades(rawTrades, None, since, limit)
|
|
1911
|
+
tradesFilteredBySymbol = self.filter_by_symbol(trades, symbol)
|
|
1912
|
+
result = self.array_concat(result, tradesFilteredBySymbol)
|
|
1913
|
+
return result
|
|
1914
|
+
|
|
1915
|
+
async def fetch_orders_by_ids(self, ids, symbol: Str = None, params={}):
|
|
1916
|
+
"""
|
|
1917
|
+
fetch orders by the list of order id
|
|
1918
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
|
|
1919
|
+
:param str[]|None ids: list of order id
|
|
1920
|
+
:param dict [params]: extra parameters specific to the kraken api endpoint
|
|
1921
|
+
:returns dict[]: a list of `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1922
|
+
"""
|
|
1923
|
+
await self.load_markets()
|
|
1924
|
+
response = await self.privatePostQueryOrders(self.extend({
|
|
1925
|
+
'trades': True, # whether or not to include trades in output(optional, default False)
|
|
1926
|
+
'txid': ','.join(ids), # comma delimited list of transaction ids to query info about(20 maximum)
|
|
1927
|
+
}, params))
|
|
1928
|
+
result = self.safe_value(response, 'result', {})
|
|
1929
|
+
orders = []
|
|
1930
|
+
orderIds = list(result.keys())
|
|
1931
|
+
for i in range(0, len(orderIds)):
|
|
1932
|
+
id = orderIds[i]
|
|
1933
|
+
item = result[id]
|
|
1934
|
+
order = self.parse_order(self.extend({'id': id}, item))
|
|
1935
|
+
orders.append(order)
|
|
1936
|
+
return orders
|
|
1937
|
+
|
|
1938
|
+
async def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
1939
|
+
"""
|
|
1940
|
+
fetch all trades made by the user
|
|
1941
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getTradeHistory
|
|
1942
|
+
:param str symbol: unified market symbol
|
|
1943
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
|
1944
|
+
:param int [limit]: the maximum number of trades structures to retrieve
|
|
1945
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1946
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
1947
|
+
"""
|
|
1948
|
+
await self.load_markets()
|
|
1949
|
+
request: dict = {
|
|
1950
|
+
# 'type': 'all', # any position, closed position, closing position, no position
|
|
1951
|
+
# 'trades': False, # whether or not to include trades related to position in output
|
|
1952
|
+
# 'start': 1234567890, # starting unix timestamp or trade tx id of results(exclusive)
|
|
1953
|
+
# 'end': 1234567890, # ending unix timestamp or trade tx id of results(inclusive)
|
|
1954
|
+
# 'ofs' = result offset
|
|
1955
|
+
}
|
|
1956
|
+
if since is not None:
|
|
1957
|
+
request['start'] = self.parse_to_int(since / 1000)
|
|
1958
|
+
response = await self.privatePostTradesHistory(self.extend(request, params))
|
|
1959
|
+
#
|
|
1960
|
+
# {
|
|
1961
|
+
# "error": [],
|
|
1962
|
+
# "result": {
|
|
1963
|
+
# "trades": {
|
|
1964
|
+
# "GJ3NYQ-XJRTF-THZABF": {
|
|
1965
|
+
# "ordertxid": "TKH2SE-ZIF5E-CFI7LT",
|
|
1966
|
+
# "postxid": "OEN3VX-M7IF5-JNBJAM",
|
|
1967
|
+
# "pair": "XICNXETH",
|
|
1968
|
+
# "time": 1527213229.4491,
|
|
1969
|
+
# "type": "sell",
|
|
1970
|
+
# "ordertype": "limit",
|
|
1971
|
+
# "price": "0.001612",
|
|
1972
|
+
# "cost": "0.025792",
|
|
1973
|
+
# "fee": "0.000026",
|
|
1974
|
+
# "vol": "16.00000000",
|
|
1975
|
+
# "margin": "0.000000",
|
|
1976
|
+
# "misc": ""
|
|
1977
|
+
# },
|
|
1978
|
+
# ...
|
|
1979
|
+
# },
|
|
1980
|
+
# "count": 9760,
|
|
1981
|
+
# },
|
|
1982
|
+
# }
|
|
1983
|
+
#
|
|
1984
|
+
trades = response['result']['trades']
|
|
1985
|
+
ids = list(trades.keys())
|
|
1986
|
+
for i in range(0, len(ids)):
|
|
1987
|
+
trades[ids[i]]['id'] = ids[i]
|
|
1988
|
+
market = None
|
|
1989
|
+
if symbol is not None:
|
|
1990
|
+
market = self.market(symbol)
|
|
1991
|
+
return self.parse_trades(trades, market, since, limit)
|
|
1992
|
+
|
|
1993
|
+
async def cancel_order(self, id: str, symbol: Str = None, params={}):
|
|
1994
|
+
"""
|
|
1995
|
+
cancels an open order
|
|
1996
|
+
:see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelOrder
|
|
1997
|
+
:param str id: order id
|
|
1998
|
+
:param str symbol: unified symbol of the market the order was made in
|
|
1999
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2000
|
+
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2001
|
+
"""
|
|
2002
|
+
await self.load_markets()
|
|
2003
|
+
response = None
|
|
2004
|
+
clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId', id)
|
|
2005
|
+
request: dict = {
|
|
2006
|
+
'txid': clientOrderId, # order id or userref
|
|
2007
|
+
}
|
|
2008
|
+
params = self.omit(params, ['userref', 'clientOrderId'])
|
|
2009
|
+
try:
|
|
2010
|
+
response = await self.privatePostCancelOrder(self.extend(request, params))
|
|
2011
|
+
#
|
|
2012
|
+
# {
|
|
2013
|
+
# error: [],
|
|
2014
|
+
# result: {
|
|
2015
|
+
# count: '1'
|
|
2016
|
+
# }
|
|
2017
|
+
# }
|
|
2018
|
+
#
|
|
2019
|
+
except Exception as e:
|
|
2020
|
+
if self.last_http_response:
|
|
2021
|
+
if self.last_http_response.find('EOrder:Unknown order') >= 0:
|
|
2022
|
+
raise OrderNotFound(self.id + ' cancelOrder() error ' + self.last_http_response)
|
|
2023
|
+
raise e
|
|
2024
|
+
return self.safe_order({
|
|
2025
|
+
'info': response,
|
|
2026
|
+
})
|
|
2027
|
+
|
|
2028
|
+
async def cancel_orders(self, ids, symbol: Str = None, params={}):
|
|
2029
|
+
"""
|
|
2030
|
+
cancel multiple orders
|
|
2031
|
+
:see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelOrderBatch
|
|
2032
|
+
:param str[] ids: open orders transaction ID(txid) or user reference(userref)
|
|
2033
|
+
:param str symbol: unified market symbol
|
|
2034
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2035
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2036
|
+
"""
|
|
2037
|
+
request: dict = {
|
|
2038
|
+
'orders': ids,
|
|
2039
|
+
}
|
|
2040
|
+
response = await self.privatePostCancelOrderBatch(self.extend(request, params))
|
|
2041
|
+
#
|
|
2042
|
+
# {
|
|
2043
|
+
# "error": [],
|
|
2044
|
+
# "result": {
|
|
2045
|
+
# "count": 2
|
|
2046
|
+
# }
|
|
2047
|
+
# }
|
|
2048
|
+
#
|
|
2049
|
+
return [
|
|
2050
|
+
self.safe_order({
|
|
2051
|
+
'info': response,
|
|
2052
|
+
}),
|
|
2053
|
+
]
|
|
2054
|
+
|
|
2055
|
+
async def cancel_all_orders(self, symbol: Str = None, params={}):
|
|
2056
|
+
"""
|
|
2057
|
+
cancel all open orders
|
|
2058
|
+
:see: https://docs.kraken.com/rest/#tag/Trading/operation/cancelAllOrders
|
|
2059
|
+
:param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
|
|
2060
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2061
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2062
|
+
"""
|
|
2063
|
+
await self.load_markets()
|
|
2064
|
+
response = await self.privatePostCancelAll(params)
|
|
2065
|
+
#
|
|
2066
|
+
# {
|
|
2067
|
+
# error: [],
|
|
2068
|
+
# result: {
|
|
2069
|
+
# count: '1'
|
|
2070
|
+
# }
|
|
2071
|
+
# }
|
|
2072
|
+
#
|
|
2073
|
+
return [
|
|
2074
|
+
self.safe_order({
|
|
2075
|
+
'info': response,
|
|
2076
|
+
}),
|
|
2077
|
+
]
|
|
2078
|
+
|
|
2079
|
+
async def cancel_all_orders_after(self, timeout: Int, params={}):
|
|
2080
|
+
"""
|
|
2081
|
+
dead man's switch, cancel all orders after the given timeout
|
|
2082
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Trading/operation/cancelAllOrdersAfter
|
|
2083
|
+
:param number timeout: time in milliseconds, 0 represents cancel the timer
|
|
2084
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2085
|
+
:returns dict: the api result
|
|
2086
|
+
"""
|
|
2087
|
+
if timeout > 86400000:
|
|
2088
|
+
raise BadRequest(self.id + 'cancelAllOrdersAfter timeout should be less than 86400000 milliseconds')
|
|
2089
|
+
await self.load_markets()
|
|
2090
|
+
request: dict = {
|
|
2091
|
+
'timeout': (self.parse_to_int(timeout / 1000)) if (timeout > 0) else 0,
|
|
2092
|
+
}
|
|
2093
|
+
response = await self.privatePostCancelAllOrdersAfter(self.extend(request, params))
|
|
2094
|
+
#
|
|
2095
|
+
# {
|
|
2096
|
+
# "error": [],
|
|
2097
|
+
# "result": {
|
|
2098
|
+
# "currentTime": "2023-03-24T17:41:56Z",
|
|
2099
|
+
# "triggerTime": "2023-03-24T17:42:56Z"
|
|
2100
|
+
# }
|
|
2101
|
+
# }
|
|
2102
|
+
#
|
|
2103
|
+
return response
|
|
2104
|
+
|
|
2105
|
+
async def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
2106
|
+
"""
|
|
2107
|
+
fetch all unfilled currently open orders
|
|
2108
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenOrders
|
|
2109
|
+
:param str symbol: unified market symbol
|
|
2110
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
|
2111
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
|
2112
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2113
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2114
|
+
"""
|
|
2115
|
+
await self.load_markets()
|
|
2116
|
+
request: dict = {}
|
|
2117
|
+
if since is not None:
|
|
2118
|
+
request['start'] = self.parse_to_int(since / 1000)
|
|
2119
|
+
query = params
|
|
2120
|
+
clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
|
|
2121
|
+
if clientOrderId is not None:
|
|
2122
|
+
request['userref'] = clientOrderId
|
|
2123
|
+
query = self.omit(params, ['userref', 'clientOrderId'])
|
|
2124
|
+
response = await self.privatePostOpenOrders(self.extend(request, query))
|
|
2125
|
+
market = None
|
|
2126
|
+
if symbol is not None:
|
|
2127
|
+
market = self.market(symbol)
|
|
2128
|
+
result = self.safe_dict(response, 'result', {})
|
|
2129
|
+
orders = self.safe_dict(result, 'open', {})
|
|
2130
|
+
return self.parse_orders(orders, market, since, limit)
|
|
2131
|
+
|
|
2132
|
+
async def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
2133
|
+
"""
|
|
2134
|
+
fetches information on multiple closed orders made by the user
|
|
2135
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getClosedOrders
|
|
2136
|
+
:param str symbol: unified market symbol of the market orders were made in
|
|
2137
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
|
2138
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
|
2139
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2140
|
+
:param int [params.until]: timestamp in ms of the latest entry
|
|
2141
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
2142
|
+
"""
|
|
2143
|
+
await self.load_markets()
|
|
2144
|
+
request: dict = {}
|
|
2145
|
+
if since is not None:
|
|
2146
|
+
request['start'] = self.parse_to_int(since / 1000)
|
|
2147
|
+
query = params
|
|
2148
|
+
clientOrderId = self.safe_value_2(params, 'userref', 'clientOrderId')
|
|
2149
|
+
if clientOrderId is not None:
|
|
2150
|
+
request['userref'] = clientOrderId
|
|
2151
|
+
query = self.omit(params, ['userref', 'clientOrderId'])
|
|
2152
|
+
request, params = self.handle_until_option('end', request, params)
|
|
2153
|
+
response = await self.privatePostClosedOrders(self.extend(request, query))
|
|
2154
|
+
#
|
|
2155
|
+
# {
|
|
2156
|
+
# "error":[],
|
|
2157
|
+
# "result":{
|
|
2158
|
+
# "closed":{
|
|
2159
|
+
# "OETZYO-UL524-QJMXCT":{
|
|
2160
|
+
# "refid":null,
|
|
2161
|
+
# "userref":null,
|
|
2162
|
+
# "status":"canceled",
|
|
2163
|
+
# "reason":"User requested",
|
|
2164
|
+
# "opentm":1601489313.3898,
|
|
2165
|
+
# "closetm":1601489346.5507,
|
|
2166
|
+
# "starttm":0,
|
|
2167
|
+
# "expiretm":0,
|
|
2168
|
+
# "descr":{
|
|
2169
|
+
# "pair":"ETHUSDT",
|
|
2170
|
+
# "type":"buy",
|
|
2171
|
+
# "ordertype":"limit",
|
|
2172
|
+
# "price":"330.00",
|
|
2173
|
+
# "price2":"0",
|
|
2174
|
+
# "leverage":"none",
|
|
2175
|
+
# "order":"buy 0.02100000 ETHUSDT @ limit 330.00",
|
|
2176
|
+
# "close":""
|
|
2177
|
+
# },
|
|
2178
|
+
# "vol":"0.02100000",
|
|
2179
|
+
# "vol_exec":"0.00000000",
|
|
2180
|
+
# "cost":"0.00000",
|
|
2181
|
+
# "fee":"0.00000",
|
|
2182
|
+
# "price":"0.00000",
|
|
2183
|
+
# "stopprice":"0.00000",
|
|
2184
|
+
# "limitprice":"0.00000",
|
|
2185
|
+
# "misc":"",
|
|
2186
|
+
# "oflags":"fciq"
|
|
2187
|
+
# },
|
|
2188
|
+
# },
|
|
2189
|
+
# "count":16
|
|
2190
|
+
# }
|
|
2191
|
+
# }
|
|
2192
|
+
#
|
|
2193
|
+
market = None
|
|
2194
|
+
if symbol is not None:
|
|
2195
|
+
market = self.market(symbol)
|
|
2196
|
+
result = self.safe_dict(response, 'result', {})
|
|
2197
|
+
orders = self.safe_dict(result, 'closed', {})
|
|
2198
|
+
return self.parse_orders(orders, market, since, limit)
|
|
2199
|
+
|
|
2200
|
+
def parse_transaction_status(self, status: Str):
|
|
2201
|
+
# IFEX transaction states
|
|
2202
|
+
statuses: dict = {
|
|
2203
|
+
'Initial': 'pending',
|
|
2204
|
+
'Pending': 'pending',
|
|
2205
|
+
'Success': 'ok',
|
|
2206
|
+
'Settled': 'pending',
|
|
2207
|
+
'Failure': 'failed',
|
|
2208
|
+
'Partial': 'ok',
|
|
2209
|
+
}
|
|
2210
|
+
return self.safe_string(statuses, status, status)
|
|
2211
|
+
|
|
2212
|
+
def parse_network(self, network):
|
|
2213
|
+
withdrawMethods = self.safe_value(self.options, 'withdrawMethods', {})
|
|
2214
|
+
return self.safe_string(withdrawMethods, network, network)
|
|
2215
|
+
|
|
2216
|
+
def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
|
|
2217
|
+
#
|
|
2218
|
+
# fetchDeposits
|
|
2219
|
+
#
|
|
2220
|
+
# {
|
|
2221
|
+
# "method": "Ether(Hex)",
|
|
2222
|
+
# "aclass": "currency",
|
|
2223
|
+
# "asset": "XETH",
|
|
2224
|
+
# "refid": "Q2CANKL-LBFVEE-U4Y2WQ",
|
|
2225
|
+
# "txid": "0x57fd704dab1a73c20e24c8696099b695d596924b401b261513cfdab23…",
|
|
2226
|
+
# "info": "0x615f9ba7a9575b0ab4d571b2b36b1b324bd83290",
|
|
2227
|
+
# "amount": "7.9999257900",
|
|
2228
|
+
# "fee": "0.0000000000",
|
|
2229
|
+
# "time": 1529223212,
|
|
2230
|
+
# "status": "Success"
|
|
2231
|
+
# }
|
|
2232
|
+
#
|
|
2233
|
+
# there can be an additional 'status-prop' field present
|
|
2234
|
+
# deposit pending review by exchange => 'on-hold'
|
|
2235
|
+
# the deposit is initiated by the exchange => 'return'
|
|
2236
|
+
#
|
|
2237
|
+
# {
|
|
2238
|
+
# "type": 'deposit',
|
|
2239
|
+
# "method": 'Fidor Bank AG(Wire Transfer)',
|
|
2240
|
+
# "aclass": 'currency',
|
|
2241
|
+
# "asset": 'ZEUR',
|
|
2242
|
+
# "refid": 'xxx-xxx-xxx',
|
|
2243
|
+
# "txid": '12341234',
|
|
2244
|
+
# "info": 'BANKCODEXXX',
|
|
2245
|
+
# "amount": '38769.08',
|
|
2246
|
+
# "fee": '0.0000',
|
|
2247
|
+
# "time": 1644306552,
|
|
2248
|
+
# "status": 'Success',
|
|
2249
|
+
# status-prop: 'on-hold'
|
|
2250
|
+
# }
|
|
2251
|
+
#
|
|
2252
|
+
#
|
|
2253
|
+
# fetchWithdrawals
|
|
2254
|
+
#
|
|
2255
|
+
# {
|
|
2256
|
+
# "method": "Ether",
|
|
2257
|
+
# "aclass": "currency",
|
|
2258
|
+
# "asset": "XETH",
|
|
2259
|
+
# "refid": "A2BF34S-O7LBNQ-UE4Y4O",
|
|
2260
|
+
# "txid": "0x288b83c6b0904d8400ef44e1c9e2187b5c8f7ea3d838222d53f701a15b5c274d",
|
|
2261
|
+
# "info": "0x7cb275a5e07ba943fee972e165d80daa67cb2dd0",
|
|
2262
|
+
# "amount": "9.9950000000",
|
|
2263
|
+
# "fee": "0.0050000000",
|
|
2264
|
+
# "time": 1530481750,
|
|
2265
|
+
# "status": "Success"
|
|
2266
|
+
# "key":"Huobi wallet",
|
|
2267
|
+
# "network":"Tron"
|
|
2268
|
+
# status-prop: 'on-hold' # self field might not be present in some cases
|
|
2269
|
+
# }
|
|
2270
|
+
#
|
|
2271
|
+
# withdraw
|
|
2272
|
+
#
|
|
2273
|
+
# {
|
|
2274
|
+
# "refid": "AGBSO6T-UFMTTQ-I7KGS6"
|
|
2275
|
+
# }
|
|
2276
|
+
#
|
|
2277
|
+
id = self.safe_string(transaction, 'refid')
|
|
2278
|
+
txid = self.safe_string(transaction, 'txid')
|
|
2279
|
+
timestamp = self.safe_timestamp(transaction, 'time')
|
|
2280
|
+
currencyId = self.safe_string(transaction, 'asset')
|
|
2281
|
+
code = self.safe_currency_code(currencyId, currency)
|
|
2282
|
+
address = self.safe_string(transaction, 'info')
|
|
2283
|
+
amount = self.safe_number(transaction, 'amount')
|
|
2284
|
+
status = self.parse_transaction_status(self.safe_string(transaction, 'status'))
|
|
2285
|
+
statusProp = self.safe_string(transaction, 'status-prop')
|
|
2286
|
+
isOnHoldDeposit = statusProp == 'on-hold'
|
|
2287
|
+
isCancellationRequest = statusProp == 'cancel-pending'
|
|
2288
|
+
isOnHoldWithdrawal = statusProp == 'onhold'
|
|
2289
|
+
if isOnHoldDeposit or isCancellationRequest or isOnHoldWithdrawal:
|
|
2290
|
+
status = 'pending'
|
|
2291
|
+
type = self.safe_string(transaction, 'type') # injected from the outside
|
|
2292
|
+
feeCost = self.safe_number(transaction, 'fee')
|
|
2293
|
+
if feeCost is None:
|
|
2294
|
+
if type == 'deposit':
|
|
2295
|
+
feeCost = 0
|
|
2296
|
+
return {
|
|
2297
|
+
'info': transaction,
|
|
2298
|
+
'id': id,
|
|
2299
|
+
'currency': code,
|
|
2300
|
+
'amount': amount,
|
|
2301
|
+
'network': self.parse_network(self.safe_string(transaction, 'network')),
|
|
2302
|
+
'address': address,
|
|
2303
|
+
'addressTo': None,
|
|
2304
|
+
'addressFrom': None,
|
|
2305
|
+
'tag': None,
|
|
2306
|
+
'tagTo': None,
|
|
2307
|
+
'tagFrom': None,
|
|
2308
|
+
'status': status,
|
|
2309
|
+
'type': type,
|
|
2310
|
+
'updated': None,
|
|
2311
|
+
'txid': txid,
|
|
2312
|
+
'timestamp': timestamp,
|
|
2313
|
+
'datetime': self.iso8601(timestamp),
|
|
2314
|
+
'comment': None,
|
|
2315
|
+
'internal': None,
|
|
2316
|
+
'fee': {
|
|
2317
|
+
'currency': code,
|
|
2318
|
+
'cost': feeCost,
|
|
2319
|
+
},
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
def parse_transactions_by_type(self, type, transactions, code: Str = None, since: Int = None, limit: Int = None):
|
|
2323
|
+
result = []
|
|
2324
|
+
for i in range(0, len(transactions)):
|
|
2325
|
+
transaction = self.parse_transaction(self.extend({
|
|
2326
|
+
'type': type,
|
|
2327
|
+
}, transactions[i]))
|
|
2328
|
+
result.append(transaction)
|
|
2329
|
+
return self.filter_by_currency_since_limit(result, code, since, limit)
|
|
2330
|
+
|
|
2331
|
+
async def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
|
2332
|
+
"""
|
|
2333
|
+
fetch all deposits made to an account
|
|
2334
|
+
:see: https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentDeposits
|
|
2335
|
+
:param str code: unified currency code
|
|
2336
|
+
:param int [since]: the earliest time in ms to fetch deposits for
|
|
2337
|
+
:param int [limit]: the maximum number of deposits structures to retrieve
|
|
2338
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2339
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2340
|
+
"""
|
|
2341
|
+
# https://www.kraken.com/en-us/help/api#deposit-status
|
|
2342
|
+
if code is None:
|
|
2343
|
+
raise ArgumentsRequired(self.id + ' fetchDeposits() requires a currency code argument')
|
|
2344
|
+
await self.load_markets()
|
|
2345
|
+
currency = self.currency(code)
|
|
2346
|
+
request: dict = {
|
|
2347
|
+
'asset': currency['id'],
|
|
2348
|
+
}
|
|
2349
|
+
if since is not None:
|
|
2350
|
+
request['start'] = since
|
|
2351
|
+
response = await self.privatePostDepositStatus(self.extend(request, params))
|
|
2352
|
+
#
|
|
2353
|
+
# { error: [],
|
|
2354
|
+
# "result": [{"method": "Ether(Hex)",
|
|
2355
|
+
# "aclass": "currency",
|
|
2356
|
+
# "asset": "XETH",
|
|
2357
|
+
# "refid": "Q2CANKL-LBFVEE-U4Y2WQ",
|
|
2358
|
+
# "txid": "0x57fd704dab1a73c20e24c8696099b695d596924b401b261513cfdab23…",
|
|
2359
|
+
# "info": "0x615f9ba7a9575b0ab4d571b2b36b1b324bd83290",
|
|
2360
|
+
# "amount": "7.9999257900",
|
|
2361
|
+
# "fee": "0.0000000000",
|
|
2362
|
+
# "time": 1529223212,
|
|
2363
|
+
# "status": "Success" }]}
|
|
2364
|
+
#
|
|
2365
|
+
return self.parse_transactions_by_type('deposit', response['result'], code, since, limit)
|
|
2366
|
+
|
|
2367
|
+
async def fetch_time(self, params={}):
|
|
2368
|
+
"""
|
|
2369
|
+
fetches the current integer timestamp in milliseconds from the exchange server
|
|
2370
|
+
:see: https://docs.kraken.com/rest/#tag/Spot-Market-Data/operation/getServerTime
|
|
2371
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2372
|
+
:returns int: the current integer timestamp in milliseconds from the exchange server
|
|
2373
|
+
"""
|
|
2374
|
+
# https://www.kraken.com/en-us/features/api#get-server-time
|
|
2375
|
+
response = await self.publicGetTime(params)
|
|
2376
|
+
#
|
|
2377
|
+
# {
|
|
2378
|
+
# "error": [],
|
|
2379
|
+
# "result": {
|
|
2380
|
+
# "unixtime": 1591502873,
|
|
2381
|
+
# "rfc1123": "Sun, 7 Jun 20 04:07:53 +0000"
|
|
2382
|
+
# }
|
|
2383
|
+
# }
|
|
2384
|
+
#
|
|
2385
|
+
result = self.safe_value(response, 'result', {})
|
|
2386
|
+
return self.safe_timestamp(result, 'unixtime')
|
|
2387
|
+
|
|
2388
|
+
async def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
|
2389
|
+
"""
|
|
2390
|
+
fetch all withdrawals made from an account
|
|
2391
|
+
:see: https://docs.kraken.com/rest/#tag/Funding/operation/getStatusRecentWithdrawals
|
|
2392
|
+
:param str code: unified currency code
|
|
2393
|
+
:param int [since]: the earliest time in ms to fetch withdrawals for
|
|
2394
|
+
:param int [limit]: the maximum number of withdrawals structures to retrieve
|
|
2395
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2396
|
+
:param dict [params.end]: End timestamp, withdrawals created strictly after will be not be included in the response
|
|
2397
|
+
:param boolean [params.paginate]: default False, when True will automatically paginate by calling self endpoint multiple times
|
|
2398
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2399
|
+
"""
|
|
2400
|
+
await self.load_markets()
|
|
2401
|
+
paginate = False
|
|
2402
|
+
paginate, params = self.handle_option_and_params(params, 'fetchWithdrawals', 'paginate')
|
|
2403
|
+
if paginate:
|
|
2404
|
+
params['cursor'] = True
|
|
2405
|
+
return await self.fetch_paginated_call_cursor('fetchWithdrawals', code, since, limit, params, 'next_cursor', 'cursor')
|
|
2406
|
+
request: dict = {}
|
|
2407
|
+
if code is not None:
|
|
2408
|
+
currency = self.currency(code)
|
|
2409
|
+
request['asset'] = currency['id']
|
|
2410
|
+
if since is not None:
|
|
2411
|
+
request['since'] = str(since)
|
|
2412
|
+
response = await self.privatePostWithdrawStatus(self.extend(request, params))
|
|
2413
|
+
#
|
|
2414
|
+
# with no pagination
|
|
2415
|
+
# { error: [],
|
|
2416
|
+
# "result": [{"method": "Ether",
|
|
2417
|
+
# "aclass": "currency",
|
|
2418
|
+
# "asset": "XETH",
|
|
2419
|
+
# "refid": "A2BF34S-O7LBNQ-UE4Y4O",
|
|
2420
|
+
# "txid": "0x298c83c7b0904d8400ef43e1c9e2287b518f7ea3d838822d53f704a1565c274d",
|
|
2421
|
+
# "info": "0x7cb275a5e07ba943fee972e165d80daa67cb2dd0",
|
|
2422
|
+
# "amount": "9.9950000000",
|
|
2423
|
+
# "fee": "0.0050000000",
|
|
2424
|
+
# "time": 1530481750,
|
|
2425
|
+
# "status": "Success" }]}
|
|
2426
|
+
# with pagination
|
|
2427
|
+
# {
|
|
2428
|
+
# "error":[],
|
|
2429
|
+
# "result":{
|
|
2430
|
+
# "withdrawals":[
|
|
2431
|
+
# {
|
|
2432
|
+
# "method":"Tether USD(TRC20)",
|
|
2433
|
+
# "aclass":"currency",
|
|
2434
|
+
# "asset":"USDT",
|
|
2435
|
+
# "refid":"BSNFZU2-MEFN4G-J3NEZV",
|
|
2436
|
+
# "txid":"1c7a642fb7387bbc2c6a2c509fd1ae146937f4cf793b4079a4f0715e3a02615a",
|
|
2437
|
+
# "info":"TQmdxSuC16EhFg8FZWtYgrfFRosoRF7bCp",
|
|
2438
|
+
# "amount":"1996.50000000",
|
|
2439
|
+
# "fee":"2.50000000",
|
|
2440
|
+
# "time":1669126657,
|
|
2441
|
+
# "status":"Success",
|
|
2442
|
+
# "key":"poloniex",
|
|
2443
|
+
# "network":"Tron"
|
|
2444
|
+
# },
|
|
2445
|
+
# ...
|
|
2446
|
+
# ],
|
|
2447
|
+
# "next_cursor":"HgAAAAAAAABGVFRSd3k1LVF4Y0JQY05Gd0xRY0NxenFndHpybkwBAQH2AwEBAAAAAQAAAAAAAAABAAAAAAAZAAAAAAAAAA=="
|
|
2448
|
+
# }
|
|
2449
|
+
# }
|
|
2450
|
+
#
|
|
2451
|
+
rawWithdrawals = None
|
|
2452
|
+
result = self.safe_value(response, 'result')
|
|
2453
|
+
if not isinstance(result, list):
|
|
2454
|
+
rawWithdrawals = self.add_pagination_cursor_to_result(result)
|
|
2455
|
+
else:
|
|
2456
|
+
rawWithdrawals = result
|
|
2457
|
+
return self.parse_transactions_by_type('withdrawal', rawWithdrawals, code, since, limit)
|
|
2458
|
+
|
|
2459
|
+
def add_pagination_cursor_to_result(self, result):
|
|
2460
|
+
cursor = self.safe_string(result, 'next_cursor')
|
|
2461
|
+
data = self.safe_value(result, 'withdrawals')
|
|
2462
|
+
dataLength = len(data)
|
|
2463
|
+
if cursor is not None and dataLength > 0:
|
|
2464
|
+
last = data[dataLength - 1]
|
|
2465
|
+
last['next_cursor'] = cursor
|
|
2466
|
+
data[dataLength - 1] = last
|
|
2467
|
+
return data
|
|
2468
|
+
|
|
2469
|
+
async def create_deposit_address(self, code: str, params={}):
|
|
2470
|
+
"""
|
|
2471
|
+
create a currency deposit address
|
|
2472
|
+
:see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
|
|
2473
|
+
:param str code: unified currency code of the currency for the deposit address
|
|
2474
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2475
|
+
:returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
|
|
2476
|
+
"""
|
|
2477
|
+
request: dict = {
|
|
2478
|
+
'new': 'true',
|
|
2479
|
+
}
|
|
2480
|
+
return await self.fetch_deposit_address(code, self.extend(request, params))
|
|
2481
|
+
|
|
2482
|
+
async def fetch_deposit_methods(self, code: str, params={}):
|
|
2483
|
+
"""
|
|
2484
|
+
fetch deposit methods for a currency associated with self account
|
|
2485
|
+
:see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositMethods
|
|
2486
|
+
:param str code: unified currency code
|
|
2487
|
+
:param dict [params]: extra parameters specific to the kraken api endpoint
|
|
2488
|
+
:returns dict: of deposit methods
|
|
2489
|
+
"""
|
|
2490
|
+
await self.load_markets()
|
|
2491
|
+
currency = self.currency(code)
|
|
2492
|
+
request: dict = {
|
|
2493
|
+
'asset': currency['id'],
|
|
2494
|
+
}
|
|
2495
|
+
response = await self.privatePostDepositMethods(self.extend(request, params))
|
|
2496
|
+
#
|
|
2497
|
+
# {
|
|
2498
|
+
# "error":[],
|
|
2499
|
+
# "result":[
|
|
2500
|
+
# {"method":"Ether(Hex)","limit":false,"gen-address":true}
|
|
2501
|
+
# ]
|
|
2502
|
+
# }
|
|
2503
|
+
#
|
|
2504
|
+
# {
|
|
2505
|
+
# "error":[],
|
|
2506
|
+
# "result":[
|
|
2507
|
+
# {"method":"Tether USD(ERC20)","limit":false,"address-setup-fee":"0.00000000","gen-address":true},
|
|
2508
|
+
# {"method":"Tether USD(TRC20)","limit":false,"address-setup-fee":"0.00000000","gen-address":true}
|
|
2509
|
+
# ]
|
|
2510
|
+
# }
|
|
2511
|
+
#
|
|
2512
|
+
# {
|
|
2513
|
+
# "error":[],
|
|
2514
|
+
# "result":[
|
|
2515
|
+
# {"method":"Bitcoin","limit":false,"fee":"0.0000000000","gen-address":true}
|
|
2516
|
+
# ]
|
|
2517
|
+
# }
|
|
2518
|
+
#
|
|
2519
|
+
return self.safe_value(response, 'result')
|
|
2520
|
+
|
|
2521
|
+
async def fetch_deposit_address(self, code: str, params={}):
|
|
2522
|
+
"""
|
|
2523
|
+
fetch the deposit address for a currency associated with self account
|
|
2524
|
+
:see: https://docs.kraken.com/rest/#tag/Funding/operation/getDepositAddresses
|
|
2525
|
+
:param str code: unified currency code
|
|
2526
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2527
|
+
:returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
|
|
2528
|
+
"""
|
|
2529
|
+
await self.load_markets()
|
|
2530
|
+
currency = self.currency(code)
|
|
2531
|
+
network = self.safe_string_upper(params, 'network')
|
|
2532
|
+
networks = self.safe_value(self.options, 'networks', {})
|
|
2533
|
+
network = self.safe_string(networks, network, network) # support ETH > ERC20 aliases
|
|
2534
|
+
params = self.omit(params, 'network')
|
|
2535
|
+
if (code == 'USDT') and (network == 'TRC20'):
|
|
2536
|
+
code = code + '-' + network
|
|
2537
|
+
defaultDepositMethods = self.safe_value(self.options, 'depositMethods', {})
|
|
2538
|
+
defaultDepositMethod = self.safe_string(defaultDepositMethods, code)
|
|
2539
|
+
depositMethod = self.safe_string(params, 'method', defaultDepositMethod)
|
|
2540
|
+
# if the user has specified an exchange-specific method in params
|
|
2541
|
+
# we pass it, otherwise we take the 'network' unified param
|
|
2542
|
+
if depositMethod is None:
|
|
2543
|
+
depositMethods = await self.fetch_deposit_methods(code)
|
|
2544
|
+
if network is not None:
|
|
2545
|
+
# find best matching deposit method, or fallback to the first one
|
|
2546
|
+
for i in range(0, len(depositMethods)):
|
|
2547
|
+
entry = self.safe_string(depositMethods[i], 'method')
|
|
2548
|
+
if entry.find(network) >= 0:
|
|
2549
|
+
depositMethod = entry
|
|
2550
|
+
break
|
|
2551
|
+
# if depositMethod was not specified, fallback to the first available deposit method
|
|
2552
|
+
if depositMethod is None:
|
|
2553
|
+
firstDepositMethod = self.safe_value(depositMethods, 0, {})
|
|
2554
|
+
depositMethod = self.safe_string(firstDepositMethod, 'method')
|
|
2555
|
+
request: dict = {
|
|
2556
|
+
'asset': currency['id'],
|
|
2557
|
+
'method': depositMethod,
|
|
2558
|
+
}
|
|
2559
|
+
response = await self.privatePostDepositAddresses(self.extend(request, params))
|
|
2560
|
+
#
|
|
2561
|
+
# {
|
|
2562
|
+
# "error":[],
|
|
2563
|
+
# "result":[
|
|
2564
|
+
# {"address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3","expiretm":"0"}
|
|
2565
|
+
# ]
|
|
2566
|
+
# }
|
|
2567
|
+
#
|
|
2568
|
+
result = self.safe_value(response, 'result', [])
|
|
2569
|
+
firstResult = self.safe_value(result, 0, {})
|
|
2570
|
+
if firstResult is None:
|
|
2571
|
+
raise InvalidAddress(self.id + ' privatePostDepositAddresses() returned no addresses for ' + code)
|
|
2572
|
+
return self.parse_deposit_address(firstResult, currency)
|
|
2573
|
+
|
|
2574
|
+
def parse_deposit_address(self, depositAddress, currency: Currency = None):
|
|
2575
|
+
#
|
|
2576
|
+
# {
|
|
2577
|
+
# "address":"0x77b5051f97efa9cc52c9ad5b023a53fc15c200d3",
|
|
2578
|
+
# "expiretm":"0"
|
|
2579
|
+
# }
|
|
2580
|
+
#
|
|
2581
|
+
address = self.safe_string(depositAddress, 'address')
|
|
2582
|
+
tag = self.safe_string(depositAddress, 'tag')
|
|
2583
|
+
currency = self.safe_currency(None, currency)
|
|
2584
|
+
code = currency['code']
|
|
2585
|
+
self.check_address(address)
|
|
2586
|
+
return {
|
|
2587
|
+
'currency': code,
|
|
2588
|
+
'address': address,
|
|
2589
|
+
'tag': tag,
|
|
2590
|
+
'network': None,
|
|
2591
|
+
'info': depositAddress,
|
|
2592
|
+
}
|
|
2593
|
+
|
|
2594
|
+
async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
|
|
2595
|
+
"""
|
|
2596
|
+
make a withdrawal
|
|
2597
|
+
:see: https://docs.kraken.com/rest/#tag/Funding/operation/withdrawFunds
|
|
2598
|
+
:param str code: unified currency code
|
|
2599
|
+
:param float amount: the amount to withdraw
|
|
2600
|
+
:param str address: the address to withdraw to
|
|
2601
|
+
:param str tag:
|
|
2602
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2603
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2604
|
+
"""
|
|
2605
|
+
tag, params = self.handle_withdraw_tag_and_params(tag, params)
|
|
2606
|
+
self.check_address(address)
|
|
2607
|
+
if 'key' in params:
|
|
2608
|
+
await self.load_markets()
|
|
2609
|
+
currency = self.currency(code)
|
|
2610
|
+
request: dict = {
|
|
2611
|
+
'asset': currency['id'],
|
|
2612
|
+
'amount': amount,
|
|
2613
|
+
'address': address,
|
|
2614
|
+
}
|
|
2615
|
+
response = await self.privatePostWithdraw(self.extend(request, params))
|
|
2616
|
+
#
|
|
2617
|
+
# {
|
|
2618
|
+
# "error": [],
|
|
2619
|
+
# "result": {
|
|
2620
|
+
# "refid": "AGBSO6T-UFMTTQ-I7KGS6"
|
|
2621
|
+
# }
|
|
2622
|
+
# }
|
|
2623
|
+
#
|
|
2624
|
+
result = self.safe_dict(response, 'result', {})
|
|
2625
|
+
return self.parse_transaction(result, currency)
|
|
2626
|
+
raise ExchangeError(self.id + " withdraw() requires a 'key' parameter(withdrawal key name, up on your account)")
|
|
2627
|
+
|
|
2628
|
+
async def fetch_positions(self, symbols: Strings = None, params={}):
|
|
2629
|
+
"""
|
|
2630
|
+
fetch all open positions
|
|
2631
|
+
:see: https://docs.kraken.com/rest/#tag/Account-Data/operation/getOpenPositions
|
|
2632
|
+
:param str[] [symbols]: not used by kraken fetchPositions()
|
|
2633
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2634
|
+
:returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
|
2635
|
+
"""
|
|
2636
|
+
await self.load_markets()
|
|
2637
|
+
request: dict = {
|
|
2638
|
+
# 'txid': 'comma delimited list of transaction ids to restrict output to',
|
|
2639
|
+
'docalcs': 'true', # whether or not to include profit/loss calculations
|
|
2640
|
+
'consolidation': 'market', # what to consolidate the positions data around, market will consolidate positions based on market pair
|
|
2641
|
+
}
|
|
2642
|
+
response = await self.privatePostOpenPositions(self.extend(request, params))
|
|
2643
|
+
#
|
|
2644
|
+
# no consolidation
|
|
2645
|
+
#
|
|
2646
|
+
# {
|
|
2647
|
+
# "error": [],
|
|
2648
|
+
# "result": {
|
|
2649
|
+
# 'TGUFMY-FLESJ-VYIX3J': {
|
|
2650
|
+
# "ordertxid": "O3LRNU-ZKDG5-XNCDFR",
|
|
2651
|
+
# "posstatus": "open",
|
|
2652
|
+
# "pair": "ETHUSDT",
|
|
2653
|
+
# "time": 1611557231.4584,
|
|
2654
|
+
# "type": "buy",
|
|
2655
|
+
# "ordertype": "market",
|
|
2656
|
+
# "cost": "28.49800",
|
|
2657
|
+
# "fee": "0.07979",
|
|
2658
|
+
# "vol": "0.02000000",
|
|
2659
|
+
# "vol_closed": "0.00000000",
|
|
2660
|
+
# "margin": "14.24900",
|
|
2661
|
+
# "terms": "0.0200% per 4 hours",
|
|
2662
|
+
# "rollovertm": "1611571631",
|
|
2663
|
+
# "misc": "",
|
|
2664
|
+
# "oflags": ""
|
|
2665
|
+
# }
|
|
2666
|
+
# }
|
|
2667
|
+
# }
|
|
2668
|
+
#
|
|
2669
|
+
# consolidation by market
|
|
2670
|
+
#
|
|
2671
|
+
# {
|
|
2672
|
+
# "error": [],
|
|
2673
|
+
# "result": [
|
|
2674
|
+
# {
|
|
2675
|
+
# "pair": "ETHUSDT",
|
|
2676
|
+
# "positions": "1",
|
|
2677
|
+
# "type": "buy",
|
|
2678
|
+
# "leverage": "2.00000",
|
|
2679
|
+
# "cost": "28.49800",
|
|
2680
|
+
# "fee": "0.07979",
|
|
2681
|
+
# "vol": "0.02000000",
|
|
2682
|
+
# "vol_closed": "0.00000000",
|
|
2683
|
+
# "margin": "14.24900"
|
|
2684
|
+
# }
|
|
2685
|
+
# ]
|
|
2686
|
+
# }
|
|
2687
|
+
#
|
|
2688
|
+
symbols = self.market_symbols(symbols)
|
|
2689
|
+
result = self.safe_list(response, 'result')
|
|
2690
|
+
results = self.parse_positions(result, symbols)
|
|
2691
|
+
return self.filter_by_array_positions(results, 'symbol', symbols, False)
|
|
2692
|
+
|
|
2693
|
+
def parse_position(self, position: dict, market: Market = None):
|
|
2694
|
+
#
|
|
2695
|
+
# {
|
|
2696
|
+
# "pair": "ETHUSDT",
|
|
2697
|
+
# "positions": "1",
|
|
2698
|
+
# "type": "buy",
|
|
2699
|
+
# "leverage": "2.00000",
|
|
2700
|
+
# "cost": "28.49800",
|
|
2701
|
+
# "fee": "0.07979",
|
|
2702
|
+
# "vol": "0.02000000",
|
|
2703
|
+
# "vol_closed": "0.00000000",
|
|
2704
|
+
# "margin": "14.24900"
|
|
2705
|
+
# }
|
|
2706
|
+
#
|
|
2707
|
+
marketId = self.safe_string(position, 'pair')
|
|
2708
|
+
rawSide = self.safe_string(position, 'type')
|
|
2709
|
+
side = 'long' if (rawSide == 'buy') else 'short'
|
|
2710
|
+
return self.safe_position({
|
|
2711
|
+
'info': position,
|
|
2712
|
+
'id': None,
|
|
2713
|
+
'symbol': self.safe_symbol(marketId, market),
|
|
2714
|
+
'notional': None,
|
|
2715
|
+
'marginMode': None,
|
|
2716
|
+
'liquidationPrice': None,
|
|
2717
|
+
'entryPrice': None,
|
|
2718
|
+
'unrealizedPnl': self.safe_number(position, 'net'),
|
|
2719
|
+
'realizedPnl': None,
|
|
2720
|
+
'percentage': None,
|
|
2721
|
+
'contracts': self.safe_number(position, 'vol'),
|
|
2722
|
+
'contractSize': None,
|
|
2723
|
+
'markPrice': None,
|
|
2724
|
+
'lastPrice': None,
|
|
2725
|
+
'side': side,
|
|
2726
|
+
'hedged': None,
|
|
2727
|
+
'timestamp': None,
|
|
2728
|
+
'datetime': None,
|
|
2729
|
+
'lastUpdateTimestamp': None,
|
|
2730
|
+
'maintenanceMargin': None,
|
|
2731
|
+
'maintenanceMarginPercentage': None,
|
|
2732
|
+
'collateral': None,
|
|
2733
|
+
'initialMargin': self.safe_number(position, 'margin'),
|
|
2734
|
+
'initialMarginPercentage': None,
|
|
2735
|
+
'leverage': self.safe_number(position, 'leverage'),
|
|
2736
|
+
'marginRatio': None,
|
|
2737
|
+
'stopLossPrice': None,
|
|
2738
|
+
'takeProfitPrice': None,
|
|
2739
|
+
})
|
|
2740
|
+
|
|
2741
|
+
def parse_account_type(self, account):
|
|
2742
|
+
accountByType: dict = {
|
|
2743
|
+
'spot': 'Spot Wallet',
|
|
2744
|
+
'swap': 'Futures Wallet',
|
|
2745
|
+
'future': 'Futures Wallet',
|
|
2746
|
+
}
|
|
2747
|
+
return self.safe_string(accountByType, account, account)
|
|
2748
|
+
|
|
2749
|
+
async def transfer_out(self, code: str, amount, params={}):
|
|
2750
|
+
"""
|
|
2751
|
+
transfer from spot wallet to futures wallet
|
|
2752
|
+
:see: https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
|
|
2753
|
+
:param str code: Unified currency code
|
|
2754
|
+
:param float amount: Size of the transfer
|
|
2755
|
+
:param dict [params]: Exchange specific parameters
|
|
2756
|
+
:returns: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
|
2757
|
+
"""
|
|
2758
|
+
return await self.transfer(code, amount, 'spot', 'swap', params)
|
|
2759
|
+
|
|
2760
|
+
async def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
|
2761
|
+
"""
|
|
2762
|
+
:see: https://docs.kraken.com/rest/#tag/User-Funding/operation/walletTransfer
|
|
2763
|
+
transfers currencies between sub-accounts(only spot->swap direction is supported)
|
|
2764
|
+
:param str code: Unified currency code
|
|
2765
|
+
:param float amount: Size of the transfer
|
|
2766
|
+
:param str fromAccount: 'spot' or 'Spot Wallet'
|
|
2767
|
+
:param str toAccount: 'swap' or 'Futures Wallet'
|
|
2768
|
+
:param dict [params]: Exchange specific parameters
|
|
2769
|
+
:returns: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
|
2770
|
+
"""
|
|
2771
|
+
await self.load_markets()
|
|
2772
|
+
currency = self.currency(code)
|
|
2773
|
+
fromAccount = self.parse_account_type(fromAccount)
|
|
2774
|
+
toAccount = self.parse_account_type(toAccount)
|
|
2775
|
+
request: dict = {
|
|
2776
|
+
'amount': self.currency_to_precision(code, amount),
|
|
2777
|
+
'from': fromAccount,
|
|
2778
|
+
'to': toAccount,
|
|
2779
|
+
'asset': currency['id'],
|
|
2780
|
+
}
|
|
2781
|
+
if fromAccount != 'Spot Wallet':
|
|
2782
|
+
raise BadRequest(self.id + ' transfer cannot transfer from ' + fromAccount + ' to ' + toAccount + '. Use krakenfutures instead to transfer from the futures account.')
|
|
2783
|
+
response = await self.privatePostWalletTransfer(self.extend(request, params))
|
|
2784
|
+
#
|
|
2785
|
+
# {
|
|
2786
|
+
# "error":[
|
|
2787
|
+
# ],
|
|
2788
|
+
# "result":{
|
|
2789
|
+
# "refid":"BOIUSIF-M7DLMN-UXZ3P5"
|
|
2790
|
+
# }
|
|
2791
|
+
# }
|
|
2792
|
+
#
|
|
2793
|
+
transfer = self.parse_transfer(response, currency)
|
|
2794
|
+
return self.extend(transfer, {
|
|
2795
|
+
'amount': amount,
|
|
2796
|
+
'fromAccount': fromAccount,
|
|
2797
|
+
'toAccount': toAccount,
|
|
2798
|
+
})
|
|
2799
|
+
|
|
2800
|
+
def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
|
|
2801
|
+
#
|
|
2802
|
+
# transfer
|
|
2803
|
+
#
|
|
2804
|
+
# {
|
|
2805
|
+
# "error":[
|
|
2806
|
+
# ],
|
|
2807
|
+
# "result":{
|
|
2808
|
+
# "refid":"BOIUSIF-M7DLMN-UXZ3P5"
|
|
2809
|
+
# }
|
|
2810
|
+
# }
|
|
2811
|
+
#
|
|
2812
|
+
result = self.safe_value(transfer, 'result', {})
|
|
2813
|
+
refid = self.safe_string(result, 'refid')
|
|
2814
|
+
return {
|
|
2815
|
+
'info': transfer,
|
|
2816
|
+
'id': refid,
|
|
2817
|
+
'timestamp': None,
|
|
2818
|
+
'datetime': None,
|
|
2819
|
+
'currency': self.safe_string(currency, 'code'),
|
|
2820
|
+
'amount': None,
|
|
2821
|
+
'fromAccount': None,
|
|
2822
|
+
'toAccount': None,
|
|
2823
|
+
'status': 'sucess',
|
|
2824
|
+
}
|
|
2825
|
+
|
|
2826
|
+
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
|
2827
|
+
url = '/' + self.version + '/' + api + '/' + path
|
|
2828
|
+
if api == 'public':
|
|
2829
|
+
if params:
|
|
2830
|
+
# urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
|
|
2831
|
+
url += '?' + self.urlencode_nested(params)
|
|
2832
|
+
elif api == 'private':
|
|
2833
|
+
isCancelOrderBatch = (path == 'CancelOrderBatch')
|
|
2834
|
+
self.check_required_credentials()
|
|
2835
|
+
nonce = str(self.nonce())
|
|
2836
|
+
# urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
|
|
2837
|
+
if isCancelOrderBatch:
|
|
2838
|
+
body = self.json(self.extend({'nonce': nonce}, params))
|
|
2839
|
+
else:
|
|
2840
|
+
body = self.urlencode_nested(self.extend({'nonce': nonce}, params))
|
|
2841
|
+
auth = self.encode(nonce + body)
|
|
2842
|
+
hash = self.hash(auth, 'sha256', 'binary')
|
|
2843
|
+
binary = self.encode(url)
|
|
2844
|
+
binhash = self.binary_concat(binary, hash)
|
|
2845
|
+
secret = self.base64_to_binary(self.secret)
|
|
2846
|
+
signature = self.hmac(binhash, secret, hashlib.sha512, 'base64')
|
|
2847
|
+
headers = {
|
|
2848
|
+
'API-Key': self.apiKey,
|
|
2849
|
+
'API-Sign': signature,
|
|
2850
|
+
# 'Content-Type': 'application/x-www-form-urlencoded',
|
|
2851
|
+
}
|
|
2852
|
+
if isCancelOrderBatch:
|
|
2853
|
+
headers['Content-Type'] = 'application/json'
|
|
2854
|
+
else:
|
|
2855
|
+
headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
|
2856
|
+
else:
|
|
2857
|
+
url = '/' + path
|
|
2858
|
+
url = self.urls['api'][api] + url
|
|
2859
|
+
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
|
2860
|
+
|
|
2861
|
+
def nonce(self):
|
|
2862
|
+
return self.milliseconds()
|
|
2863
|
+
|
|
2864
|
+
def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
|
|
2865
|
+
if code == 520:
|
|
2866
|
+
raise ExchangeNotAvailable(self.id + ' ' + str(code) + ' ' + reason)
|
|
2867
|
+
# todo: rewrite self for "broad" exceptions matching
|
|
2868
|
+
if body.find('Invalid order') >= 0:
|
|
2869
|
+
raise InvalidOrder(self.id + ' ' + body)
|
|
2870
|
+
if body.find('Invalid nonce') >= 0:
|
|
2871
|
+
raise InvalidNonce(self.id + ' ' + body)
|
|
2872
|
+
if body.find('Insufficient funds') >= 0:
|
|
2873
|
+
raise InsufficientFunds(self.id + ' ' + body)
|
|
2874
|
+
if body.find('Cancel pending') >= 0:
|
|
2875
|
+
raise CancelPending(self.id + ' ' + body)
|
|
2876
|
+
if body.find('Invalid arguments:volume') >= 0:
|
|
2877
|
+
raise InvalidOrder(self.id + ' ' + body)
|
|
2878
|
+
if body.find('Invalid arguments:viqc') >= 0:
|
|
2879
|
+
raise InvalidOrder(self.id + ' ' + body)
|
|
2880
|
+
if body.find('Rate limit exceeded') >= 0:
|
|
2881
|
+
raise RateLimitExceeded(self.id + ' ' + body)
|
|
2882
|
+
if response is None:
|
|
2883
|
+
return None
|
|
2884
|
+
if body[0] == '{':
|
|
2885
|
+
if not isinstance(response, str):
|
|
2886
|
+
if 'error' in response:
|
|
2887
|
+
numErrors = len(response['error'])
|
|
2888
|
+
if numErrors:
|
|
2889
|
+
message = self.id + ' ' + body
|
|
2890
|
+
for i in range(0, len(response['error'])):
|
|
2891
|
+
error = response['error'][i]
|
|
2892
|
+
self.throw_exactly_matched_exception(self.exceptions, error, message)
|
|
2893
|
+
raise ExchangeError(message)
|
|
2894
|
+
return None
|