ccxt-ir 4.3.46.0.1__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccxt/__init__.py +358 -0
- ccxt/abantether.py +316 -0
- ccxt/abstract/__init__.py +0 -0
- ccxt/abstract/abantether.py +5 -0
- ccxt/abstract/ace.py +15 -0
- ccxt/abstract/afratether.py +6 -0
- ccxt/abstract/alpaca.py +70 -0
- ccxt/abstract/arzinja.py +5 -0
- ccxt/abstract/arzplus.py +7 -0
- ccxt/abstract/ascendex.py +77 -0
- ccxt/abstract/bequant.py +115 -0
- ccxt/abstract/bigone.py +45 -0
- ccxt/abstract/binance.py +712 -0
- ccxt/abstract/binancecoinm.py +712 -0
- ccxt/abstract/binanceus.py +764 -0
- ccxt/abstract/binanceusdm.py +712 -0
- ccxt/abstract/bingx.py +113 -0
- ccxt/abstract/bit2c.py +27 -0
- ccxt/abstract/bitbank.py +27 -0
- ccxt/abstract/bitbay.py +53 -0
- ccxt/abstract/bitbns.py +40 -0
- ccxt/abstract/bitcoincom.py +115 -0
- ccxt/abstract/bitfinex.py +69 -0
- ccxt/abstract/bitfinex2.py +139 -0
- ccxt/abstract/bitflyer.py +38 -0
- ccxt/abstract/bitget.py +508 -0
- ccxt/abstract/bithumb.py +32 -0
- ccxt/abstract/bitimen.py +7 -0
- ccxt/abstract/bitir.py +7 -0
- ccxt/abstract/bitmart.py +99 -0
- ccxt/abstract/bitmex.py +97 -0
- ccxt/abstract/bitopro.py +29 -0
- ccxt/abstract/bitpanda.py +35 -0
- ccxt/abstract/bitpin.py +7 -0
- ccxt/abstract/bitrue.py +72 -0
- ccxt/abstract/bitso.py +43 -0
- ccxt/abstract/bitstamp.py +258 -0
- ccxt/abstract/bitteam.py +29 -0
- ccxt/abstract/bitvavo.py +27 -0
- ccxt/abstract/bl3p.py +19 -0
- ccxt/abstract/blockchaincom.py +28 -0
- ccxt/abstract/blofin.py +37 -0
- ccxt/abstract/btcalpha.py +18 -0
- ccxt/abstract/btcbox.py +13 -0
- ccxt/abstract/btcmarkets.py +39 -0
- ccxt/abstract/btcturk.py +20 -0
- ccxt/abstract/bybit.py +298 -0
- ccxt/abstract/cex.py +33 -0
- ccxt/abstract/coinbase.py +94 -0
- ccxt/abstract/coinbaseadvanced.py +94 -0
- ccxt/abstract/coinbaseexchange.py +67 -0
- ccxt/abstract/coinbaseinternational.py +39 -0
- ccxt/abstract/coincatch.py +94 -0
- ccxt/abstract/coincheck.py +33 -0
- ccxt/abstract/coinex.py +237 -0
- ccxt/abstract/coinlist.py +54 -0
- ccxt/abstract/coinmate.py +62 -0
- ccxt/abstract/coinmetro.py +34 -0
- ccxt/abstract/coinone.py +67 -0
- ccxt/abstract/coinsph.py +54 -0
- ccxt/abstract/coinspot.py +28 -0
- ccxt/abstract/cryptocom.py +107 -0
- ccxt/abstract/currencycom.py +68 -0
- ccxt/abstract/delta.py +50 -0
- ccxt/abstract/deribit.py +125 -0
- ccxt/abstract/digifinex.py +91 -0
- ccxt/abstract/eterex.py +5 -0
- ccxt/abstract/excoino.py +7 -0
- ccxt/abstract/exir.py +8 -0
- ccxt/abstract/exmo.py +55 -0
- ccxt/abstract/exnovin.py +6 -0
- ccxt/abstract/farhadexchange.py +5 -0
- ccxt/abstract/fmfwio.py +115 -0
- ccxt/abstract/gate.py +265 -0
- ccxt/abstract/gateio.py +265 -0
- ccxt/abstract/gemini.py +58 -0
- ccxt/abstract/hashkey.py +67 -0
- ccxt/abstract/hitbtc.py +115 -0
- ccxt/abstract/hitbtc3.py +115 -0
- ccxt/abstract/hitobit.py +8 -0
- ccxt/abstract/hollaex.py +33 -0
- ccxt/abstract/htx.py +548 -0
- ccxt/abstract/huobi.py +548 -0
- ccxt/abstract/huobijp.py +114 -0
- ccxt/abstract/hyperliquid.py +6 -0
- ccxt/abstract/idex.py +26 -0
- ccxt/abstract/independentreserve.py +37 -0
- ccxt/abstract/indodax.py +26 -0
- ccxt/abstract/jibitex.py +7 -0
- ccxt/abstract/kraken.py +57 -0
- ccxt/abstract/krakenfutures.py +38 -0
- ccxt/abstract/kucoin.py +214 -0
- ccxt/abstract/kucoinfutures.py +233 -0
- ccxt/abstract/kuna.py +182 -0
- ccxt/abstract/latoken.py +56 -0
- ccxt/abstract/lbank.py +61 -0
- ccxt/abstract/luno.py +37 -0
- ccxt/abstract/lykke.py +29 -0
- ccxt/abstract/mercado.py +25 -0
- ccxt/abstract/mexc.py +178 -0
- ccxt/abstract/ndax.py +97 -0
- ccxt/abstract/nobitex.py +7 -0
- ccxt/abstract/novadax.py +29 -0
- ccxt/abstract/oceanex.py +22 -0
- ccxt/abstract/okcoin.py +74 -0
- ccxt/abstract/okexchange.py +8 -0
- ccxt/abstract/okx.py +324 -0
- ccxt/abstract/ompfinex.py +7 -0
- ccxt/abstract/onetrading.py +35 -0
- ccxt/abstract/oxfun.py +34 -0
- ccxt/abstract/p2b.py +22 -0
- ccxt/abstract/paradex.py +40 -0
- ccxt/abstract/paymium.py +28 -0
- ccxt/abstract/phemex.py +115 -0
- ccxt/abstract/poloniex.py +69 -0
- ccxt/abstract/poloniexfutures.py +48 -0
- ccxt/abstract/probit.py +23 -0
- ccxt/abstract/ramzinex.py +7 -0
- ccxt/abstract/sarmayex.py +5 -0
- ccxt/abstract/sarrafex.py +7 -0
- ccxt/abstract/tabdeal.py +7 -0
- ccxt/abstract/tetherland.py +5 -0
- ccxt/abstract/timex.py +62 -0
- ccxt/abstract/tokocrypto.py +37 -0
- ccxt/abstract/tradeogre.py +16 -0
- ccxt/abstract/twox.py +5 -0
- ccxt/abstract/ubitex.py +7 -0
- ccxt/abstract/upbit.py +38 -0
- ccxt/abstract/vertex.py +19 -0
- ccxt/abstract/wallex.py +8 -0
- ccxt/abstract/wavesexchange.py +154 -0
- ccxt/abstract/wazirx.py +30 -0
- ccxt/abstract/whitebit.py +98 -0
- ccxt/abstract/woo.py +83 -0
- ccxt/abstract/woofipro.py +119 -0
- ccxt/abstract/xt.py +152 -0
- ccxt/abstract/yobit.py +16 -0
- ccxt/abstract/zaif.py +38 -0
- ccxt/abstract/zonda.py +53 -0
- ccxt/ace.py +1012 -0
- ccxt/afratether.py +293 -0
- ccxt/alpaca.py +1083 -0
- ccxt/arzinja.py +285 -0
- ccxt/arzplus.py +412 -0
- ccxt/ascendex.py +3330 -0
- ccxt/async_support/__init__.py +337 -0
- ccxt/async_support/abantether.py +316 -0
- ccxt/async_support/ace.py +1012 -0
- ccxt/async_support/afratether.py +293 -0
- ccxt/async_support/alpaca.py +1083 -0
- ccxt/async_support/arzinja.py +285 -0
- ccxt/async_support/arzplus.py +412 -0
- ccxt/async_support/ascendex.py +3330 -0
- ccxt/async_support/base/__init__.py +1 -0
- ccxt/async_support/base/exchange.py +1966 -0
- ccxt/async_support/base/throttler.py +50 -0
- ccxt/async_support/base/ws/__init__.py +38 -0
- ccxt/async_support/base/ws/aiohttp_client.py +125 -0
- ccxt/async_support/base/ws/cache.py +212 -0
- ccxt/async_support/base/ws/client.py +193 -0
- ccxt/async_support/base/ws/fast_client.py +96 -0
- ccxt/async_support/base/ws/functions.py +59 -0
- ccxt/async_support/base/ws/future.py +58 -0
- ccxt/async_support/base/ws/order_book.py +78 -0
- ccxt/async_support/base/ws/order_book_side.py +174 -0
- ccxt/async_support/bequant.py +33 -0
- ccxt/async_support/bigone.py +2113 -0
- ccxt/async_support/binance.py +12234 -0
- ccxt/async_support/binancecoinm.py +45 -0
- ccxt/async_support/binanceus.py +211 -0
- ccxt/async_support/binanceusdm.py +58 -0
- ccxt/async_support/bingx.py +4325 -0
- ccxt/async_support/bit2c.py +866 -0
- ccxt/async_support/bitbank.py +1001 -0
- ccxt/async_support/bitbay.py +17 -0
- ccxt/async_support/bitbns.py +1154 -0
- ccxt/async_support/bitcoincom.py +17 -0
- ccxt/async_support/bitfinex.py +1617 -0
- ccxt/async_support/bitfinex2.py +3552 -0
- ccxt/async_support/bitflyer.py +995 -0
- ccxt/async_support/bitget.py +8273 -0
- ccxt/async_support/bithumb.py +1061 -0
- ccxt/async_support/bitimen.py +401 -0
- ccxt/async_support/bitir.py +490 -0
- ccxt/async_support/bitmart.py +4415 -0
- ccxt/async_support/bitmex.py +2756 -0
- ccxt/async_support/bitopro.py +1630 -0
- ccxt/async_support/bitpanda.py +16 -0
- ccxt/async_support/bitpin.py +454 -0
- ccxt/async_support/bitrue.py +3027 -0
- ccxt/async_support/bitso.py +1670 -0
- ccxt/async_support/bitstamp.py +2203 -0
- ccxt/async_support/bitteam.py +2239 -0
- ccxt/async_support/bitvavo.py +1968 -0
- ccxt/async_support/bl3p.py +485 -0
- ccxt/async_support/blockchaincom.py +1104 -0
- ccxt/async_support/blofin.py +2066 -0
- ccxt/async_support/btcalpha.py +891 -0
- ccxt/async_support/btcbox.py +544 -0
- ccxt/async_support/btcmarkets.py +1221 -0
- ccxt/async_support/btcturk.py +911 -0
- ccxt/async_support/bybit.py +8159 -0
- ccxt/async_support/cex.py +1605 -0
- ccxt/async_support/coinbase.py +4475 -0
- ccxt/async_support/coinbaseadvanced.py +17 -0
- ccxt/async_support/coinbaseexchange.py +1734 -0
- ccxt/async_support/coinbaseinternational.py +1899 -0
- ccxt/async_support/coincatch.py +5069 -0
- ccxt/async_support/coincheck.py +815 -0
- ccxt/async_support/coinex.py +5526 -0
- ccxt/async_support/coinlist.py +2243 -0
- ccxt/async_support/coinmate.py +1067 -0
- ccxt/async_support/coinmetro.py +1797 -0
- ccxt/async_support/coinone.py +1127 -0
- ccxt/async_support/coinsph.py +1850 -0
- ccxt/async_support/coinspot.py +534 -0
- ccxt/async_support/cryptocom.py +2822 -0
- ccxt/async_support/currencycom.py +1950 -0
- ccxt/async_support/delta.py +3376 -0
- ccxt/async_support/deribit.py +3437 -0
- ccxt/async_support/digifinex.py +3960 -0
- ccxt/async_support/eterex.py +286 -0
- ccxt/async_support/excoino.py +399 -0
- ccxt/async_support/exir.py +375 -0
- ccxt/async_support/exmo.py +2462 -0
- ccxt/async_support/exnovin.py +360 -0
- ccxt/async_support/farhadexchange.py +266 -0
- ccxt/async_support/fmfwio.py +34 -0
- ccxt/async_support/gate.py +6976 -0
- ccxt/async_support/gateio.py +16 -0
- ccxt/async_support/gemini.py +1825 -0
- ccxt/async_support/hashkey.py +4150 -0
- ccxt/async_support/hitbtc.py +3423 -0
- ccxt/async_support/hitbtc3.py +16 -0
- ccxt/async_support/hitobit.py +391 -0
- ccxt/async_support/hollaex.py +1813 -0
- ccxt/async_support/htx.py +8506 -0
- ccxt/async_support/huobi.py +16 -0
- ccxt/async_support/huobijp.py +1801 -0
- ccxt/async_support/hyperliquid.py +2431 -0
- ccxt/async_support/idex.py +1766 -0
- ccxt/async_support/independentreserve.py +784 -0
- ccxt/async_support/indodax.py +1247 -0
- ccxt/async_support/jibitex.py +395 -0
- ccxt/async_support/kraken.py +2894 -0
- ccxt/async_support/krakenfutures.py +2601 -0
- ccxt/async_support/kucoin.py +4602 -0
- ccxt/async_support/kucoinfutures.py +2698 -0
- ccxt/async_support/kuna.py +1841 -0
- ccxt/async_support/latoken.py +1664 -0
- ccxt/async_support/lbank.py +2683 -0
- ccxt/async_support/luno.py +1067 -0
- ccxt/async_support/lykke.py +1270 -0
- ccxt/async_support/mercado.py +842 -0
- ccxt/async_support/mexc.py +5369 -0
- ccxt/async_support/ndax.py +2354 -0
- ccxt/async_support/nobitex.py +419 -0
- ccxt/async_support/novadax.py +1484 -0
- ccxt/async_support/oceanex.py +903 -0
- ccxt/async_support/okcoin.py +2936 -0
- ccxt/async_support/okexchange.py +349 -0
- ccxt/async_support/okx.py +7827 -0
- ccxt/async_support/ompfinex.py +472 -0
- ccxt/async_support/onetrading.py +1911 -0
- ccxt/async_support/oxfun.py +2773 -0
- ccxt/async_support/p2b.py +1194 -0
- ccxt/async_support/paradex.py +2015 -0
- ccxt/async_support/paymium.py +564 -0
- ccxt/async_support/phemex.py +4473 -0
- ccxt/async_support/poloniex.py +2232 -0
- ccxt/async_support/poloniexfutures.py +1717 -0
- ccxt/async_support/probit.py +1734 -0
- ccxt/async_support/ramzinex.py +476 -0
- ccxt/async_support/sarmayex.py +357 -0
- ccxt/async_support/sarrafex.py +478 -0
- ccxt/async_support/tabdeal.py +364 -0
- ccxt/async_support/tetherland.py +349 -0
- ccxt/async_support/timex.py +1593 -0
- ccxt/async_support/tokocrypto.py +2405 -0
- ccxt/async_support/tradeogre.py +608 -0
- ccxt/async_support/twox.py +326 -0
- ccxt/async_support/ubitex.py +409 -0
- ccxt/async_support/upbit.py +1833 -0
- ccxt/async_support/vertex.py +2922 -0
- ccxt/async_support/wallex.py +445 -0
- ccxt/async_support/wavesexchange.py +2473 -0
- ccxt/async_support/wazirx.py +1224 -0
- ccxt/async_support/whitebit.py +2469 -0
- ccxt/async_support/woo.py +3114 -0
- ccxt/async_support/woofipro.py +2533 -0
- ccxt/async_support/xt.py +4454 -0
- ccxt/async_support/yobit.py +1283 -0
- ccxt/async_support/zaif.py +725 -0
- ccxt/async_support/zonda.py +1828 -0
- ccxt/base/__init__.py +27 -0
- ccxt/base/decimal_to_precision.py +174 -0
- ccxt/base/errors.py +242 -0
- ccxt/base/exchange.py +5941 -0
- ccxt/base/precise.py +287 -0
- ccxt/base/types.py +502 -0
- ccxt/bequant.py +33 -0
- ccxt/bigone.py +2112 -0
- ccxt/binance.py +12233 -0
- ccxt/binancecoinm.py +45 -0
- ccxt/binanceus.py +211 -0
- ccxt/binanceusdm.py +58 -0
- ccxt/bingx.py +4324 -0
- ccxt/bit2c.py +866 -0
- ccxt/bitbank.py +1001 -0
- ccxt/bitbay.py +17 -0
- ccxt/bitbns.py +1154 -0
- ccxt/bitcoincom.py +17 -0
- ccxt/bitfinex.py +1617 -0
- ccxt/bitfinex2.py +3552 -0
- ccxt/bitflyer.py +995 -0
- ccxt/bitget.py +8272 -0
- ccxt/bithumb.py +1061 -0
- ccxt/bitimen.py +401 -0
- ccxt/bitir.py +490 -0
- ccxt/bitmart.py +4415 -0
- ccxt/bitmex.py +2756 -0
- ccxt/bitopro.py +1630 -0
- ccxt/bitpanda.py +16 -0
- ccxt/bitpin.py +454 -0
- ccxt/bitrue.py +3026 -0
- ccxt/bitso.py +1670 -0
- ccxt/bitstamp.py +2203 -0
- ccxt/bitteam.py +2239 -0
- ccxt/bitvavo.py +1968 -0
- ccxt/bl3p.py +485 -0
- ccxt/blockchaincom.py +1104 -0
- ccxt/blofin.py +2066 -0
- ccxt/btcalpha.py +891 -0
- ccxt/btcbox.py +544 -0
- ccxt/btcmarkets.py +1221 -0
- ccxt/btcturk.py +911 -0
- ccxt/bybit.py +8158 -0
- ccxt/cex.py +1605 -0
- ccxt/coinbase.py +4474 -0
- ccxt/coinbaseadvanced.py +17 -0
- ccxt/coinbaseexchange.py +1734 -0
- ccxt/coinbaseinternational.py +1899 -0
- ccxt/coincatch.py +5069 -0
- ccxt/coincheck.py +815 -0
- ccxt/coinex.py +5525 -0
- ccxt/coinlist.py +2243 -0
- ccxt/coinmate.py +1067 -0
- ccxt/coinmetro.py +1797 -0
- ccxt/coinone.py +1127 -0
- ccxt/coinsph.py +1850 -0
- ccxt/coinspot.py +534 -0
- ccxt/cryptocom.py +2822 -0
- ccxt/currencycom.py +1950 -0
- ccxt/delta.py +3376 -0
- ccxt/deribit.py +3437 -0
- ccxt/digifinex.py +3959 -0
- ccxt/eterex.py +286 -0
- ccxt/excoino.py +399 -0
- ccxt/exir.py +375 -0
- ccxt/exmo.py +2462 -0
- ccxt/exnovin.py +360 -0
- ccxt/farhadexchange.py +266 -0
- ccxt/fmfwio.py +34 -0
- ccxt/gate.py +6975 -0
- ccxt/gateio.py +16 -0
- ccxt/gemini.py +1824 -0
- ccxt/hashkey.py +4150 -0
- ccxt/hitbtc.py +3423 -0
- ccxt/hitbtc3.py +16 -0
- ccxt/hitobit.py +391 -0
- ccxt/hollaex.py +1813 -0
- ccxt/htx.py +8505 -0
- ccxt/huobi.py +16 -0
- ccxt/huobijp.py +1801 -0
- ccxt/hyperliquid.py +2430 -0
- ccxt/idex.py +1766 -0
- ccxt/independentreserve.py +784 -0
- ccxt/indodax.py +1247 -0
- ccxt/jibitex.py +395 -0
- ccxt/kraken.py +2894 -0
- ccxt/krakenfutures.py +2601 -0
- ccxt/kucoin.py +4601 -0
- ccxt/kucoinfutures.py +2698 -0
- ccxt/kuna.py +1841 -0
- ccxt/latoken.py +1664 -0
- ccxt/lbank.py +2682 -0
- ccxt/luno.py +1067 -0
- ccxt/lykke.py +1270 -0
- ccxt/mercado.py +842 -0
- ccxt/mexc.py +5369 -0
- ccxt/ndax.py +2354 -0
- ccxt/nobitex.py +419 -0
- ccxt/novadax.py +1484 -0
- ccxt/oceanex.py +903 -0
- ccxt/okcoin.py +2936 -0
- ccxt/okexchange.py +349 -0
- ccxt/okx.py +7826 -0
- ccxt/ompfinex.py +472 -0
- ccxt/onetrading.py +1911 -0
- ccxt/oxfun.py +2772 -0
- ccxt/p2b.py +1194 -0
- ccxt/paradex.py +2015 -0
- ccxt/paymium.py +564 -0
- ccxt/phemex.py +4473 -0
- ccxt/poloniex.py +2232 -0
- ccxt/poloniexfutures.py +1717 -0
- ccxt/pro/__init__.py +149 -0
- ccxt/pro/alpaca.py +685 -0
- ccxt/pro/ascendex.py +916 -0
- ccxt/pro/bequant.py +38 -0
- ccxt/pro/binance.py +3488 -0
- ccxt/pro/binancecoinm.py +28 -0
- ccxt/pro/binanceus.py +48 -0
- ccxt/pro/binanceusdm.py +31 -0
- ccxt/pro/bingx.py +1264 -0
- ccxt/pro/bitcoincom.py +34 -0
- ccxt/pro/bitfinex.py +621 -0
- ccxt/pro/bitfinex2.py +1083 -0
- ccxt/pro/bitget.py +1692 -0
- ccxt/pro/bithumb.py +368 -0
- ccxt/pro/bitmart.py +1449 -0
- ccxt/pro/bitmex.py +1656 -0
- ccxt/pro/bitopro.py +445 -0
- ccxt/pro/bitpanda.py +15 -0
- ccxt/pro/bitrue.py +447 -0
- ccxt/pro/bitstamp.py +522 -0
- ccxt/pro/bitvavo.py +1270 -0
- ccxt/pro/blockchaincom.py +738 -0
- ccxt/pro/blofin.py +692 -0
- ccxt/pro/bybit.py +2000 -0
- ccxt/pro/cex.py +1440 -0
- ccxt/pro/coinbase.py +678 -0
- ccxt/pro/coinbaseadvanced.py +16 -0
- ccxt/pro/coinbaseexchange.py +895 -0
- ccxt/pro/coinbaseinternational.py +620 -0
- ccxt/pro/coincatch.py +1464 -0
- ccxt/pro/coincheck.py +199 -0
- ccxt/pro/coinex.py +1061 -0
- ccxt/pro/coinone.py +395 -0
- ccxt/pro/cryptocom.py +947 -0
- ccxt/pro/currencycom.py +536 -0
- ccxt/pro/deribit.py +892 -0
- ccxt/pro/exmo.py +629 -0
- ccxt/pro/gate.py +1416 -0
- ccxt/pro/gateio.py +15 -0
- ccxt/pro/gemini.py +865 -0
- ccxt/pro/hashkey.py +802 -0
- ccxt/pro/hitbtc.py +1216 -0
- ccxt/pro/hollaex.py +563 -0
- ccxt/pro/htx.py +2215 -0
- ccxt/pro/huobi.py +15 -0
- ccxt/pro/huobijp.py +570 -0
- ccxt/pro/hyperliquid.py +525 -0
- ccxt/pro/idex.py +672 -0
- ccxt/pro/independentreserve.py +270 -0
- ccxt/pro/kraken.py +1356 -0
- ccxt/pro/krakenfutures.py +1492 -0
- ccxt/pro/kucoin.py +1133 -0
- ccxt/pro/kucoinfutures.py +1081 -0
- ccxt/pro/lbank.py +843 -0
- ccxt/pro/luno.py +303 -0
- ccxt/pro/mexc.py +1122 -0
- ccxt/pro/ndax.py +506 -0
- ccxt/pro/okcoin.py +698 -0
- ccxt/pro/okx.py +1851 -0
- ccxt/pro/onetrading.py +1275 -0
- ccxt/pro/oxfun.py +950 -0
- ccxt/pro/p2b.py +419 -0
- ccxt/pro/paradex.py +352 -0
- ccxt/pro/phemex.py +1441 -0
- ccxt/pro/poloniex.py +1166 -0
- ccxt/pro/poloniexfutures.py +990 -0
- ccxt/pro/probit.py +551 -0
- ccxt/pro/upbit.py +520 -0
- ccxt/pro/vertex.py +943 -0
- ccxt/pro/wazirx.py +749 -0
- ccxt/pro/whitebit.py +864 -0
- ccxt/pro/woo.py +1078 -0
- ccxt/pro/woofipro.py +1183 -0
- ccxt/pro/xt.py +1067 -0
- ccxt/probit.py +1734 -0
- ccxt/ramzinex.py +476 -0
- ccxt/sarmayex.py +357 -0
- ccxt/sarrafex.py +478 -0
- ccxt/static_dependencies/__init__.py +1 -0
- ccxt/static_dependencies/ecdsa/__init__.py +14 -0
- ccxt/static_dependencies/ecdsa/_version.py +520 -0
- ccxt/static_dependencies/ecdsa/curves.py +56 -0
- ccxt/static_dependencies/ecdsa/der.py +221 -0
- ccxt/static_dependencies/ecdsa/ecdsa.py +310 -0
- ccxt/static_dependencies/ecdsa/ellipticcurve.py +197 -0
- ccxt/static_dependencies/ecdsa/keys.py +332 -0
- ccxt/static_dependencies/ecdsa/numbertheory.py +531 -0
- ccxt/static_dependencies/ecdsa/rfc6979.py +100 -0
- ccxt/static_dependencies/ecdsa/util.py +266 -0
- ccxt/static_dependencies/ethereum/__init__.py +7 -0
- ccxt/static_dependencies/ethereum/abi/__init__.py +16 -0
- ccxt/static_dependencies/ethereum/abi/abi.py +19 -0
- ccxt/static_dependencies/ethereum/abi/base.py +152 -0
- ccxt/static_dependencies/ethereum/abi/codec.py +217 -0
- ccxt/static_dependencies/ethereum/abi/constants.py +3 -0
- ccxt/static_dependencies/ethereum/abi/decoding.py +565 -0
- ccxt/static_dependencies/ethereum/abi/encoding.py +720 -0
- ccxt/static_dependencies/ethereum/abi/exceptions.py +139 -0
- ccxt/static_dependencies/ethereum/abi/grammar.py +443 -0
- ccxt/static_dependencies/ethereum/abi/packed.py +13 -0
- ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
- ccxt/static_dependencies/ethereum/abi/registry.py +643 -0
- ccxt/static_dependencies/ethereum/abi/tools/__init__.py +3 -0
- ccxt/static_dependencies/ethereum/abi/tools/_strategies.py +230 -0
- ccxt/static_dependencies/ethereum/abi/utils/__init__.py +0 -0
- ccxt/static_dependencies/ethereum/abi/utils/numeric.py +83 -0
- ccxt/static_dependencies/ethereum/abi/utils/padding.py +27 -0
- ccxt/static_dependencies/ethereum/abi/utils/string.py +19 -0
- ccxt/static_dependencies/ethereum/account/__init__.py +3 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/__init__.py +4 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/encoding_and_hashing.py +239 -0
- ccxt/static_dependencies/ethereum/account/encode_typed_data/helpers.py +40 -0
- ccxt/static_dependencies/ethereum/account/messages.py +263 -0
- ccxt/static_dependencies/ethereum/account/py.typed +0 -0
- ccxt/static_dependencies/ethereum/hexbytes/__init__.py +5 -0
- ccxt/static_dependencies/ethereum/hexbytes/_utils.py +54 -0
- ccxt/static_dependencies/ethereum/hexbytes/main.py +65 -0
- ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
- ccxt/static_dependencies/ethereum/typing/__init__.py +63 -0
- ccxt/static_dependencies/ethereum/typing/abi.py +6 -0
- ccxt/static_dependencies/ethereum/typing/bls.py +7 -0
- ccxt/static_dependencies/ethereum/typing/discovery.py +5 -0
- ccxt/static_dependencies/ethereum/typing/encoding.py +7 -0
- ccxt/static_dependencies/ethereum/typing/enums.py +17 -0
- ccxt/static_dependencies/ethereum/typing/ethpm.py +9 -0
- ccxt/static_dependencies/ethereum/typing/evm.py +20 -0
- ccxt/static_dependencies/ethereum/typing/networks.py +1122 -0
- ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
- ccxt/static_dependencies/ethereum/utils/__init__.py +115 -0
- ccxt/static_dependencies/ethereum/utils/abi.py +72 -0
- ccxt/static_dependencies/ethereum/utils/address.py +171 -0
- ccxt/static_dependencies/ethereum/utils/applicators.py +151 -0
- ccxt/static_dependencies/ethereum/utils/conversions.py +190 -0
- ccxt/static_dependencies/ethereum/utils/currency.py +107 -0
- ccxt/static_dependencies/ethereum/utils/curried/__init__.py +269 -0
- ccxt/static_dependencies/ethereum/utils/debug.py +20 -0
- ccxt/static_dependencies/ethereum/utils/decorators.py +132 -0
- ccxt/static_dependencies/ethereum/utils/encoding.py +6 -0
- ccxt/static_dependencies/ethereum/utils/exceptions.py +4 -0
- ccxt/static_dependencies/ethereum/utils/functional.py +75 -0
- ccxt/static_dependencies/ethereum/utils/hexadecimal.py +74 -0
- ccxt/static_dependencies/ethereum/utils/humanize.py +188 -0
- ccxt/static_dependencies/ethereum/utils/logging.py +159 -0
- ccxt/static_dependencies/ethereum/utils/module_loading.py +31 -0
- ccxt/static_dependencies/ethereum/utils/numeric.py +43 -0
- ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
- ccxt/static_dependencies/ethereum/utils/toolz.py +76 -0
- ccxt/static_dependencies/ethereum/utils/types.py +54 -0
- ccxt/static_dependencies/ethereum/utils/typing/__init__.py +18 -0
- ccxt/static_dependencies/ethereum/utils/typing/misc.py +14 -0
- ccxt/static_dependencies/ethereum/utils/units.py +31 -0
- ccxt/static_dependencies/keccak/__init__.py +3 -0
- ccxt/static_dependencies/keccak/keccak.py +197 -0
- ccxt/static_dependencies/lark/__init__.py +38 -0
- ccxt/static_dependencies/lark/__pyinstaller/__init__.py +6 -0
- ccxt/static_dependencies/lark/__pyinstaller/hook-lark.py +14 -0
- ccxt/static_dependencies/lark/ast_utils.py +59 -0
- ccxt/static_dependencies/lark/common.py +86 -0
- ccxt/static_dependencies/lark/exceptions.py +292 -0
- ccxt/static_dependencies/lark/grammar.py +130 -0
- ccxt/static_dependencies/lark/grammars/__init__.py +0 -0
- ccxt/static_dependencies/lark/indenter.py +143 -0
- ccxt/static_dependencies/lark/lark.py +658 -0
- ccxt/static_dependencies/lark/lexer.py +678 -0
- ccxt/static_dependencies/lark/load_grammar.py +1428 -0
- ccxt/static_dependencies/lark/parse_tree_builder.py +391 -0
- ccxt/static_dependencies/lark/parser_frontends.py +257 -0
- ccxt/static_dependencies/lark/parsers/__init__.py +0 -0
- ccxt/static_dependencies/lark/parsers/cyk.py +340 -0
- ccxt/static_dependencies/lark/parsers/earley.py +314 -0
- ccxt/static_dependencies/lark/parsers/earley_common.py +42 -0
- ccxt/static_dependencies/lark/parsers/earley_forest.py +801 -0
- ccxt/static_dependencies/lark/parsers/grammar_analysis.py +203 -0
- ccxt/static_dependencies/lark/parsers/lalr_analysis.py +332 -0
- ccxt/static_dependencies/lark/parsers/lalr_interactive_parser.py +158 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser.py +122 -0
- ccxt/static_dependencies/lark/parsers/lalr_parser_state.py +110 -0
- ccxt/static_dependencies/lark/parsers/xearley.py +165 -0
- ccxt/static_dependencies/lark/reconstruct.py +107 -0
- ccxt/static_dependencies/lark/tools/__init__.py +70 -0
- ccxt/static_dependencies/lark/tools/nearley.py +202 -0
- ccxt/static_dependencies/lark/tools/serialize.py +32 -0
- ccxt/static_dependencies/lark/tools/standalone.py +196 -0
- ccxt/static_dependencies/lark/tree.py +267 -0
- ccxt/static_dependencies/lark/tree_matcher.py +186 -0
- ccxt/static_dependencies/lark/tree_templates.py +180 -0
- ccxt/static_dependencies/lark/utils.py +343 -0
- ccxt/static_dependencies/lark/visitors.py +596 -0
- ccxt/static_dependencies/marshmallow/__init__.py +81 -0
- ccxt/static_dependencies/marshmallow/base.py +65 -0
- ccxt/static_dependencies/marshmallow/class_registry.py +94 -0
- ccxt/static_dependencies/marshmallow/decorators.py +231 -0
- ccxt/static_dependencies/marshmallow/error_store.py +60 -0
- ccxt/static_dependencies/marshmallow/exceptions.py +71 -0
- ccxt/static_dependencies/marshmallow/fields.py +2114 -0
- ccxt/static_dependencies/marshmallow/orderedset.py +89 -0
- ccxt/static_dependencies/marshmallow/schema.py +1228 -0
- ccxt/static_dependencies/marshmallow/types.py +12 -0
- ccxt/static_dependencies/marshmallow/utils.py +378 -0
- ccxt/static_dependencies/marshmallow/validate.py +678 -0
- ccxt/static_dependencies/marshmallow/warnings.py +2 -0
- ccxt/static_dependencies/marshmallow_dataclass/__init__.py +1047 -0
- ccxt/static_dependencies/marshmallow_dataclass/collection_field.py +51 -0
- ccxt/static_dependencies/marshmallow_dataclass/lazy_class_attribute.py +45 -0
- ccxt/static_dependencies/marshmallow_dataclass/mypy.py +71 -0
- ccxt/static_dependencies/marshmallow_dataclass/typing.py +14 -0
- ccxt/static_dependencies/marshmallow_dataclass/union_field.py +82 -0
- ccxt/static_dependencies/marshmallow_oneofschema/__init__.py +1 -0
- ccxt/static_dependencies/marshmallow_oneofschema/one_of_schema.py +193 -0
- ccxt/static_dependencies/msgpack/__init__.py +55 -0
- ccxt/static_dependencies/msgpack/exceptions.py +48 -0
- ccxt/static_dependencies/msgpack/ext.py +168 -0
- ccxt/static_dependencies/msgpack/fallback.py +951 -0
- ccxt/static_dependencies/parsimonious/__init__.py +10 -0
- ccxt/static_dependencies/parsimonious/exceptions.py +105 -0
- ccxt/static_dependencies/parsimonious/expressions.py +479 -0
- ccxt/static_dependencies/parsimonious/grammar.py +487 -0
- ccxt/static_dependencies/parsimonious/nodes.py +325 -0
- ccxt/static_dependencies/parsimonious/utils.py +40 -0
- ccxt/static_dependencies/starknet/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/data_types.py +123 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/cairo_types.py +77 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser.py +46 -0
- ccxt/static_dependencies/starknet/cairo/deprecated_parse/parser_transformer.py +138 -0
- ccxt/static_dependencies/starknet/cairo/felt.py +64 -0
- ccxt/static_dependencies/starknet/cairo/type_parser.py +121 -0
- ccxt/static_dependencies/starknet/cairo/v1/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v1/type_parser.py +59 -0
- ccxt/static_dependencies/starknet/cairo/v2/__init__.py +0 -0
- ccxt/static_dependencies/starknet/cairo/v2/type_parser.py +77 -0
- ccxt/static_dependencies/starknet/ccxt_utils.py +7 -0
- ccxt/static_dependencies/starknet/common.py +15 -0
- ccxt/static_dependencies/starknet/constants.py +39 -0
- ccxt/static_dependencies/starknet/hash/__init__.py +0 -0
- ccxt/static_dependencies/starknet/hash/address.py +79 -0
- ccxt/static_dependencies/starknet/hash/compiled_class_hash_objects.py +111 -0
- ccxt/static_dependencies/starknet/hash/selector.py +16 -0
- ccxt/static_dependencies/starknet/hash/storage.py +12 -0
- ccxt/static_dependencies/starknet/hash/utils.py +78 -0
- ccxt/static_dependencies/starknet/models/__init__.py +0 -0
- ccxt/static_dependencies/starknet/models/typed_data.py +45 -0
- ccxt/static_dependencies/starknet/serialization/__init__.py +24 -0
- ccxt/static_dependencies/starknet/serialization/_calldata_reader.py +40 -0
- ccxt/static_dependencies/starknet/serialization/_context.py +142 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/__init__.py +10 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/_common.py +82 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/array_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/bool_serializer.py +37 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/byte_array_serializer.py +66 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/cairo_data_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/enum_serializer.py +71 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/felt_serializer.py +50 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/named_tuple_serializer.py +58 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/option_serializer.py +43 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/output_serializer.py +40 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/payload_serializer.py +72 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/struct_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/tuple_serializer.py +36 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint256_serializer.py +76 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/uint_serializer.py +100 -0
- ccxt/static_dependencies/starknet/serialization/data_serializers/unit_serializer.py +32 -0
- ccxt/static_dependencies/starknet/serialization/errors.py +10 -0
- ccxt/static_dependencies/starknet/serialization/factory.py +229 -0
- ccxt/static_dependencies/starknet/serialization/function_serialization_adapter.py +110 -0
- ccxt/static_dependencies/starknet/serialization/tuple_dataclass.py +59 -0
- ccxt/static_dependencies/starknet/utils/__init__.py +0 -0
- ccxt/static_dependencies/starknet/utils/constructor_args_translator.py +86 -0
- ccxt/static_dependencies/starknet/utils/iterable.py +13 -0
- ccxt/static_dependencies/starknet/utils/schema.py +13 -0
- ccxt/static_dependencies/starknet/utils/typed_data.py +182 -0
- ccxt/static_dependencies/starkware/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/__init__.py +0 -0
- ccxt/static_dependencies/starkware/crypto/fast_pedersen_hash.py +50 -0
- ccxt/static_dependencies/starkware/crypto/math_utils.py +78 -0
- ccxt/static_dependencies/starkware/crypto/signature.py +2344 -0
- ccxt/static_dependencies/starkware/crypto/utils.py +63 -0
- ccxt/static_dependencies/sympy/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/__init__.py +0 -0
- ccxt/static_dependencies/sympy/core/intfunc.py +35 -0
- ccxt/static_dependencies/sympy/external/__init__.py +0 -0
- ccxt/static_dependencies/sympy/external/gmpy.py +345 -0
- ccxt/static_dependencies/sympy/external/importtools.py +187 -0
- ccxt/static_dependencies/sympy/external/ntheory.py +637 -0
- ccxt/static_dependencies/sympy/external/pythonmpq.py +341 -0
- ccxt/static_dependencies/toolz/__init__.py +26 -0
- ccxt/static_dependencies/toolz/_signatures.py +784 -0
- ccxt/static_dependencies/toolz/_version.py +520 -0
- ccxt/static_dependencies/toolz/compatibility.py +30 -0
- ccxt/static_dependencies/toolz/curried/__init__.py +101 -0
- ccxt/static_dependencies/toolz/curried/exceptions.py +22 -0
- ccxt/static_dependencies/toolz/curried/operator.py +22 -0
- ccxt/static_dependencies/toolz/dicttoolz.py +339 -0
- ccxt/static_dependencies/toolz/functoolz.py +1049 -0
- ccxt/static_dependencies/toolz/itertoolz.py +1057 -0
- ccxt/static_dependencies/toolz/recipes.py +46 -0
- ccxt/static_dependencies/toolz/utils.py +9 -0
- ccxt/static_dependencies/typing_inspect/__init__.py +0 -0
- ccxt/static_dependencies/typing_inspect/typing_inspect.py +851 -0
- ccxt/tabdeal.py +364 -0
- ccxt/test/__init__.py +3 -0
- ccxt/test/base/__init__.py +29 -0
- ccxt/test/base/test_account.py +26 -0
- ccxt/test/base/test_balance.py +56 -0
- ccxt/test/base/test_borrow_interest.py +35 -0
- ccxt/test/base/test_borrow_rate.py +32 -0
- ccxt/test/base/test_calculate_fee.py +51 -0
- ccxt/test/base/test_crypto.py +127 -0
- ccxt/test/base/test_currency.py +76 -0
- ccxt/test/base/test_datetime.py +109 -0
- ccxt/test/base/test_decimal_to_precision.py +392 -0
- ccxt/test/base/test_deep_extend.py +68 -0
- ccxt/test/base/test_deposit_withdrawal.py +50 -0
- ccxt/test/base/test_exchange_datetime_functions.py +76 -0
- ccxt/test/base/test_funding_rate_history.py +29 -0
- ccxt/test/base/test_last_price.py +31 -0
- ccxt/test/base/test_ledger_entry.py +45 -0
- ccxt/test/base/test_ledger_item.py +48 -0
- ccxt/test/base/test_leverage_tier.py +33 -0
- ccxt/test/base/test_liquidation.py +50 -0
- ccxt/test/base/test_margin_mode.py +24 -0
- ccxt/test/base/test_margin_modification.py +35 -0
- ccxt/test/base/test_market.py +193 -0
- ccxt/test/base/test_number.py +411 -0
- ccxt/test/base/test_ohlcv.py +33 -0
- ccxt/test/base/test_open_interest.py +32 -0
- ccxt/test/base/test_order.py +64 -0
- ccxt/test/base/test_order_book.py +69 -0
- ccxt/test/base/test_position.py +60 -0
- ccxt/test/base/test_shared_methods.py +353 -0
- ccxt/test/base/test_status.py +24 -0
- ccxt/test/base/test_throttle.py +126 -0
- ccxt/test/base/test_ticker.py +92 -0
- ccxt/test/base/test_trade.py +47 -0
- ccxt/test/base/test_trading_fee.py +26 -0
- ccxt/test/base/test_transaction.py +39 -0
- ccxt/test/test_async.py +1649 -0
- ccxt/test/test_sync.py +1648 -0
- ccxt/test/tests_async.py +1558 -0
- ccxt/test/tests_helpers.py +287 -0
- ccxt/test/tests_init.py +39 -0
- ccxt/test/tests_sync.py +1555 -0
- ccxt/tetherland.py +349 -0
- ccxt/timex.py +1593 -0
- ccxt/tokocrypto.py +2405 -0
- ccxt/tradeogre.py +608 -0
- ccxt/twox.py +326 -0
- ccxt/ubitex.py +409 -0
- ccxt/upbit.py +1833 -0
- ccxt/vertex.py +2922 -0
- ccxt/wallex.py +445 -0
- ccxt/wavesexchange.py +2472 -0
- ccxt/wazirx.py +1224 -0
- ccxt/whitebit.py +2469 -0
- ccxt/woo.py +3114 -0
- ccxt/woofipro.py +2533 -0
- ccxt/xt.py +4453 -0
- ccxt/yobit.py +1283 -0
- ccxt/zaif.py +725 -0
- ccxt/zonda.py +1828 -0
- ccxt_ir-4.3.46.0.1.dist-info/LICENSE.txt +21 -0
- ccxt_ir-4.3.46.0.1.dist-info/METADATA +655 -0
- ccxt_ir-4.3.46.0.1.dist-info/RECORD +772 -0
- ccxt_ir-4.3.46.0.1.dist-info/WHEEL +6 -0
- ccxt_ir-4.3.46.0.1.dist-info/top_level.txt +1 -0
ccxt/okcoin.py
ADDED
|
@@ -0,0 +1,2936 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
|
4
|
+
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
|
5
|
+
|
|
6
|
+
from ccxt.base.exchange import Exchange
|
|
7
|
+
from ccxt.abstract.okcoin import ImplicitAPI
|
|
8
|
+
import hashlib
|
|
9
|
+
from ccxt.base.types import Balances, Currencies, Currency, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, 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 AccountNotEnabled
|
|
15
|
+
from ccxt.base.errors import AccountSuspended
|
|
16
|
+
from ccxt.base.errors import ArgumentsRequired
|
|
17
|
+
from ccxt.base.errors import BadRequest
|
|
18
|
+
from ccxt.base.errors import BadSymbol
|
|
19
|
+
from ccxt.base.errors import InsufficientFunds
|
|
20
|
+
from ccxt.base.errors import InvalidAddress
|
|
21
|
+
from ccxt.base.errors import InvalidOrder
|
|
22
|
+
from ccxt.base.errors import OrderNotFound
|
|
23
|
+
from ccxt.base.errors import CancelPending
|
|
24
|
+
from ccxt.base.errors import NotSupported
|
|
25
|
+
from ccxt.base.errors import NetworkError
|
|
26
|
+
from ccxt.base.errors import RateLimitExceeded
|
|
27
|
+
from ccxt.base.errors import ExchangeNotAvailable
|
|
28
|
+
from ccxt.base.errors import OnMaintenance
|
|
29
|
+
from ccxt.base.errors import InvalidNonce
|
|
30
|
+
from ccxt.base.errors import RequestTimeout
|
|
31
|
+
from ccxt.base.decimal_to_precision import TICK_SIZE
|
|
32
|
+
from ccxt.base.precise import Precise
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class okcoin(Exchange, ImplicitAPI):
|
|
36
|
+
|
|
37
|
+
def describe(self):
|
|
38
|
+
return self.deep_extend(super(okcoin, self).describe(), {
|
|
39
|
+
'id': 'okcoin',
|
|
40
|
+
'name': 'OKCoin',
|
|
41
|
+
'countries': ['CN', 'US'],
|
|
42
|
+
'version': 'v5',
|
|
43
|
+
# cheapest endpoint is 100 requests per 2 seconds
|
|
44
|
+
# 50 requests per second => 1000 / 50 = 20ms
|
|
45
|
+
'rateLimit': 20,
|
|
46
|
+
'pro': True,
|
|
47
|
+
'has': {
|
|
48
|
+
'CORS': None,
|
|
49
|
+
'spot': True,
|
|
50
|
+
'margin': False,
|
|
51
|
+
'swap': False,
|
|
52
|
+
'future': True,
|
|
53
|
+
'option': None,
|
|
54
|
+
'cancelOrder': True,
|
|
55
|
+
'createMarketBuyOrderWithCost': True,
|
|
56
|
+
'createMarketOrderWithCost': False,
|
|
57
|
+
'createMarketSellOrderWithCost': False,
|
|
58
|
+
'createOrder': True,
|
|
59
|
+
'fetchBalance': True,
|
|
60
|
+
'fetchBorrowInterest': False,
|
|
61
|
+
'fetchBorrowRate': False,
|
|
62
|
+
'fetchBorrowRateHistories': False,
|
|
63
|
+
'fetchBorrowRateHistory': False,
|
|
64
|
+
'fetchBorrowRates': False,
|
|
65
|
+
'fetchBorrowRatesPerSymbol': False,
|
|
66
|
+
'fetchClosedOrders': True,
|
|
67
|
+
'fetchCurrencies': True, # see below
|
|
68
|
+
'fetchDepositAddress': True,
|
|
69
|
+
'fetchDeposits': True,
|
|
70
|
+
'fetchFundingHistory': False,
|
|
71
|
+
'fetchFundingRate': False,
|
|
72
|
+
'fetchFundingRateHistory': False,
|
|
73
|
+
'fetchLedger': True,
|
|
74
|
+
'fetchMarkets': True,
|
|
75
|
+
'fetchMyTrades': True,
|
|
76
|
+
'fetchOHLCV': True,
|
|
77
|
+
'fetchOpenOrders': True,
|
|
78
|
+
'fetchOrder': True,
|
|
79
|
+
'fetchOrderBook': True,
|
|
80
|
+
'fetchOrders': None,
|
|
81
|
+
'fetchOrderTrades': True,
|
|
82
|
+
'fetchPosition': False,
|
|
83
|
+
'fetchPositions': False,
|
|
84
|
+
'fetchTicker': True,
|
|
85
|
+
'fetchTickers': True,
|
|
86
|
+
'fetchTime': True,
|
|
87
|
+
'fetchTrades': True,
|
|
88
|
+
'fetchTransactions': None,
|
|
89
|
+
'fetchWithdrawals': True,
|
|
90
|
+
'reduceMargin': False,
|
|
91
|
+
'repayCrossMargin': False,
|
|
92
|
+
'repayIsolatedMargin': False,
|
|
93
|
+
'setMargin': False,
|
|
94
|
+
'transfer': True,
|
|
95
|
+
'withdraw': True,
|
|
96
|
+
},
|
|
97
|
+
'timeframes': {
|
|
98
|
+
'1m': '1m',
|
|
99
|
+
'3m': '3m',
|
|
100
|
+
'5m': '5m',
|
|
101
|
+
'15m': '15m',
|
|
102
|
+
'30m': '30m',
|
|
103
|
+
'1h': '1H',
|
|
104
|
+
'2h': '2H',
|
|
105
|
+
'4h': '4H',
|
|
106
|
+
'6h': '6H',
|
|
107
|
+
'12h': '12H',
|
|
108
|
+
'1d': '1D',
|
|
109
|
+
'1w': '1W',
|
|
110
|
+
'1M': '1M',
|
|
111
|
+
'3M': '3M',
|
|
112
|
+
},
|
|
113
|
+
'hostname': 'okcoin.com',
|
|
114
|
+
'urls': {
|
|
115
|
+
'logo': 'https://user-images.githubusercontent.com/51840849/87295551-102fbf00-c50e-11ea-90a9-462eebba5829.jpg',
|
|
116
|
+
'api': {
|
|
117
|
+
'rest': 'https://www.{hostname}',
|
|
118
|
+
},
|
|
119
|
+
'www': 'https://www.okcoin.com',
|
|
120
|
+
'doc': 'https://www.okcoin.com/docs/en/',
|
|
121
|
+
'fees': 'https://www.okcoin.com/coin-fees',
|
|
122
|
+
'referral': 'https://www.okcoin.com/account/register?flag=activity&channelId=600001513',
|
|
123
|
+
'test': {
|
|
124
|
+
'rest': 'https://testnet.okex.com',
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
'api': {
|
|
128
|
+
'public': {
|
|
129
|
+
'get': {
|
|
130
|
+
'market/tickers': 1,
|
|
131
|
+
'market/ticker': 1,
|
|
132
|
+
'market/books': 1 / 2,
|
|
133
|
+
'market/candles': 1 / 2,
|
|
134
|
+
'market/history-candles': 1 / 2,
|
|
135
|
+
'market/trades': 1 / 5,
|
|
136
|
+
'market/history-trades': 2,
|
|
137
|
+
'market/platform-24-volume': 10,
|
|
138
|
+
'market/open-oracle': 50,
|
|
139
|
+
'market/exchange-rate': 20,
|
|
140
|
+
'public/instruments': 1,
|
|
141
|
+
'public/time': 2,
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
'private': {
|
|
145
|
+
'get': {
|
|
146
|
+
# trade
|
|
147
|
+
'trade/order': 1 / 3,
|
|
148
|
+
'trade/orders-pending': 1 / 3,
|
|
149
|
+
'trade/orders-history': 1 / 2,
|
|
150
|
+
'trade/orders-history-archive': 1 / 2,
|
|
151
|
+
'trade/fills': 1 / 3,
|
|
152
|
+
'trade/fills-history': 2.2,
|
|
153
|
+
'trade/fills-archive': 2,
|
|
154
|
+
'trade/order-algo': 1,
|
|
155
|
+
'trade/orders-algo-pending': 1,
|
|
156
|
+
'trade/orders-algo-history': 1,
|
|
157
|
+
# rfq
|
|
158
|
+
'otc/rfq/trade': 4,
|
|
159
|
+
'otc/rfq/history': 4,
|
|
160
|
+
# account
|
|
161
|
+
'account/balance': 2,
|
|
162
|
+
'account/bills': 5 / 3,
|
|
163
|
+
'account/bills-archive': 5 / 3,
|
|
164
|
+
'account/config': 4,
|
|
165
|
+
'account/max-size': 4,
|
|
166
|
+
'account/max-avail-size': 4,
|
|
167
|
+
'account/trade-fee': 4,
|
|
168
|
+
'account/max-withdrawal': 4,
|
|
169
|
+
# funding or assets
|
|
170
|
+
'asset/currencies': 5 / 3,
|
|
171
|
+
'asset/balances': 5 / 3,
|
|
172
|
+
'asset/asset-valuation': 10,
|
|
173
|
+
'asset/transfer-state': 10,
|
|
174
|
+
'asset/bills': 5 / 3,
|
|
175
|
+
'asset/deposit-lightning': 5,
|
|
176
|
+
'asset/deposit-address': 5 / 3,
|
|
177
|
+
'asset/deposit-history': 5 / 3,
|
|
178
|
+
'asset/withdrawal-history': 5 / 3,
|
|
179
|
+
'asset/deposit-withdraw-status': 20,
|
|
180
|
+
# fiat
|
|
181
|
+
'fiat/deposit-history': 5 / 3,
|
|
182
|
+
'fiat-withdraw-history': 5 / 3,
|
|
183
|
+
'fiat-channel': 5 / 3,
|
|
184
|
+
# sub-account
|
|
185
|
+
'users/subaccount/list': 10,
|
|
186
|
+
'users/subaccount/apiKey': 10,
|
|
187
|
+
'account/subaccount/balances': 10,
|
|
188
|
+
'asset/subaccount/balances': 10,
|
|
189
|
+
'asset/subaccount/bills': 10,
|
|
190
|
+
},
|
|
191
|
+
'post': {
|
|
192
|
+
# trade
|
|
193
|
+
'trade/order': 1 / 3,
|
|
194
|
+
'trade/batch-orders': 1 / 15,
|
|
195
|
+
'trade/cancel-order': 1 / 3,
|
|
196
|
+
'trade/cancel-batch-orders': 1 / 15,
|
|
197
|
+
'trade/amend-order': 1 / 3,
|
|
198
|
+
'trade/amend-batch-orders': 1 / 150,
|
|
199
|
+
'trade/order-algo': 1,
|
|
200
|
+
'trade/cancel-algos': 1,
|
|
201
|
+
'trade/cancel-advance-algos': 1,
|
|
202
|
+
# rfq
|
|
203
|
+
'otc/rfq/quote': 4,
|
|
204
|
+
'otc/rfq/trade': 4,
|
|
205
|
+
# funding
|
|
206
|
+
'asset/transfer': 4,
|
|
207
|
+
'asset/withdrawal': 4,
|
|
208
|
+
'asset/withdrawal-lightning': 4,
|
|
209
|
+
'asset/withdrawal-cancel': 4,
|
|
210
|
+
# fiat
|
|
211
|
+
'fiat/deposit': 5 / 3,
|
|
212
|
+
'fiat/cancel-deposit': 5 / 3,
|
|
213
|
+
'fiat/withdrawal': 5 / 3,
|
|
214
|
+
'fiat/cancel-withdrawal': 5 / 3,
|
|
215
|
+
# sub-account
|
|
216
|
+
'asset/subaccount/transfer': 10,
|
|
217
|
+
},
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
'fees': {
|
|
221
|
+
'trading': {
|
|
222
|
+
'taker': 0.002,
|
|
223
|
+
'maker': 0.001,
|
|
224
|
+
},
|
|
225
|
+
'spot': {
|
|
226
|
+
'taker': 0.0015,
|
|
227
|
+
'maker': 0.0010,
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
'requiredCredentials': {
|
|
231
|
+
'apiKey': True,
|
|
232
|
+
'secret': True,
|
|
233
|
+
'password': True,
|
|
234
|
+
},
|
|
235
|
+
'exceptions': {
|
|
236
|
+
'exact': {
|
|
237
|
+
# Public error codes from 50000-53999
|
|
238
|
+
# General Class
|
|
239
|
+
'1': ExchangeError, # Operation failed
|
|
240
|
+
'2': ExchangeError, # Bulk operation partially succeeded
|
|
241
|
+
'50000': BadRequest, # Body can not be empty
|
|
242
|
+
'50001': OnMaintenance, # Matching engine upgrading. Please try again later
|
|
243
|
+
'50002': BadRequest, # Json data format error
|
|
244
|
+
'50004': RequestTimeout, # Endpoint request timeout(does not indicate success or failure of order, please check order status)
|
|
245
|
+
'50005': ExchangeNotAvailable, # API is offline or unavailable
|
|
246
|
+
'50006': BadRequest, # Invalid Content_Type, please use "application/json" format
|
|
247
|
+
'50007': AccountSuspended, # Account blocked
|
|
248
|
+
'50008': AuthenticationError, # User does not exist
|
|
249
|
+
'50009': AccountSuspended, # Account is suspended due to ongoing liquidation
|
|
250
|
+
'50010': ExchangeError, # User ID can not be empty
|
|
251
|
+
'50011': RateLimitExceeded, # Request too frequent
|
|
252
|
+
'50012': ExchangeError, # Account status invalid
|
|
253
|
+
'50013': ExchangeNotAvailable, # System is busy, please try again later
|
|
254
|
+
'50014': BadRequest, # Parameter {0} can not be empty
|
|
255
|
+
'50015': ExchangeError, # Either parameter {0} or {1} is required
|
|
256
|
+
'50016': ExchangeError, # Parameter {0} does not match parameter {1}
|
|
257
|
+
'50017': ExchangeError, # The position is frozen due to ADL. Operation restricted
|
|
258
|
+
'50018': ExchangeError, # Currency {0} is frozen due to ADL. Operation restricted
|
|
259
|
+
'50019': ExchangeError, # The account is frozen due to ADL. Operation restricted
|
|
260
|
+
'50020': ExchangeError, # The position is frozen due to liquidation. Operation restricted
|
|
261
|
+
'50021': ExchangeError, # Currency {0} is frozen due to liquidation. Operation restricted
|
|
262
|
+
'50022': ExchangeError, # The account is frozen due to liquidation. Operation restricted
|
|
263
|
+
'50023': ExchangeError, # Funding fee frozen. Operation restricted
|
|
264
|
+
'50024': BadRequest, # Parameter {0} and {1} can not exist at the same time
|
|
265
|
+
'50025': ExchangeError, # Parameter {0} count exceeds the limit {1}
|
|
266
|
+
'50026': ExchangeNotAvailable, # System error, please try again later.
|
|
267
|
+
'50027': PermissionDenied, # The account is restricted from trading
|
|
268
|
+
'50028': ExchangeError, # Unable to take the order, please reach out to support center for details
|
|
269
|
+
'50029': ExchangeError, # This instrument({0}) is unavailable at present due to risk management. Please contact customer service for help.
|
|
270
|
+
'50030': PermissionDenied, # No permission to use self API
|
|
271
|
+
'50032': AccountSuspended, # This asset is blocked, allow its trading and try again
|
|
272
|
+
'50033': AccountSuspended, # This instrument is blocked, allow its trading and try again
|
|
273
|
+
'50035': BadRequest, # This endpoint requires that APIKey must be bound to IP
|
|
274
|
+
'50036': BadRequest, # Invalid expTime
|
|
275
|
+
'50037': BadRequest, # Order expired
|
|
276
|
+
'50038': ExchangeError, # This feature is temporarily unavailable in demo trading
|
|
277
|
+
'50039': ExchangeError, # The before parameter is not available for implementing timestamp pagination
|
|
278
|
+
'50041': ExchangeError, # You are not currently on the whitelist, please contact customer service
|
|
279
|
+
'50044': BadRequest, # Must select one broker type
|
|
280
|
+
# API Class
|
|
281
|
+
'50100': ExchangeError, # API frozen, please contact customer service
|
|
282
|
+
'50101': AuthenticationError, # Broker id of APIKey does not match current environment
|
|
283
|
+
'50102': InvalidNonce, # Timestamp request expired
|
|
284
|
+
'50103': AuthenticationError, # Request header "OK_ACCESS_KEY" can not be empty
|
|
285
|
+
'50104': AuthenticationError, # Request header "OK_ACCESS_PASSPHRASE" can not be empty
|
|
286
|
+
'50105': AuthenticationError, # Request header "OK_ACCESS_PASSPHRASE" incorrect
|
|
287
|
+
'50106': AuthenticationError, # Request header "OK_ACCESS_SIGN" can not be empty
|
|
288
|
+
'50107': AuthenticationError, # Request header "OK_ACCESS_TIMESTAMP" can not be empty
|
|
289
|
+
'50108': ExchangeError, # Exchange ID does not exist
|
|
290
|
+
'50109': ExchangeError, # Exchange domain does not exist
|
|
291
|
+
'50110': PermissionDenied, # Invalid IP
|
|
292
|
+
'50111': AuthenticationError, # Invalid OK_ACCESS_KEY
|
|
293
|
+
'50112': AuthenticationError, # Invalid OK_ACCESS_TIMESTAMP
|
|
294
|
+
'50113': AuthenticationError, # Invalid signature
|
|
295
|
+
'50114': AuthenticationError, # Invalid authorization
|
|
296
|
+
'50115': BadRequest, # Invalid request method
|
|
297
|
+
# Trade Class
|
|
298
|
+
'51000': BadRequest, # Parameter {0} error
|
|
299
|
+
'51001': BadSymbol, # Instrument ID does not exist
|
|
300
|
+
'51002': BadSymbol, # Instrument ID does not match underlying index
|
|
301
|
+
'51003': BadRequest, # Either client order ID or order ID is required
|
|
302
|
+
'51004': InvalidOrder, # Order amount exceeds current tier limit
|
|
303
|
+
'51005': InvalidOrder, # Order amount exceeds the limit
|
|
304
|
+
'51006': InvalidOrder, # Order price out of the limit
|
|
305
|
+
'51007': InvalidOrder, # Order placement failed. Order amount should be at least 1 contract(showing up when placing an order with less than 1 contract)
|
|
306
|
+
'51008': InsufficientFunds, # Order placement failed due to insufficient balance
|
|
307
|
+
'51009': AccountSuspended, # Order placement function is blocked by the platform
|
|
308
|
+
'51010': AccountNotEnabled, # Account level too low {"code":"1","data":[{"clOrdId":"uJrfGFth9F","ordId":"","sCode":"51010","sMsg":"The current account mode does not support self API interface. ","tag":""}],"msg":"Operation failed."}
|
|
309
|
+
'51011': InvalidOrder, # Duplicated order ID
|
|
310
|
+
'51012': BadSymbol, # Token does not exist
|
|
311
|
+
'51014': BadSymbol, # Index does not exist
|
|
312
|
+
'51015': BadSymbol, # Instrument ID does not match instrument type
|
|
313
|
+
'51016': InvalidOrder, # Duplicated client order ID
|
|
314
|
+
'51017': ExchangeError, # Borrow amount exceeds the limit
|
|
315
|
+
'51018': ExchangeError, # User with option account can not hold net short positions
|
|
316
|
+
'51019': ExchangeError, # No net long positions can be held under isolated margin mode in options
|
|
317
|
+
'51020': InvalidOrder, # Order amount should be greater than the min available amount
|
|
318
|
+
'51023': ExchangeError, # Position does not exist
|
|
319
|
+
'51024': AccountSuspended, # Unified accountblocked
|
|
320
|
+
'51025': ExchangeError, # Order count exceeds the limit
|
|
321
|
+
'51026': BadSymbol, # Instrument type does not match underlying index
|
|
322
|
+
'51030': InvalidOrder, # Funding fee is being settled.
|
|
323
|
+
'51031': InvalidOrder, # This order price is not within the closing price range
|
|
324
|
+
'51032': InvalidOrder, # Closing all positions at market price.
|
|
325
|
+
'51033': InvalidOrder, # The total amount per order for self pair has reached the upper limit.
|
|
326
|
+
'51037': InvalidOrder, # The current account risk status only supports you to place IOC orders that can reduce the risk of your account.
|
|
327
|
+
'51038': InvalidOrder, # There is already an IOC order under the current risk module that reduces the risk of the account.
|
|
328
|
+
'51044': InvalidOrder, # The order type {0}, {1} is not allowed to set stop loss and take profit
|
|
329
|
+
'51046': InvalidOrder, # The take profit trigger price must be higher than the order price
|
|
330
|
+
'51047': InvalidOrder, # The stop loss trigger price must be lower than the order price
|
|
331
|
+
'51048': InvalidOrder, # The take profit trigger price should be lower than the order price
|
|
332
|
+
'51049': InvalidOrder, # The stop loss trigger price should be higher than the order price
|
|
333
|
+
'51050': InvalidOrder, # The take profit trigger price should be higher than the best ask price
|
|
334
|
+
'51051': InvalidOrder, # The stop loss trigger price should be lower than the best ask price
|
|
335
|
+
'51052': InvalidOrder, # The take profit trigger price should be lower than the best bid price
|
|
336
|
+
'51053': InvalidOrder, # The stop loss trigger price should be higher than the best bid price
|
|
337
|
+
'51054': BadRequest, # Getting information timed out, please try again later
|
|
338
|
+
'51056': InvalidOrder, # Action not allowed
|
|
339
|
+
'51058': InvalidOrder, # No available position for self algo order
|
|
340
|
+
'51059': InvalidOrder, # Strategy for the current state does not support self operation
|
|
341
|
+
'51100': InvalidOrder, # Trading amount does not meet the min tradable amount
|
|
342
|
+
'51102': InvalidOrder, # Entered amount exceeds the max pending count
|
|
343
|
+
'51103': InvalidOrder, # Entered amount exceeds the max pending order count of the underlying asset
|
|
344
|
+
'51108': InvalidOrder, # Positions exceed the limit for closing out with the market price
|
|
345
|
+
'51109': InvalidOrder, # No available offer
|
|
346
|
+
'51110': InvalidOrder, # You can only place a limit order after Call Auction has started
|
|
347
|
+
'51111': BadRequest, # Maximum {0} orders can be placed in bulk
|
|
348
|
+
'51112': InvalidOrder, # Close order size exceeds your available size
|
|
349
|
+
'51113': RateLimitExceeded, # Market-price liquidation requests too frequent
|
|
350
|
+
'51115': InvalidOrder, # Cancel all pending close-orders before liquidation
|
|
351
|
+
'51116': InvalidOrder, # Order price or trigger price exceeds {0}
|
|
352
|
+
'51117': InvalidOrder, # Pending close-orders count exceeds limit
|
|
353
|
+
'51118': InvalidOrder, # Total amount should exceed the min amount per order
|
|
354
|
+
'51119': InsufficientFunds, # Order placement failed due to insufficient balance
|
|
355
|
+
'51120': InvalidOrder, # Order quantity is less than {0}, please try again
|
|
356
|
+
'51121': InvalidOrder, # Order count should be the integer multiples of the lot size
|
|
357
|
+
'51122': InvalidOrder, # Order price should be higher than the min price {0}
|
|
358
|
+
'51124': InvalidOrder, # You can only place limit orders during call auction
|
|
359
|
+
'51125': InvalidOrder, # Currently there are reduce + reverse position pending orders in margin trading. Please cancel all reduce + reverse position pending orders and continue
|
|
360
|
+
'51126': InvalidOrder, # Currently there are reduce only pending orders in margin trading.Please cancel all reduce only pending orders and continue
|
|
361
|
+
'51127': InsufficientFunds, # Available balance is 0
|
|
362
|
+
'51128': InvalidOrder, # Multi-currency margin account can not do cross-margin trading
|
|
363
|
+
'51129': InvalidOrder, # The value of the position and buy order has reached the position limit, and no further buying is allowed
|
|
364
|
+
'51130': BadSymbol, # Fixed margin currency error
|
|
365
|
+
'51131': InsufficientFunds, # Insufficient balance
|
|
366
|
+
'51132': InvalidOrder, # Your position amount is negative and less than the minimum trading amount
|
|
367
|
+
'51133': InvalidOrder, # Reduce-only feature is unavailable for the spot transactions by multi-currency margin account
|
|
368
|
+
'51134': InvalidOrder, # Closing failed. Please check your holdings and pending orders
|
|
369
|
+
'51135': InvalidOrder, # Your closing price has triggered the limit price, and the max buy price is {0}
|
|
370
|
+
'51136': InvalidOrder, # Your closing price has triggered the limit price, and the min sell price is {0}
|
|
371
|
+
'51137': InvalidOrder, # Your opening price has triggered the limit price, and the max buy price is {0}
|
|
372
|
+
'51138': InvalidOrder, # Your opening price has triggered the limit price, and the min sell price is {0}
|
|
373
|
+
'51139': InvalidOrder, # Reduce-only feature is unavailable for the spot transactions by simple account
|
|
374
|
+
'51156': BadRequest, # You're leading trades in long/short mode and can't use self API endpoint to close positions
|
|
375
|
+
'51159': BadRequest, # You're leading trades in buy/sell mode. If you want to place orders using self API endpoint, the orders must be in the same direction existing positions and open orders.
|
|
376
|
+
'51162': InvalidOrder, # You have {instrument} open orders. Cancel these orders and try again
|
|
377
|
+
'51163': InvalidOrder, # You hold {instrument} positions. Close these positions and try again
|
|
378
|
+
'51166': InvalidOrder, # Currently, we don't support leading trades with self instrument
|
|
379
|
+
'51174': InvalidOrder, # The number of {param0} pending orders reached the upper limit of {param1}(orders).
|
|
380
|
+
'51201': InvalidOrder, # Value of per market order cannot exceed 100,000 USDT
|
|
381
|
+
'51202': InvalidOrder, # Market - order amount exceeds the max amount
|
|
382
|
+
'51203': InvalidOrder, # Order amount exceeds the limit {0}
|
|
383
|
+
'51204': InvalidOrder, # The price for the limit order can not be empty
|
|
384
|
+
'51205': InvalidOrder, # Reduce-Only is not available
|
|
385
|
+
'51250': InvalidOrder, # Algo order price is out of the available range
|
|
386
|
+
'51251': InvalidOrder, # Algo order type error(when user place an iceberg order)
|
|
387
|
+
'51252': InvalidOrder, # Algo order price is out of the available range
|
|
388
|
+
'51253': InvalidOrder, # Average amount exceeds the limit of per iceberg order
|
|
389
|
+
'51254': InvalidOrder, # Iceberg average amount error(when user place an iceberg order)
|
|
390
|
+
'51255': InvalidOrder, # Limit of per iceberg order: Total amount/1000 < x <= Total amount
|
|
391
|
+
'51256': InvalidOrder, # Iceberg order price variance error
|
|
392
|
+
'51257': InvalidOrder, # Trail order callback rate error
|
|
393
|
+
'51258': InvalidOrder, # Trail - order placement failed. The trigger price of a sell order should be higher than the last transaction price
|
|
394
|
+
'51259': InvalidOrder, # Trail - order placement failed. The trigger price of a buy order should be lower than the last transaction price
|
|
395
|
+
'51260': InvalidOrder, # Maximum {0} pending trail - orders can be held at the same time
|
|
396
|
+
'51261': InvalidOrder, # Each user can hold up to {0} pending stop - orders at the same time
|
|
397
|
+
'51262': InvalidOrder, # Maximum {0} pending iceberg orders can be held at the same time
|
|
398
|
+
'51263': InvalidOrder, # Maximum {0} pending time-weighted orders can be held at the same time
|
|
399
|
+
'51264': InvalidOrder, # Average amount exceeds the limit of per time-weighted order
|
|
400
|
+
'51265': InvalidOrder, # Time-weighted order limit error
|
|
401
|
+
'51267': InvalidOrder, # Time-weighted order strategy initiative rate error
|
|
402
|
+
'51268': InvalidOrder, # Time-weighted order strategy initiative range error
|
|
403
|
+
'51269': InvalidOrder, # Time-weighted order interval error, the interval should be {0}<= x<={1}
|
|
404
|
+
'51270': InvalidOrder, # The limit of time-weighted order price variance is 0 < x <= 1%
|
|
405
|
+
'51271': InvalidOrder, # Sweep ratio should be 0 < x <= 100%
|
|
406
|
+
'51272': InvalidOrder, # Price variance should be 0 < x <= 1%
|
|
407
|
+
'51273': InvalidOrder, # Total amount should be more than {0}
|
|
408
|
+
'51274': InvalidOrder, # Total quantity of time-weighted order must be larger than single order limit
|
|
409
|
+
'51275': InvalidOrder, # The amount of single stop-market order can not exceed the upper limit
|
|
410
|
+
'51276': InvalidOrder, # Stop - Market orders cannot specify a price
|
|
411
|
+
'51277': InvalidOrder, # TP trigger price can not be higher than the last price
|
|
412
|
+
'51278': InvalidOrder, # SL trigger price can not be lower than the last price
|
|
413
|
+
'51279': InvalidOrder, # TP trigger price can not be lower than the last price
|
|
414
|
+
'51280': InvalidOrder, # SL trigger price can not be higher than the last price
|
|
415
|
+
'51321': InvalidOrder, # You're leading trades. Currently, we don't support leading trades with arbitrage, iceberg, or TWAP bots
|
|
416
|
+
'51322': InvalidOrder, # You're leading trades that have been filled at market price. We've canceled your open stop orders to close your positions
|
|
417
|
+
'51323': BadRequest, # You're already leading trades with take profit or stop loss settings. Cancel your existing stop orders to proceed
|
|
418
|
+
'51324': BadRequest, # As a lead trader, you hold positions in {instrument}. To close your positions, place orders in the amount that equals the available amount for closing
|
|
419
|
+
'51325': InvalidOrder, # As a lead trader, you must use market price when placing stop orders
|
|
420
|
+
'51327': InvalidOrder, # closeFraction is only available for futures and perpetual swaps
|
|
421
|
+
'51328': InvalidOrder, # closeFraction is only available for reduceOnly orders
|
|
422
|
+
'51329': InvalidOrder, # closeFraction is only available in NET mode
|
|
423
|
+
'51330': InvalidOrder, # closeFraction is only available for stop market orders
|
|
424
|
+
'51400': OrderNotFound, # Cancellation failed order does not exist
|
|
425
|
+
'51401': OrderNotFound, # Cancellation failed order is already canceled
|
|
426
|
+
'51402': OrderNotFound, # Cancellation failed order is already completed
|
|
427
|
+
'51403': InvalidOrder, # Cancellation failed order type does not support cancellation
|
|
428
|
+
'51404': InvalidOrder, # Order cancellation unavailable during the second phase of call auction
|
|
429
|
+
'51405': ExchangeError, # Cancellation failed do not have any pending orders
|
|
430
|
+
'51406': ExchangeError, # Canceled - order count exceeds the limit {0}
|
|
431
|
+
'51407': BadRequest, # Either order ID or client order ID is required
|
|
432
|
+
'51408': ExchangeError, # Pair ID or name does not match the order info
|
|
433
|
+
'51409': ExchangeError, # Either pair ID or pair name ID is required
|
|
434
|
+
'51410': CancelPending, # Cancellation failed order is already under cancelling status
|
|
435
|
+
'51500': ExchangeError, # Either order price or amount is required
|
|
436
|
+
'51501': ExchangeError, # Maximum {0} orders can be modified
|
|
437
|
+
'51502': InsufficientFunds, # Order modification failed for insufficient margin
|
|
438
|
+
'51503': ExchangeError, # Order modification failed order does not exist
|
|
439
|
+
'51506': ExchangeError, # Order modification unavailable for the order type
|
|
440
|
+
'51508': ExchangeError, # Orders are not allowed to be modified during the call auction
|
|
441
|
+
'51509': ExchangeError, # Modification failed order has been canceled
|
|
442
|
+
'51510': ExchangeError, # Modification failed order has been completed
|
|
443
|
+
'51511': ExchangeError, # Modification failed order price did not meet the requirement for Post Only
|
|
444
|
+
'51600': ExchangeError, # Status not found
|
|
445
|
+
'51601': ExchangeError, # Order status and order ID cannot exist at the same time
|
|
446
|
+
'51602': ExchangeError, # Either order status or order ID is required
|
|
447
|
+
'51603': OrderNotFound, # Order does not exist
|
|
448
|
+
'51732': AuthenticationError, # Required user KYC level not met
|
|
449
|
+
'51733': AuthenticationError, # User is under risk control
|
|
450
|
+
'51734': AuthenticationError, # User KYC Country is not supported
|
|
451
|
+
'51735': ExchangeError, # Sub-account is not supported
|
|
452
|
+
'51736': InsufficientFunds, # Insufficient {ccy} balance
|
|
453
|
+
# Data class
|
|
454
|
+
'52000': ExchangeError, # No updates
|
|
455
|
+
# SPOT/MARGIN error codes 54000-54999
|
|
456
|
+
'54000': ExchangeError, # Margin transactions unavailable
|
|
457
|
+
'54001': ExchangeError, # Only Multi-currency margin account can be set to borrow coins automatically
|
|
458
|
+
# FUNDING error codes 58000-58999
|
|
459
|
+
'58000': ExchangeError, # Account type {0} does not supported when getting the sub-account balance
|
|
460
|
+
'58001': AuthenticationError, # Incorrect trade password
|
|
461
|
+
'58002': PermissionDenied, # Please activate Savings Account first
|
|
462
|
+
'58003': ExchangeError, # Currency type is not supported by Savings Account
|
|
463
|
+
'58004': AccountSuspended, # Account blocked(transfer & withdrawal endpoint: either end of the account does not authorize the transfer)
|
|
464
|
+
'58005': ExchangeError, # The redeemed amount must be no greater than {0}
|
|
465
|
+
'58006': ExchangeError, # Service unavailable for token {0}
|
|
466
|
+
'58007': ExchangeError, # Abnormal Assets interface. Please try again later
|
|
467
|
+
'58100': ExchangeError, # The trading product triggers risk control, and the platform has suspended the fund transfer-out function with related users. Please wait patiently
|
|
468
|
+
'58101': AccountSuspended, # Transfer suspended(transfer endpoint: either end of the account does not authorize the transfer)
|
|
469
|
+
'58102': RateLimitExceeded, # Too frequent transfer(transfer too frequently)
|
|
470
|
+
'58103': ExchangeError, # Parent account user id does not match sub-account user id
|
|
471
|
+
'58104': ExchangeError, # Since your P2P transaction is abnormal, you are restricted from making fund transfers. Please contact customer support to remove the restriction
|
|
472
|
+
'58105': ExchangeError, # Since your P2P transaction is abnormal, you are restricted from making fund transfers. Please transfer funds on our website or app to complete identity verification
|
|
473
|
+
'58106': ExchangeError, # Please enable the account for spot contract
|
|
474
|
+
'58107': ExchangeError, # Please enable the account for futures contract
|
|
475
|
+
'58108': ExchangeError, # Please enable the account for option contract
|
|
476
|
+
'58109': ExchangeError, # Please enable the account for swap contract
|
|
477
|
+
'58110': ExchangeError, # The contract triggers risk control, and the platform has suspended the fund transfer function of it. Please wait patiently
|
|
478
|
+
'58111': ExchangeError, # Funds transfer unavailable perpetual contract is charging the funding fee. Please try again later
|
|
479
|
+
'58112': ExchangeError, # Your fund transfer failed. Please try again later
|
|
480
|
+
'58114': ExchangeError, # Transfer amount must be more than 0
|
|
481
|
+
'58115': ExchangeError, # Sub-account does not exist
|
|
482
|
+
'58116': ExchangeError, # Transfer amount exceeds the limit
|
|
483
|
+
'58117': ExchangeError, # Account assets are abnormal, please deal with negative assets before transferring
|
|
484
|
+
'58125': BadRequest, # Non-tradable assets can only be transferred from sub-accounts to main accounts
|
|
485
|
+
'58126': BadRequest, # Non-tradable assets can only be transferred between funding accounts
|
|
486
|
+
'58127': BadRequest, # Main account API Key does not support current transfer 'type' parameter. Please refer to the API documentation.
|
|
487
|
+
'58128': BadRequest, # Sub-account API Key does not support current transfer 'type' parameter. Please refer to the API documentation.
|
|
488
|
+
'58200': ExchangeError, # Withdrawal from {0} to {1} is unavailable for self currency
|
|
489
|
+
'58201': ExchangeError, # Withdrawal amount exceeds the daily limit
|
|
490
|
+
'58202': ExchangeError, # The minimum withdrawal amount for NEO is 1, and the amount must be an integer
|
|
491
|
+
'58203': InvalidAddress, # Please add a withdrawal address
|
|
492
|
+
'58204': AccountSuspended, # Withdrawal suspended
|
|
493
|
+
'58205': ExchangeError, # Withdrawal amount exceeds the upper limit
|
|
494
|
+
'58206': ExchangeError, # Withdrawal amount is lower than the lower limit
|
|
495
|
+
'58207': InvalidAddress, # Withdrawal failed due to address error
|
|
496
|
+
'58208': ExchangeError, # Withdrawal failed. Please link your email
|
|
497
|
+
'58209': ExchangeError, # Withdrawal failed. Withdraw feature is not available for sub-accounts
|
|
498
|
+
'58210': ExchangeError, # Withdrawal fee exceeds the upper limit
|
|
499
|
+
'58211': ExchangeError, # Withdrawal fee is lower than the lower limit(withdrawal endpoint: incorrect fee)
|
|
500
|
+
'58212': ExchangeError, # Withdrawal fee should be {0}% of the withdrawal amount
|
|
501
|
+
'58213': AuthenticationError, # Please set trading password before withdrawal
|
|
502
|
+
'58221': BadRequest, # Missing label of withdrawal address.
|
|
503
|
+
'58222': BadRequest, # Illegal withdrawal address.
|
|
504
|
+
'58224': BadRequest, # This type of crypto does not support on-chain withdrawing to OKX addresses. Please withdraw through internal transfers.
|
|
505
|
+
'58227': BadRequest, # Withdrawal of non-tradable assets can be withdrawn all at once only
|
|
506
|
+
'58228': BadRequest, # Withdrawal of non-tradable assets requires that the API Key must be bound to an IP
|
|
507
|
+
'58229': InsufficientFunds, # Insufficient funding account balance to pay fees {fee} USDT
|
|
508
|
+
'58300': ExchangeError, # Deposit-address count exceeds the limit
|
|
509
|
+
'58350': InsufficientFunds, # Insufficient balance
|
|
510
|
+
# Account error codes 59000-59999
|
|
511
|
+
'59000': ExchangeError, # Your settings failed have positions or open orders
|
|
512
|
+
'59001': ExchangeError, # Switching unavailable have borrowings
|
|
513
|
+
'59100': ExchangeError, # You have open positions. Please cancel all open positions before changing the leverage
|
|
514
|
+
'59101': ExchangeError, # You have pending orders with isolated positions. Please cancel all the pending orders and adjust the leverage
|
|
515
|
+
'59102': ExchangeError, # Leverage exceeds the maximum leverage. Please adjust the leverage
|
|
516
|
+
'59103': InsufficientFunds, # Leverage is too low and no sufficient margin in your account. Please adjust the leverage
|
|
517
|
+
'59104': ExchangeError, # The leverage is too high. The borrowed position has exceeded the maximum position of self leverage. Please adjust the leverage
|
|
518
|
+
'59105': ExchangeError, # Leverage can not be less than {0}. Please adjust the leverage
|
|
519
|
+
'59106': ExchangeError, # The max available margin corresponding to your order tier is {0}. Please adjust your margin and place a new order
|
|
520
|
+
'59107': ExchangeError, # You have pending orders under the service, please modify the leverage after canceling all pending orders
|
|
521
|
+
'59108': InsufficientFunds, # Low leverage and insufficient margin, please adjust the leverage
|
|
522
|
+
'59109': ExchangeError, # Account equity less than the required margin amount after adjustment. Please adjust the leverage
|
|
523
|
+
'59128': InvalidOrder, # As a lead trader, you can't lead trades in {instrument} with leverage higher than {num}
|
|
524
|
+
'59200': InsufficientFunds, # Insufficient account balance
|
|
525
|
+
'59201': InsufficientFunds, # Negative account balance
|
|
526
|
+
'59216': BadRequest, # The position doesn't exist. Please try again
|
|
527
|
+
'59300': ExchangeError, # Margin call failed. Position does not exist
|
|
528
|
+
'59301': ExchangeError, # Margin adjustment failed for exceeding the max limit
|
|
529
|
+
'59313': ExchangeError, # Unable to repay. You haven't borrowed any {ccy} {ccyPair} in Quick margin mode.
|
|
530
|
+
'59401': ExchangeError, # Holdings already reached the limit
|
|
531
|
+
'59500': ExchangeError, # Only the APIKey of the main account has permission
|
|
532
|
+
'59501': ExchangeError, # Only 50 APIKeys can be created per account
|
|
533
|
+
'59502': ExchangeError, # Note name cannot be duplicate with the currently created APIKey note name
|
|
534
|
+
'59503': ExchangeError, # Each APIKey can bind up to 20 IP addresses
|
|
535
|
+
'59504': ExchangeError, # The sub account does not support the withdrawal function
|
|
536
|
+
'59505': ExchangeError, # The passphrase format is incorrect
|
|
537
|
+
'59506': ExchangeError, # APIKey does not exist
|
|
538
|
+
'59507': ExchangeError, # The two accounts involved in a transfer must be two different sub accounts under the same parent account
|
|
539
|
+
'59508': AccountSuspended, # The sub account of {0} is suspended
|
|
540
|
+
# WebSocket error Codes from 60000-63999
|
|
541
|
+
'60001': AuthenticationError, # "OK_ACCESS_KEY" can not be empty
|
|
542
|
+
'60002': AuthenticationError, # "OK_ACCESS_SIGN" can not be empty
|
|
543
|
+
'60003': AuthenticationError, # "OK_ACCESS_PASSPHRASE" can not be empty
|
|
544
|
+
'60004': AuthenticationError, # Invalid OK_ACCESS_TIMESTAMP
|
|
545
|
+
'60005': AuthenticationError, # Invalid OK_ACCESS_KEY
|
|
546
|
+
'60006': InvalidNonce, # Timestamp request expired
|
|
547
|
+
'60007': AuthenticationError, # Invalid sign
|
|
548
|
+
'60008': AuthenticationError, # Login is not supported for public channels
|
|
549
|
+
'60009': AuthenticationError, # Login failed
|
|
550
|
+
'60010': AuthenticationError, # Already logged in
|
|
551
|
+
'60011': AuthenticationError, # Please log in
|
|
552
|
+
'60012': BadRequest, # Illegal request
|
|
553
|
+
'60013': BadRequest, # Invalid args
|
|
554
|
+
'60014': RateLimitExceeded, # Requests too frequent
|
|
555
|
+
'60015': NetworkError, # Connection closed was no data transmission in the last 30 seconds
|
|
556
|
+
'60016': ExchangeNotAvailable, # Buffer is full, cannot write data
|
|
557
|
+
'60017': BadRequest, # Invalid url path
|
|
558
|
+
'60018': BadRequest, # The {0} {1} {2} {3} {4} does not exist
|
|
559
|
+
'60019': BadRequest, # Invalid op {op}
|
|
560
|
+
'63999': ExchangeError, # Internal system error
|
|
561
|
+
'70010': BadRequest, # Timestamp parameters need to be in Unix timestamp format in milliseconds.
|
|
562
|
+
'70013': BadRequest, # endTs needs to be bigger than or equal to beginTs.
|
|
563
|
+
'70016': BadRequest, # Please specify your instrument settings for at least one instType.
|
|
564
|
+
},
|
|
565
|
+
'broad': {
|
|
566
|
+
'Internal Server Error': ExchangeNotAvailable, # {"code":500,"data":{},"detailMsg":"","error_code":"500","error_message":"Internal Server Error","msg":"Internal Server Error"}
|
|
567
|
+
'server error': ExchangeNotAvailable, # {"code":500,"data":{},"detailMsg":"","error_code":"500","error_message":"server error 1236805249","msg":"server error 1236805249"}
|
|
568
|
+
},
|
|
569
|
+
},
|
|
570
|
+
'precisionMode': TICK_SIZE,
|
|
571
|
+
'options': {
|
|
572
|
+
'fetchOHLCV': {
|
|
573
|
+
'type': 'Candles', # Candles or HistoryCandles
|
|
574
|
+
},
|
|
575
|
+
'createMarketBuyOrderRequiresPrice': True,
|
|
576
|
+
'fetchMarkets': ['spot'],
|
|
577
|
+
'defaultType': 'spot', # 'account', 'spot', 'futures', 'swap', 'option'
|
|
578
|
+
'accountsByType': {
|
|
579
|
+
'classic': '1',
|
|
580
|
+
'spot': '1',
|
|
581
|
+
'funding': '6',
|
|
582
|
+
'main': '6',
|
|
583
|
+
'unified': '18',
|
|
584
|
+
},
|
|
585
|
+
'accountsById': {
|
|
586
|
+
'1': 'spot',
|
|
587
|
+
'6': 'funding',
|
|
588
|
+
'18': 'unified',
|
|
589
|
+
},
|
|
590
|
+
'auth': {
|
|
591
|
+
'time': 'public',
|
|
592
|
+
'currencies': 'private',
|
|
593
|
+
'instruments': 'public',
|
|
594
|
+
'rate': 'public',
|
|
595
|
+
'{instrument_id}/constituents': 'public',
|
|
596
|
+
},
|
|
597
|
+
'warnOnFetchCurrenciesWithoutAuthorization': False,
|
|
598
|
+
'defaultNetwork': 'ERC20',
|
|
599
|
+
'networks': {
|
|
600
|
+
'ERC20': 'Ethereum',
|
|
601
|
+
},
|
|
602
|
+
},
|
|
603
|
+
'commonCurrencies': {
|
|
604
|
+
# OKEX refers to ERC20 version of Aeternity(AEToken)
|
|
605
|
+
'AE': 'AET', # https://github.com/ccxt/ccxt/issues/4981
|
|
606
|
+
'BOX': 'DefiBox',
|
|
607
|
+
'HOT': 'Hydro Protocol',
|
|
608
|
+
'HSR': 'HC',
|
|
609
|
+
'MAG': 'Maggie',
|
|
610
|
+
'SBTC': 'Super Bitcoin',
|
|
611
|
+
'TRADE': 'Unitrade',
|
|
612
|
+
'YOYO': 'YOYOW',
|
|
613
|
+
'WIN': 'WinToken', # https://github.com/ccxt/ccxt/issues/5701
|
|
614
|
+
},
|
|
615
|
+
})
|
|
616
|
+
|
|
617
|
+
def fetch_time(self, params={}):
|
|
618
|
+
"""
|
|
619
|
+
fetches the current integer timestamp in milliseconds from the exchange server
|
|
620
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
621
|
+
:returns int: the current integer timestamp in milliseconds from the exchange server
|
|
622
|
+
"""
|
|
623
|
+
response = self.publicGetPublicTime(params)
|
|
624
|
+
#
|
|
625
|
+
# {
|
|
626
|
+
# "iso": "2015-01-07T23:47:25.201Z",
|
|
627
|
+
# "epoch": 1420674445.201
|
|
628
|
+
# }
|
|
629
|
+
#
|
|
630
|
+
return self.parse8601(self.safe_string(response, 'iso'))
|
|
631
|
+
|
|
632
|
+
def fetch_markets(self, params={}) -> List[Market]:
|
|
633
|
+
"""
|
|
634
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-public-data-get-instruments
|
|
635
|
+
retrieves data on all markets for okcoin
|
|
636
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
637
|
+
:returns dict[]: an array of objects representing market data
|
|
638
|
+
"""
|
|
639
|
+
request: dict = {
|
|
640
|
+
'instType': 'SPOT',
|
|
641
|
+
}
|
|
642
|
+
response = self.publicGetPublicInstruments(self.extend(request, params))
|
|
643
|
+
markets = self.safe_value(response, 'data', [])
|
|
644
|
+
return self.parse_markets(markets)
|
|
645
|
+
|
|
646
|
+
def parse_market(self, market: dict) -> Market:
|
|
647
|
+
#
|
|
648
|
+
# spot markets
|
|
649
|
+
#
|
|
650
|
+
# {
|
|
651
|
+
# "base_currency": "EOS",
|
|
652
|
+
# "instrument_id": "EOS-OKB",
|
|
653
|
+
# "min_size": "0.01",
|
|
654
|
+
# "quote_currency": "OKB",
|
|
655
|
+
# "size_increment": "0.000001",
|
|
656
|
+
# "tick_size": "0.0001"
|
|
657
|
+
# }
|
|
658
|
+
#
|
|
659
|
+
id = self.safe_string(market, 'instId')
|
|
660
|
+
type = self.safe_string_lower(market, 'instType')
|
|
661
|
+
if type == 'futures':
|
|
662
|
+
type = 'future'
|
|
663
|
+
spot = (type == 'spot')
|
|
664
|
+
future = (type == 'future')
|
|
665
|
+
swap = (type == 'swap')
|
|
666
|
+
option = (type == 'option')
|
|
667
|
+
contract = swap or future or option
|
|
668
|
+
baseId = self.safe_string(market, 'baseCcy')
|
|
669
|
+
quoteId = self.safe_string(market, 'quoteCcy')
|
|
670
|
+
base = self.safe_currency_code(baseId)
|
|
671
|
+
quote = self.safe_currency_code(quoteId)
|
|
672
|
+
symbol = base + '/' + quote
|
|
673
|
+
tickSize = self.safe_string(market, 'tickSz')
|
|
674
|
+
fees = self.safe_value_2(self.fees, type, 'trading', {})
|
|
675
|
+
maxLeverage = self.safe_string(market, 'lever', '1')
|
|
676
|
+
maxLeverage = Precise.string_max(maxLeverage, '1')
|
|
677
|
+
maxSpotCost = self.safe_number(market, 'maxMktSz')
|
|
678
|
+
return self.extend(fees, {
|
|
679
|
+
'id': id,
|
|
680
|
+
'symbol': symbol,
|
|
681
|
+
'base': base,
|
|
682
|
+
'quote': quote,
|
|
683
|
+
'settle': None,
|
|
684
|
+
'baseId': baseId,
|
|
685
|
+
'quoteId': quoteId,
|
|
686
|
+
'settleId': None,
|
|
687
|
+
'type': type,
|
|
688
|
+
'spot': spot,
|
|
689
|
+
'margin': spot and (Precise.string_gt(maxLeverage, '1')),
|
|
690
|
+
'swap': False,
|
|
691
|
+
'future': False,
|
|
692
|
+
'option': False,
|
|
693
|
+
'active': True,
|
|
694
|
+
'contract': False,
|
|
695
|
+
'linear': None,
|
|
696
|
+
'inverse': None,
|
|
697
|
+
'contractSize': self.safe_number(market, 'ctVal') if contract else None,
|
|
698
|
+
'expiry': None,
|
|
699
|
+
'expiryDatetime': None,
|
|
700
|
+
'strike': None,
|
|
701
|
+
'optionType': None,
|
|
702
|
+
'created': self.safe_integer(market, 'listTime'),
|
|
703
|
+
'precision': {
|
|
704
|
+
'amount': self.safe_number(market, 'lotSz'),
|
|
705
|
+
'price': self.parse_number(tickSize),
|
|
706
|
+
},
|
|
707
|
+
'limits': {
|
|
708
|
+
'leverage': {
|
|
709
|
+
'min': self.parse_number('1'),
|
|
710
|
+
'max': self.parse_number(maxLeverage),
|
|
711
|
+
},
|
|
712
|
+
'amount': {
|
|
713
|
+
'min': self.safe_number(market, 'minSz'),
|
|
714
|
+
'max': None,
|
|
715
|
+
},
|
|
716
|
+
'price': {
|
|
717
|
+
'min': None,
|
|
718
|
+
'max': None,
|
|
719
|
+
},
|
|
720
|
+
'cost': {
|
|
721
|
+
'min': None,
|
|
722
|
+
'max': None if contract else maxSpotCost,
|
|
723
|
+
},
|
|
724
|
+
},
|
|
725
|
+
'info': market,
|
|
726
|
+
})
|
|
727
|
+
|
|
728
|
+
def safe_network(self, networkId):
|
|
729
|
+
networksById: dict = {
|
|
730
|
+
'Bitcoin': 'BTC',
|
|
731
|
+
'Omni': 'OMNI',
|
|
732
|
+
'TRON': 'TRC20',
|
|
733
|
+
}
|
|
734
|
+
return self.safe_string(networksById, networkId, networkId)
|
|
735
|
+
|
|
736
|
+
def fetch_currencies(self, params={}) -> Currencies:
|
|
737
|
+
"""
|
|
738
|
+
fetches all available currencies on an exchange
|
|
739
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
740
|
+
:returns dict: an associative dictionary of currencies
|
|
741
|
+
"""
|
|
742
|
+
if not self.check_required_credentials(False):
|
|
743
|
+
if self.options['warnOnFetchCurrenciesWithoutAuthorization']:
|
|
744
|
+
raise ExchangeError(self.id + ' fetchCurrencies() is a private API endpoint that requires authentication with API keys. Set the API keys on the exchange instance or exchange.options["warnOnFetchCurrenciesWithoutAuthorization"] = False to suppress self warning message.')
|
|
745
|
+
return None
|
|
746
|
+
else:
|
|
747
|
+
response = self.privateGetAssetCurrencies(params)
|
|
748
|
+
data = self.safe_value(response, 'data', [])
|
|
749
|
+
result: dict = {}
|
|
750
|
+
dataByCurrencyId = self.group_by(data, 'ccy')
|
|
751
|
+
currencyIds = list(dataByCurrencyId.keys())
|
|
752
|
+
for i in range(0, len(currencyIds)):
|
|
753
|
+
currencyId = currencyIds[i]
|
|
754
|
+
currency = self.safe_currency(currencyId)
|
|
755
|
+
code = currency['code']
|
|
756
|
+
chains = dataByCurrencyId[currencyId]
|
|
757
|
+
networks: dict = {}
|
|
758
|
+
currencyActive = False
|
|
759
|
+
depositEnabled = False
|
|
760
|
+
withdrawEnabled = False
|
|
761
|
+
maxPrecision = None
|
|
762
|
+
for j in range(0, len(chains)):
|
|
763
|
+
chain = chains[j]
|
|
764
|
+
canDeposit = self.safe_value(chain, 'canDep')
|
|
765
|
+
depositEnabled = canDeposit if (canDeposit) else depositEnabled
|
|
766
|
+
canWithdraw = self.safe_value(chain, 'canWd')
|
|
767
|
+
withdrawEnabled = canWithdraw if (canWithdraw) else withdrawEnabled
|
|
768
|
+
canInternal = self.safe_value(chain, 'canInternal')
|
|
769
|
+
active = True if (canDeposit and canWithdraw and canInternal) else False
|
|
770
|
+
currencyActive = active if (active) else currencyActive
|
|
771
|
+
networkId = self.safe_string(chain, 'chain')
|
|
772
|
+
if (networkId is not None) and (networkId.find('-') >= 0):
|
|
773
|
+
parts = networkId.split('-')
|
|
774
|
+
chainPart = self.safe_string(parts, 1, networkId)
|
|
775
|
+
networkCode = self.safe_network(chainPart)
|
|
776
|
+
precision = self.parse_precision(self.safe_string(chain, 'wdTickSz'))
|
|
777
|
+
if maxPrecision is None:
|
|
778
|
+
maxPrecision = precision
|
|
779
|
+
else:
|
|
780
|
+
maxPrecision = Precise.string_min(maxPrecision, precision)
|
|
781
|
+
networks[networkCode] = {
|
|
782
|
+
'id': networkId,
|
|
783
|
+
'network': networkCode,
|
|
784
|
+
'active': active,
|
|
785
|
+
'deposit': canDeposit,
|
|
786
|
+
'withdraw': canWithdraw,
|
|
787
|
+
'fee': self.safe_number(chain, 'minFee'),
|
|
788
|
+
'precision': self.parse_number(precision),
|
|
789
|
+
'limits': {
|
|
790
|
+
'withdraw': {
|
|
791
|
+
'min': self.safe_number(chain, 'minWd'),
|
|
792
|
+
'max': self.safe_number(chain, 'maxWd'),
|
|
793
|
+
},
|
|
794
|
+
},
|
|
795
|
+
'info': chain,
|
|
796
|
+
}
|
|
797
|
+
firstChain = self.safe_value(chains, 0)
|
|
798
|
+
result[code] = {
|
|
799
|
+
'info': chains,
|
|
800
|
+
'code': code,
|
|
801
|
+
'id': currencyId,
|
|
802
|
+
'name': self.safe_string(firstChain, 'name'),
|
|
803
|
+
'active': currencyActive,
|
|
804
|
+
'deposit': depositEnabled,
|
|
805
|
+
'withdraw': withdrawEnabled,
|
|
806
|
+
'fee': None,
|
|
807
|
+
'precision': self.parse_number(maxPrecision),
|
|
808
|
+
'limits': {
|
|
809
|
+
'amount': {
|
|
810
|
+
'min': None,
|
|
811
|
+
'max': None,
|
|
812
|
+
},
|
|
813
|
+
},
|
|
814
|
+
'networks': networks,
|
|
815
|
+
}
|
|
816
|
+
return result
|
|
817
|
+
|
|
818
|
+
def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
|
819
|
+
"""
|
|
820
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-order-book
|
|
821
|
+
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
822
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
|
823
|
+
:param int [limit]: the maximum amount of order book entries to return
|
|
824
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
825
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
826
|
+
"""
|
|
827
|
+
self.load_markets()
|
|
828
|
+
market = self.market(symbol)
|
|
829
|
+
request: dict = {
|
|
830
|
+
'instId': market['id'],
|
|
831
|
+
}
|
|
832
|
+
limit = 20 if (limit is None) else limit
|
|
833
|
+
if limit is not None:
|
|
834
|
+
request['sz'] = limit # max 400
|
|
835
|
+
response = self.publicGetMarketBooks(self.extend(request, params))
|
|
836
|
+
#
|
|
837
|
+
# {
|
|
838
|
+
# "code": "0",
|
|
839
|
+
# "msg": "",
|
|
840
|
+
# "data": [
|
|
841
|
+
# {
|
|
842
|
+
# "asks": [
|
|
843
|
+
# ["0.07228","4.211619","0","2"], # price, amount, liquidated orders, total open orders
|
|
844
|
+
# ["0.0723","299.880364","0","2"],
|
|
845
|
+
# ["0.07231","3.72832","0","1"],
|
|
846
|
+
# ],
|
|
847
|
+
# "bids": [
|
|
848
|
+
# ["0.07221","18.5","0","1"],
|
|
849
|
+
# ["0.0722","18.5","0","1"],
|
|
850
|
+
# ["0.07219","0.505407","0","1"],
|
|
851
|
+
# ],
|
|
852
|
+
# "ts": "1621438475342"
|
|
853
|
+
# }
|
|
854
|
+
# ]
|
|
855
|
+
# }
|
|
856
|
+
#
|
|
857
|
+
data = self.safe_value(response, 'data', [])
|
|
858
|
+
first = self.safe_value(data, 0, {})
|
|
859
|
+
timestamp = self.safe_integer(first, 'ts')
|
|
860
|
+
return self.parse_order_book(first, symbol, timestamp)
|
|
861
|
+
|
|
862
|
+
def parse_ticker(self, ticker: dict, market: Market = None) -> Ticker:
|
|
863
|
+
#
|
|
864
|
+
# {
|
|
865
|
+
# "instType": "SPOT",
|
|
866
|
+
# "instId": "ETH-BTC",
|
|
867
|
+
# "last": "0.07319",
|
|
868
|
+
# "lastSz": "0.044378",
|
|
869
|
+
# "askPx": "0.07322",
|
|
870
|
+
# "askSz": "4.2",
|
|
871
|
+
# "bidPx": "0.0732",
|
|
872
|
+
# "bidSz": "6.050058",
|
|
873
|
+
# "open24h": "0.07801",
|
|
874
|
+
# "high24h": "0.07975",
|
|
875
|
+
# "low24h": "0.06019",
|
|
876
|
+
# "volCcy24h": "11788.887619",
|
|
877
|
+
# "vol24h": "167493.829229",
|
|
878
|
+
# "ts": "1621440583784",
|
|
879
|
+
# "sodUtc0": "0.07872",
|
|
880
|
+
# "sodUtc8": "0.07345"
|
|
881
|
+
# }
|
|
882
|
+
#
|
|
883
|
+
timestamp = self.safe_integer(ticker, 'ts')
|
|
884
|
+
marketId = self.safe_string(ticker, 'instId')
|
|
885
|
+
market = self.safe_market(marketId, market, '-')
|
|
886
|
+
symbol = market['symbol']
|
|
887
|
+
last = self.safe_string(ticker, 'last')
|
|
888
|
+
open = self.safe_string(ticker, 'open24h')
|
|
889
|
+
spot = self.safe_bool(market, 'spot', False)
|
|
890
|
+
quoteVolume = self.safe_string(ticker, 'volCcy24h') if spot else None
|
|
891
|
+
baseVolume = self.safe_string(ticker, 'vol24h')
|
|
892
|
+
high = self.safe_string(ticker, 'high24h')
|
|
893
|
+
low = self.safe_string(ticker, 'low24h')
|
|
894
|
+
return self.safe_ticker({
|
|
895
|
+
'symbol': symbol,
|
|
896
|
+
'timestamp': timestamp,
|
|
897
|
+
'datetime': self.iso8601(timestamp),
|
|
898
|
+
'high': high,
|
|
899
|
+
'low': low,
|
|
900
|
+
'bid': self.safe_string(ticker, 'bidPx'),
|
|
901
|
+
'bidVolume': self.safe_string(ticker, 'bidSz'),
|
|
902
|
+
'ask': self.safe_string(ticker, 'askPx'),
|
|
903
|
+
'askVolume': self.safe_string(ticker, 'askSz'),
|
|
904
|
+
'vwap': None,
|
|
905
|
+
'open': open,
|
|
906
|
+
'close': last,
|
|
907
|
+
'last': last,
|
|
908
|
+
'previousClose': None,
|
|
909
|
+
'change': None,
|
|
910
|
+
'percentage': None,
|
|
911
|
+
'average': None,
|
|
912
|
+
'baseVolume': baseVolume,
|
|
913
|
+
'quoteVolume': quoteVolume,
|
|
914
|
+
'info': ticker,
|
|
915
|
+
}, market)
|
|
916
|
+
|
|
917
|
+
def fetch_ticker(self, symbol: str, params={}) -> Ticker:
|
|
918
|
+
"""
|
|
919
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-ticker
|
|
920
|
+
fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
921
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
922
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
923
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
924
|
+
"""
|
|
925
|
+
self.load_markets()
|
|
926
|
+
market = self.market(symbol)
|
|
927
|
+
request: dict = {
|
|
928
|
+
'instId': market['id'],
|
|
929
|
+
}
|
|
930
|
+
response = self.publicGetMarketTicker(self.extend(request, params))
|
|
931
|
+
data = self.safe_value(response, 'data', [])
|
|
932
|
+
first = self.safe_value(data, 0, {})
|
|
933
|
+
#
|
|
934
|
+
# {
|
|
935
|
+
# "code": "0",
|
|
936
|
+
# "msg": "",
|
|
937
|
+
# "data": [
|
|
938
|
+
# {
|
|
939
|
+
# "instType": "SPOT",
|
|
940
|
+
# "instId": "ETH-BTC",
|
|
941
|
+
# "last": "0.07319",
|
|
942
|
+
# "lastSz": "0.044378",
|
|
943
|
+
# "askPx": "0.07322",
|
|
944
|
+
# "askSz": "4.2",
|
|
945
|
+
# "bidPx": "0.0732",
|
|
946
|
+
# "bidSz": "6.050058",
|
|
947
|
+
# "open24h": "0.07801",
|
|
948
|
+
# "high24h": "0.07975",
|
|
949
|
+
# "low24h": "0.06019",
|
|
950
|
+
# "volCcy24h": "11788.887619",
|
|
951
|
+
# "vol24h": "167493.829229",
|
|
952
|
+
# "ts": "1621440583784",
|
|
953
|
+
# "sodUtc0": "0.07872",
|
|
954
|
+
# "sodUtc8": "0.07345"
|
|
955
|
+
# }
|
|
956
|
+
# ]
|
|
957
|
+
# }
|
|
958
|
+
#
|
|
959
|
+
return self.parse_ticker(first, market)
|
|
960
|
+
|
|
961
|
+
def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
962
|
+
"""
|
|
963
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-tickers
|
|
964
|
+
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
965
|
+
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
966
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
967
|
+
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
968
|
+
"""
|
|
969
|
+
symbols = self.market_symbols(symbols)
|
|
970
|
+
request: dict = {
|
|
971
|
+
'instType': 'SPOT',
|
|
972
|
+
}
|
|
973
|
+
response = self.publicGetMarketTickers(self.extend(request, params))
|
|
974
|
+
data = self.safe_list(response, 'data', [])
|
|
975
|
+
return self.parse_tickers(data, symbols, params)
|
|
976
|
+
|
|
977
|
+
def parse_trade(self, trade: dict, market: Market = None) -> Trade:
|
|
978
|
+
#
|
|
979
|
+
# public fetchTrades
|
|
980
|
+
#
|
|
981
|
+
# {
|
|
982
|
+
# "instId": "ETH-BTC",
|
|
983
|
+
# "side": "sell",
|
|
984
|
+
# "sz": "0.119501",
|
|
985
|
+
# "px": "0.07065",
|
|
986
|
+
# "tradeId": "15826757",
|
|
987
|
+
# "ts": "1621446178316"
|
|
988
|
+
# }
|
|
989
|
+
#
|
|
990
|
+
# private fetchMyTrades
|
|
991
|
+
#
|
|
992
|
+
# {
|
|
993
|
+
# "side": "buy",
|
|
994
|
+
# "fillSz": "0.007533",
|
|
995
|
+
# "fillPx": "2654.98",
|
|
996
|
+
# "fee": "-0.000007533",
|
|
997
|
+
# "ordId": "317321390244397056",
|
|
998
|
+
# "instType": "SPOT",
|
|
999
|
+
# "instId": "ETH-USDT",
|
|
1000
|
+
# "clOrdId": "",
|
|
1001
|
+
# "posSide": "net",
|
|
1002
|
+
# "billId": "317321390265368576",
|
|
1003
|
+
# "tag": "0",
|
|
1004
|
+
# "execType": "T",
|
|
1005
|
+
# "tradeId": "107601752",
|
|
1006
|
+
# "feeCcy": "ETH",
|
|
1007
|
+
# "ts": "1621927314985"
|
|
1008
|
+
# }
|
|
1009
|
+
#
|
|
1010
|
+
id = self.safe_string(trade, 'tradeId')
|
|
1011
|
+
marketId = self.safe_string(trade, 'instId')
|
|
1012
|
+
market = self.safe_market(marketId, market, '-')
|
|
1013
|
+
symbol = market['symbol']
|
|
1014
|
+
timestamp = self.safe_integer(trade, 'ts')
|
|
1015
|
+
price = self.safe_string_2(trade, 'fillPx', 'px')
|
|
1016
|
+
amount = self.safe_string_2(trade, 'fillSz', 'sz')
|
|
1017
|
+
side = self.safe_string(trade, 'side')
|
|
1018
|
+
orderId = self.safe_string(trade, 'ordId')
|
|
1019
|
+
feeCostString = self.safe_string(trade, 'fee')
|
|
1020
|
+
fee = None
|
|
1021
|
+
if feeCostString is not None:
|
|
1022
|
+
feeCostSigned = Precise.string_neg(feeCostString)
|
|
1023
|
+
feeCurrencyId = self.safe_string(trade, 'feeCcy')
|
|
1024
|
+
feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
|
|
1025
|
+
fee = {
|
|
1026
|
+
'cost': feeCostSigned,
|
|
1027
|
+
'currency': feeCurrencyCode,
|
|
1028
|
+
}
|
|
1029
|
+
takerOrMaker = self.safe_string(trade, 'execType')
|
|
1030
|
+
if takerOrMaker == 'T':
|
|
1031
|
+
takerOrMaker = 'taker'
|
|
1032
|
+
elif takerOrMaker == 'M':
|
|
1033
|
+
takerOrMaker = 'maker'
|
|
1034
|
+
return self.safe_trade({
|
|
1035
|
+
'info': trade,
|
|
1036
|
+
'timestamp': timestamp,
|
|
1037
|
+
'datetime': self.iso8601(timestamp),
|
|
1038
|
+
'symbol': symbol,
|
|
1039
|
+
'id': id,
|
|
1040
|
+
'order': orderId,
|
|
1041
|
+
'type': None,
|
|
1042
|
+
'takerOrMaker': takerOrMaker,
|
|
1043
|
+
'side': side,
|
|
1044
|
+
'price': price,
|
|
1045
|
+
'amount': amount,
|
|
1046
|
+
'cost': None,
|
|
1047
|
+
'fee': fee,
|
|
1048
|
+
}, market)
|
|
1049
|
+
|
|
1050
|
+
def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
1051
|
+
"""
|
|
1052
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-trades
|
|
1053
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-trades-history
|
|
1054
|
+
get the list of most recent trades for a particular symbol
|
|
1055
|
+
:param str symbol: unified symbol of the market to fetch trades for
|
|
1056
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
1057
|
+
:param int [limit]: the maximum amount of trades to fetch
|
|
1058
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1059
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
1060
|
+
"""
|
|
1061
|
+
self.load_markets()
|
|
1062
|
+
market = self.market(symbol)
|
|
1063
|
+
if (limit is None) or (limit > 100):
|
|
1064
|
+
limit = 100 # maximum = default = 100
|
|
1065
|
+
request: dict = {
|
|
1066
|
+
'instId': market['id'],
|
|
1067
|
+
}
|
|
1068
|
+
method = None
|
|
1069
|
+
method, params = self.handle_option_and_params(params, 'fetchTrades', 'method', 'publicGetMarketTrades')
|
|
1070
|
+
response = None
|
|
1071
|
+
if method == 'publicGetMarketTrades':
|
|
1072
|
+
response = self.publicGetMarketTrades(self.extend(request, params))
|
|
1073
|
+
else:
|
|
1074
|
+
response = self.publicGetMarketHistoryTrades(self.extend(request, params))
|
|
1075
|
+
data = self.safe_list(response, 'data', [])
|
|
1076
|
+
return self.parse_trades(data, market, since, limit)
|
|
1077
|
+
|
|
1078
|
+
def parse_ohlcv(self, ohlcv, market: Market = None) -> list:
|
|
1079
|
+
#
|
|
1080
|
+
# [
|
|
1081
|
+
# "1678928760000", # timestamp
|
|
1082
|
+
# "24341.4", # open
|
|
1083
|
+
# "24344", # high
|
|
1084
|
+
# "24313.2", # low
|
|
1085
|
+
# "24323", # close
|
|
1086
|
+
# "628", # contract volume
|
|
1087
|
+
# "2.5819", # base volume
|
|
1088
|
+
# "62800", # quote volume
|
|
1089
|
+
# "0" # candlestick state
|
|
1090
|
+
# ]
|
|
1091
|
+
#
|
|
1092
|
+
return [
|
|
1093
|
+
self.safe_integer(ohlcv, 0),
|
|
1094
|
+
self.safe_number(ohlcv, 1),
|
|
1095
|
+
self.safe_number(ohlcv, 2),
|
|
1096
|
+
self.safe_number(ohlcv, 3),
|
|
1097
|
+
self.safe_number(ohlcv, 4),
|
|
1098
|
+
self.safe_number(ohlcv, 5),
|
|
1099
|
+
]
|
|
1100
|
+
|
|
1101
|
+
def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
1102
|
+
"""
|
|
1103
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-candlesticks
|
|
1104
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-market-data-get-candlesticks-history
|
|
1105
|
+
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
1106
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
1107
|
+
:param str timeframe: the length of time each candle represents
|
|
1108
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
1109
|
+
:param int [limit]: the maximum amount of candles to fetch
|
|
1110
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1111
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
1112
|
+
"""
|
|
1113
|
+
self.load_markets()
|
|
1114
|
+
market = self.market(symbol)
|
|
1115
|
+
duration = self.parse_timeframe(timeframe)
|
|
1116
|
+
options = self.safe_value(self.options, 'fetchOHLCV', {})
|
|
1117
|
+
bar = self.safe_string(self.timeframes, timeframe, timeframe)
|
|
1118
|
+
timezone = self.safe_string(options, 'timezone', 'UTC')
|
|
1119
|
+
if (timezone == 'UTC') and (duration >= 21600): # if utc and timeframe >= 6h
|
|
1120
|
+
bar += timezone.lower()
|
|
1121
|
+
request: dict = {
|
|
1122
|
+
'instId': market['id'],
|
|
1123
|
+
'bar': bar,
|
|
1124
|
+
}
|
|
1125
|
+
if limit is not None:
|
|
1126
|
+
request['limit'] = limit # default 100, max 100
|
|
1127
|
+
method = None
|
|
1128
|
+
method, params = self.handle_option_and_params(params, 'fetchOHLCV', 'method', 'publicGetMarketCandles')
|
|
1129
|
+
response = None
|
|
1130
|
+
if method == 'publicGetMarketCandles':
|
|
1131
|
+
response = self.publicGetMarketCandles(self.extend(request, params))
|
|
1132
|
+
else:
|
|
1133
|
+
response = self.publicGetMarketHistoryCandles(self.extend(request, params))
|
|
1134
|
+
data = self.safe_list(response, 'data', [])
|
|
1135
|
+
return self.parse_ohlcvs(data, market, timeframe, since, limit)
|
|
1136
|
+
|
|
1137
|
+
def parse_account_balance(self, response):
|
|
1138
|
+
#
|
|
1139
|
+
# account
|
|
1140
|
+
#
|
|
1141
|
+
# [
|
|
1142
|
+
# {
|
|
1143
|
+
# "balance": 0,
|
|
1144
|
+
# "available": 0,
|
|
1145
|
+
# "currency": "BTC",
|
|
1146
|
+
# "hold": 0
|
|
1147
|
+
# },
|
|
1148
|
+
# {
|
|
1149
|
+
# "balance": 0,
|
|
1150
|
+
# "available": 0,
|
|
1151
|
+
# "currency": "ETH",
|
|
1152
|
+
# "hold": 0
|
|
1153
|
+
# }
|
|
1154
|
+
# ]
|
|
1155
|
+
#
|
|
1156
|
+
# spot
|
|
1157
|
+
#
|
|
1158
|
+
# [
|
|
1159
|
+
# {
|
|
1160
|
+
# "frozen": "0",
|
|
1161
|
+
# "hold": "0",
|
|
1162
|
+
# "id": "2149632",
|
|
1163
|
+
# "currency": "BTC",
|
|
1164
|
+
# "balance": "0.0000000497717339",
|
|
1165
|
+
# "available": "0.0000000497717339",
|
|
1166
|
+
# "holds": "0"
|
|
1167
|
+
# },
|
|
1168
|
+
# {
|
|
1169
|
+
# "frozen": "0",
|
|
1170
|
+
# "hold": "0",
|
|
1171
|
+
# "id": "2149632",
|
|
1172
|
+
# "currency": "ICN",
|
|
1173
|
+
# "balance": "0.00000000925",
|
|
1174
|
+
# "available": "0.00000000925",
|
|
1175
|
+
# "holds": "0"
|
|
1176
|
+
# }
|
|
1177
|
+
# ]
|
|
1178
|
+
#
|
|
1179
|
+
result: dict = {
|
|
1180
|
+
'info': response,
|
|
1181
|
+
'timestamp': None,
|
|
1182
|
+
'datetime': None,
|
|
1183
|
+
}
|
|
1184
|
+
for i in range(0, len(response)):
|
|
1185
|
+
balance = response[i]
|
|
1186
|
+
currencyId = self.safe_string(balance, 'currency')
|
|
1187
|
+
code = self.safe_currency_code(currencyId)
|
|
1188
|
+
account = self.account()
|
|
1189
|
+
account['total'] = self.safe_string(balance, 'balance')
|
|
1190
|
+
account['used'] = self.safe_string(balance, 'hold')
|
|
1191
|
+
account['free'] = self.safe_string(balance, 'available')
|
|
1192
|
+
result[code] = account
|
|
1193
|
+
return self.safe_balance(result)
|
|
1194
|
+
|
|
1195
|
+
def fetch_balance(self, params={}) -> Balances:
|
|
1196
|
+
"""
|
|
1197
|
+
query for balance and get the amount of funds available for trading or funds locked in orders
|
|
1198
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1199
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
|
1200
|
+
"""
|
|
1201
|
+
self.load_markets()
|
|
1202
|
+
marketType, query = self.handle_market_type_and_params('fetchBalance', None, params)
|
|
1203
|
+
request: dict = {
|
|
1204
|
+
# 'ccy': 'BTC,ETH', # comma-separated list of currency ids
|
|
1205
|
+
}
|
|
1206
|
+
response = None
|
|
1207
|
+
if marketType == 'funding':
|
|
1208
|
+
response = self.privateGetAssetBalances(self.extend(request, query))
|
|
1209
|
+
else:
|
|
1210
|
+
response = self.privateGetAccountBalance(self.extend(request, query))
|
|
1211
|
+
#
|
|
1212
|
+
# {
|
|
1213
|
+
# "code": "0",
|
|
1214
|
+
# "data": [
|
|
1215
|
+
# {
|
|
1216
|
+
# "category": "1",
|
|
1217
|
+
# "delivery": "",
|
|
1218
|
+
# "exercise": "",
|
|
1219
|
+
# "instType": "SPOT",
|
|
1220
|
+
# "level": "Lv1",
|
|
1221
|
+
# "maker": "-0.0008",
|
|
1222
|
+
# "taker": "-0.001",
|
|
1223
|
+
# "ts": "1639043138472"
|
|
1224
|
+
# }
|
|
1225
|
+
# ],
|
|
1226
|
+
# "msg": ""
|
|
1227
|
+
# }
|
|
1228
|
+
#
|
|
1229
|
+
if marketType == 'funding':
|
|
1230
|
+
return self.parse_funding_balance(response)
|
|
1231
|
+
else:
|
|
1232
|
+
return self.parse_trading_balance(response)
|
|
1233
|
+
|
|
1234
|
+
def parse_trading_balance(self, response):
|
|
1235
|
+
result: dict = {'info': response}
|
|
1236
|
+
data = self.safe_value(response, 'data', [])
|
|
1237
|
+
first = self.safe_value(data, 0, {})
|
|
1238
|
+
timestamp = self.safe_integer(first, 'uTime')
|
|
1239
|
+
details = self.safe_value(first, 'details', [])
|
|
1240
|
+
for i in range(0, len(details)):
|
|
1241
|
+
balance = details[i]
|
|
1242
|
+
currencyId = self.safe_string(balance, 'ccy')
|
|
1243
|
+
code = self.safe_currency_code(currencyId)
|
|
1244
|
+
account = self.account()
|
|
1245
|
+
# it may be incorrect to use total, free and used for swap accounts
|
|
1246
|
+
eq = self.safe_string(balance, 'eq')
|
|
1247
|
+
availEq = self.safe_string(balance, 'availEq')
|
|
1248
|
+
if (eq is None) or (availEq is None):
|
|
1249
|
+
account['free'] = self.safe_string(balance, 'availBal')
|
|
1250
|
+
account['used'] = self.safe_string(balance, 'frozenBal')
|
|
1251
|
+
else:
|
|
1252
|
+
account['total'] = eq
|
|
1253
|
+
account['free'] = availEq
|
|
1254
|
+
result[code] = account
|
|
1255
|
+
result['timestamp'] = timestamp
|
|
1256
|
+
result['datetime'] = self.iso8601(timestamp)
|
|
1257
|
+
return self.safe_balance(result)
|
|
1258
|
+
|
|
1259
|
+
def parse_funding_balance(self, response):
|
|
1260
|
+
result: dict = {'info': response}
|
|
1261
|
+
data = self.safe_value(response, 'data', [])
|
|
1262
|
+
for i in range(0, len(data)):
|
|
1263
|
+
balance = data[i]
|
|
1264
|
+
currencyId = self.safe_string(balance, 'ccy')
|
|
1265
|
+
code = self.safe_currency_code(currencyId)
|
|
1266
|
+
account = self.account()
|
|
1267
|
+
# it may be incorrect to use total, free and used for swap accounts
|
|
1268
|
+
account['total'] = self.safe_string(balance, 'bal')
|
|
1269
|
+
account['free'] = self.safe_string(balance, 'availBal')
|
|
1270
|
+
account['used'] = self.safe_string(balance, 'frozenBal')
|
|
1271
|
+
result[code] = account
|
|
1272
|
+
return self.safe_balance(result)
|
|
1273
|
+
|
|
1274
|
+
def create_market_buy_order_with_cost(self, symbol: str, cost: float, params={}):
|
|
1275
|
+
"""
|
|
1276
|
+
create a market buy order by providing the symbol and cost
|
|
1277
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-place-order
|
|
1278
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1279
|
+
:param float cost: how much you want to trade in units of the quote currency
|
|
1280
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1281
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1282
|
+
"""
|
|
1283
|
+
self.load_markets()
|
|
1284
|
+
market = self.market(symbol)
|
|
1285
|
+
if not market['spot']:
|
|
1286
|
+
raise NotSupported(self.id + ' createMarketBuyOrderWithCost() supports spot orders only')
|
|
1287
|
+
params['createMarketBuyOrderRequiresPrice'] = False
|
|
1288
|
+
params['tgtCcy'] = 'quote_ccy'
|
|
1289
|
+
return self.create_order(symbol, 'market', 'buy', cost, None, params)
|
|
1290
|
+
|
|
1291
|
+
def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
1292
|
+
"""
|
|
1293
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-place-order
|
|
1294
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-place-algo-order
|
|
1295
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-place-multiple-orders
|
|
1296
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-advance-algo-order
|
|
1297
|
+
create a trade order
|
|
1298
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1299
|
+
:param str type: 'market' or 'limit'
|
|
1300
|
+
:param str side: 'buy' or 'sell'
|
|
1301
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
|
1302
|
+
:param float price: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
1303
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1304
|
+
:param bool [params.reduceOnly]: MARGIN orders only, or swap/future orders in net mode
|
|
1305
|
+
:param bool [params.postOnly]: True to place a post only order
|
|
1306
|
+
:param float [params.triggerPrice]: conditional orders only, the price at which the order is to be triggered
|
|
1307
|
+
:param dict [params.takeProfit]: *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered(perpetual swap markets only)
|
|
1308
|
+
:param float [params.takeProfit.triggerPrice]: take profit trigger price
|
|
1309
|
+
:param float [params.takeProfit.price]: used for take profit limit orders, not used for take profit market price orders
|
|
1310
|
+
:param str [params.takeProfit.type]: 'market' or 'limit' used to specify the take profit price type
|
|
1311
|
+
:param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered(perpetual swap markets only)
|
|
1312
|
+
:param float [params.stopLoss.triggerPrice]: stop loss trigger price
|
|
1313
|
+
:param float [params.stopLoss.price]: used for stop loss limit orders, not used for stop loss market price orders
|
|
1314
|
+
:param str [params.stopLoss.type]: 'market' or 'limit' used to specify the stop loss price type
|
|
1315
|
+
:param float [params.cost]: *spot market buy only* the quote quantity that can be used alternative for the amount
|
|
1316
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1317
|
+
"""
|
|
1318
|
+
self.load_markets()
|
|
1319
|
+
market = self.market(symbol)
|
|
1320
|
+
request = self.create_order_request(symbol, type, side, amount, price, params)
|
|
1321
|
+
method = self.safe_string(self.options, 'createOrder', 'privatePostTradeBatchOrders')
|
|
1322
|
+
requestOrdType = self.safe_string(request, 'ordType')
|
|
1323
|
+
if (requestOrdType == 'trigger') or (requestOrdType == 'conditional') or (type == 'oco') or (type == 'move_order_stop') or (type == 'iceberg') or (type == 'twap'):
|
|
1324
|
+
method = 'privatePostTradeOrderAlgo'
|
|
1325
|
+
if method == 'privatePostTradeBatchOrders':
|
|
1326
|
+
# keep the request body the same
|
|
1327
|
+
# submit a single order in an array to the batch order endpoint
|
|
1328
|
+
# because it has a lower ratelimit
|
|
1329
|
+
request = [request]
|
|
1330
|
+
response = None
|
|
1331
|
+
if method == 'privatePostTradeOrder':
|
|
1332
|
+
response = self.privatePostTradeOrder(request)
|
|
1333
|
+
elif method == 'privatePostTradeOrderAlgo':
|
|
1334
|
+
response = self.privatePostTradeOrderAlgo(request)
|
|
1335
|
+
elif method == 'privatePostTradeBatchOrders':
|
|
1336
|
+
response = self.privatePostTradeBatchOrders(request)
|
|
1337
|
+
else:
|
|
1338
|
+
raise ExchangeError(self.id + ' createOrder() self.options["createOrder"] must be either privatePostTradeBatchOrders or privatePostTradeOrder or privatePostTradeOrderAlgo')
|
|
1339
|
+
data = self.safe_value(response, 'data', [])
|
|
1340
|
+
first = self.safe_value(data, 0)
|
|
1341
|
+
order = self.parse_order(first, market)
|
|
1342
|
+
order['type'] = type
|
|
1343
|
+
order['side'] = side
|
|
1344
|
+
return order
|
|
1345
|
+
|
|
1346
|
+
def create_order_request(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
|
1347
|
+
market = self.market(symbol)
|
|
1348
|
+
request: dict = {
|
|
1349
|
+
'instId': market['id'],
|
|
1350
|
+
# 'ccy': currency['id'], # only applicable to cross MARGIN orders in single-currency margin
|
|
1351
|
+
# 'clOrdId': clientOrderId, # up to 32 characters, must be unique
|
|
1352
|
+
# 'tag': tag, # up to 8 characters
|
|
1353
|
+
'side': side,
|
|
1354
|
+
# 'posSide': 'long', # long, short, # required in the long/short mode, and can only be long or short(only for future or swap)
|
|
1355
|
+
'ordType': type,
|
|
1356
|
+
# 'ordType': type, # privatePostTradeOrder: market, limit, post_only, fok, ioc, optimal_limit_ioc
|
|
1357
|
+
# 'ordType': type, # privatePostTradeOrderAlgo: conditional, oco, trigger, move_order_stop, iceberg, twap
|
|
1358
|
+
# 'sz': self.amount_to_precision(symbol, amount),
|
|
1359
|
+
# 'px': self.price_to_precision(symbol, price), # limit orders only
|
|
1360
|
+
# 'reduceOnly': False,
|
|
1361
|
+
#
|
|
1362
|
+
# 'triggerPx': 10, # stopPrice(trigger orders)
|
|
1363
|
+
# 'orderPx': 10, # Order price if -1, the order will be executed at the market price.(trigger orders)
|
|
1364
|
+
# 'triggerPxType': 'last', # Conditional default is last, mark or index(trigger orders)
|
|
1365
|
+
#
|
|
1366
|
+
# 'tpTriggerPx': 10, # takeProfitPrice(conditional orders)
|
|
1367
|
+
# 'tpTriggerPxType': 'last', # Conditional default is last, mark or index(conditional orders)
|
|
1368
|
+
# 'tpOrdPx': 10, # Order price for Take-Profit orders, if -1 will be executed at market price(conditional orders)
|
|
1369
|
+
#
|
|
1370
|
+
# 'slTriggerPx': 10, # stopLossPrice(conditional orders)
|
|
1371
|
+
# 'slTriggerPxType': 'last', # Conditional default is last, mark or index(conditional orders)
|
|
1372
|
+
# 'slOrdPx': 10, # Order price for Stop-Loss orders, if -1 will be executed at market price(conditional orders)
|
|
1373
|
+
}
|
|
1374
|
+
triggerPrice = self.safe_value_n(params, ['triggerPrice', 'stopPrice', 'triggerPx'])
|
|
1375
|
+
timeInForce = self.safe_string(params, 'timeInForce', 'GTC')
|
|
1376
|
+
takeProfitPrice = self.safe_value_2(params, 'takeProfitPrice', 'tpTriggerPx')
|
|
1377
|
+
tpOrdPx = self.safe_value(params, 'tpOrdPx', price)
|
|
1378
|
+
tpTriggerPxType = self.safe_string(params, 'tpTriggerPxType', 'last')
|
|
1379
|
+
stopLossPrice = self.safe_value_2(params, 'stopLossPrice', 'slTriggerPx')
|
|
1380
|
+
slOrdPx = self.safe_value(params, 'slOrdPx', price)
|
|
1381
|
+
slTriggerPxType = self.safe_string(params, 'slTriggerPxType', 'last')
|
|
1382
|
+
clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
|
|
1383
|
+
stopLoss = self.safe_value(params, 'stopLoss')
|
|
1384
|
+
stopLossDefined = (stopLoss is not None)
|
|
1385
|
+
takeProfit = self.safe_value(params, 'takeProfit')
|
|
1386
|
+
takeProfitDefined = (takeProfit is not None)
|
|
1387
|
+
defaultMarginMode = self.safe_string_2(self.options, 'defaultMarginMode', 'marginMode', 'cross')
|
|
1388
|
+
marginMode = self.safe_string_2(params, 'marginMode', 'tdMode') # cross or isolated, tdMode not ommited so be extended into the request
|
|
1389
|
+
margin = False
|
|
1390
|
+
if (marginMode is not None) and (marginMode != 'cash'):
|
|
1391
|
+
margin = True
|
|
1392
|
+
else:
|
|
1393
|
+
marginMode = defaultMarginMode
|
|
1394
|
+
margin = self.safe_bool(params, 'margin', False)
|
|
1395
|
+
if margin:
|
|
1396
|
+
defaultCurrency = market['quote'] if (side == 'buy') else market['base']
|
|
1397
|
+
currency = self.safe_string(params, 'ccy', defaultCurrency)
|
|
1398
|
+
request['ccy'] = self.safe_currency_code(currency)
|
|
1399
|
+
tradeMode = marginMode if margin else 'cash'
|
|
1400
|
+
request['tdMode'] = tradeMode
|
|
1401
|
+
isMarketOrder = type == 'market'
|
|
1402
|
+
postOnly = False
|
|
1403
|
+
postOnly, params = self.handle_post_only(isMarketOrder, type == 'post_only', params)
|
|
1404
|
+
params = self.omit(params, ['currency', 'ccy', 'marginMode', 'timeInForce', 'stopPrice', 'triggerPrice', 'clientOrderId', 'stopLossPrice', 'takeProfitPrice', 'slOrdPx', 'tpOrdPx', 'margin', 'stopLoss', 'takeProfit'])
|
|
1405
|
+
ioc = (timeInForce == 'IOC') or (type == 'ioc')
|
|
1406
|
+
fok = (timeInForce == 'FOK') or (type == 'fok')
|
|
1407
|
+
trigger = (triggerPrice is not None) or (type == 'trigger')
|
|
1408
|
+
conditional = (stopLossPrice is not None) or (takeProfitPrice is not None) or (type == 'conditional')
|
|
1409
|
+
marketIOC = (isMarketOrder and ioc) or (type == 'optimal_limit_ioc')
|
|
1410
|
+
defaultTgtCcy = self.safe_string(self.options, 'tgtCcy', 'base_ccy')
|
|
1411
|
+
tgtCcy = self.safe_string(params, 'tgtCcy', defaultTgtCcy)
|
|
1412
|
+
if (not margin):
|
|
1413
|
+
request['tgtCcy'] = tgtCcy
|
|
1414
|
+
if isMarketOrder or marketIOC:
|
|
1415
|
+
request['ordType'] = 'market'
|
|
1416
|
+
if side == 'buy':
|
|
1417
|
+
# spot market buy: "sz" can refer either to base currency units or to quote currency units
|
|
1418
|
+
# see documentation: https://www.okx.com/docs-v5/en/#rest-api-trade-place-order
|
|
1419
|
+
if tgtCcy == 'quote_ccy':
|
|
1420
|
+
# quote_ccy: sz refers to units of quote currency
|
|
1421
|
+
quoteAmount = None
|
|
1422
|
+
createMarketBuyOrderRequiresPrice = True
|
|
1423
|
+
createMarketBuyOrderRequiresPrice, params = self.handle_option_and_params(params, 'createOrder', 'createMarketBuyOrderRequiresPrice', True)
|
|
1424
|
+
cost = self.safe_number_2(params, 'cost', 'sz')
|
|
1425
|
+
params = self.omit(params, ['cost', 'sz'])
|
|
1426
|
+
if cost is not None:
|
|
1427
|
+
quoteAmount = self.cost_to_precision(symbol, cost)
|
|
1428
|
+
elif createMarketBuyOrderRequiresPrice:
|
|
1429
|
+
if price is None:
|
|
1430
|
+
raise InvalidOrder(self.id + ' createOrder() requires the price argument for market buy orders to calculate the total cost to spend(amount * price), alternatively set the createMarketBuyOrderRequiresPrice option or param to False and pass the cost to spend(quote quantity) in the amount argument')
|
|
1431
|
+
else:
|
|
1432
|
+
amountString = self.number_to_string(amount)
|
|
1433
|
+
priceString = self.number_to_string(price)
|
|
1434
|
+
costRequest = Precise.string_mul(amountString, priceString)
|
|
1435
|
+
quoteAmount = self.cost_to_precision(symbol, costRequest)
|
|
1436
|
+
else:
|
|
1437
|
+
quoteAmount = self.cost_to_precision(symbol, amount)
|
|
1438
|
+
request['sz'] = quoteAmount
|
|
1439
|
+
else:
|
|
1440
|
+
request['sz'] = self.amount_to_precision(symbol, amount)
|
|
1441
|
+
else:
|
|
1442
|
+
request['sz'] = self.amount_to_precision(symbol, amount)
|
|
1443
|
+
else:
|
|
1444
|
+
request['sz'] = self.amount_to_precision(symbol, amount)
|
|
1445
|
+
if (not trigger) and (not conditional):
|
|
1446
|
+
request['px'] = self.price_to_precision(symbol, price)
|
|
1447
|
+
if postOnly:
|
|
1448
|
+
request['ordType'] = 'post_only'
|
|
1449
|
+
elif ioc and not marketIOC:
|
|
1450
|
+
request['ordType'] = 'ioc'
|
|
1451
|
+
elif fok:
|
|
1452
|
+
request['ordType'] = 'fok'
|
|
1453
|
+
elif stopLossDefined or takeProfitDefined:
|
|
1454
|
+
if stopLossDefined:
|
|
1455
|
+
stopLossTriggerPrice = self.safe_value_n(stopLoss, ['triggerPrice', 'stopPrice', 'slTriggerPx'])
|
|
1456
|
+
if stopLossTriggerPrice is None:
|
|
1457
|
+
raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["stopLoss"]["triggerPrice"], or params["stopLoss"]["stopPrice"], or params["stopLoss"]["slTriggerPx"] for a stop loss order')
|
|
1458
|
+
request['slTriggerPx'] = self.price_to_precision(symbol, stopLossTriggerPrice)
|
|
1459
|
+
stopLossLimitPrice = self.safe_value_n(stopLoss, ['price', 'stopLossPrice', 'slOrdPx'])
|
|
1460
|
+
stopLossOrderType = self.safe_string(stopLoss, 'type')
|
|
1461
|
+
if stopLossOrderType is not None:
|
|
1462
|
+
stopLossLimitOrderType = (stopLossOrderType == 'limit')
|
|
1463
|
+
stopLossMarketOrderType = (stopLossOrderType == 'market')
|
|
1464
|
+
if (not stopLossLimitOrderType) and (not stopLossMarketOrderType):
|
|
1465
|
+
raise InvalidOrder(self.id + ' createOrder() params["stopLoss"]["type"] must be either "limit" or "market"')
|
|
1466
|
+
elif stopLossLimitOrderType:
|
|
1467
|
+
if stopLossLimitPrice is None:
|
|
1468
|
+
raise InvalidOrder(self.id + ' createOrder() requires a limit price in params["stopLoss"]["price"] or params["stopLoss"]["slOrdPx"] for a stop loss limit order')
|
|
1469
|
+
else:
|
|
1470
|
+
request['slOrdPx'] = self.price_to_precision(symbol, stopLossLimitPrice)
|
|
1471
|
+
elif stopLossOrderType == 'market':
|
|
1472
|
+
request['slOrdPx'] = '-1'
|
|
1473
|
+
elif stopLossLimitPrice is not None:
|
|
1474
|
+
request['slOrdPx'] = self.price_to_precision(symbol, stopLossLimitPrice) # limit sl order
|
|
1475
|
+
else:
|
|
1476
|
+
request['slOrdPx'] = '-1' # market sl order
|
|
1477
|
+
stopLossTriggerPriceType = self.safe_string_2(stopLoss, 'triggerPriceType', 'slTriggerPxType', 'last')
|
|
1478
|
+
if stopLossTriggerPriceType is not None:
|
|
1479
|
+
if (stopLossTriggerPriceType != 'last') and (stopLossTriggerPriceType != 'index') and (stopLossTriggerPriceType != 'mark'):
|
|
1480
|
+
raise InvalidOrder(self.id + ' createOrder() stop loss trigger price type must be one of "last", "index" or "mark"')
|
|
1481
|
+
request['slTriggerPxType'] = stopLossTriggerPriceType
|
|
1482
|
+
if takeProfitDefined:
|
|
1483
|
+
takeProfitTriggerPrice = self.safe_value_n(takeProfit, ['triggerPrice', 'stopPrice', 'tpTriggerPx'])
|
|
1484
|
+
if takeProfitTriggerPrice is None:
|
|
1485
|
+
raise InvalidOrder(self.id + ' createOrder() requires a trigger price in params["takeProfit"]["triggerPrice"], or params["takeProfit"]["stopPrice"], or params["takeProfit"]["tpTriggerPx"] for a take profit order')
|
|
1486
|
+
request['tpTriggerPx'] = self.price_to_precision(symbol, takeProfitTriggerPrice)
|
|
1487
|
+
takeProfitLimitPrice = self.safe_value_n(takeProfit, ['price', 'takeProfitPrice', 'tpOrdPx'])
|
|
1488
|
+
takeProfitOrderType = self.safe_string(takeProfit, 'type')
|
|
1489
|
+
if takeProfitOrderType is not None:
|
|
1490
|
+
takeProfitLimitOrderType = (takeProfitOrderType == 'limit')
|
|
1491
|
+
takeProfitMarketOrderType = (takeProfitOrderType == 'market')
|
|
1492
|
+
if (not takeProfitLimitOrderType) and (not takeProfitMarketOrderType):
|
|
1493
|
+
raise InvalidOrder(self.id + ' createOrder() params["takeProfit"]["type"] must be either "limit" or "market"')
|
|
1494
|
+
elif takeProfitLimitOrderType:
|
|
1495
|
+
if takeProfitLimitPrice is None:
|
|
1496
|
+
raise InvalidOrder(self.id + ' createOrder() requires a limit price in params["takeProfit"]["price"] or params["takeProfit"]["tpOrdPx"] for a take profit limit order')
|
|
1497
|
+
else:
|
|
1498
|
+
request['tpOrdPx'] = self.price_to_precision(symbol, takeProfitLimitPrice)
|
|
1499
|
+
elif takeProfitOrderType == 'market':
|
|
1500
|
+
request['tpOrdPx'] = '-1'
|
|
1501
|
+
elif takeProfitLimitPrice is not None:
|
|
1502
|
+
request['tpOrdPx'] = self.price_to_precision(symbol, takeProfitLimitPrice) # limit tp order
|
|
1503
|
+
else:
|
|
1504
|
+
request['tpOrdPx'] = '-1' # market tp order
|
|
1505
|
+
takeProfitTriggerPriceType = self.safe_string_2(takeProfit, 'triggerPriceType', 'tpTriggerPxType', 'last')
|
|
1506
|
+
if takeProfitTriggerPriceType is not None:
|
|
1507
|
+
if (takeProfitTriggerPriceType != 'last') and (takeProfitTriggerPriceType != 'index') and (takeProfitTriggerPriceType != 'mark'):
|
|
1508
|
+
raise InvalidOrder(self.id + ' createOrder() take profit trigger price type must be one of "last", "index" or "mark"')
|
|
1509
|
+
request['tpTriggerPxType'] = takeProfitTriggerPriceType
|
|
1510
|
+
elif trigger:
|
|
1511
|
+
request['ordType'] = 'trigger'
|
|
1512
|
+
request['triggerPx'] = self.price_to_precision(symbol, triggerPrice)
|
|
1513
|
+
request['orderPx'] = '-1' if isMarketOrder else self.price_to_precision(symbol, price)
|
|
1514
|
+
elif conditional:
|
|
1515
|
+
request['ordType'] = 'conditional'
|
|
1516
|
+
twoWayCondition = ((takeProfitPrice is not None) and (stopLossPrice is not None))
|
|
1517
|
+
# if TP and SL are sent together
|
|
1518
|
+
# 'conditional' only stop-loss order will be applied
|
|
1519
|
+
if twoWayCondition:
|
|
1520
|
+
request['ordType'] = 'oco'
|
|
1521
|
+
if takeProfitPrice is not None:
|
|
1522
|
+
request['tpTriggerPx'] = self.price_to_precision(symbol, takeProfitPrice)
|
|
1523
|
+
request['tpOrdPx'] = '-1' if (tpOrdPx is None) else self.price_to_precision(symbol, tpOrdPx)
|
|
1524
|
+
request['tpTriggerPxType'] = tpTriggerPxType
|
|
1525
|
+
if stopLossPrice is not None:
|
|
1526
|
+
request['slTriggerPx'] = self.price_to_precision(symbol, stopLossPrice)
|
|
1527
|
+
request['slOrdPx'] = '-1' if (slOrdPx is None) else self.price_to_precision(symbol, slOrdPx)
|
|
1528
|
+
request['slTriggerPxType'] = slTriggerPxType
|
|
1529
|
+
if clientOrderId is None:
|
|
1530
|
+
brokerId = self.safe_string(self.options, 'brokerId')
|
|
1531
|
+
if brokerId is not None:
|
|
1532
|
+
request['clOrdId'] = brokerId + self.uuid16()
|
|
1533
|
+
request['tag'] = brokerId
|
|
1534
|
+
else:
|
|
1535
|
+
request['clOrdId'] = clientOrderId
|
|
1536
|
+
params = self.omit(params, ['clOrdId', 'clientOrderId'])
|
|
1537
|
+
return self.extend(request, params)
|
|
1538
|
+
|
|
1539
|
+
def cancel_order(self, id: str, symbol: Str = None, params={}):
|
|
1540
|
+
"""
|
|
1541
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-order
|
|
1542
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-algo-order
|
|
1543
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-advance-algo-order
|
|
1544
|
+
cancels an open order
|
|
1545
|
+
:param str id: order id
|
|
1546
|
+
:param str symbol: unified symbol of the market the order was made in
|
|
1547
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1548
|
+
:param bool [params.stop]: True if cancel trigger or conditional orders
|
|
1549
|
+
:param bool [params.advanced]: True if canceling advanced orders only
|
|
1550
|
+
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1551
|
+
"""
|
|
1552
|
+
if symbol is None:
|
|
1553
|
+
raise ArgumentsRequired(self.id + ' cancelOrder() requires a symbol argument')
|
|
1554
|
+
self.load_markets()
|
|
1555
|
+
stop = self.safe_value_2(params, 'stop', 'trigger')
|
|
1556
|
+
advanced = self.safe_value(params, 'advanced')
|
|
1557
|
+
if stop or advanced:
|
|
1558
|
+
orderInner = self.cancel_orders([id], symbol, params)
|
|
1559
|
+
return self.safe_value(orderInner, 0)
|
|
1560
|
+
market = self.market(symbol)
|
|
1561
|
+
request: dict = {
|
|
1562
|
+
'instId': market['id'],
|
|
1563
|
+
# 'ordId': id, # either ordId or clOrdId is required
|
|
1564
|
+
# 'clOrdId': clientOrderId,
|
|
1565
|
+
}
|
|
1566
|
+
clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
|
|
1567
|
+
if clientOrderId is not None:
|
|
1568
|
+
request['clOrdId'] = clientOrderId
|
|
1569
|
+
else:
|
|
1570
|
+
request['ordId'] = str(id)
|
|
1571
|
+
query = self.omit(params, ['clOrdId', 'clientOrderId'])
|
|
1572
|
+
response = self.privatePostTradeCancelOrder(self.extend(request, query))
|
|
1573
|
+
# {"code":"0","data":[{"clOrdId":"","ordId":"317251910906576896","sCode":"0","sMsg":""}],"msg":""}
|
|
1574
|
+
data = self.safe_value(response, 'data', [])
|
|
1575
|
+
order = self.safe_dict(data, 0)
|
|
1576
|
+
return self.parse_order(order, market)
|
|
1577
|
+
|
|
1578
|
+
def parse_ids(self, ids):
|
|
1579
|
+
"""
|
|
1580
|
+
* @ignore
|
|
1581
|
+
:param string[]|str ids: order ids
|
|
1582
|
+
:returns str[]: list of order ids
|
|
1583
|
+
"""
|
|
1584
|
+
if isinstance(ids, str):
|
|
1585
|
+
return ids.split(',')
|
|
1586
|
+
else:
|
|
1587
|
+
return ids
|
|
1588
|
+
|
|
1589
|
+
def cancel_orders(self, ids, symbol: Str = None, params={}):
|
|
1590
|
+
"""
|
|
1591
|
+
cancel multiple orders
|
|
1592
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-multiple-orders
|
|
1593
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-algo-order
|
|
1594
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-cancel-advance-algo-order
|
|
1595
|
+
:param str[] ids: order ids
|
|
1596
|
+
:param str symbol: unified market symbol
|
|
1597
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1598
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1599
|
+
"""
|
|
1600
|
+
if symbol is None:
|
|
1601
|
+
raise ArgumentsRequired(self.id + ' cancelOrders() requires a symbol argument')
|
|
1602
|
+
self.load_markets()
|
|
1603
|
+
stop = self.safe_value_2(params, 'stop', 'trigger')
|
|
1604
|
+
advanced = self.safe_value(params, 'advanced')
|
|
1605
|
+
params = self.omit(params, ['stop', 'trigger', 'advanced'])
|
|
1606
|
+
market = self.market(symbol)
|
|
1607
|
+
request = []
|
|
1608
|
+
clientOrderIds = self.parse_ids(self.safe_value_2(params, 'clOrdId', 'clientOrderId'))
|
|
1609
|
+
algoIds = self.parse_ids(self.safe_value(params, 'algoId'))
|
|
1610
|
+
if clientOrderIds is None:
|
|
1611
|
+
ids = self.parse_ids(ids)
|
|
1612
|
+
if algoIds is not None:
|
|
1613
|
+
for i in range(0, len(algoIds)):
|
|
1614
|
+
request.append({
|
|
1615
|
+
'algoId': algoIds[i],
|
|
1616
|
+
'instId': market['id'],
|
|
1617
|
+
})
|
|
1618
|
+
for i in range(0, len(ids)):
|
|
1619
|
+
if stop or advanced:
|
|
1620
|
+
request.append({
|
|
1621
|
+
'algoId': ids[i],
|
|
1622
|
+
'instId': market['id'],
|
|
1623
|
+
})
|
|
1624
|
+
else:
|
|
1625
|
+
request.append({
|
|
1626
|
+
'ordId': ids[i],
|
|
1627
|
+
'instId': market['id'],
|
|
1628
|
+
})
|
|
1629
|
+
else:
|
|
1630
|
+
for i in range(0, len(clientOrderIds)):
|
|
1631
|
+
request.append({
|
|
1632
|
+
'instId': market['id'],
|
|
1633
|
+
'clOrdId': clientOrderIds[i],
|
|
1634
|
+
})
|
|
1635
|
+
response = None
|
|
1636
|
+
if stop:
|
|
1637
|
+
response = self.privatePostTradeCancelAlgos(request)
|
|
1638
|
+
elif advanced:
|
|
1639
|
+
response = self.privatePostTradeCancelAdvanceAlgos(request)
|
|
1640
|
+
else:
|
|
1641
|
+
response = self.privatePostTradeCancelBatchOrders(request) # * dont self.extend with params, otherwise ARRAY will be turned into OBJECT
|
|
1642
|
+
#
|
|
1643
|
+
# {
|
|
1644
|
+
# "code": "0",
|
|
1645
|
+
# "data": [
|
|
1646
|
+
# {
|
|
1647
|
+
# "clOrdId": "e123456789ec4dBC1123456ba123b45e",
|
|
1648
|
+
# "ordId": "405071912345641543",
|
|
1649
|
+
# "sCode": "0",
|
|
1650
|
+
# "sMsg": ""
|
|
1651
|
+
# },
|
|
1652
|
+
# ...
|
|
1653
|
+
# ],
|
|
1654
|
+
# "msg": ""
|
|
1655
|
+
# }
|
|
1656
|
+
#
|
|
1657
|
+
#
|
|
1658
|
+
ordersData = self.safe_list(response, 'data', [])
|
|
1659
|
+
return self.parse_orders(ordersData, market, None, None, params)
|
|
1660
|
+
|
|
1661
|
+
def parse_order_status(self, status: Str):
|
|
1662
|
+
statuses: dict = {
|
|
1663
|
+
'canceled': 'canceled',
|
|
1664
|
+
'live': 'open',
|
|
1665
|
+
'partially_filled': 'open',
|
|
1666
|
+
'filled': 'closed',
|
|
1667
|
+
'effective': 'closed',
|
|
1668
|
+
}
|
|
1669
|
+
return self.safe_string(statuses, status, status)
|
|
1670
|
+
|
|
1671
|
+
def parse_order(self, order: dict, market: Market = None) -> Order:
|
|
1672
|
+
#
|
|
1673
|
+
# createOrder
|
|
1674
|
+
#
|
|
1675
|
+
# {
|
|
1676
|
+
# "clOrdId": "oktswap6",
|
|
1677
|
+
# "ordId": "312269865356374016",
|
|
1678
|
+
# "tag": "",
|
|
1679
|
+
# "sCode": "0",
|
|
1680
|
+
# "sMsg": ""
|
|
1681
|
+
# }
|
|
1682
|
+
#
|
|
1683
|
+
# editOrder
|
|
1684
|
+
#
|
|
1685
|
+
# {
|
|
1686
|
+
# "clOrdId": "e847386590ce4dBCc1a045253497a547",
|
|
1687
|
+
# "ordId": "559176536793178112",
|
|
1688
|
+
# "reqId": "",
|
|
1689
|
+
# "sCode": "0",
|
|
1690
|
+
# "sMsg": ""
|
|
1691
|
+
# }
|
|
1692
|
+
#
|
|
1693
|
+
# Spot and Swap fetchOrder, fetchOpenOrders
|
|
1694
|
+
#
|
|
1695
|
+
# {
|
|
1696
|
+
# "accFillSz": "0",
|
|
1697
|
+
# "avgPx": "",
|
|
1698
|
+
# "cTime": "1621910749815",
|
|
1699
|
+
# "category": "normal",
|
|
1700
|
+
# "ccy": "",
|
|
1701
|
+
# "clOrdId": "",
|
|
1702
|
+
# "fee": "0",
|
|
1703
|
+
# "feeCcy": "ETH",
|
|
1704
|
+
# "fillPx": "",
|
|
1705
|
+
# "fillSz": "0",
|
|
1706
|
+
# "fillTime": "",
|
|
1707
|
+
# "instId": "ETH-USDT",
|
|
1708
|
+
# "instType": "SPOT",
|
|
1709
|
+
# "lever": "",
|
|
1710
|
+
# "ordId": "317251910906576896",
|
|
1711
|
+
# "ordType": "limit",
|
|
1712
|
+
# "pnl": "0",
|
|
1713
|
+
# "posSide": "net",
|
|
1714
|
+
# "px": "2000",
|
|
1715
|
+
# "rebate": "0",
|
|
1716
|
+
# "rebateCcy": "USDT",
|
|
1717
|
+
# "side": "buy",
|
|
1718
|
+
# "slOrdPx": "",
|
|
1719
|
+
# "slTriggerPx": "",
|
|
1720
|
+
# "state": "live",
|
|
1721
|
+
# "sz": "0.001",
|
|
1722
|
+
# "tag": "",
|
|
1723
|
+
# "tdMode": "cash",
|
|
1724
|
+
# "tpOrdPx": "",
|
|
1725
|
+
# "tpTriggerPx": "",
|
|
1726
|
+
# "tradeId": "",
|
|
1727
|
+
# "uTime": "1621910749815"
|
|
1728
|
+
# }
|
|
1729
|
+
#
|
|
1730
|
+
# Algo Order fetchOpenOrders, fetchCanceledOrders, fetchClosedOrders
|
|
1731
|
+
#
|
|
1732
|
+
# {
|
|
1733
|
+
# "activePx": "",
|
|
1734
|
+
# "activePxType": "",
|
|
1735
|
+
# "actualPx": "",
|
|
1736
|
+
# "actualSide": "buy",
|
|
1737
|
+
# "actualSz": "0",
|
|
1738
|
+
# "algoId": "431375349042380800",
|
|
1739
|
+
# "cTime": "1649119897778",
|
|
1740
|
+
# "callbackRatio": "",
|
|
1741
|
+
# "callbackSpread": "",
|
|
1742
|
+
# "ccy": "",
|
|
1743
|
+
# "ctVal": "0.01",
|
|
1744
|
+
# "instId": "BTC-USDT-SWAP",
|
|
1745
|
+
# "instType": "SWAP",
|
|
1746
|
+
# "last": "46538.9",
|
|
1747
|
+
# "lever": "125",
|
|
1748
|
+
# "moveTriggerPx": "",
|
|
1749
|
+
# "notionalUsd": "467.059",
|
|
1750
|
+
# "ordId": "",
|
|
1751
|
+
# "ordPx": "50000",
|
|
1752
|
+
# "ordType": "trigger",
|
|
1753
|
+
# "posSide": "long",
|
|
1754
|
+
# "pxLimit": "",
|
|
1755
|
+
# "pxSpread": "",
|
|
1756
|
+
# "pxVar": "",
|
|
1757
|
+
# "side": "buy",
|
|
1758
|
+
# "slOrdPx": "",
|
|
1759
|
+
# "slTriggerPx": "",
|
|
1760
|
+
# "slTriggerPxType": "",
|
|
1761
|
+
# "state": "live",
|
|
1762
|
+
# "sz": "1",
|
|
1763
|
+
# "szLimit": "",
|
|
1764
|
+
# "tag": "",
|
|
1765
|
+
# "tdMode": "isolated",
|
|
1766
|
+
# "tgtCcy": "",
|
|
1767
|
+
# "timeInterval": "",
|
|
1768
|
+
# "tpOrdPx": "",
|
|
1769
|
+
# "tpTriggerPx": "",
|
|
1770
|
+
# "tpTriggerPxType": "",
|
|
1771
|
+
# "triggerPx": "50000",
|
|
1772
|
+
# "triggerPxType": "last",
|
|
1773
|
+
# "triggerTime": "",
|
|
1774
|
+
# "uly": "BTC-USDT"
|
|
1775
|
+
# }
|
|
1776
|
+
#
|
|
1777
|
+
id = self.safe_string_2(order, 'algoId', 'ordId')
|
|
1778
|
+
timestamp = self.safe_integer(order, 'cTime')
|
|
1779
|
+
lastUpdateTimestamp = self.safe_integer(order, 'uTime')
|
|
1780
|
+
lastTradeTimestamp = self.safe_integer(order, 'fillTime')
|
|
1781
|
+
side = self.safe_string(order, 'side')
|
|
1782
|
+
type = self.safe_string(order, 'ordType')
|
|
1783
|
+
postOnly = None
|
|
1784
|
+
timeInForce = None
|
|
1785
|
+
if type == 'post_only':
|
|
1786
|
+
postOnly = True
|
|
1787
|
+
type = 'limit'
|
|
1788
|
+
elif type == 'fok':
|
|
1789
|
+
timeInForce = 'FOK'
|
|
1790
|
+
type = 'limit'
|
|
1791
|
+
elif type == 'ioc':
|
|
1792
|
+
timeInForce = 'IOC'
|
|
1793
|
+
type = 'limit'
|
|
1794
|
+
marketId = self.safe_string(order, 'instId')
|
|
1795
|
+
market = self.safe_market(marketId, market)
|
|
1796
|
+
symbol = self.safe_symbol(marketId, market, '-')
|
|
1797
|
+
filled = self.safe_string(order, 'accFillSz')
|
|
1798
|
+
price = self.safe_string_2(order, 'px', 'ordPx')
|
|
1799
|
+
average = self.safe_string(order, 'avgPx')
|
|
1800
|
+
status = self.parse_order_status(self.safe_string(order, 'state'))
|
|
1801
|
+
feeCostString = self.safe_string(order, 'fee')
|
|
1802
|
+
amount = None
|
|
1803
|
+
cost = None
|
|
1804
|
+
# spot market buy: "sz" can refer either to base currency units or to quote currency units
|
|
1805
|
+
# see documentation: https://www.okx.com/docs-v5/en/#rest-api-trade-place-order
|
|
1806
|
+
defaultTgtCcy = self.safe_string(self.options, 'tgtCcy', 'base_ccy')
|
|
1807
|
+
tgtCcy = self.safe_string(order, 'tgtCcy', defaultTgtCcy)
|
|
1808
|
+
if (side == 'buy') and (type == 'market') and (tgtCcy == 'quote_ccy'):
|
|
1809
|
+
# "sz" refers to the cost
|
|
1810
|
+
cost = self.safe_string(order, 'sz')
|
|
1811
|
+
else:
|
|
1812
|
+
# "sz" refers to the trade currency amount
|
|
1813
|
+
amount = self.safe_string(order, 'sz')
|
|
1814
|
+
fee = None
|
|
1815
|
+
if feeCostString is not None:
|
|
1816
|
+
feeCostSigned = Precise.string_neg(feeCostString)
|
|
1817
|
+
feeCurrencyId = self.safe_string(order, 'feeCcy')
|
|
1818
|
+
feeCurrencyCode = self.safe_currency_code(feeCurrencyId)
|
|
1819
|
+
fee = {
|
|
1820
|
+
'cost': self.parse_number(feeCostSigned),
|
|
1821
|
+
'currency': feeCurrencyCode,
|
|
1822
|
+
}
|
|
1823
|
+
clientOrderId = self.safe_string(order, 'clOrdId')
|
|
1824
|
+
if (clientOrderId is not None) and (len(clientOrderId) < 1):
|
|
1825
|
+
clientOrderId = None # fix empty clientOrderId string
|
|
1826
|
+
stopLossPrice = self.safe_number_2(order, 'slTriggerPx', 'slOrdPx')
|
|
1827
|
+
takeProfitPrice = self.safe_number_2(order, 'tpTriggerPx', 'tpOrdPx')
|
|
1828
|
+
stopPrice = self.safe_number_n(order, ['triggerPx', 'moveTriggerPx'])
|
|
1829
|
+
reduceOnlyRaw = self.safe_string(order, 'reduceOnly')
|
|
1830
|
+
reduceOnly = False
|
|
1831
|
+
if reduceOnly is not None:
|
|
1832
|
+
reduceOnly = (reduceOnlyRaw == 'true')
|
|
1833
|
+
return self.safe_order({
|
|
1834
|
+
'info': order,
|
|
1835
|
+
'id': id,
|
|
1836
|
+
'clientOrderId': clientOrderId,
|
|
1837
|
+
'timestamp': timestamp,
|
|
1838
|
+
'datetime': self.iso8601(timestamp),
|
|
1839
|
+
'lastTradeTimestamp': lastTradeTimestamp,
|
|
1840
|
+
'lastUpdateTimestamp': lastUpdateTimestamp,
|
|
1841
|
+
'symbol': symbol,
|
|
1842
|
+
'type': type,
|
|
1843
|
+
'timeInForce': timeInForce,
|
|
1844
|
+
'postOnly': postOnly,
|
|
1845
|
+
'side': side,
|
|
1846
|
+
'price': price,
|
|
1847
|
+
'stopLossPrice': stopLossPrice,
|
|
1848
|
+
'takeProfitPrice': takeProfitPrice,
|
|
1849
|
+
'stopPrice': stopPrice,
|
|
1850
|
+
'triggerPrice': stopPrice,
|
|
1851
|
+
'average': average,
|
|
1852
|
+
'cost': cost,
|
|
1853
|
+
'amount': amount,
|
|
1854
|
+
'filled': filled,
|
|
1855
|
+
'remaining': None,
|
|
1856
|
+
'status': status,
|
|
1857
|
+
'fee': fee,
|
|
1858
|
+
'trades': None,
|
|
1859
|
+
'reduceOnly': reduceOnly,
|
|
1860
|
+
}, market)
|
|
1861
|
+
|
|
1862
|
+
def fetch_order(self, id: str, symbol: Str = None, params={}):
|
|
1863
|
+
"""
|
|
1864
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-order-details
|
|
1865
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-algo-order-list
|
|
1866
|
+
fetches information on an order made by the user
|
|
1867
|
+
:param str symbol: unified symbol of the market the order was made in
|
|
1868
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1869
|
+
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1870
|
+
"""
|
|
1871
|
+
if symbol is None:
|
|
1872
|
+
raise ArgumentsRequired(self.id + ' fetchOrder() requires a symbol argument')
|
|
1873
|
+
self.load_markets()
|
|
1874
|
+
market = self.market(symbol)
|
|
1875
|
+
request: dict = {
|
|
1876
|
+
'instId': market['id'],
|
|
1877
|
+
# 'clOrdId': 'abcdef12345', # optional, [a-z0-9]{1,32}
|
|
1878
|
+
# 'ordId': id,
|
|
1879
|
+
}
|
|
1880
|
+
clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
|
|
1881
|
+
stop = self.safe_value_2(params, 'stop', 'trigger')
|
|
1882
|
+
if stop:
|
|
1883
|
+
if clientOrderId is not None:
|
|
1884
|
+
request['algoClOrdId'] = clientOrderId
|
|
1885
|
+
else:
|
|
1886
|
+
request['algoId'] = id
|
|
1887
|
+
else:
|
|
1888
|
+
if clientOrderId is not None:
|
|
1889
|
+
request['clOrdId'] = clientOrderId
|
|
1890
|
+
else:
|
|
1891
|
+
request['ordId'] = id
|
|
1892
|
+
query = self.omit(params, ['clientOrderId', 'stop', 'trigger'])
|
|
1893
|
+
response = None
|
|
1894
|
+
if stop:
|
|
1895
|
+
response = self.privateGetTradeOrderAlgo(self.extend(request, query))
|
|
1896
|
+
else:
|
|
1897
|
+
response = self.privateGetTradeOrder(self.extend(request, query))
|
|
1898
|
+
data = self.safe_value(response, 'data', [])
|
|
1899
|
+
order = self.safe_dict(data, 0)
|
|
1900
|
+
return self.parse_order(order)
|
|
1901
|
+
|
|
1902
|
+
def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1903
|
+
"""
|
|
1904
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-order-list
|
|
1905
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-algo-order-list
|
|
1906
|
+
fetch all unfilled currently open orders
|
|
1907
|
+
:param str symbol: unified market symbol
|
|
1908
|
+
:param int [since]: the earliest time in ms to fetch open orders for
|
|
1909
|
+
:param int [limit]: the maximum number of open orders structures to retrieve
|
|
1910
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1911
|
+
:param bool [params.stop]: True if fetching trigger or conditional orders
|
|
1912
|
+
:param str [params.ordType]: "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"
|
|
1913
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1914
|
+
"""
|
|
1915
|
+
self.load_markets()
|
|
1916
|
+
request: dict = {
|
|
1917
|
+
# 'instId': market['id'],
|
|
1918
|
+
# 'ordType': 'limit', # market, limit, post_only, fok, ioc, comma-separated, stop orders: conditional, oco, trigger, move_order_stop, iceberg, or twap
|
|
1919
|
+
# 'state': 'live', # live, partially_filled
|
|
1920
|
+
# 'after': orderId,
|
|
1921
|
+
# 'before': orderId,
|
|
1922
|
+
# 'limit': limit, # default 100, max 100
|
|
1923
|
+
}
|
|
1924
|
+
market = None
|
|
1925
|
+
if symbol is not None:
|
|
1926
|
+
market = self.market(symbol)
|
|
1927
|
+
request['instId'] = market['id']
|
|
1928
|
+
if limit is not None:
|
|
1929
|
+
request['limit'] = limit # default 100, max 100
|
|
1930
|
+
ordType = self.safe_string(params, 'ordType')
|
|
1931
|
+
stop = self.safe_value(params, 'stop') or (self.safe_string(params, 'ordType') is not None)
|
|
1932
|
+
if stop and (ordType is None):
|
|
1933
|
+
request['ordType'] = 'trigger' # default to trigger
|
|
1934
|
+
params = self.omit(params, ['stop'])
|
|
1935
|
+
response = None
|
|
1936
|
+
if stop:
|
|
1937
|
+
response = self.privateGetTradeOrdersAlgoPending(self.extend(request, params))
|
|
1938
|
+
else:
|
|
1939
|
+
response = self.privateGetTradeOrdersPending(self.extend(request, params))
|
|
1940
|
+
data = self.safe_list(response, 'data', [])
|
|
1941
|
+
return self.parse_orders(data, market, since, limit)
|
|
1942
|
+
|
|
1943
|
+
def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1944
|
+
"""
|
|
1945
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-algo-order-history
|
|
1946
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-order-history-last-3-months
|
|
1947
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-order-history-last-7-days
|
|
1948
|
+
fetches information on multiple closed orders made by the user
|
|
1949
|
+
:param str symbol: unified market symbol of the market orders were made in
|
|
1950
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
|
1951
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
|
1952
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1953
|
+
:param bool [params.stop]: True if fetching trigger or conditional orders
|
|
1954
|
+
:param str [params.ordType]: "conditional", "oco", "trigger", "move_order_stop", "iceberg", or "twap"
|
|
1955
|
+
:returns Order[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1956
|
+
"""
|
|
1957
|
+
self.load_markets()
|
|
1958
|
+
request: dict = {
|
|
1959
|
+
'instType': 'SPOT',
|
|
1960
|
+
}
|
|
1961
|
+
market = None
|
|
1962
|
+
if symbol is not None:
|
|
1963
|
+
market = self.market(symbol)
|
|
1964
|
+
request['instId'] = market['id']
|
|
1965
|
+
ordType = self.safe_string(params, 'ordType')
|
|
1966
|
+
stop = self.safe_value(params, 'stop') or (self.safe_string(params, 'ordType') is not None)
|
|
1967
|
+
if stop and (ordType is None):
|
|
1968
|
+
request['ordType'] = 'trigger' # default to trigger
|
|
1969
|
+
params = self.omit(params, ['stop'])
|
|
1970
|
+
response = None
|
|
1971
|
+
if stop:
|
|
1972
|
+
response = self.privateGetTradeOrdersAlgoHistory(self.extend(request, params))
|
|
1973
|
+
else:
|
|
1974
|
+
method = None
|
|
1975
|
+
method, params = self.handle_option_and_params(params, 'fetchClosedOrders', 'method', 'privateGetTradeOrdersHistory')
|
|
1976
|
+
if method == 'privateGetTradeOrdersHistory':
|
|
1977
|
+
response = self.privateGetTradeOrdersHistory(self.extend(request, params))
|
|
1978
|
+
else:
|
|
1979
|
+
response = self.privateGetTradeOrdersHistoryArchive(self.extend(request, params))
|
|
1980
|
+
# {
|
|
1981
|
+
# "code": "0",
|
|
1982
|
+
# "data": [
|
|
1983
|
+
# {
|
|
1984
|
+
# "accFillSz": "0",
|
|
1985
|
+
# "avgPx": "",
|
|
1986
|
+
# "cTime": "1621910749815",
|
|
1987
|
+
# "category": "normal",
|
|
1988
|
+
# "ccy": "",
|
|
1989
|
+
# "clOrdId": "",
|
|
1990
|
+
# "fee": "0",
|
|
1991
|
+
# "feeCcy": "ETH",
|
|
1992
|
+
# "fillPx": "",
|
|
1993
|
+
# "fillSz": "0",
|
|
1994
|
+
# "fillTime": "",
|
|
1995
|
+
# "instId": "ETH-USDT",
|
|
1996
|
+
# "instType": "SPOT",
|
|
1997
|
+
# "lever": "",
|
|
1998
|
+
# "ordId": "317251910906576896",
|
|
1999
|
+
# "ordType": "limit",
|
|
2000
|
+
# "pnl": "0",
|
|
2001
|
+
# "posSide": "net",
|
|
2002
|
+
# "px":"20 00",
|
|
2003
|
+
# "rebate": "0",
|
|
2004
|
+
# "rebateCcy": "USDT",
|
|
2005
|
+
# "side": "buy",
|
|
2006
|
+
# "slOrdPx": "",
|
|
2007
|
+
# "slTriggerPx": "",
|
|
2008
|
+
# "state": "live",
|
|
2009
|
+
# "sz":"0. 001",
|
|
2010
|
+
# "tag": "",
|
|
2011
|
+
# "tdMode": "cash",
|
|
2012
|
+
# "tpOrdPx": "",
|
|
2013
|
+
# "tpTriggerPx": "",
|
|
2014
|
+
# "tradeId": "",
|
|
2015
|
+
# "uTime": "1621910749815"
|
|
2016
|
+
# }
|
|
2017
|
+
# ],
|
|
2018
|
+
# "msg":""
|
|
2019
|
+
# }
|
|
2020
|
+
#
|
|
2021
|
+
data = self.safe_list(response, 'data', [])
|
|
2022
|
+
return self.parse_orders(data, market, since, limit)
|
|
2023
|
+
|
|
2024
|
+
def parse_deposit_address(self, depositAddress, currency: Currency = None):
|
|
2025
|
+
#
|
|
2026
|
+
# {
|
|
2027
|
+
# "addr": "okbtothemoon",
|
|
2028
|
+
# "memo": "971668", # may be missing
|
|
2029
|
+
# "tag":"52055", # may be missing
|
|
2030
|
+
# "pmtId": "", # may be missing
|
|
2031
|
+
# "ccy": "BTC",
|
|
2032
|
+
# "to": "6", # 1 SPOT, 3 FUTURES, 6 FUNDING, 9 SWAP, 12 OPTION, 18 Unified account
|
|
2033
|
+
# "selected": True
|
|
2034
|
+
# }
|
|
2035
|
+
#
|
|
2036
|
+
# {
|
|
2037
|
+
# "ccy":"usdt-erc20",
|
|
2038
|
+
# "to":"6",
|
|
2039
|
+
# "addr":"0x696abb81974a8793352cbd33aadcf78eda3cfdfa",
|
|
2040
|
+
# "selected":true
|
|
2041
|
+
# }
|
|
2042
|
+
#
|
|
2043
|
+
# {
|
|
2044
|
+
# "chain": "ETH-OKExChain",
|
|
2045
|
+
# "addrEx": {"comment": "6040348"}, # some currencies like TON may have self field,
|
|
2046
|
+
# "ctAddr": "72315c",
|
|
2047
|
+
# "ccy": "ETH",
|
|
2048
|
+
# "to": "6",
|
|
2049
|
+
# "addr": "0x1c9f2244d1ccaa060bd536827c18925db10db102",
|
|
2050
|
+
# "selected": True
|
|
2051
|
+
# }
|
|
2052
|
+
#
|
|
2053
|
+
address = self.safe_string(depositAddress, 'addr')
|
|
2054
|
+
tag = self.safe_string_n(depositAddress, ['tag', 'pmtId', 'memo'])
|
|
2055
|
+
if tag is None:
|
|
2056
|
+
addrEx = self.safe_value(depositAddress, 'addrEx', {})
|
|
2057
|
+
tag = self.safe_string(addrEx, 'comment')
|
|
2058
|
+
currencyId = self.safe_string(depositAddress, 'ccy')
|
|
2059
|
+
currency = self.safe_currency(currencyId, currency)
|
|
2060
|
+
code = currency['code']
|
|
2061
|
+
chain = self.safe_string(depositAddress, 'chain')
|
|
2062
|
+
networkId = chain.replace(currencyId + '-', '')
|
|
2063
|
+
network = self.network_id_to_code(networkId)
|
|
2064
|
+
# inconsistent naming responses from exchange
|
|
2065
|
+
# with respect to network naming provided in currency info vs address chain-names and ids
|
|
2066
|
+
#
|
|
2067
|
+
# response from address endpoint:
|
|
2068
|
+
# {
|
|
2069
|
+
# "chain": "USDT-Polygon",
|
|
2070
|
+
# "ctAddr": "",
|
|
2071
|
+
# "ccy": "USDT",
|
|
2072
|
+
# "to":"6" ,
|
|
2073
|
+
# "addr": "0x1903441e386cc49d937f6302955b5feb4286dcfa",
|
|
2074
|
+
# "selected": True
|
|
2075
|
+
# }
|
|
2076
|
+
# network information from currency['networks'] field:
|
|
2077
|
+
# Polygon: {
|
|
2078
|
+
# "info": {
|
|
2079
|
+
# "canDep": False,
|
|
2080
|
+
# "canInternal": False,
|
|
2081
|
+
# "canWd": False,
|
|
2082
|
+
# "ccy": "USDT",
|
|
2083
|
+
# "chain": "USDT-Polygon-Bridge",
|
|
2084
|
+
# "mainNet": False,
|
|
2085
|
+
# "maxFee": "26.879528",
|
|
2086
|
+
# "minFee": "13.439764",
|
|
2087
|
+
# "minWd": "0.001",
|
|
2088
|
+
# "name": ''
|
|
2089
|
+
# },
|
|
2090
|
+
# "id": "USDT-Polygon-Bridge",
|
|
2091
|
+
# "network": "Polygon",
|
|
2092
|
+
# "active": False,
|
|
2093
|
+
# "deposit": False,
|
|
2094
|
+
# "withdraw": False,
|
|
2095
|
+
# "fee": 13.439764,
|
|
2096
|
+
# "precision": None,
|
|
2097
|
+
# "limits": {
|
|
2098
|
+
# "withdraw": {
|
|
2099
|
+
# "min": 0.001,
|
|
2100
|
+
# "max": None
|
|
2101
|
+
# }
|
|
2102
|
+
# }
|
|
2103
|
+
# },
|
|
2104
|
+
#
|
|
2105
|
+
self.check_address(address)
|
|
2106
|
+
return {
|
|
2107
|
+
'currency': code,
|
|
2108
|
+
'address': address,
|
|
2109
|
+
'tag': tag,
|
|
2110
|
+
'network': network,
|
|
2111
|
+
'info': depositAddress,
|
|
2112
|
+
}
|
|
2113
|
+
|
|
2114
|
+
def fetch_deposit_address(self, code: str, params={}):
|
|
2115
|
+
"""
|
|
2116
|
+
fetch the deposit address for a currency associated with self account
|
|
2117
|
+
:see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
|
|
2118
|
+
:param str code: unified currency code
|
|
2119
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2120
|
+
:returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
|
|
2121
|
+
"""
|
|
2122
|
+
self.load_markets()
|
|
2123
|
+
defaultNetwork = self.safe_string(self.options, 'defaultNetwork', 'ERC20')
|
|
2124
|
+
networkId = self.safe_string(params, 'network', defaultNetwork)
|
|
2125
|
+
networkCode = self.network_id_to_code(networkId)
|
|
2126
|
+
params = self.omit(params, 'network')
|
|
2127
|
+
response = self.fetch_deposit_addresses_by_network(code, params)
|
|
2128
|
+
result = self.safe_value(response, networkCode)
|
|
2129
|
+
if result is None:
|
|
2130
|
+
raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + networkCode + ' deposit address for ' + code)
|
|
2131
|
+
return result
|
|
2132
|
+
|
|
2133
|
+
def fetch_deposit_addresses_by_network(self, code: str, params={}):
|
|
2134
|
+
"""
|
|
2135
|
+
fetch a dictionary of addresses for a currency, indexed by network
|
|
2136
|
+
:see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
|
|
2137
|
+
:param str code: unified currency code of the currency for the deposit address
|
|
2138
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2139
|
+
:returns dict: a dictionary of `address structures <https://docs.ccxt.com/#/?id=address-structure>` indexed by the network
|
|
2140
|
+
"""
|
|
2141
|
+
self.load_markets()
|
|
2142
|
+
currency = self.currency(code)
|
|
2143
|
+
request: dict = {
|
|
2144
|
+
'ccy': currency['id'],
|
|
2145
|
+
}
|
|
2146
|
+
response = self.privateGetAssetDepositAddress(self.extend(request, params))
|
|
2147
|
+
#
|
|
2148
|
+
# {
|
|
2149
|
+
# "code": "0",
|
|
2150
|
+
# "msg": "",
|
|
2151
|
+
# "data": [
|
|
2152
|
+
# {
|
|
2153
|
+
# "addr": "okbtothemoon",
|
|
2154
|
+
# "memo": "971668", # may be missing
|
|
2155
|
+
# "tag":"52055", # may be missing
|
|
2156
|
+
# "pmtId": "", # may be missing
|
|
2157
|
+
# "ccy": "BTC",
|
|
2158
|
+
# "to": "6", # 1 SPOT, 3 FUTURES, 6 FUNDING, 9 SWAP, 12 OPTION, 18 Unified account
|
|
2159
|
+
# "selected": True
|
|
2160
|
+
# },
|
|
2161
|
+
# # {"ccy":"usdt-erc20","to":"6","addr":"0x696abb81974a8793352cbd33aadcf78eda3cfdfa","selected":true},
|
|
2162
|
+
# # {"ccy":"usdt-trc20","to":"6","addr":"TRrd5SiSZrfQVRKm4e9SRSbn2LNTYqCjqx","selected":true},
|
|
2163
|
+
# # {"ccy":"usdt_okexchain","to":"6","addr":"0x696abb81974a8793352cbd33aadcf78eda3cfdfa","selected":true},
|
|
2164
|
+
# # {"ccy":"usdt_kip20","to":"6","addr":"0x696abb81974a8793352cbd33aadcf78eda3cfdfa","selected":true},
|
|
2165
|
+
# ]
|
|
2166
|
+
# }
|
|
2167
|
+
#
|
|
2168
|
+
data = self.safe_value(response, 'data', [])
|
|
2169
|
+
filtered = self.filter_by(data, 'selected', True)
|
|
2170
|
+
parsed = self.parse_deposit_addresses(filtered, [currency['code']], False)
|
|
2171
|
+
return self.index_by(parsed, 'network')
|
|
2172
|
+
|
|
2173
|
+
def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
|
|
2174
|
+
"""
|
|
2175
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-funds-transfer
|
|
2176
|
+
transfer currency internally between wallets on the same account
|
|
2177
|
+
:param str code: unified currency code
|
|
2178
|
+
:param float amount: amount to transfer
|
|
2179
|
+
:param str fromAccount: account to transfer from
|
|
2180
|
+
:param str toAccount: account to transfer to
|
|
2181
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2182
|
+
:returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
|
|
2183
|
+
"""
|
|
2184
|
+
self.load_markets()
|
|
2185
|
+
currency = self.currency(code)
|
|
2186
|
+
accountsByType = self.safe_value(self.options, 'accountsByType', {})
|
|
2187
|
+
fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
|
|
2188
|
+
toId = self.safe_string(accountsByType, toAccount, toAccount)
|
|
2189
|
+
request: dict = {
|
|
2190
|
+
'ccy': currency['id'],
|
|
2191
|
+
'amt': self.currency_to_precision(code, amount),
|
|
2192
|
+
'type': '0', # 0 = transfer within account by default, 1 = master account to sub-account, 2 = sub-account to master account, 3 = sub-account to master account(Only applicable to APIKey from sub-account), 4 = sub-account to sub-account
|
|
2193
|
+
'from': fromId, # remitting account, 6: Funding account, 18: Trading account
|
|
2194
|
+
'to': toId, # beneficiary account, 6: Funding account, 18: Trading account
|
|
2195
|
+
# 'subAcct': 'sub-account-name', # optional, only required when type is 1, 2 or 4
|
|
2196
|
+
# 'loanTrans': False, # Whether or not borrowed coins can be transferred out under Multi-currency margin and Portfolio margin. The default is False
|
|
2197
|
+
# 'clientId': 'client-supplied id', # A combination of case-sensitive alphanumerics, all numbers, or all letters of up to 32 characters
|
|
2198
|
+
# 'omitPosRisk': False, # Ignore position risk. Default is False. Applicable to Portfolio margin
|
|
2199
|
+
}
|
|
2200
|
+
if fromId == 'master':
|
|
2201
|
+
request['type'] = '1'
|
|
2202
|
+
request['subAcct'] = toId
|
|
2203
|
+
request['from'] = self.safe_string(params, 'from', '6')
|
|
2204
|
+
request['to'] = self.safe_string(params, 'to', '6')
|
|
2205
|
+
elif toId == 'master':
|
|
2206
|
+
request['type'] = '2'
|
|
2207
|
+
request['subAcct'] = fromId
|
|
2208
|
+
request['from'] = self.safe_string(params, 'from', '6')
|
|
2209
|
+
request['to'] = self.safe_string(params, 'to', '6')
|
|
2210
|
+
response = self.privatePostAssetTransfer(self.extend(request, params))
|
|
2211
|
+
#
|
|
2212
|
+
# {
|
|
2213
|
+
# "code": "0",
|
|
2214
|
+
# "msg": "",
|
|
2215
|
+
# "data": [
|
|
2216
|
+
# {
|
|
2217
|
+
# "transId": "754147",
|
|
2218
|
+
# "ccy": "USDT",
|
|
2219
|
+
# "from": "6",
|
|
2220
|
+
# "amt": "0.1",
|
|
2221
|
+
# "to": "18"
|
|
2222
|
+
# }
|
|
2223
|
+
# ]
|
|
2224
|
+
# }
|
|
2225
|
+
#
|
|
2226
|
+
data = self.safe_value(response, 'data', [])
|
|
2227
|
+
rawTransfer = self.safe_dict(data, 0, {})
|
|
2228
|
+
return self.parse_transfer(rawTransfer, currency)
|
|
2229
|
+
|
|
2230
|
+
def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
|
|
2231
|
+
#
|
|
2232
|
+
# transfer
|
|
2233
|
+
#
|
|
2234
|
+
# {
|
|
2235
|
+
# "transId": "754147",
|
|
2236
|
+
# "ccy": "USDT",
|
|
2237
|
+
# "from": "6",
|
|
2238
|
+
# "amt": "0.1",
|
|
2239
|
+
# "to": "18"
|
|
2240
|
+
# }
|
|
2241
|
+
#
|
|
2242
|
+
# fetchTransfer
|
|
2243
|
+
#
|
|
2244
|
+
# {
|
|
2245
|
+
# "amt": "5",
|
|
2246
|
+
# "ccy": "USDT",
|
|
2247
|
+
# "from": "18",
|
|
2248
|
+
# "instId": "",
|
|
2249
|
+
# "state": "success",
|
|
2250
|
+
# "subAcct": "",
|
|
2251
|
+
# "to": "6",
|
|
2252
|
+
# "toInstId": "",
|
|
2253
|
+
# "transId": "464424732",
|
|
2254
|
+
# "type": "0"
|
|
2255
|
+
# }
|
|
2256
|
+
#
|
|
2257
|
+
# fetchTransfers
|
|
2258
|
+
#
|
|
2259
|
+
# {
|
|
2260
|
+
# "bal": "70.6874353780312913",
|
|
2261
|
+
# "balChg": "-4.0000000000000000", # negative means "to funding", positive meand "from funding"
|
|
2262
|
+
# "billId": "588900695232225299",
|
|
2263
|
+
# "ccy": "USDT",
|
|
2264
|
+
# "execType": "",
|
|
2265
|
+
# "fee": "",
|
|
2266
|
+
# "from": "18",
|
|
2267
|
+
# "instId": "",
|
|
2268
|
+
# "instType": "",
|
|
2269
|
+
# "mgnMode": "",
|
|
2270
|
+
# "notes": "To Funding Account",
|
|
2271
|
+
# "ordId": "",
|
|
2272
|
+
# "pnl": "",
|
|
2273
|
+
# "posBal": "",
|
|
2274
|
+
# "posBalChg": "",
|
|
2275
|
+
# "price": "0",
|
|
2276
|
+
# "subType": "12",
|
|
2277
|
+
# "sz": "-4",
|
|
2278
|
+
# "to": "6",
|
|
2279
|
+
# "ts": "1686676866989",
|
|
2280
|
+
# "type": "1"
|
|
2281
|
+
# }
|
|
2282
|
+
#
|
|
2283
|
+
id = self.safe_string_2(transfer, 'transId', 'billId')
|
|
2284
|
+
currencyId = self.safe_string(transfer, 'ccy')
|
|
2285
|
+
code = self.safe_currency_code(currencyId, currency)
|
|
2286
|
+
amount = self.safe_number(transfer, 'amt')
|
|
2287
|
+
fromAccountId = self.safe_string(transfer, 'from')
|
|
2288
|
+
toAccountId = self.safe_string(transfer, 'to')
|
|
2289
|
+
accountsById = self.safe_value(self.options, 'accountsById', {})
|
|
2290
|
+
timestamp = self.safe_integer(transfer, 'ts', self.milliseconds())
|
|
2291
|
+
balanceChange = self.safe_string(transfer, 'sz')
|
|
2292
|
+
if balanceChange is not None:
|
|
2293
|
+
amount = self.parse_number(Precise.string_abs(balanceChange))
|
|
2294
|
+
return {
|
|
2295
|
+
'info': transfer,
|
|
2296
|
+
'id': id,
|
|
2297
|
+
'timestamp': timestamp,
|
|
2298
|
+
'datetime': self.iso8601(timestamp),
|
|
2299
|
+
'currency': code,
|
|
2300
|
+
'amount': amount,
|
|
2301
|
+
'fromAccount': self.safe_string(accountsById, fromAccountId),
|
|
2302
|
+
'toAccount': self.safe_string(accountsById, toAccountId),
|
|
2303
|
+
'status': self.parse_transfer_status(self.safe_string(transfer, 'state')),
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
def parse_transfer_status(self, status: Str) -> Str:
|
|
2307
|
+
statuses: dict = {
|
|
2308
|
+
'success': 'ok',
|
|
2309
|
+
}
|
|
2310
|
+
return self.safe_string(statuses, status, status)
|
|
2311
|
+
|
|
2312
|
+
def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
|
|
2313
|
+
"""
|
|
2314
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-withdrawal
|
|
2315
|
+
make a withdrawal
|
|
2316
|
+
:param str code: unified currency code
|
|
2317
|
+
:param float amount: the amount to withdraw
|
|
2318
|
+
:param str address: the address to withdraw to
|
|
2319
|
+
:param str tag:
|
|
2320
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2321
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2322
|
+
"""
|
|
2323
|
+
tag, params = self.handle_withdraw_tag_and_params(tag, params)
|
|
2324
|
+
self.check_address(address)
|
|
2325
|
+
self.load_markets()
|
|
2326
|
+
currency = self.currency(code)
|
|
2327
|
+
if (tag is not None) and (len(tag) > 0):
|
|
2328
|
+
address = address + ':' + tag
|
|
2329
|
+
request: dict = {
|
|
2330
|
+
'ccy': currency['id'],
|
|
2331
|
+
'toAddr': address,
|
|
2332
|
+
'dest': '4',
|
|
2333
|
+
'amt': self.number_to_string(amount),
|
|
2334
|
+
}
|
|
2335
|
+
network = self.safe_string(params, 'network') # self line allows the user to specify either ERC20 or ETH
|
|
2336
|
+
if network is not None:
|
|
2337
|
+
networks = self.safe_value(self.options, 'networks', {})
|
|
2338
|
+
network = self.safe_string(networks, network.upper(), network) # handle ETH>ERC20 alias
|
|
2339
|
+
request['chain'] = currency['id'] + '-' + network
|
|
2340
|
+
params = self.omit(params, 'network')
|
|
2341
|
+
fee = self.safe_string(params, 'fee')
|
|
2342
|
+
if fee is None:
|
|
2343
|
+
targetNetwork = self.safe_value(currency['networks'], self.network_id_to_code(network), {})
|
|
2344
|
+
fee = self.safe_string(targetNetwork, 'fee')
|
|
2345
|
+
if fee is None:
|
|
2346
|
+
raise ArgumentsRequired(self.id + ' withdraw() requires a "fee" string parameter, network transaction fee must be ≥ 0. Withdrawals to OKCoin or OKX are fee-free, please set "0". Withdrawing to external digital asset address requires network transaction fee.')
|
|
2347
|
+
request['fee'] = self.number_to_string(fee) # withdrawals to OKCoin or OKX are fee-free, please set 0
|
|
2348
|
+
response = self.privatePostAssetWithdrawal(self.extend(request, params))
|
|
2349
|
+
#
|
|
2350
|
+
# {
|
|
2351
|
+
# "code": "0",
|
|
2352
|
+
# "msg": "",
|
|
2353
|
+
# "data": [
|
|
2354
|
+
# {
|
|
2355
|
+
# "amt": "0.1",
|
|
2356
|
+
# "wdId": "67485",
|
|
2357
|
+
# "ccy": "BTC"
|
|
2358
|
+
# }
|
|
2359
|
+
# ]
|
|
2360
|
+
# }
|
|
2361
|
+
#
|
|
2362
|
+
data = self.safe_value(response, 'data', [])
|
|
2363
|
+
transaction = self.safe_dict(data, 0)
|
|
2364
|
+
return self.parse_transaction(transaction, currency)
|
|
2365
|
+
|
|
2366
|
+
def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
|
2367
|
+
"""
|
|
2368
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-get-deposit-history
|
|
2369
|
+
fetch all deposits made to an account
|
|
2370
|
+
:param str code: unified currency code
|
|
2371
|
+
:param int [since]: the earliest time in ms to fetch deposits for
|
|
2372
|
+
:param int [limit]: the maximum number of deposits structures to retrieve
|
|
2373
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2374
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2375
|
+
"""
|
|
2376
|
+
self.load_markets()
|
|
2377
|
+
request: dict = {
|
|
2378
|
+
# 'ccy': currency['id'],
|
|
2379
|
+
# 'state': 2, # 0 waiting for confirmation, 1 deposit credited, 2 deposit successful
|
|
2380
|
+
# 'after': since,
|
|
2381
|
+
# 'before' self.milliseconds(),
|
|
2382
|
+
# 'limit': limit, # default 100, max 100
|
|
2383
|
+
}
|
|
2384
|
+
currency = None
|
|
2385
|
+
if code is not None:
|
|
2386
|
+
currency = self.currency(code)
|
|
2387
|
+
request['ccy'] = currency['id']
|
|
2388
|
+
if since is not None:
|
|
2389
|
+
request['before'] = max(since - 1, 0)
|
|
2390
|
+
if limit is not None:
|
|
2391
|
+
request['limit'] = limit # default 100, max 100
|
|
2392
|
+
request, params = self.handle_until_option('after', request, params)
|
|
2393
|
+
response = self.privateGetAssetDepositHistory(self.extend(request, params))
|
|
2394
|
+
#
|
|
2395
|
+
# {
|
|
2396
|
+
# "code": "0",
|
|
2397
|
+
# "msg": "",
|
|
2398
|
+
# "data": [
|
|
2399
|
+
# {
|
|
2400
|
+
# "amt": "0.01044408",
|
|
2401
|
+
# "txId": "1915737_3_0_0_asset",
|
|
2402
|
+
# "ccy": "BTC",
|
|
2403
|
+
# "from": "13801825426",
|
|
2404
|
+
# "to": "",
|
|
2405
|
+
# "ts": "1597026383085",
|
|
2406
|
+
# "state": "2",
|
|
2407
|
+
# "depId": "4703879"
|
|
2408
|
+
# },
|
|
2409
|
+
# {
|
|
2410
|
+
# "amt": "491.6784211",
|
|
2411
|
+
# "txId": "1744594_3_184_0_asset",
|
|
2412
|
+
# "ccy": "OKB",
|
|
2413
|
+
# "from": "",
|
|
2414
|
+
# "to": "",
|
|
2415
|
+
# "ts": "1597026383085",
|
|
2416
|
+
# "state": "2",
|
|
2417
|
+
# "depId": "4703809"
|
|
2418
|
+
# },
|
|
2419
|
+
# {
|
|
2420
|
+
# "amt": "223.18782496",
|
|
2421
|
+
# "txId": "6d892c669225b1092c780bf0da0c6f912fc7dc8f6b8cc53b003288624c",
|
|
2422
|
+
# "ccy": "USDT",
|
|
2423
|
+
# "from": "",
|
|
2424
|
+
# "to": "39kK4XvgEuM7rX9frgyHoZkWqx4iKu1spD",
|
|
2425
|
+
# "ts": "1597026383085",
|
|
2426
|
+
# "state": "2",
|
|
2427
|
+
# "depId": "4703779"
|
|
2428
|
+
# }
|
|
2429
|
+
# ]
|
|
2430
|
+
# }
|
|
2431
|
+
#
|
|
2432
|
+
data = self.safe_list(response, 'data', [])
|
|
2433
|
+
return self.parse_transactions(data, currency, since, limit, params)
|
|
2434
|
+
|
|
2435
|
+
def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
|
2436
|
+
"""
|
|
2437
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-get-withdrawal-history
|
|
2438
|
+
fetch all withdrawals made from an account
|
|
2439
|
+
:param str code: unified currency code
|
|
2440
|
+
:param int [since]: the earliest time in ms to fetch withdrawals for
|
|
2441
|
+
:param int [limit]: the maximum number of withdrawals structures to retrieve
|
|
2442
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2443
|
+
:returns dict[]: a list of `transaction structures <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
2444
|
+
"""
|
|
2445
|
+
self.load_markets()
|
|
2446
|
+
request: dict = {
|
|
2447
|
+
# 'ccy': currency['id'],
|
|
2448
|
+
# 'state': 2, # -3: pending cancel, -2 canceled, -1 failed, 0, pending, 1 sending, 2 sent, 3 awaiting email verification, 4 awaiting manual verification, 5 awaiting identity verification
|
|
2449
|
+
# 'after': since,
|
|
2450
|
+
# 'before': self.milliseconds(),
|
|
2451
|
+
# 'limit': limit, # default 100, max 100
|
|
2452
|
+
}
|
|
2453
|
+
currency = None
|
|
2454
|
+
if code is not None:
|
|
2455
|
+
currency = self.currency(code)
|
|
2456
|
+
request['ccy'] = currency['id']
|
|
2457
|
+
if since is not None:
|
|
2458
|
+
request['before'] = max(since - 1, 0)
|
|
2459
|
+
if limit is not None:
|
|
2460
|
+
request['limit'] = limit # default 100, max 100
|
|
2461
|
+
request, params = self.handle_until_option('after', request, params)
|
|
2462
|
+
response = self.privateGetAssetWithdrawalHistory(self.extend(request, params))
|
|
2463
|
+
#
|
|
2464
|
+
# {
|
|
2465
|
+
# "code": "0",
|
|
2466
|
+
# "msg": "",
|
|
2467
|
+
# "data": [
|
|
2468
|
+
# {
|
|
2469
|
+
# "amt": "0.094",
|
|
2470
|
+
# "wdId": "4703879",
|
|
2471
|
+
# "fee": "0.01000000eth",
|
|
2472
|
+
# "txId": "0x62477bac6509a04512819bb1455e923a60dea5966c7caeaa0b24eb8fb0432b85",
|
|
2473
|
+
# "ccy": "ETH",
|
|
2474
|
+
# "from": "13426335357",
|
|
2475
|
+
# "to": "0xA41446125D0B5b6785f6898c9D67874D763A1519",
|
|
2476
|
+
# "ts": "1597026383085",
|
|
2477
|
+
# "state": "2"
|
|
2478
|
+
# },
|
|
2479
|
+
# {
|
|
2480
|
+
# "amt": "0.01",
|
|
2481
|
+
# "wdId": "4703879",
|
|
2482
|
+
# "fee": "0.00000000btc",
|
|
2483
|
+
# "txId": "",
|
|
2484
|
+
# "ccy": "BTC",
|
|
2485
|
+
# "from": "13426335357",
|
|
2486
|
+
# "to": "13426335357",
|
|
2487
|
+
# "ts": "1597026383085",
|
|
2488
|
+
# "state": "2"
|
|
2489
|
+
# }
|
|
2490
|
+
# ]
|
|
2491
|
+
# }
|
|
2492
|
+
#
|
|
2493
|
+
data = self.safe_list(response, 'data', [])
|
|
2494
|
+
return self.parse_transactions(data, currency, since, limit, params)
|
|
2495
|
+
|
|
2496
|
+
def parse_transaction_status(self, status: Str):
|
|
2497
|
+
#
|
|
2498
|
+
# deposit statuses
|
|
2499
|
+
#
|
|
2500
|
+
# {
|
|
2501
|
+
# "0": "waiting for confirmation",
|
|
2502
|
+
# "1": "confirmation account",
|
|
2503
|
+
# "2": "recharge success"
|
|
2504
|
+
# }
|
|
2505
|
+
#
|
|
2506
|
+
# withdrawal statues
|
|
2507
|
+
#
|
|
2508
|
+
# {
|
|
2509
|
+
# '-3': "pending cancel",
|
|
2510
|
+
# "-2": "cancelled",
|
|
2511
|
+
# "-1": "failed",
|
|
2512
|
+
# "0": "pending",
|
|
2513
|
+
# "1": "sending",
|
|
2514
|
+
# "2": "sent",
|
|
2515
|
+
# "3": "email confirmation",
|
|
2516
|
+
# "4": "manual confirmation",
|
|
2517
|
+
# "5": "awaiting identity confirmation"
|
|
2518
|
+
# }
|
|
2519
|
+
#
|
|
2520
|
+
statuses: dict = {
|
|
2521
|
+
'-3': 'pending',
|
|
2522
|
+
'-2': 'canceled',
|
|
2523
|
+
'-1': 'failed',
|
|
2524
|
+
'0': 'pending',
|
|
2525
|
+
'1': 'pending',
|
|
2526
|
+
'2': 'ok',
|
|
2527
|
+
'3': 'pending',
|
|
2528
|
+
'4': 'pending',
|
|
2529
|
+
'5': 'pending',
|
|
2530
|
+
}
|
|
2531
|
+
return self.safe_string(statuses, status, status)
|
|
2532
|
+
|
|
2533
|
+
def parse_transaction(self, transaction: dict, currency: Currency = None) -> Transaction:
|
|
2534
|
+
#
|
|
2535
|
+
# withdraw
|
|
2536
|
+
#
|
|
2537
|
+
# {
|
|
2538
|
+
# "amt": "0.1",
|
|
2539
|
+
# "wdId": "67485",
|
|
2540
|
+
# "ccy": "BTC"
|
|
2541
|
+
# }
|
|
2542
|
+
#
|
|
2543
|
+
# fetchWithdrawals
|
|
2544
|
+
#
|
|
2545
|
+
# {
|
|
2546
|
+
# "amt": "0.094",
|
|
2547
|
+
# "wdId": "4703879",
|
|
2548
|
+
# "fee": "0.01000000eth",
|
|
2549
|
+
# "txId": "0x62477bac6509a04512819bb1455e923a60dea5966c7caeaa0b24eb8fb0432b85",
|
|
2550
|
+
# "ccy": "ETH",
|
|
2551
|
+
# "from": "13426335357",
|
|
2552
|
+
# "to": "0xA41446125D0B5b6785f6898c9D67874D763A1519",
|
|
2553
|
+
# "tag",
|
|
2554
|
+
# "pmtId",
|
|
2555
|
+
# "memo",
|
|
2556
|
+
# "ts": "1597026383085",
|
|
2557
|
+
# "state": "2"
|
|
2558
|
+
# }
|
|
2559
|
+
#
|
|
2560
|
+
# fetchDeposits
|
|
2561
|
+
#
|
|
2562
|
+
# {
|
|
2563
|
+
# "amt": "0.01044408",
|
|
2564
|
+
# "txId": "1915737_3_0_0_asset",
|
|
2565
|
+
# "ccy": "BTC",
|
|
2566
|
+
# "from": "13801825426",
|
|
2567
|
+
# "to": "",
|
|
2568
|
+
# "ts": "1597026383085",
|
|
2569
|
+
# "state": "2",
|
|
2570
|
+
# "depId": "4703879"
|
|
2571
|
+
# }
|
|
2572
|
+
#
|
|
2573
|
+
type = None
|
|
2574
|
+
id = None
|
|
2575
|
+
withdrawalId = self.safe_string(transaction, 'wdId')
|
|
2576
|
+
addressFrom = self.safe_string(transaction, 'from')
|
|
2577
|
+
addressTo = self.safe_string(transaction, 'to')
|
|
2578
|
+
address = addressTo
|
|
2579
|
+
tagTo = self.safe_string_2(transaction, 'tag', 'memo')
|
|
2580
|
+
tagTo = self.safe_string_2(transaction, 'pmtId', tagTo)
|
|
2581
|
+
if withdrawalId is not None:
|
|
2582
|
+
type = 'withdrawal'
|
|
2583
|
+
id = withdrawalId
|
|
2584
|
+
else:
|
|
2585
|
+
# the payment_id will appear on new deposits but appears to be removed from the response after 2 months
|
|
2586
|
+
id = self.safe_string(transaction, 'depId')
|
|
2587
|
+
type = 'deposit'
|
|
2588
|
+
currencyId = self.safe_string(transaction, 'ccy')
|
|
2589
|
+
code = self.safe_currency_code(currencyId)
|
|
2590
|
+
amount = self.safe_number(transaction, 'amt')
|
|
2591
|
+
status = self.parse_transaction_status(self.safe_string(transaction, 'state'))
|
|
2592
|
+
txid = self.safe_string(transaction, 'txId')
|
|
2593
|
+
timestamp = self.safe_integer(transaction, 'ts')
|
|
2594
|
+
feeCost = None
|
|
2595
|
+
if type == 'deposit':
|
|
2596
|
+
feeCost = 0
|
|
2597
|
+
else:
|
|
2598
|
+
feeCost = self.safe_number(transaction, 'fee')
|
|
2599
|
+
# todo parse tags
|
|
2600
|
+
return {
|
|
2601
|
+
'info': transaction,
|
|
2602
|
+
'id': id,
|
|
2603
|
+
'currency': code,
|
|
2604
|
+
'amount': amount,
|
|
2605
|
+
'network': None,
|
|
2606
|
+
'addressFrom': addressFrom,
|
|
2607
|
+
'addressTo': addressTo,
|
|
2608
|
+
'address': address,
|
|
2609
|
+
'tagFrom': None,
|
|
2610
|
+
'tagTo': tagTo,
|
|
2611
|
+
'tag': tagTo,
|
|
2612
|
+
'status': status,
|
|
2613
|
+
'type': type,
|
|
2614
|
+
'updated': None,
|
|
2615
|
+
'txid': txid,
|
|
2616
|
+
'timestamp': timestamp,
|
|
2617
|
+
'datetime': self.iso8601(timestamp),
|
|
2618
|
+
'comment': None,
|
|
2619
|
+
'internal': None,
|
|
2620
|
+
'fee': {
|
|
2621
|
+
'currency': code,
|
|
2622
|
+
'cost': feeCost,
|
|
2623
|
+
},
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2626
|
+
def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
2627
|
+
"""
|
|
2628
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-transaction-details-last-3-days
|
|
2629
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-trade-get-transaction-details-last-3-months
|
|
2630
|
+
fetch all trades made by the user
|
|
2631
|
+
:param str symbol: unified market symbol
|
|
2632
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
|
2633
|
+
:param int [limit]: the maximum number of trades structures to retrieve
|
|
2634
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2635
|
+
:returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
2636
|
+
"""
|
|
2637
|
+
self.load_markets()
|
|
2638
|
+
request: dict = {
|
|
2639
|
+
'instType': 'SPOT',
|
|
2640
|
+
}
|
|
2641
|
+
if (limit is not None) and (limit > 100):
|
|
2642
|
+
limit = 100
|
|
2643
|
+
market = None
|
|
2644
|
+
if symbol is not None:
|
|
2645
|
+
market = self.market(symbol)
|
|
2646
|
+
request['instId'] = market['id']
|
|
2647
|
+
method = None
|
|
2648
|
+
method, params = self.handle_option_and_params(params, 'fetchMyTrades', 'method', 'privateGetTradeFillsHistory')
|
|
2649
|
+
response = None
|
|
2650
|
+
if method == 'privateGetTradeFillsHistory':
|
|
2651
|
+
response = self.privateGetTradeFillsHistory(self.extend(request, params))
|
|
2652
|
+
else:
|
|
2653
|
+
response = self.privateGetTradeFills(self.extend(request, params))
|
|
2654
|
+
data = self.safe_list(response, 'data', [])
|
|
2655
|
+
return self.parse_trades(data, market, since, limit)
|
|
2656
|
+
|
|
2657
|
+
def fetch_order_trades(self, id: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
2658
|
+
"""
|
|
2659
|
+
fetch all the trades made from a single order
|
|
2660
|
+
:param str id: order id
|
|
2661
|
+
:param str symbol: unified market symbol
|
|
2662
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
|
2663
|
+
:param int [limit]: the maximum number of trades to retrieve
|
|
2664
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2665
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
|
|
2666
|
+
"""
|
|
2667
|
+
request: dict = {
|
|
2668
|
+
# 'instrument_id': market['id'],
|
|
2669
|
+
'order_id': id,
|
|
2670
|
+
# 'after': '1', # return the page after the specified page number
|
|
2671
|
+
# 'before': '1', # return the page before the specified page number
|
|
2672
|
+
# 'limit': limit, # optional, number of results per request, default = maximum = 100
|
|
2673
|
+
}
|
|
2674
|
+
return self.fetch_my_trades(symbol, since, limit, self.extend(request, params))
|
|
2675
|
+
|
|
2676
|
+
def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
2677
|
+
"""
|
|
2678
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-funding-asset-bills-details
|
|
2679
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-account-get-bills-details-last-7-days
|
|
2680
|
+
:see: https://www.okcoin.com/docs-v5/en/#rest-api-account-get-bills-details-last-3-months
|
|
2681
|
+
fetch the history of changes, actions done by the user or operations that altered balance of the user
|
|
2682
|
+
:param str code: unified currency code, default is None
|
|
2683
|
+
:param int [since]: timestamp in ms of the earliest ledger entry, default is None
|
|
2684
|
+
:param int [limit]: max number of ledger entrys to return, default is None
|
|
2685
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
2686
|
+
:returns dict: a `ledger structure <https://docs.ccxt.com/#/?id=ledger-structure>`
|
|
2687
|
+
"""
|
|
2688
|
+
self.load_markets()
|
|
2689
|
+
method = None
|
|
2690
|
+
method, params = self.handle_option_and_params(params, 'fetchLedger', 'method', 'privateGetAccountBills')
|
|
2691
|
+
request: dict = {
|
|
2692
|
+
# 'instType': None, # 'SPOT', 'MARGIN', 'SWAP', 'FUTURES", 'OPTION'
|
|
2693
|
+
# 'ccy': None, # currency['id'],
|
|
2694
|
+
# 'ctType': None, # 'linear', 'inverse', only applicable to FUTURES/SWAP
|
|
2695
|
+
# 'type': varies depending the 'method' endpoint :
|
|
2696
|
+
# - https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-7-days
|
|
2697
|
+
# - https://www.okx.com/docs-v5/en/#rest-api-funding-asset-bills-details
|
|
2698
|
+
# - https://www.okx.com/docs-v5/en/#rest-api-account-get-bills-details-last-3-months
|
|
2699
|
+
# 'after': 'id', # return records earlier than the requested bill id
|
|
2700
|
+
# 'before': 'id', # return records newer than the requested bill id
|
|
2701
|
+
# 'limit': 100, # default 100, max 100
|
|
2702
|
+
}
|
|
2703
|
+
if limit is not None:
|
|
2704
|
+
request['limit'] = limit
|
|
2705
|
+
currency = None
|
|
2706
|
+
if code is not None:
|
|
2707
|
+
currency = self.currency(code)
|
|
2708
|
+
request['ccy'] = currency['id']
|
|
2709
|
+
request, params = self.handle_until_option('end', request, params)
|
|
2710
|
+
response = None
|
|
2711
|
+
if method == 'privateGetAccountBillsArchive':
|
|
2712
|
+
response = self.privateGetAccountBillsArchive(self.extend(request, params))
|
|
2713
|
+
elif method == 'privateGetAssetBills':
|
|
2714
|
+
response = self.privateGetAssetBills(self.extend(request, params))
|
|
2715
|
+
else:
|
|
2716
|
+
response = self.privateGetAccountBills(self.extend(request, params))
|
|
2717
|
+
#
|
|
2718
|
+
# privateGetAccountBills, privateGetAccountBillsArchive
|
|
2719
|
+
#
|
|
2720
|
+
# {
|
|
2721
|
+
# "code": "0",
|
|
2722
|
+
# "msg": "",
|
|
2723
|
+
# "data": [
|
|
2724
|
+
# {
|
|
2725
|
+
# "bal": "0.0000819307998198",
|
|
2726
|
+
# "balChg": "-664.2679586599999802",
|
|
2727
|
+
# "billId": "310394313544966151",
|
|
2728
|
+
# "ccy": "USDT",
|
|
2729
|
+
# "fee": "0",
|
|
2730
|
+
# "from": "",
|
|
2731
|
+
# "instId": "LTC-USDT",
|
|
2732
|
+
# "instType": "SPOT",
|
|
2733
|
+
# "mgnMode": "cross",
|
|
2734
|
+
# "notes": "",
|
|
2735
|
+
# "ordId": "310394313519800320",
|
|
2736
|
+
# "pnl": "0",
|
|
2737
|
+
# "posBal": "0",
|
|
2738
|
+
# "posBalChg": "0",
|
|
2739
|
+
# "subType": "2",
|
|
2740
|
+
# "sz": "664.26795866",
|
|
2741
|
+
# "to": "",
|
|
2742
|
+
# "ts": "1620275771196",
|
|
2743
|
+
# "type": "2"
|
|
2744
|
+
# }
|
|
2745
|
+
# ]
|
|
2746
|
+
# }
|
|
2747
|
+
#
|
|
2748
|
+
# privateGetAssetBills
|
|
2749
|
+
#
|
|
2750
|
+
# {
|
|
2751
|
+
# "code": "0",
|
|
2752
|
+
# "msg": "",
|
|
2753
|
+
# "data": [
|
|
2754
|
+
# {
|
|
2755
|
+
# "billId": "12344",
|
|
2756
|
+
# "ccy": "BTC",
|
|
2757
|
+
# "balChg": "2",
|
|
2758
|
+
# "bal": "12",
|
|
2759
|
+
# "type": "1",
|
|
2760
|
+
# "ts": "1597026383085"
|
|
2761
|
+
# }
|
|
2762
|
+
# ]
|
|
2763
|
+
# }
|
|
2764
|
+
#
|
|
2765
|
+
data = self.safe_value(response, 'data', [])
|
|
2766
|
+
return self.parse_ledger(data, currency, since, limit)
|
|
2767
|
+
|
|
2768
|
+
def parse_ledger_entry_type(self, type):
|
|
2769
|
+
types: dict = {
|
|
2770
|
+
'1': 'transfer', # transfer
|
|
2771
|
+
'2': 'trade', # trade
|
|
2772
|
+
'3': 'trade', # delivery
|
|
2773
|
+
'4': 'rebate', # auto token conversion
|
|
2774
|
+
'5': 'trade', # liquidation
|
|
2775
|
+
'6': 'transfer', # margin transfer
|
|
2776
|
+
'7': 'trade', # interest deduction
|
|
2777
|
+
'8': 'fee', # funding rate
|
|
2778
|
+
'9': 'trade', # adl
|
|
2779
|
+
'10': 'trade', # clawback
|
|
2780
|
+
'11': 'trade', # system token conversion
|
|
2781
|
+
}
|
|
2782
|
+
return self.safe_string(types, type, type)
|
|
2783
|
+
|
|
2784
|
+
def parse_ledger_entry(self, item: dict, currency: Currency = None):
|
|
2785
|
+
#
|
|
2786
|
+
# privateGetAccountBills, privateGetAccountBillsArchive
|
|
2787
|
+
#
|
|
2788
|
+
# {
|
|
2789
|
+
# "bal": "0.0000819307998198",
|
|
2790
|
+
# "balChg": "-664.2679586599999802",
|
|
2791
|
+
# "billId": "310394313544966151",
|
|
2792
|
+
# "ccy": "USDT",
|
|
2793
|
+
# "fee": "0",
|
|
2794
|
+
# "from": "",
|
|
2795
|
+
# "instId": "LTC-USDT",
|
|
2796
|
+
# "instType": "SPOT",
|
|
2797
|
+
# "mgnMode": "cross",
|
|
2798
|
+
# "notes": "",
|
|
2799
|
+
# "ordId": "310394313519800320",
|
|
2800
|
+
# "pnl": "0",
|
|
2801
|
+
# "posBal": "0",
|
|
2802
|
+
# "posBalChg": "0",
|
|
2803
|
+
# "subType": "2",
|
|
2804
|
+
# "sz": "664.26795866",
|
|
2805
|
+
# "to": "",
|
|
2806
|
+
# "ts": "1620275771196",
|
|
2807
|
+
# "type": "2"
|
|
2808
|
+
# }
|
|
2809
|
+
#
|
|
2810
|
+
# privateGetAssetBills
|
|
2811
|
+
#
|
|
2812
|
+
# {
|
|
2813
|
+
# "billId": "12344",
|
|
2814
|
+
# "ccy": "BTC",
|
|
2815
|
+
# "balChg": "2",
|
|
2816
|
+
# "bal": "12",
|
|
2817
|
+
# "type": "1",
|
|
2818
|
+
# "ts": "1597026383085"
|
|
2819
|
+
# }
|
|
2820
|
+
#
|
|
2821
|
+
id = self.safe_string(item, 'billId')
|
|
2822
|
+
account = None
|
|
2823
|
+
referenceId = self.safe_string(item, 'ordId')
|
|
2824
|
+
referenceAccount = None
|
|
2825
|
+
type = self.parse_ledger_entry_type(self.safe_string(item, 'type'))
|
|
2826
|
+
code = self.safe_currency_code(self.safe_string(item, 'ccy'), currency)
|
|
2827
|
+
amountString = self.safe_string(item, 'balChg')
|
|
2828
|
+
amount = self.parse_number(amountString)
|
|
2829
|
+
timestamp = self.safe_integer(item, 'ts')
|
|
2830
|
+
feeCostString = self.safe_string(item, 'fee')
|
|
2831
|
+
fee = None
|
|
2832
|
+
if feeCostString is not None:
|
|
2833
|
+
fee = {
|
|
2834
|
+
'cost': self.parse_number(Precise.string_neg(feeCostString)),
|
|
2835
|
+
'currency': code,
|
|
2836
|
+
}
|
|
2837
|
+
before = None
|
|
2838
|
+
afterString = self.safe_string(item, 'bal')
|
|
2839
|
+
after = self.parse_number(afterString)
|
|
2840
|
+
status = 'ok'
|
|
2841
|
+
marketId = self.safe_string(item, 'instId')
|
|
2842
|
+
symbol = self.safe_symbol(marketId, None, '-')
|
|
2843
|
+
return {
|
|
2844
|
+
'id': id,
|
|
2845
|
+
'info': item,
|
|
2846
|
+
'timestamp': timestamp,
|
|
2847
|
+
'datetime': self.iso8601(timestamp),
|
|
2848
|
+
'account': account,
|
|
2849
|
+
'referenceId': referenceId,
|
|
2850
|
+
'referenceAccount': referenceAccount,
|
|
2851
|
+
'type': type,
|
|
2852
|
+
'currency': code,
|
|
2853
|
+
'symbol': symbol,
|
|
2854
|
+
'amount': amount,
|
|
2855
|
+
'before': before, # balance before
|
|
2856
|
+
'after': after, # balance after
|
|
2857
|
+
'status': status,
|
|
2858
|
+
'fee': fee,
|
|
2859
|
+
}
|
|
2860
|
+
|
|
2861
|
+
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
|
2862
|
+
isArray = isinstance(params, list)
|
|
2863
|
+
request = '/api/' + self.version + '/' + self.implode_params(path, params)
|
|
2864
|
+
query = self.omit(params, self.extract_params(path))
|
|
2865
|
+
url = self.implode_hostname(self.urls['api']['rest']) + request
|
|
2866
|
+
if api == 'public':
|
|
2867
|
+
if query:
|
|
2868
|
+
url += '?' + self.urlencode(query)
|
|
2869
|
+
elif api == 'private':
|
|
2870
|
+
self.check_required_credentials()
|
|
2871
|
+
timestamp = self.iso8601(self.milliseconds())
|
|
2872
|
+
headers = {
|
|
2873
|
+
'OK-ACCESS-KEY': self.apiKey,
|
|
2874
|
+
'OK-ACCESS-PASSPHRASE': self.password,
|
|
2875
|
+
'OK-ACCESS-TIMESTAMP': timestamp,
|
|
2876
|
+
# 'OK-FROM': '',
|
|
2877
|
+
# 'OK-TO': '',
|
|
2878
|
+
# 'OK-LIMIT': '',
|
|
2879
|
+
}
|
|
2880
|
+
auth = timestamp + method + request
|
|
2881
|
+
if method == 'GET':
|
|
2882
|
+
if query:
|
|
2883
|
+
urlencodedQuery = '?' + self.urlencode(query)
|
|
2884
|
+
url += urlencodedQuery
|
|
2885
|
+
auth += urlencodedQuery
|
|
2886
|
+
else:
|
|
2887
|
+
if isArray or query:
|
|
2888
|
+
body = self.json(query)
|
|
2889
|
+
auth += body
|
|
2890
|
+
headers['Content-Type'] = 'application/json'
|
|
2891
|
+
signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256, 'base64')
|
|
2892
|
+
headers['OK-ACCESS-SIGN'] = signature
|
|
2893
|
+
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
|
2894
|
+
|
|
2895
|
+
def parse_balance_by_type(self, type, response):
|
|
2896
|
+
if type == 'funding':
|
|
2897
|
+
return self.parse_funding_balance(response)
|
|
2898
|
+
else:
|
|
2899
|
+
return self.parse_trading_balance(response)
|
|
2900
|
+
|
|
2901
|
+
def handle_errors(self, httpCode: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
|
|
2902
|
+
if not response:
|
|
2903
|
+
return None # fallback to default error handler
|
|
2904
|
+
#
|
|
2905
|
+
# {
|
|
2906
|
+
# "code": "1",
|
|
2907
|
+
# "data": [
|
|
2908
|
+
# {
|
|
2909
|
+
# "clOrdId": "",
|
|
2910
|
+
# "ordId": "",
|
|
2911
|
+
# "sCode": "51119",
|
|
2912
|
+
# "sMsg": "Order placement failed due to insufficient balance. ",
|
|
2913
|
+
# "tag": ""
|
|
2914
|
+
# }
|
|
2915
|
+
# ],
|
|
2916
|
+
# "msg": ""
|
|
2917
|
+
# },
|
|
2918
|
+
# {
|
|
2919
|
+
# "code": "58001",
|
|
2920
|
+
# "data": [],
|
|
2921
|
+
# "msg": "Incorrect trade password"
|
|
2922
|
+
# }
|
|
2923
|
+
#
|
|
2924
|
+
code = self.safe_string(response, 'code')
|
|
2925
|
+
if code != '0':
|
|
2926
|
+
feedback = self.id + ' ' + body
|
|
2927
|
+
data = self.safe_value(response, 'data', [])
|
|
2928
|
+
for i in range(0, len(data)):
|
|
2929
|
+
error = data[i]
|
|
2930
|
+
errorCode = self.safe_string(error, 'sCode')
|
|
2931
|
+
message = self.safe_string(error, 'sMsg')
|
|
2932
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
|
2933
|
+
self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
|
|
2934
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
|
|
2935
|
+
raise ExchangeError(feedback) # unknown message
|
|
2936
|
+
return None
|