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/pro/okx.py
ADDED
|
@@ -0,0 +1,1851 @@
|
|
|
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
|
+
import ccxt.async_support
|
|
7
|
+
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
|
|
8
|
+
import hashlib
|
|
9
|
+
from ccxt.base.types import Balances, Int, Liquidation, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, FundingRates, Trade
|
|
10
|
+
from ccxt.async_support.base.ws.client import Client
|
|
11
|
+
from typing import List
|
|
12
|
+
from ccxt.base.errors import ExchangeError
|
|
13
|
+
from ccxt.base.errors import AuthenticationError
|
|
14
|
+
from ccxt.base.errors import ArgumentsRequired
|
|
15
|
+
from ccxt.base.errors import BadRequest
|
|
16
|
+
from ccxt.base.errors import InvalidNonce
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class okx(ccxt.async_support.okx):
|
|
20
|
+
|
|
21
|
+
def describe(self):
|
|
22
|
+
return self.deep_extend(super(okx, self).describe(), {
|
|
23
|
+
'has': {
|
|
24
|
+
'ws': True,
|
|
25
|
+
'watchTicker': True,
|
|
26
|
+
'watchTickers': True,
|
|
27
|
+
'watchOrderBook': True,
|
|
28
|
+
'watchTrades': True,
|
|
29
|
+
'watchTradesForSymbols': True,
|
|
30
|
+
'watchOrderBookForSymbols': True,
|
|
31
|
+
'watchBalance': True,
|
|
32
|
+
'watchLiquidations': 'emulated',
|
|
33
|
+
'watchLiquidationsForSymbols': True,
|
|
34
|
+
'watchMyLiquidations': 'emulated',
|
|
35
|
+
'watchMyLiquidationsForSymbols': True,
|
|
36
|
+
'watchOHLCV': True,
|
|
37
|
+
'watchOHLCVForSymbols': True,
|
|
38
|
+
'watchOrders': True,
|
|
39
|
+
'watchMyTrades': True,
|
|
40
|
+
'watchPositions': True,
|
|
41
|
+
'watchFundingRate': True,
|
|
42
|
+
'watchFundingRates': True,
|
|
43
|
+
'createOrderWs': True,
|
|
44
|
+
'editOrderWs': True,
|
|
45
|
+
'cancelOrderWs': True,
|
|
46
|
+
'cancelOrdersWs': True,
|
|
47
|
+
'cancelAllOrdersWs': True,
|
|
48
|
+
},
|
|
49
|
+
'urls': {
|
|
50
|
+
'api': {
|
|
51
|
+
'ws': 'wss://ws.okx.com:8443/ws/v5',
|
|
52
|
+
},
|
|
53
|
+
'test': {
|
|
54
|
+
'ws': 'wss://wspap.okx.com:8443/ws/v5',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
'options': {
|
|
58
|
+
'watchOrderBook': {
|
|
59
|
+
#
|
|
60
|
+
# bbo-tbt
|
|
61
|
+
# 1. Newly added channel that sends tick-by-tick Level 1 data
|
|
62
|
+
# 2. All API users can subscribe
|
|
63
|
+
# 3. Public depth channel, verification not required
|
|
64
|
+
#
|
|
65
|
+
# books-l2-tbt
|
|
66
|
+
# 1. Only users who're VIP5 and above can subscribe
|
|
67
|
+
# 2. Identity verification required before subscription
|
|
68
|
+
#
|
|
69
|
+
# books50-l2-tbt
|
|
70
|
+
# 1. Only users who're VIP4 and above can subscribe
|
|
71
|
+
# 2. Identity verification required before subscription
|
|
72
|
+
#
|
|
73
|
+
# books
|
|
74
|
+
# 1. All API users can subscribe
|
|
75
|
+
# 2. Public depth channel, verification not required
|
|
76
|
+
#
|
|
77
|
+
# books5
|
|
78
|
+
# 1. All API users can subscribe
|
|
79
|
+
# 2. Public depth channel, verification not required
|
|
80
|
+
# 3. Data feeds will be delivered every 100ms(vs. every 200ms now)
|
|
81
|
+
#
|
|
82
|
+
'depth': 'books',
|
|
83
|
+
},
|
|
84
|
+
'watchBalance': 'spot', # margin, futures, swap
|
|
85
|
+
'watchTicker': {
|
|
86
|
+
'channel': 'tickers', # tickers, sprd-tickers, index-tickers, block-tickers
|
|
87
|
+
},
|
|
88
|
+
'watchTickers': {
|
|
89
|
+
'channel': 'tickers', # tickers, sprd-tickers, index-tickers, block-tickers
|
|
90
|
+
},
|
|
91
|
+
'watchOrders': {
|
|
92
|
+
'type': 'ANY', # SPOT, MARGIN, SWAP, FUTURES, OPTION, ANY
|
|
93
|
+
},
|
|
94
|
+
'watchMyTrades': {
|
|
95
|
+
'type': 'ANY', # SPOT, MARGIN, SWAP, FUTURES, OPTION, ANY
|
|
96
|
+
},
|
|
97
|
+
'createOrderWs': {
|
|
98
|
+
'op': 'batch-orders', # order, batch-orders
|
|
99
|
+
},
|
|
100
|
+
'editOrderWs': {
|
|
101
|
+
'op': 'amend-order', # amend-order, batch-amend-orders
|
|
102
|
+
},
|
|
103
|
+
'ws': {
|
|
104
|
+
# 'inflate': True,
|
|
105
|
+
},
|
|
106
|
+
'checksum': True,
|
|
107
|
+
},
|
|
108
|
+
'streaming': {
|
|
109
|
+
# okex does not support built-in ws protocol-level ping-pong
|
|
110
|
+
# instead it requires a custom text-based ping-pong
|
|
111
|
+
'ping': self.ping,
|
|
112
|
+
'keepAlive': 20000,
|
|
113
|
+
},
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
def get_url(self, channel: str, access='public'):
|
|
117
|
+
# for context: https://www.okx.com/help-center/changes-to-v5-api-websocket-subscription-parameter-and-url
|
|
118
|
+
isSandbox = self.options['sandboxMode']
|
|
119
|
+
sandboxSuffix = '?brokerId=9999' if isSandbox else ''
|
|
120
|
+
isBusiness = (access == 'business')
|
|
121
|
+
isPublic = (access == 'public')
|
|
122
|
+
url = self.urls['api']['ws']
|
|
123
|
+
if isBusiness or (channel.find('candle') > -1) or (channel == 'orders-algo'):
|
|
124
|
+
return url + '/business' + sandboxSuffix
|
|
125
|
+
elif isPublic:
|
|
126
|
+
return url + '/public' + sandboxSuffix
|
|
127
|
+
return url + '/private' + sandboxSuffix
|
|
128
|
+
|
|
129
|
+
async def subscribe_multiple(self, access, channel, symbols: Strings = None, params={}):
|
|
130
|
+
await self.load_markets()
|
|
131
|
+
if symbols is None:
|
|
132
|
+
symbols = self.symbols
|
|
133
|
+
symbols = self.market_symbols(symbols)
|
|
134
|
+
url = self.get_url(channel, access)
|
|
135
|
+
messageHash = channel
|
|
136
|
+
args = []
|
|
137
|
+
messageHash += '::' + ','.join(symbols)
|
|
138
|
+
for i in range(0, len(symbols)):
|
|
139
|
+
marketId = self.market_id(symbols[i])
|
|
140
|
+
arg: dict = {
|
|
141
|
+
'channel': channel,
|
|
142
|
+
'instId': marketId,
|
|
143
|
+
}
|
|
144
|
+
args.append(self.extend(arg, params))
|
|
145
|
+
request: dict = {
|
|
146
|
+
'op': 'subscribe',
|
|
147
|
+
'args': args,
|
|
148
|
+
}
|
|
149
|
+
return await self.watch(url, messageHash, request, messageHash)
|
|
150
|
+
|
|
151
|
+
async def subscribe(self, access, messageHash, channel, symbol, params={}):
|
|
152
|
+
await self.load_markets()
|
|
153
|
+
url = self.get_url(channel, access)
|
|
154
|
+
firstArgument: dict = {
|
|
155
|
+
'channel': channel,
|
|
156
|
+
}
|
|
157
|
+
if symbol is not None:
|
|
158
|
+
market = self.market(symbol)
|
|
159
|
+
messageHash += ':' + market['id']
|
|
160
|
+
firstArgument['instId'] = market['id']
|
|
161
|
+
request: dict = {
|
|
162
|
+
'op': 'subscribe',
|
|
163
|
+
'args': [
|
|
164
|
+
self.deep_extend(firstArgument, params),
|
|
165
|
+
],
|
|
166
|
+
}
|
|
167
|
+
return await self.watch(url, messageHash, request, messageHash)
|
|
168
|
+
|
|
169
|
+
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
170
|
+
"""
|
|
171
|
+
get the list of most recent trades for a particular symbol
|
|
172
|
+
:param str symbol: unified symbol of the market to fetch trades for
|
|
173
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
174
|
+
:param int [limit]: the maximum amount of trades to fetch
|
|
175
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
176
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
177
|
+
"""
|
|
178
|
+
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
|
179
|
+
|
|
180
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
181
|
+
"""
|
|
182
|
+
get the list of most recent trades for a particular symbol
|
|
183
|
+
:param str symbol: unified symbol of the market to fetch trades for
|
|
184
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
|
185
|
+
:param int [limit]: the maximum amount of trades to fetch
|
|
186
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
187
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
|
188
|
+
"""
|
|
189
|
+
symbolsLength = len(symbols)
|
|
190
|
+
if symbolsLength == 0:
|
|
191
|
+
raise ArgumentsRequired(self.id + ' watchTradesForSymbols() requires a non-empty array of symbols')
|
|
192
|
+
await self.load_markets()
|
|
193
|
+
symbols = self.market_symbols(symbols)
|
|
194
|
+
channel = 'trades'
|
|
195
|
+
topics = []
|
|
196
|
+
messageHashes = []
|
|
197
|
+
for i in range(0, len(symbols)):
|
|
198
|
+
symbol = symbols[i]
|
|
199
|
+
messageHashes.append(channel + ':' + symbol)
|
|
200
|
+
marketId = self.market_id(symbol)
|
|
201
|
+
topic: dict = {
|
|
202
|
+
'channel': channel,
|
|
203
|
+
'instId': marketId,
|
|
204
|
+
}
|
|
205
|
+
topics.append(topic)
|
|
206
|
+
request: dict = {
|
|
207
|
+
'op': 'subscribe',
|
|
208
|
+
'args': topics,
|
|
209
|
+
}
|
|
210
|
+
url = self.get_url(channel, 'public')
|
|
211
|
+
trades = await self.watch_multiple(url, messageHashes, request, messageHashes)
|
|
212
|
+
if self.newUpdates:
|
|
213
|
+
first = self.safe_value(trades, 0)
|
|
214
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
|
215
|
+
limit = trades.getLimit(tradeSymbol, limit)
|
|
216
|
+
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
|
217
|
+
|
|
218
|
+
def handle_trades(self, client: Client, message):
|
|
219
|
+
#
|
|
220
|
+
# {
|
|
221
|
+
# "arg": {channel: "trades", instId: "BTC-USDT"},
|
|
222
|
+
# "data": [
|
|
223
|
+
# {
|
|
224
|
+
# "instId": "BTC-USDT",
|
|
225
|
+
# "tradeId": "216970876",
|
|
226
|
+
# "px": "31684.5",
|
|
227
|
+
# "sz": "0.00001186",
|
|
228
|
+
# "side": "buy",
|
|
229
|
+
# "ts": "1626531038288"
|
|
230
|
+
# }
|
|
231
|
+
# ]
|
|
232
|
+
# }
|
|
233
|
+
#
|
|
234
|
+
arg = self.safe_value(message, 'arg', {})
|
|
235
|
+
channel = self.safe_string(arg, 'channel')
|
|
236
|
+
marketId = self.safe_string(arg, 'instId')
|
|
237
|
+
symbol = self.safe_symbol(marketId)
|
|
238
|
+
data = self.safe_value(message, 'data', [])
|
|
239
|
+
tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
|
240
|
+
for i in range(0, len(data)):
|
|
241
|
+
trade = self.parse_trade(data[i])
|
|
242
|
+
messageHash = channel + ':' + symbol
|
|
243
|
+
stored = self.safe_value(self.trades, symbol)
|
|
244
|
+
if stored is None:
|
|
245
|
+
stored = ArrayCache(tradesLimit)
|
|
246
|
+
self.trades[symbol] = stored
|
|
247
|
+
stored.append(trade)
|
|
248
|
+
client.resolve(stored, messageHash)
|
|
249
|
+
|
|
250
|
+
async def watch_funding_rate(self, symbol: str, params={}) -> FundingRate:
|
|
251
|
+
"""
|
|
252
|
+
watch the current funding rate
|
|
253
|
+
:see: https://www.okx.com/docs-v5/en/#public-data-websocket-funding-rate-channel
|
|
254
|
+
:param str symbol: unified market symbol
|
|
255
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
256
|
+
:returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
|
|
257
|
+
"""
|
|
258
|
+
symbol = self.symbol(symbol)
|
|
259
|
+
fr = await self.watch_funding_rates([symbol], params)
|
|
260
|
+
return fr[symbol]
|
|
261
|
+
|
|
262
|
+
async def watch_funding_rates(self, symbols: List[str], params={}) -> FundingRates:
|
|
263
|
+
"""
|
|
264
|
+
watch the funding rate for multiple markets
|
|
265
|
+
:see: https://www.okx.com/docs-v5/en/#public-data-websocket-funding-rate-channel
|
|
266
|
+
:param str[] symbols: list of unified market symbols
|
|
267
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
268
|
+
:returns dict: a dictionary of `funding rates structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexe by market symbols
|
|
269
|
+
"""
|
|
270
|
+
await self.load_markets()
|
|
271
|
+
symbols = self.market_symbols(symbols)
|
|
272
|
+
channel = 'funding-rate'
|
|
273
|
+
topics = []
|
|
274
|
+
messageHashes = []
|
|
275
|
+
for i in range(0, len(symbols)):
|
|
276
|
+
symbol = symbols[i]
|
|
277
|
+
messageHashes.append(channel + ':' + symbol)
|
|
278
|
+
marketId = self.market_id(symbol)
|
|
279
|
+
topic: dict = {
|
|
280
|
+
'channel': channel,
|
|
281
|
+
'instId': marketId,
|
|
282
|
+
}
|
|
283
|
+
topics.append(topic)
|
|
284
|
+
request: dict = {
|
|
285
|
+
'op': 'subscribe',
|
|
286
|
+
'args': topics,
|
|
287
|
+
}
|
|
288
|
+
url = self.get_url(channel, 'public')
|
|
289
|
+
fundingRate = await self.watch_multiple(url, messageHashes, request, messageHashes)
|
|
290
|
+
if self.newUpdates:
|
|
291
|
+
symbol = self.safe_string(fundingRate, 'symbol')
|
|
292
|
+
result: dict = {}
|
|
293
|
+
result[symbol] = fundingRate
|
|
294
|
+
return result
|
|
295
|
+
return self.filter_by_array(self.fundingRates, 'symbol', symbols)
|
|
296
|
+
|
|
297
|
+
def handle_funding_rate(self, client: Client, message):
|
|
298
|
+
#
|
|
299
|
+
# "data":[
|
|
300
|
+
# {
|
|
301
|
+
# "fundingRate":"0.0001875391284828",
|
|
302
|
+
# "fundingTime":"1700726400000",
|
|
303
|
+
# "instId":"BTC-USD-SWAP",
|
|
304
|
+
# "instType":"SWAP",
|
|
305
|
+
# "method": "next_period",
|
|
306
|
+
# "maxFundingRate":"0.00375",
|
|
307
|
+
# "minFundingRate":"-0.00375",
|
|
308
|
+
# "nextFundingRate":"0.0002608059239328",
|
|
309
|
+
# "nextFundingTime":"1700755200000",
|
|
310
|
+
# "premium": "0.0001233824646391",
|
|
311
|
+
# "settFundingRate":"0.0001699799259033",
|
|
312
|
+
# "settState":"settled",
|
|
313
|
+
# "ts":"1700724675402"
|
|
314
|
+
# }
|
|
315
|
+
# ]
|
|
316
|
+
#
|
|
317
|
+
data = self.safe_list(message, 'data', [])
|
|
318
|
+
for i in range(0, len(data)):
|
|
319
|
+
rawfr = data[i]
|
|
320
|
+
fundingRate = self.parse_funding_rate(rawfr)
|
|
321
|
+
symbol = fundingRate['symbol']
|
|
322
|
+
self.fundingRates[symbol] = fundingRate
|
|
323
|
+
client.resolve(fundingRate, 'funding-rate' + ':' + fundingRate['symbol'])
|
|
324
|
+
|
|
325
|
+
async def watch_ticker(self, symbol: str, params={}) -> Ticker:
|
|
326
|
+
"""
|
|
327
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
|
|
328
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
329
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
330
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
331
|
+
:param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
|
|
332
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
333
|
+
"""
|
|
334
|
+
channel = None
|
|
335
|
+
channel, params = self.handle_option_and_params(params, 'watchTicker', 'channel', 'tickers')
|
|
336
|
+
params['channel'] = channel
|
|
337
|
+
ticker = await self.watch_tickers([symbol], params)
|
|
338
|
+
return self.safe_value(ticker, symbol)
|
|
339
|
+
|
|
340
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
|
341
|
+
"""
|
|
342
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-tickers-channel
|
|
343
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
344
|
+
:param str[] [symbols]: unified symbol of the market to fetch the ticker for
|
|
345
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
346
|
+
:param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
|
|
347
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
348
|
+
"""
|
|
349
|
+
if self.is_empty(symbols):
|
|
350
|
+
raise ArgumentsRequired(self.id + ' watchTickers requires a list of symbols')
|
|
351
|
+
channel = None
|
|
352
|
+
channel, params = self.handle_option_and_params(params, 'watchTickers', 'channel', 'tickers')
|
|
353
|
+
newTickers = await self.subscribe_multiple('public', channel, symbols, params)
|
|
354
|
+
if self.newUpdates:
|
|
355
|
+
return newTickers
|
|
356
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
|
357
|
+
|
|
358
|
+
def handle_ticker(self, client: Client, message):
|
|
359
|
+
#
|
|
360
|
+
# {
|
|
361
|
+
# "arg": {channel: "tickers", instId: "BTC-USDT"},
|
|
362
|
+
# "data": [
|
|
363
|
+
# {
|
|
364
|
+
# "instType": "SPOT",
|
|
365
|
+
# "instId": "BTC-USDT",
|
|
366
|
+
# "last": "31500.1",
|
|
367
|
+
# "lastSz": "0.00001754",
|
|
368
|
+
# "askPx": "31500.1",
|
|
369
|
+
# "askSz": "0.00998144",
|
|
370
|
+
# "bidPx": "31500",
|
|
371
|
+
# "bidSz": "3.05652439",
|
|
372
|
+
# "open24h": "31697",
|
|
373
|
+
# "high24h": "32248",
|
|
374
|
+
# "low24h": "31165.6",
|
|
375
|
+
# "sodUtc0": "31385.5",
|
|
376
|
+
# "sodUtc8": "32134.9",
|
|
377
|
+
# "volCcy24h": "503403597.38138519",
|
|
378
|
+
# "vol24h": "15937.10781721",
|
|
379
|
+
# "ts": "1626526618762"
|
|
380
|
+
# }
|
|
381
|
+
# ]
|
|
382
|
+
# }
|
|
383
|
+
#
|
|
384
|
+
arg = self.safe_value(message, 'arg', {})
|
|
385
|
+
channel = self.safe_string(arg, 'channel')
|
|
386
|
+
data = self.safe_value(message, 'data', [])
|
|
387
|
+
newTickers = []
|
|
388
|
+
for i in range(0, len(data)):
|
|
389
|
+
ticker = self.parse_ticker(data[i])
|
|
390
|
+
symbol = ticker['symbol']
|
|
391
|
+
self.tickers[symbol] = ticker
|
|
392
|
+
newTickers.append(ticker)
|
|
393
|
+
messageHashes = self.find_message_hashes(client, channel + '::')
|
|
394
|
+
for i in range(0, len(messageHashes)):
|
|
395
|
+
messageHash = messageHashes[i]
|
|
396
|
+
parts = messageHash.split('::')
|
|
397
|
+
symbolsString = parts[1]
|
|
398
|
+
symbols = symbolsString.split(',')
|
|
399
|
+
tickers = self.filter_by_array(newTickers, 'symbol', symbols)
|
|
400
|
+
tickersSymbols = list(tickers.keys())
|
|
401
|
+
numTickers = len(tickersSymbols)
|
|
402
|
+
if numTickers > 0:
|
|
403
|
+
client.resolve(tickers, messageHash)
|
|
404
|
+
return message
|
|
405
|
+
|
|
406
|
+
async def watch_liquidations_for_symbols(self, symbols: List[str] = None, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
|
|
407
|
+
"""
|
|
408
|
+
watch the public liquidations of a trading pair
|
|
409
|
+
:see: https://www.okx.com/docs-v5/en/#public-data-websocket-liquidation-orders-channel
|
|
410
|
+
:param str symbol: unified CCXT market symbol
|
|
411
|
+
:param int [since]: the earliest time in ms to fetch liquidations for
|
|
412
|
+
:param int [limit]: the maximum number of liquidation structures to retrieve
|
|
413
|
+
:param dict [params]: exchange specific parameters for the okx api endpoint
|
|
414
|
+
:returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
|
|
415
|
+
"""
|
|
416
|
+
await self.load_markets()
|
|
417
|
+
symbols = self.market_symbols(symbols, None, True, True)
|
|
418
|
+
messageHash = 'liquidations'
|
|
419
|
+
if symbols is not None:
|
|
420
|
+
messageHash += '::' + ','.join(symbols)
|
|
421
|
+
market = self.get_market_from_symbols(symbols)
|
|
422
|
+
type = None
|
|
423
|
+
type, params = self.handle_market_type_and_params('watchliquidationsForSymbols', market, params)
|
|
424
|
+
channel = 'liquidation-orders'
|
|
425
|
+
if type == 'spot':
|
|
426
|
+
type = 'SWAP'
|
|
427
|
+
elif type == 'future':
|
|
428
|
+
type = 'futures'
|
|
429
|
+
uppercaseType = type.upper()
|
|
430
|
+
request = {
|
|
431
|
+
'instType': uppercaseType,
|
|
432
|
+
}
|
|
433
|
+
newLiquidations = await self.subscribe('public', messageHash, channel, None, self.extend(request, params))
|
|
434
|
+
if self.newUpdates:
|
|
435
|
+
return newLiquidations
|
|
436
|
+
return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit, True)
|
|
437
|
+
|
|
438
|
+
def handle_liquidation(self, client: Client, message):
|
|
439
|
+
#
|
|
440
|
+
# {
|
|
441
|
+
# "arg": {
|
|
442
|
+
# "channel": "liquidation-orders",
|
|
443
|
+
# "instType": "SWAP"
|
|
444
|
+
# },
|
|
445
|
+
# "data": [
|
|
446
|
+
# {
|
|
447
|
+
# "details": [
|
|
448
|
+
# {
|
|
449
|
+
# "bkLoss": "0",
|
|
450
|
+
# "bkPx": "0.007831",
|
|
451
|
+
# "ccy": "",
|
|
452
|
+
# "posSide": "short",
|
|
453
|
+
# "side": "buy",
|
|
454
|
+
# "sz": "13",
|
|
455
|
+
# "ts": "1692266434010"
|
|
456
|
+
# }
|
|
457
|
+
# ],
|
|
458
|
+
# "instFamily": "IOST-USDT",
|
|
459
|
+
# "instId": "IOST-USDT-SWAP",
|
|
460
|
+
# "instType": "SWAP",
|
|
461
|
+
# "uly": "IOST-USDT"
|
|
462
|
+
# }
|
|
463
|
+
# ]
|
|
464
|
+
# }
|
|
465
|
+
#
|
|
466
|
+
rawLiquidations = self.safe_list(message, 'data', [])
|
|
467
|
+
for i in range(0, len(rawLiquidations)):
|
|
468
|
+
rawLiquidation = rawLiquidations[i]
|
|
469
|
+
liquidation = self.parse_ws_liquidation(rawLiquidation)
|
|
470
|
+
symbol = self.safe_string(liquidation, 'symbol')
|
|
471
|
+
liquidations = self.safe_value(self.liquidations, symbol)
|
|
472
|
+
if liquidations is None:
|
|
473
|
+
limit = self.safe_integer(self.options, 'liquidationsLimit', 1000)
|
|
474
|
+
liquidations = ArrayCache(limit)
|
|
475
|
+
liquidations.append(liquidation)
|
|
476
|
+
self.liquidations[symbol] = liquidations
|
|
477
|
+
client.resolve([liquidation], 'liquidations')
|
|
478
|
+
client.resolve([liquidation], 'liquidations::' + symbol)
|
|
479
|
+
|
|
480
|
+
async def watch_my_liquidations_for_symbols(self, symbols: List[str] = None, since: Int = None, limit: Int = None, params={}) -> List[Liquidation]:
|
|
481
|
+
"""
|
|
482
|
+
watch the private liquidations of a trading pair
|
|
483
|
+
:see: https://www.okx.com/docs-v5/en/#trading-account-websocket-balance-and-position-channel
|
|
484
|
+
:param str symbol: unified CCXT market symbol
|
|
485
|
+
:param int [since]: the earliest time in ms to fetch liquidations for
|
|
486
|
+
:param int [limit]: the maximum number of liquidation structures to retrieve
|
|
487
|
+
:param dict [params]: exchange specific parameters for the okx api endpoint
|
|
488
|
+
:returns dict: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
|
|
489
|
+
"""
|
|
490
|
+
await self.load_markets()
|
|
491
|
+
isStop = self.safe_value_2(params, 'stop', 'trigger', False)
|
|
492
|
+
params = self.omit(params, ['stop', 'trigger'])
|
|
493
|
+
await self.authenticate({'access': 'business' if isStop else 'private'})
|
|
494
|
+
symbols = self.market_symbols(symbols, None, True, True)
|
|
495
|
+
messageHash = 'myLiquidations'
|
|
496
|
+
if symbols is not None:
|
|
497
|
+
messageHash += '::' + ','.join(symbols)
|
|
498
|
+
channel = 'balance_and_position'
|
|
499
|
+
newLiquidations = await self.subscribe('private', messageHash, channel, None, params)
|
|
500
|
+
if self.newUpdates:
|
|
501
|
+
return newLiquidations
|
|
502
|
+
return self.filter_by_symbols_since_limit(self.liquidations, symbols, since, limit, True)
|
|
503
|
+
|
|
504
|
+
def handle_my_liquidation(self, client: Client, message):
|
|
505
|
+
#
|
|
506
|
+
# {
|
|
507
|
+
# "arg": {
|
|
508
|
+
# "channel": "balance_and_position",
|
|
509
|
+
# "uid": "77982378738415879"
|
|
510
|
+
# },
|
|
511
|
+
# "data": [{
|
|
512
|
+
# "pTime": "1597026383085",
|
|
513
|
+
# "eventType": "snapshot",
|
|
514
|
+
# "balData": [{
|
|
515
|
+
# "ccy": "BTC",
|
|
516
|
+
# "cashBal": "1",
|
|
517
|
+
# "uTime": "1597026383085"
|
|
518
|
+
# }],
|
|
519
|
+
# "posData": [{
|
|
520
|
+
# "posId": "1111111111",
|
|
521
|
+
# "tradeId": "2",
|
|
522
|
+
# "instId": "BTC-USD-191018",
|
|
523
|
+
# "instType": "FUTURES",
|
|
524
|
+
# "mgnMode": "cross",
|
|
525
|
+
# "posSide": "long",
|
|
526
|
+
# "pos": "10",
|
|
527
|
+
# "ccy": "BTC",
|
|
528
|
+
# "posCcy": "",
|
|
529
|
+
# "avgPx": "3320",
|
|
530
|
+
# "uTIme": "1597026383085"
|
|
531
|
+
# }],
|
|
532
|
+
# "trades": [{
|
|
533
|
+
# "instId": "BTC-USD-191018",
|
|
534
|
+
# "tradeId": "2",
|
|
535
|
+
# }]
|
|
536
|
+
# }]
|
|
537
|
+
# }
|
|
538
|
+
#
|
|
539
|
+
rawLiquidations = self.safe_list(message, 'data', [])
|
|
540
|
+
for i in range(0, len(rawLiquidations)):
|
|
541
|
+
rawLiquidation = rawLiquidations[i]
|
|
542
|
+
eventType = self.safe_string(rawLiquidation, 'eventType')
|
|
543
|
+
if eventType != 'liquidation':
|
|
544
|
+
return
|
|
545
|
+
liquidation = self.parse_ws_my_liquidation(rawLiquidation)
|
|
546
|
+
symbol = self.safe_string(liquidation, 'symbol')
|
|
547
|
+
liquidations = self.safe_value(self.liquidations, symbol)
|
|
548
|
+
if liquidations is None:
|
|
549
|
+
limit = self.safe_integer(self.options, 'myLiquidationsLimit', 1000)
|
|
550
|
+
liquidations = ArrayCache(limit)
|
|
551
|
+
liquidations.append(liquidation)
|
|
552
|
+
self.liquidations[symbol] = liquidations
|
|
553
|
+
client.resolve([liquidation], 'myLiquidations')
|
|
554
|
+
client.resolve([liquidation], 'myLiquidations::' + symbol)
|
|
555
|
+
|
|
556
|
+
def parse_ws_my_liquidation(self, liquidation, market=None):
|
|
557
|
+
#
|
|
558
|
+
# {
|
|
559
|
+
# "pTime": "1597026383085",
|
|
560
|
+
# "eventType": "snapshot",
|
|
561
|
+
# "balData": [{
|
|
562
|
+
# "ccy": "BTC",
|
|
563
|
+
# "cashBal": "1",
|
|
564
|
+
# "uTime": "1597026383085"
|
|
565
|
+
# }],
|
|
566
|
+
# "posData": [{
|
|
567
|
+
# "posId": "1111111111",
|
|
568
|
+
# "tradeId": "2",
|
|
569
|
+
# "instId": "BTC-USD-191018",
|
|
570
|
+
# "instType": "FUTURES",
|
|
571
|
+
# "mgnMode": "cross",
|
|
572
|
+
# "posSide": "long",
|
|
573
|
+
# "pos": "10",
|
|
574
|
+
# "ccy": "BTC",
|
|
575
|
+
# "posCcy": "",
|
|
576
|
+
# "avgPx": "3320",
|
|
577
|
+
# "uTIme": "1597026383085"
|
|
578
|
+
# }],
|
|
579
|
+
# "trades": [{
|
|
580
|
+
# "instId": "BTC-USD-191018",
|
|
581
|
+
# "tradeId": "2",
|
|
582
|
+
# }]
|
|
583
|
+
# }
|
|
584
|
+
#
|
|
585
|
+
posData = self.safe_list(liquidation, 'posData', [])
|
|
586
|
+
firstPosData = self.safe_dict(posData, 0, {})
|
|
587
|
+
marketId = self.safe_string(firstPosData, 'instId')
|
|
588
|
+
market = self.safe_market(marketId, market)
|
|
589
|
+
timestamp = self.safe_integer(firstPosData, 'uTIme')
|
|
590
|
+
return self.safe_liquidation({
|
|
591
|
+
'info': liquidation,
|
|
592
|
+
'symbol': self.safe_symbol(marketId, market),
|
|
593
|
+
'contracts': self.safe_number(firstPosData, 'pos'),
|
|
594
|
+
'contractSize': self.safe_number(market, 'contractSize'),
|
|
595
|
+
'price': self.safe_number(liquidation, 'avgPx'),
|
|
596
|
+
'baseValue': None,
|
|
597
|
+
'quoteValue': None,
|
|
598
|
+
'timestamp': timestamp,
|
|
599
|
+
'datetime': self.iso8601(timestamp),
|
|
600
|
+
})
|
|
601
|
+
|
|
602
|
+
def parse_ws_liquidation(self, liquidation, market=None):
|
|
603
|
+
#
|
|
604
|
+
# public liquidation
|
|
605
|
+
# {
|
|
606
|
+
# "details": [
|
|
607
|
+
# {
|
|
608
|
+
# "bkLoss": "0",
|
|
609
|
+
# "bkPx": "0.007831",
|
|
610
|
+
# "ccy": "",
|
|
611
|
+
# "posSide": "short",
|
|
612
|
+
# "side": "buy",
|
|
613
|
+
# "sz": "13",
|
|
614
|
+
# "ts": "1692266434010"
|
|
615
|
+
# }
|
|
616
|
+
# ],
|
|
617
|
+
# "instFamily": "IOST-USDT",
|
|
618
|
+
# "instId": "IOST-USDT-SWAP",
|
|
619
|
+
# "instType": "SWAP",
|
|
620
|
+
# "uly": "IOST-USDT"
|
|
621
|
+
# }
|
|
622
|
+
#
|
|
623
|
+
details = self.safe_list(liquidation, 'details', [])
|
|
624
|
+
liquidationDetails = self.safe_dict(details, 0, {})
|
|
625
|
+
marketId = self.safe_string(liquidation, 'instId')
|
|
626
|
+
market = self.safe_market(marketId, market)
|
|
627
|
+
timestamp = self.safe_integer(liquidationDetails, 'ts')
|
|
628
|
+
return self.safe_liquidation({
|
|
629
|
+
'info': liquidation,
|
|
630
|
+
'symbol': self.safe_symbol(marketId, market),
|
|
631
|
+
'contracts': self.safe_number(liquidationDetails, 'sz'),
|
|
632
|
+
'contractSize': self.safe_number(market, 'contractSize'),
|
|
633
|
+
'price': self.safe_number(liquidationDetails, 'bkPx'),
|
|
634
|
+
'baseValue': None,
|
|
635
|
+
'quoteValue': None,
|
|
636
|
+
'timestamp': timestamp,
|
|
637
|
+
'datetime': self.iso8601(timestamp),
|
|
638
|
+
})
|
|
639
|
+
|
|
640
|
+
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
|
641
|
+
"""
|
|
642
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
643
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
644
|
+
:param str timeframe: the length of time each candle represents
|
|
645
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
646
|
+
:param int [limit]: the maximum amount of candles to fetch
|
|
647
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
648
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
649
|
+
"""
|
|
650
|
+
await self.load_markets()
|
|
651
|
+
symbol = self.symbol(symbol)
|
|
652
|
+
interval = self.safe_string(self.timeframes, timeframe, timeframe)
|
|
653
|
+
name = 'candle' + interval
|
|
654
|
+
ohlcv = await self.subscribe('public', name, name, symbol, params)
|
|
655
|
+
if self.newUpdates:
|
|
656
|
+
limit = ohlcv.getLimit(symbol, limit)
|
|
657
|
+
return self.filter_by_since_limit(ohlcv, since, limit, 0, True)
|
|
658
|
+
|
|
659
|
+
async def watch_ohlcv_for_symbols(self, symbolsAndTimeframes: List[List[str]], since: Int = None, limit: Int = None, params={}):
|
|
660
|
+
"""
|
|
661
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
662
|
+
:param str[][] symbolsAndTimeframes: array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
|
663
|
+
:param int [since]: timestamp in ms of the earliest candle to fetch
|
|
664
|
+
:param int [limit]: the maximum amount of candles to fetch
|
|
665
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
666
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
667
|
+
"""
|
|
668
|
+
symbolsLength = len(symbolsAndTimeframes)
|
|
669
|
+
if symbolsLength == 0 or not isinstance(symbolsAndTimeframes[0], list):
|
|
670
|
+
raise ArgumentsRequired(self.id + " watchOHLCVForSymbols() requires a an array of symbols and timeframes, like [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]")
|
|
671
|
+
await self.load_markets()
|
|
672
|
+
topics = []
|
|
673
|
+
messageHashes = []
|
|
674
|
+
for i in range(0, len(symbolsAndTimeframes)):
|
|
675
|
+
symbolAndTimeframe = symbolsAndTimeframes[i]
|
|
676
|
+
sym = symbolAndTimeframe[0]
|
|
677
|
+
tf = symbolAndTimeframe[1]
|
|
678
|
+
marketId = self.market_id(sym)
|
|
679
|
+
interval = self.safe_string(self.timeframes, tf, tf)
|
|
680
|
+
channel = 'candle' + interval
|
|
681
|
+
topic: dict = {
|
|
682
|
+
'channel': channel,
|
|
683
|
+
'instId': marketId,
|
|
684
|
+
}
|
|
685
|
+
topics.append(topic)
|
|
686
|
+
messageHashes.append('multi:' + channel + ':' + sym)
|
|
687
|
+
request: dict = {
|
|
688
|
+
'op': 'subscribe',
|
|
689
|
+
'args': topics,
|
|
690
|
+
}
|
|
691
|
+
url = self.get_url('candle', 'public')
|
|
692
|
+
symbol, timeframe, candles = await self.watch_multiple(url, messageHashes, request, messageHashes)
|
|
693
|
+
if self.newUpdates:
|
|
694
|
+
limit = candles.getLimit(symbol, limit)
|
|
695
|
+
filtered = self.filter_by_since_limit(candles, since, limit, 0, True)
|
|
696
|
+
return self.create_ohlcv_object(symbol, timeframe, filtered)
|
|
697
|
+
|
|
698
|
+
def handle_ohlcv(self, client: Client, message):
|
|
699
|
+
#
|
|
700
|
+
# {
|
|
701
|
+
# "arg": {channel: "candle1m", instId: "BTC-USDT"},
|
|
702
|
+
# "data": [
|
|
703
|
+
# [
|
|
704
|
+
# "1626690720000",
|
|
705
|
+
# "31334",
|
|
706
|
+
# "31334",
|
|
707
|
+
# "31334",
|
|
708
|
+
# "31334",
|
|
709
|
+
# "0.0077",
|
|
710
|
+
# "241.2718"
|
|
711
|
+
# ]
|
|
712
|
+
# ]
|
|
713
|
+
# }
|
|
714
|
+
#
|
|
715
|
+
arg = self.safe_value(message, 'arg', {})
|
|
716
|
+
channel = self.safe_string(arg, 'channel')
|
|
717
|
+
data = self.safe_value(message, 'data', [])
|
|
718
|
+
marketId = self.safe_string(arg, 'instId')
|
|
719
|
+
market = self.safe_market(marketId)
|
|
720
|
+
symbol = market['symbol']
|
|
721
|
+
interval = channel.replace('candle', '')
|
|
722
|
+
# use a reverse lookup in a static map instead
|
|
723
|
+
timeframe = self.find_timeframe(interval)
|
|
724
|
+
for i in range(0, len(data)):
|
|
725
|
+
parsed = self.parse_ohlcv(data[i], market)
|
|
726
|
+
self.ohlcvs[symbol] = self.safe_value(self.ohlcvs, symbol, {})
|
|
727
|
+
stored = self.safe_value(self.ohlcvs[symbol], timeframe)
|
|
728
|
+
if stored is None:
|
|
729
|
+
limit = self.safe_integer(self.options, 'OHLCVLimit', 1000)
|
|
730
|
+
stored = ArrayCacheByTimestamp(limit)
|
|
731
|
+
self.ohlcvs[symbol][timeframe] = stored
|
|
732
|
+
stored.append(parsed)
|
|
733
|
+
messageHash = channel + ':' + market['id']
|
|
734
|
+
client.resolve(stored, messageHash)
|
|
735
|
+
# for multiOHLCV we need special object, to other "multi"
|
|
736
|
+
# methods, because OHLCV response item does not contain symbol
|
|
737
|
+
# or timeframe, thus otherwise it would be unrecognizable
|
|
738
|
+
messageHashForMulti = 'multi:' + channel + ':' + symbol
|
|
739
|
+
client.resolve([symbol, timeframe, stored], messageHashForMulti)
|
|
740
|
+
|
|
741
|
+
async def watch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
|
742
|
+
"""
|
|
743
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-order-book-channel
|
|
744
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
745
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
|
746
|
+
:param int [limit]: the maximum amount of order book entries to return
|
|
747
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
748
|
+
:param str [params.depth]: okx order book depth, can be books, books5, books-l2-tbt, books50-l2-tbt, bbo-tbt
|
|
749
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
750
|
+
"""
|
|
751
|
+
#
|
|
752
|
+
# bbo-tbt
|
|
753
|
+
# 1. Newly added channel that sends tick-by-tick Level 1 data
|
|
754
|
+
# 2. All API users can subscribe
|
|
755
|
+
# 3. Public depth channel, verification not required
|
|
756
|
+
#
|
|
757
|
+
# books-l2-tbt
|
|
758
|
+
# 1. Only users who're VIP5 and above can subscribe
|
|
759
|
+
# 2. Identity verification required before subscription
|
|
760
|
+
#
|
|
761
|
+
# books50-l2-tbt
|
|
762
|
+
# 1. Only users who're VIP4 and above can subscribe
|
|
763
|
+
# 2. Identity verification required before subscription
|
|
764
|
+
#
|
|
765
|
+
# books
|
|
766
|
+
# 1. All API users can subscribe
|
|
767
|
+
# 2. Public depth channel, verification not required
|
|
768
|
+
#
|
|
769
|
+
# books5
|
|
770
|
+
# 1. All API users can subscribe
|
|
771
|
+
# 2. Public depth channel, verification not required
|
|
772
|
+
# 3. Data feeds will be delivered every 100ms(vs. every 200ms now)
|
|
773
|
+
#
|
|
774
|
+
return await self.watch_order_book_for_symbols([symbol], limit, params)
|
|
775
|
+
|
|
776
|
+
async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
|
|
777
|
+
"""
|
|
778
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-market-data-ws-order-book-channel
|
|
779
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
780
|
+
:param str[] symbols: unified array of symbols
|
|
781
|
+
:param int [limit]: 1,5, 400, 50(l2-tbt, vip4+) or 40000(vip5+) the maximum amount of order book entries to return
|
|
782
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
783
|
+
:param str [params.depth]: okx order book depth, can be books, books5, books-l2-tbt, books50-l2-tbt, bbo-tbt
|
|
784
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
785
|
+
"""
|
|
786
|
+
await self.load_markets()
|
|
787
|
+
symbols = self.market_symbols(symbols)
|
|
788
|
+
depth = None
|
|
789
|
+
depth, params = self.handle_option_and_params(params, 'watchOrderBook', 'depth', 'books')
|
|
790
|
+
if limit is not None:
|
|
791
|
+
if limit == 1:
|
|
792
|
+
depth = 'bbo-tbt'
|
|
793
|
+
elif limit > 1 and limit <= 5:
|
|
794
|
+
depth = 'books5'
|
|
795
|
+
elif limit == 50:
|
|
796
|
+
depth = 'books50-l2-tbt' # Make sure you have VIP4 and above
|
|
797
|
+
elif limit == 400:
|
|
798
|
+
depth = 'books'
|
|
799
|
+
if (depth == 'books-l2-tbt') or (depth == 'books50-l2-tbt'):
|
|
800
|
+
if not self.check_required_credentials(False):
|
|
801
|
+
raise AuthenticationError(self.id + ' watchOrderBook/watchOrderBookForSymbols requires authentication for self depth. Add credentials or change the depth option to books or books5')
|
|
802
|
+
await self.authenticate({'access': 'public'})
|
|
803
|
+
topics = []
|
|
804
|
+
messageHashes = []
|
|
805
|
+
for i in range(0, len(symbols)):
|
|
806
|
+
symbol = symbols[i]
|
|
807
|
+
messageHashes.append(depth + ':' + symbol)
|
|
808
|
+
marketId = self.market_id(symbol)
|
|
809
|
+
topic: dict = {
|
|
810
|
+
'channel': depth,
|
|
811
|
+
'instId': marketId,
|
|
812
|
+
}
|
|
813
|
+
topics.append(topic)
|
|
814
|
+
request: dict = {
|
|
815
|
+
'op': 'subscribe',
|
|
816
|
+
'args': topics,
|
|
817
|
+
}
|
|
818
|
+
url = self.get_url(depth, 'public')
|
|
819
|
+
orderbook = await self.watch_multiple(url, messageHashes, request, messageHashes)
|
|
820
|
+
return orderbook.limit()
|
|
821
|
+
|
|
822
|
+
def handle_delta(self, bookside, delta):
|
|
823
|
+
#
|
|
824
|
+
# [
|
|
825
|
+
# "31685", # price
|
|
826
|
+
# "0.78069158", # amount
|
|
827
|
+
# "0", # liquidated orders
|
|
828
|
+
# "17" # orders
|
|
829
|
+
# ]
|
|
830
|
+
#
|
|
831
|
+
price = self.safe_float(delta, 0)
|
|
832
|
+
amount = self.safe_float(delta, 1)
|
|
833
|
+
bookside.store(price, amount)
|
|
834
|
+
|
|
835
|
+
def handle_deltas(self, bookside, deltas):
|
|
836
|
+
for i in range(0, len(deltas)):
|
|
837
|
+
self.handle_delta(bookside, deltas[i])
|
|
838
|
+
|
|
839
|
+
def handle_order_book_message(self, client: Client, message, orderbook, messageHash):
|
|
840
|
+
#
|
|
841
|
+
# {
|
|
842
|
+
# "asks": [
|
|
843
|
+
# ['31738.3', '0.05973179', "0", "3"],
|
|
844
|
+
# ['31738.5', '0.11035404', "0", "2"],
|
|
845
|
+
# ['31739.6', '0.01', "0", "1"],
|
|
846
|
+
# ],
|
|
847
|
+
# "bids": [
|
|
848
|
+
# ['31738.2', '0.67557666', "0", "9"],
|
|
849
|
+
# ['31738', '0.02466947', "0", "2"],
|
|
850
|
+
# ['31736.3', '0.01705046', "0", "2"],
|
|
851
|
+
# ],
|
|
852
|
+
# "instId": "BTC-USDT",
|
|
853
|
+
# "ts": "1626537446491"
|
|
854
|
+
# }
|
|
855
|
+
#
|
|
856
|
+
asks = self.safe_value(message, 'asks', [])
|
|
857
|
+
bids = self.safe_value(message, 'bids', [])
|
|
858
|
+
storedAsks = orderbook['asks']
|
|
859
|
+
storedBids = orderbook['bids']
|
|
860
|
+
self.handle_deltas(storedAsks, asks)
|
|
861
|
+
self.handle_deltas(storedBids, bids)
|
|
862
|
+
marketId = self.safe_string(message, 'instId')
|
|
863
|
+
symbol = self.safe_symbol(marketId)
|
|
864
|
+
checksum = self.safe_bool(self.options, 'checksum', True)
|
|
865
|
+
if checksum:
|
|
866
|
+
asksLength = len(storedAsks)
|
|
867
|
+
bidsLength = len(storedBids)
|
|
868
|
+
payloadArray = []
|
|
869
|
+
for i in range(0, 25):
|
|
870
|
+
if i < bidsLength:
|
|
871
|
+
payloadArray.append(self.number_to_string(storedBids[i][0]))
|
|
872
|
+
payloadArray.append(self.number_to_string(storedBids[i][1]))
|
|
873
|
+
if i < asksLength:
|
|
874
|
+
payloadArray.append(self.number_to_string(storedAsks[i][0]))
|
|
875
|
+
payloadArray.append(self.number_to_string(storedAsks[i][1]))
|
|
876
|
+
payload = ':'.join(payloadArray)
|
|
877
|
+
responseChecksum = self.safe_integer(message, 'checksum')
|
|
878
|
+
localChecksum = self.crc32(payload, True)
|
|
879
|
+
if responseChecksum != localChecksum:
|
|
880
|
+
error = InvalidNonce(self.id + ' invalid checksum')
|
|
881
|
+
del client.subscriptions[messageHash]
|
|
882
|
+
del self.orderbooks[symbol]
|
|
883
|
+
client.reject(error, messageHash)
|
|
884
|
+
timestamp = self.safe_integer(message, 'ts')
|
|
885
|
+
orderbook['timestamp'] = timestamp
|
|
886
|
+
orderbook['datetime'] = self.iso8601(timestamp)
|
|
887
|
+
return orderbook
|
|
888
|
+
|
|
889
|
+
def handle_order_book(self, client: Client, message):
|
|
890
|
+
#
|
|
891
|
+
# snapshot
|
|
892
|
+
#
|
|
893
|
+
# {
|
|
894
|
+
# "arg": {channel: 'books-l2-tbt', instId: "BTC-USDT"},
|
|
895
|
+
# "action": "snapshot",
|
|
896
|
+
# "data": [
|
|
897
|
+
# {
|
|
898
|
+
# "asks": [
|
|
899
|
+
# ['31685', '0.78069158', "0", "17"],
|
|
900
|
+
# ['31685.1', '0.0001', "0", "1"],
|
|
901
|
+
# ['31685.6', '0.04543165', "0", "1"],
|
|
902
|
+
# ],
|
|
903
|
+
# "bids": [
|
|
904
|
+
# ['31684.9', '0.01', "0", "1"],
|
|
905
|
+
# ['31682.9', '0.0001', "0", "1"],
|
|
906
|
+
# ['31680.7', '0.01', "0", "1"],
|
|
907
|
+
# ],
|
|
908
|
+
# "ts": "1626532416403",
|
|
909
|
+
# "checksum": -1023440116
|
|
910
|
+
# }
|
|
911
|
+
# ]
|
|
912
|
+
# }
|
|
913
|
+
#
|
|
914
|
+
# update
|
|
915
|
+
#
|
|
916
|
+
# {
|
|
917
|
+
# "arg": {channel: 'books-l2-tbt', instId: "BTC-USDT"},
|
|
918
|
+
# "action": "update",
|
|
919
|
+
# "data": [
|
|
920
|
+
# {
|
|
921
|
+
# "asks": [
|
|
922
|
+
# ['31657.7', '0', "0", "0"],
|
|
923
|
+
# ['31659.7', '0.01', "0", "1"],
|
|
924
|
+
# ['31987.3', '0.01', "0", "1"]
|
|
925
|
+
# ],
|
|
926
|
+
# "bids": [
|
|
927
|
+
# ['31642.9', '0.50296385', "0", "4"],
|
|
928
|
+
# ['31639.9', '0', "0", "0"],
|
|
929
|
+
# ['31638.7', '0.01', "0", "1"],
|
|
930
|
+
# ],
|
|
931
|
+
# "ts": "1626535709008",
|
|
932
|
+
# "checksum": 830931827
|
|
933
|
+
# }
|
|
934
|
+
# ]
|
|
935
|
+
# }
|
|
936
|
+
#
|
|
937
|
+
# books5
|
|
938
|
+
#
|
|
939
|
+
# {
|
|
940
|
+
# "arg": {channel: "books5", instId: "BTC-USDT"},
|
|
941
|
+
# "data": [
|
|
942
|
+
# {
|
|
943
|
+
# "asks": [
|
|
944
|
+
# ['31738.3', '0.05973179', "0", "3"],
|
|
945
|
+
# ['31738.5', '0.11035404', "0", "2"],
|
|
946
|
+
# ['31739.6', '0.01', "0", "1"],
|
|
947
|
+
# ],
|
|
948
|
+
# "bids": [
|
|
949
|
+
# ['31738.2', '0.67557666', "0", "9"],
|
|
950
|
+
# ['31738', '0.02466947', "0", "2"],
|
|
951
|
+
# ['31736.3', '0.01705046', "0", "2"],
|
|
952
|
+
# ],
|
|
953
|
+
# "instId": "BTC-USDT",
|
|
954
|
+
# "ts": "1626537446491"
|
|
955
|
+
# }
|
|
956
|
+
# ]
|
|
957
|
+
# }
|
|
958
|
+
#
|
|
959
|
+
# bbo-tbt
|
|
960
|
+
#
|
|
961
|
+
# {
|
|
962
|
+
# "arg":{
|
|
963
|
+
# "channel":"bbo-tbt",
|
|
964
|
+
# "instId":"BTC-USDT"
|
|
965
|
+
# },
|
|
966
|
+
# "data":[
|
|
967
|
+
# {
|
|
968
|
+
# "asks":[["36232.2","1.8826134","0","17"]],
|
|
969
|
+
# "bids":[["36232.1","0.00572212","0","2"]],
|
|
970
|
+
# "ts":"1651826598363"
|
|
971
|
+
# }
|
|
972
|
+
# ]
|
|
973
|
+
# }
|
|
974
|
+
#
|
|
975
|
+
arg = self.safe_dict(message, 'arg', {})
|
|
976
|
+
channel = self.safe_string(arg, 'channel')
|
|
977
|
+
action = self.safe_string(message, 'action')
|
|
978
|
+
data = self.safe_list(message, 'data', [])
|
|
979
|
+
marketId = self.safe_string(arg, 'instId')
|
|
980
|
+
market = self.safe_market(marketId)
|
|
981
|
+
symbol = market['symbol']
|
|
982
|
+
depths: dict = {
|
|
983
|
+
'bbo-tbt': 1,
|
|
984
|
+
'books': 400,
|
|
985
|
+
'books5': 5,
|
|
986
|
+
'books-l2-tbt': 400,
|
|
987
|
+
'books50-l2-tbt': 50,
|
|
988
|
+
}
|
|
989
|
+
limit = self.safe_integer(depths, channel)
|
|
990
|
+
messageHash = channel + ':' + symbol
|
|
991
|
+
if action == 'snapshot':
|
|
992
|
+
for i in range(0, len(data)):
|
|
993
|
+
update = data[i]
|
|
994
|
+
orderbook = self.order_book({}, limit)
|
|
995
|
+
self.orderbooks[symbol] = orderbook
|
|
996
|
+
orderbook['symbol'] = symbol
|
|
997
|
+
self.handle_order_book_message(client, update, orderbook, messageHash)
|
|
998
|
+
client.resolve(orderbook, messageHash)
|
|
999
|
+
elif action == 'update':
|
|
1000
|
+
if symbol in self.orderbooks:
|
|
1001
|
+
orderbook = self.orderbooks[symbol]
|
|
1002
|
+
for i in range(0, len(data)):
|
|
1003
|
+
update = data[i]
|
|
1004
|
+
self.handle_order_book_message(client, update, orderbook, messageHash)
|
|
1005
|
+
client.resolve(orderbook, messageHash)
|
|
1006
|
+
elif (channel == 'books5') or (channel == 'bbo-tbt'):
|
|
1007
|
+
if not (symbol in self.orderbooks):
|
|
1008
|
+
self.orderbooks[symbol] = self.order_book({}, limit)
|
|
1009
|
+
orderbook = self.orderbooks[symbol]
|
|
1010
|
+
for i in range(0, len(data)):
|
|
1011
|
+
update = data[i]
|
|
1012
|
+
timestamp = self.safe_integer(update, 'ts')
|
|
1013
|
+
snapshot = self.parse_order_book(update, symbol, timestamp, 'bids', 'asks', 0, 1)
|
|
1014
|
+
orderbook.reset(snapshot)
|
|
1015
|
+
client.resolve(orderbook, messageHash)
|
|
1016
|
+
return message
|
|
1017
|
+
|
|
1018
|
+
async def authenticate(self, params={}):
|
|
1019
|
+
self.check_required_credentials()
|
|
1020
|
+
access = self.safe_string(params, 'access', 'private')
|
|
1021
|
+
params = self.omit(params, ['access'])
|
|
1022
|
+
url = self.get_url('users', access)
|
|
1023
|
+
messageHash = 'authenticated'
|
|
1024
|
+
client = self.client(url)
|
|
1025
|
+
future = client.future(messageHash)
|
|
1026
|
+
authenticated = self.safe_value(client.subscriptions, messageHash)
|
|
1027
|
+
if authenticated is None:
|
|
1028
|
+
timestamp = str(self.seconds())
|
|
1029
|
+
method = 'GET'
|
|
1030
|
+
path = '/users/self/verify'
|
|
1031
|
+
auth = timestamp + method + path
|
|
1032
|
+
signature = self.hmac(self.encode(auth), self.encode(self.secret), hashlib.sha256, 'base64')
|
|
1033
|
+
operation = 'login'
|
|
1034
|
+
request: dict = {
|
|
1035
|
+
'op': operation,
|
|
1036
|
+
'args': [
|
|
1037
|
+
{
|
|
1038
|
+
'apiKey': self.apiKey,
|
|
1039
|
+
'passphrase': self.password,
|
|
1040
|
+
'timestamp': timestamp,
|
|
1041
|
+
'sign': signature,
|
|
1042
|
+
},
|
|
1043
|
+
],
|
|
1044
|
+
}
|
|
1045
|
+
message = self.extend(request, params)
|
|
1046
|
+
self.watch(url, messageHash, message, messageHash)
|
|
1047
|
+
return await future
|
|
1048
|
+
|
|
1049
|
+
async def watch_balance(self, params={}) -> Balances:
|
|
1050
|
+
"""
|
|
1051
|
+
watch balance and get the amount of funds available for trading or funds locked in orders
|
|
1052
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1053
|
+
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
|
1054
|
+
"""
|
|
1055
|
+
await self.load_markets()
|
|
1056
|
+
await self.authenticate()
|
|
1057
|
+
return await self.subscribe('private', 'account', 'account', None, params)
|
|
1058
|
+
|
|
1059
|
+
def handle_balance_and_position(self, client: Client, message):
|
|
1060
|
+
self.handle_my_liquidation(client, message)
|
|
1061
|
+
|
|
1062
|
+
def handle_balance(self, client: Client, message):
|
|
1063
|
+
#
|
|
1064
|
+
# {
|
|
1065
|
+
# "arg": {channel: "account"},
|
|
1066
|
+
# "data": [
|
|
1067
|
+
# {
|
|
1068
|
+
# "adjEq": '',
|
|
1069
|
+
# "details": [
|
|
1070
|
+
# {
|
|
1071
|
+
# "availBal": '',
|
|
1072
|
+
# "availEq": "8.21009913",
|
|
1073
|
+
# "cashBal": "8.21009913",
|
|
1074
|
+
# "ccy": "USDT",
|
|
1075
|
+
# "coinUsdPrice": "0.99994",
|
|
1076
|
+
# "crossLiab": '',
|
|
1077
|
+
# "disEq": "8.2096065240522",
|
|
1078
|
+
# "eq": "8.21009913",
|
|
1079
|
+
# "eqUsd": "8.2096065240522",
|
|
1080
|
+
# "frozenBal": "0",
|
|
1081
|
+
# "interest": '',
|
|
1082
|
+
# "isoEq": "0",
|
|
1083
|
+
# "isoLiab": '',
|
|
1084
|
+
# "liab": '',
|
|
1085
|
+
# "maxLoan": '',
|
|
1086
|
+
# "mgnRatio": '',
|
|
1087
|
+
# "notionalLever": "0",
|
|
1088
|
+
# "ordFrozen": "0",
|
|
1089
|
+
# "twap": "0",
|
|
1090
|
+
# "uTime": "1621927314996",
|
|
1091
|
+
# "upl": "0"
|
|
1092
|
+
# },
|
|
1093
|
+
# ],
|
|
1094
|
+
# "imr": '',
|
|
1095
|
+
# "isoEq": "0",
|
|
1096
|
+
# "mgnRatio": '',
|
|
1097
|
+
# "mmr": '',
|
|
1098
|
+
# "notionalUsd": '',
|
|
1099
|
+
# "ordFroz": '',
|
|
1100
|
+
# "totalEq": "22.1930992296832",
|
|
1101
|
+
# "uTime": "1626692120916"
|
|
1102
|
+
# }
|
|
1103
|
+
# ]
|
|
1104
|
+
# }
|
|
1105
|
+
#
|
|
1106
|
+
arg = self.safe_value(message, 'arg', {})
|
|
1107
|
+
channel = self.safe_string(arg, 'channel')
|
|
1108
|
+
type = 'spot'
|
|
1109
|
+
balance = self.parseTradingBalance(message)
|
|
1110
|
+
oldBalance = self.safe_value(self.balance, type, {})
|
|
1111
|
+
newBalance = self.deep_extend(oldBalance, balance)
|
|
1112
|
+
self.balance[type] = self.safe_balance(newBalance)
|
|
1113
|
+
client.resolve(self.balance[type], channel)
|
|
1114
|
+
|
|
1115
|
+
def order_to_trade(self, order, market=None):
|
|
1116
|
+
info = self.safe_value(order, 'info', {})
|
|
1117
|
+
timestamp = self.safe_integer(info, 'fillTime')
|
|
1118
|
+
feeMarketId = self.safe_string(info, 'fillFeeCcy')
|
|
1119
|
+
isTaker = self.safe_string(info, 'execType', '') == 'T'
|
|
1120
|
+
return self.safe_trade({
|
|
1121
|
+
'info': info,
|
|
1122
|
+
'timestamp': timestamp,
|
|
1123
|
+
'datetime': self.iso8601(timestamp),
|
|
1124
|
+
'symbol': self.safe_string(order, 'symbol'),
|
|
1125
|
+
'id': self.safe_string(info, 'tradeId'),
|
|
1126
|
+
'order': self.safe_string(order, 'id'),
|
|
1127
|
+
'type': self.safe_string(order, 'type'),
|
|
1128
|
+
'takerOrMaker': 'taker' if (isTaker) else 'maker',
|
|
1129
|
+
'side': self.safe_string(order, 'side'),
|
|
1130
|
+
'price': self.safe_number(info, 'fillPx'),
|
|
1131
|
+
'amount': self.safe_number(info, 'fillSz'),
|
|
1132
|
+
'cost': self.safe_number(order, 'cost'),
|
|
1133
|
+
'fee': {
|
|
1134
|
+
'cost': self.safe_number(info, 'fillFee'),
|
|
1135
|
+
'currency': self.safe_currency_code(feeMarketId),
|
|
1136
|
+
},
|
|
1137
|
+
}, market)
|
|
1138
|
+
|
|
1139
|
+
async def watch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
|
1140
|
+
"""
|
|
1141
|
+
watches information on multiple trades made by the user
|
|
1142
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-order-channel
|
|
1143
|
+
:param str [symbol]: unified market symbol of the market trades were made in
|
|
1144
|
+
:param int [since]: the earliest time in ms to fetch trades for
|
|
1145
|
+
:param int [limit]: the maximum number of trade structures to retrieve
|
|
1146
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1147
|
+
:param bool [params.stop]: True if fetching trigger or conditional trades
|
|
1148
|
+
:param str [params.type]: 'spot', 'swap', 'future', 'option', 'ANY', 'SPOT', 'MARGIN', 'SWAP', 'FUTURES' or 'OPTION'
|
|
1149
|
+
:param str [params.marginMode]: 'cross' or 'isolated', for automatically setting the type to spot margin
|
|
1150
|
+
:returns dict[]: a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
|
|
1151
|
+
"""
|
|
1152
|
+
# By default, receive order updates from any instrument type
|
|
1153
|
+
type = None
|
|
1154
|
+
type, params = self.handle_option_and_params(params, 'watchMyTrades', 'type', 'ANY')
|
|
1155
|
+
isStop = self.safe_bool(params, 'stop', False)
|
|
1156
|
+
params = self.omit(params, ['stop'])
|
|
1157
|
+
await self.load_markets()
|
|
1158
|
+
await self.authenticate({'access': 'business' if isStop else 'private'})
|
|
1159
|
+
channel = 'orders-algo' if isStop else 'orders'
|
|
1160
|
+
messageHash = channel + '::myTrades'
|
|
1161
|
+
market = None
|
|
1162
|
+
if symbol is not None:
|
|
1163
|
+
market = self.market(symbol)
|
|
1164
|
+
symbol = market['symbol']
|
|
1165
|
+
type = market['type']
|
|
1166
|
+
messageHash = messageHash + '::' + symbol
|
|
1167
|
+
if type == 'future':
|
|
1168
|
+
type = 'futures'
|
|
1169
|
+
uppercaseType = type.upper()
|
|
1170
|
+
marginMode = None
|
|
1171
|
+
marginMode, params = self.handle_margin_mode_and_params('watchMyTrades', params)
|
|
1172
|
+
if uppercaseType == 'SPOT':
|
|
1173
|
+
if marginMode is not None:
|
|
1174
|
+
uppercaseType = 'MARGIN'
|
|
1175
|
+
request: dict = {
|
|
1176
|
+
'instType': uppercaseType,
|
|
1177
|
+
}
|
|
1178
|
+
orders = await self.subscribe('private', messageHash, channel, None, self.extend(request, params))
|
|
1179
|
+
if self.newUpdates:
|
|
1180
|
+
limit = orders.getLimit(symbol, limit)
|
|
1181
|
+
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
|
|
1182
|
+
|
|
1183
|
+
async def watch_positions(self, symbols: Strings = None, since: Int = None, limit: Int = None, params={}) -> List[Position]:
|
|
1184
|
+
"""
|
|
1185
|
+
:see: https://www.okx.com/docs-v5/en/#trading-account-websocket-positions-channel
|
|
1186
|
+
watch all open positions
|
|
1187
|
+
:param str[]|None symbols: list of unified market symbols
|
|
1188
|
+
:param dict params: extra parameters specific to the exchange API endpoint
|
|
1189
|
+
:returns dict[]: a list of `position structure <https://docs.ccxt.com/en/latest/manual.html#position-structure>`
|
|
1190
|
+
"""
|
|
1191
|
+
await self.load_markets()
|
|
1192
|
+
await self.authenticate(params)
|
|
1193
|
+
symbols = self.market_symbols(symbols)
|
|
1194
|
+
request: dict = {
|
|
1195
|
+
'instType': 'ANY',
|
|
1196
|
+
}
|
|
1197
|
+
channel = 'positions'
|
|
1198
|
+
newPositions = None
|
|
1199
|
+
if symbols is None:
|
|
1200
|
+
arg: dict = {
|
|
1201
|
+
'channel': 'positions',
|
|
1202
|
+
'instType': 'ANY',
|
|
1203
|
+
}
|
|
1204
|
+
args = [arg]
|
|
1205
|
+
nonSymbolRequest: dict = {
|
|
1206
|
+
'op': 'subscribe',
|
|
1207
|
+
'args': args,
|
|
1208
|
+
}
|
|
1209
|
+
url = self.get_url(channel, 'private')
|
|
1210
|
+
newPositions = await self.watch(url, channel, nonSymbolRequest, channel)
|
|
1211
|
+
else:
|
|
1212
|
+
newPositions = await self.subscribe_multiple('private', channel, symbols, self.extend(request, params))
|
|
1213
|
+
if self.newUpdates:
|
|
1214
|
+
return newPositions
|
|
1215
|
+
return self.filter_by_symbols_since_limit(self.positions, symbols, since, limit, True)
|
|
1216
|
+
|
|
1217
|
+
def handle_positions(self, client, message):
|
|
1218
|
+
#
|
|
1219
|
+
# {
|
|
1220
|
+
# arg: {
|
|
1221
|
+
# channel: 'positions',
|
|
1222
|
+
# instType: 'ANY',
|
|
1223
|
+
# instId: 'XRP-USDT-SWAP',
|
|
1224
|
+
# uid: '464737184507959869'
|
|
1225
|
+
# },
|
|
1226
|
+
# data: [{
|
|
1227
|
+
# adl: '1',
|
|
1228
|
+
# availPos: '',
|
|
1229
|
+
# avgPx: '0.52668',
|
|
1230
|
+
# baseBal: '',
|
|
1231
|
+
# baseBorrowed: '',
|
|
1232
|
+
# baseInterest: '',
|
|
1233
|
+
# bizRefId: '',
|
|
1234
|
+
# bizRefType: '',
|
|
1235
|
+
# cTime: '1693151444408',
|
|
1236
|
+
# ccy: 'USDT',
|
|
1237
|
+
# closeOrderAlgo: [],
|
|
1238
|
+
# deltaBS: '',
|
|
1239
|
+
# deltaPA: '',
|
|
1240
|
+
# gammaBS: '',
|
|
1241
|
+
# gammaPA: '',
|
|
1242
|
+
# idxPx: '0.52683',
|
|
1243
|
+
# imr: '17.564000000000004',
|
|
1244
|
+
# instId: 'XRP-USDT-SWAP',
|
|
1245
|
+
# instType: 'SWAP',
|
|
1246
|
+
# interest: '',
|
|
1247
|
+
# last: '0.52691',
|
|
1248
|
+
# lever: '3',
|
|
1249
|
+
# liab: '',
|
|
1250
|
+
# liabCcy: '',
|
|
1251
|
+
# liqPx: '0.3287514731020614',
|
|
1252
|
+
# margin: '',
|
|
1253
|
+
# markPx: '0.52692',
|
|
1254
|
+
# mgnMode: 'cross',
|
|
1255
|
+
# mgnRatio: '69.00363001456147',
|
|
1256
|
+
# mmr: '0.26346',
|
|
1257
|
+
# notionalUsd: '52.68620388000001',
|
|
1258
|
+
# optVal: '',
|
|
1259
|
+
# pTime: '1693151906023',
|
|
1260
|
+
# pendingCloseOrdLiabVal: '',
|
|
1261
|
+
# pos: '1',
|
|
1262
|
+
# posCcy: '',
|
|
1263
|
+
# posId: '616057041198907393',
|
|
1264
|
+
# posSide: 'net',
|
|
1265
|
+
# quoteBal: '',
|
|
1266
|
+
# quoteBorrowed: '',
|
|
1267
|
+
# quoteInterest: '',
|
|
1268
|
+
# spotInUseAmt: '',
|
|
1269
|
+
# spotInUseCcy: '',
|
|
1270
|
+
# thetaBS: '',
|
|
1271
|
+
# thetaPA: '',
|
|
1272
|
+
# tradeId: '138745402',
|
|
1273
|
+
# uTime: '1693151444408',
|
|
1274
|
+
# upl: '0.0240000000000018',
|
|
1275
|
+
# uplLastPx: '0.0229999999999952',
|
|
1276
|
+
# uplRatio: '0.0013670539986328',
|
|
1277
|
+
# uplRatioLastPx: '0.001310093415356',
|
|
1278
|
+
# usdPx: '',
|
|
1279
|
+
# vegaBS: '',
|
|
1280
|
+
# vegaPA: ''
|
|
1281
|
+
# }]
|
|
1282
|
+
# }
|
|
1283
|
+
#
|
|
1284
|
+
arg = self.safe_value(message, 'arg', {})
|
|
1285
|
+
channel = self.safe_string(arg, 'channel', '')
|
|
1286
|
+
data = self.safe_value(message, 'data', [])
|
|
1287
|
+
if self.positions is None:
|
|
1288
|
+
self.positions = ArrayCacheBySymbolBySide()
|
|
1289
|
+
cache = self.positions
|
|
1290
|
+
newPositions = []
|
|
1291
|
+
for i in range(0, len(data)):
|
|
1292
|
+
rawPosition = data[i]
|
|
1293
|
+
position = self.parse_position(rawPosition)
|
|
1294
|
+
newPositions.append(position)
|
|
1295
|
+
cache.append(position)
|
|
1296
|
+
messageHashes = self.find_message_hashes(client, channel + '::')
|
|
1297
|
+
for i in range(0, len(messageHashes)):
|
|
1298
|
+
messageHash = messageHashes[i]
|
|
1299
|
+
parts = messageHash.split('::')
|
|
1300
|
+
symbolsString = parts[1]
|
|
1301
|
+
symbols = symbolsString.split(',')
|
|
1302
|
+
positions = self.filter_by_array(newPositions, 'symbol', symbols, False)
|
|
1303
|
+
if not self.is_empty(positions):
|
|
1304
|
+
client.resolve(positions, messageHash)
|
|
1305
|
+
client.resolve(newPositions, channel)
|
|
1306
|
+
|
|
1307
|
+
async def watch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
|
1308
|
+
"""
|
|
1309
|
+
watches information on multiple orders made by the user
|
|
1310
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-order-channel
|
|
1311
|
+
:param str [symbol]: unified market symbol of the market the orders were made in
|
|
1312
|
+
:param int [since]: the earliest time in ms to fetch orders for
|
|
1313
|
+
:param int [limit]: the maximum number of order structures to retrieve
|
|
1314
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1315
|
+
:param bool [params.stop]: True if fetching trigger or conditional orders
|
|
1316
|
+
:param str [params.type]: 'spot', 'swap', 'future', 'option', 'ANY', 'SPOT', 'MARGIN', 'SWAP', 'FUTURES' or 'OPTION'
|
|
1317
|
+
:param str [params.marginMode]: 'cross' or 'isolated', for automatically setting the type to spot margin
|
|
1318
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1319
|
+
"""
|
|
1320
|
+
type = None
|
|
1321
|
+
# By default, receive order updates from any instrument type
|
|
1322
|
+
type, params = self.handle_option_and_params(params, 'watchOrders', 'type', 'ANY')
|
|
1323
|
+
isStop = self.safe_value_2(params, 'stop', 'trigger', False)
|
|
1324
|
+
params = self.omit(params, ['stop', 'trigger'])
|
|
1325
|
+
await self.load_markets()
|
|
1326
|
+
await self.authenticate({'access': 'business' if isStop else 'private'})
|
|
1327
|
+
market = None
|
|
1328
|
+
if symbol is not None:
|
|
1329
|
+
market = self.market(symbol)
|
|
1330
|
+
symbol = market['symbol']
|
|
1331
|
+
type = market['type']
|
|
1332
|
+
if type == 'future':
|
|
1333
|
+
type = 'futures'
|
|
1334
|
+
uppercaseType = type.upper()
|
|
1335
|
+
marginMode = None
|
|
1336
|
+
marginMode, params = self.handle_margin_mode_and_params('watchOrders', params)
|
|
1337
|
+
if uppercaseType == 'SPOT':
|
|
1338
|
+
if marginMode is not None:
|
|
1339
|
+
uppercaseType = 'MARGIN'
|
|
1340
|
+
request: dict = {
|
|
1341
|
+
'instType': uppercaseType,
|
|
1342
|
+
}
|
|
1343
|
+
channel = 'orders-algo' if isStop else 'orders'
|
|
1344
|
+
orders = await self.subscribe('private', channel, channel, symbol, self.extend(request, params))
|
|
1345
|
+
if self.newUpdates:
|
|
1346
|
+
limit = orders.getLimit(symbol, limit)
|
|
1347
|
+
return self.filter_by_symbol_since_limit(orders, symbol, since, limit, True)
|
|
1348
|
+
|
|
1349
|
+
def handle_orders(self, client: Client, message, subscription=None):
|
|
1350
|
+
#
|
|
1351
|
+
# {
|
|
1352
|
+
# "arg":{
|
|
1353
|
+
# "channel":"orders",
|
|
1354
|
+
# "instType":"SPOT"
|
|
1355
|
+
# },
|
|
1356
|
+
# "data":[
|
|
1357
|
+
# {
|
|
1358
|
+
# "accFillSz":"0",
|
|
1359
|
+
# "amendResult":"",
|
|
1360
|
+
# "avgPx":"",
|
|
1361
|
+
# "cTime":"1634548275191",
|
|
1362
|
+
# "category":"normal",
|
|
1363
|
+
# "ccy":"",
|
|
1364
|
+
# "clOrdId":"e847386590ce4dBC330547db94a08ba0",
|
|
1365
|
+
# "code":"0",
|
|
1366
|
+
# "execType":"",
|
|
1367
|
+
# "fee":"0",
|
|
1368
|
+
# "feeCcy":"USDT",
|
|
1369
|
+
# "fillFee":"0",
|
|
1370
|
+
# "fillFeeCcy":"",
|
|
1371
|
+
# "fillNotionalUsd":"",
|
|
1372
|
+
# "fillPx":"",
|
|
1373
|
+
# "fillSz":"0",
|
|
1374
|
+
# "fillTime":"",
|
|
1375
|
+
# "instId":"ETH-USDT",
|
|
1376
|
+
# "instType":"SPOT",
|
|
1377
|
+
# "lever":"",
|
|
1378
|
+
# "msg":"",
|
|
1379
|
+
# "notionalUsd":"451.4516256",
|
|
1380
|
+
# "ordId":"370257534141235201",
|
|
1381
|
+
# "ordType":"limit",
|
|
1382
|
+
# "pnl":"0",
|
|
1383
|
+
# "posSide":"",
|
|
1384
|
+
# "px":"60000",
|
|
1385
|
+
# "rebate":"0",
|
|
1386
|
+
# "rebateCcy":"ETH",
|
|
1387
|
+
# "reqId":"",
|
|
1388
|
+
# "side":"sell",
|
|
1389
|
+
# "slOrdPx":"",
|
|
1390
|
+
# "slTriggerPx":"",
|
|
1391
|
+
# "state":"live",
|
|
1392
|
+
# "sz":"0.007526",
|
|
1393
|
+
# "tag":"",
|
|
1394
|
+
# "tdMode":"cash",
|
|
1395
|
+
# "tgtCcy":"",
|
|
1396
|
+
# "tpOrdPx":"",
|
|
1397
|
+
# "tpTriggerPx":"",
|
|
1398
|
+
# "tradeId":"",
|
|
1399
|
+
# "uTime":"1634548275191"
|
|
1400
|
+
# }
|
|
1401
|
+
# ]
|
|
1402
|
+
# }
|
|
1403
|
+
#
|
|
1404
|
+
self.handle_my_trades(client, message)
|
|
1405
|
+
arg = self.safe_value(message, 'arg', {})
|
|
1406
|
+
channel = self.safe_string(arg, 'channel')
|
|
1407
|
+
orders = self.safe_value(message, 'data', [])
|
|
1408
|
+
ordersLength = len(orders)
|
|
1409
|
+
if ordersLength > 0:
|
|
1410
|
+
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
|
|
1411
|
+
if self.orders is None:
|
|
1412
|
+
self.orders = ArrayCacheBySymbolById(limit)
|
|
1413
|
+
self.triggerOrders = ArrayCacheBySymbolById(limit)
|
|
1414
|
+
stored = self.triggerOrders if (channel == 'orders-algo') else self.orders
|
|
1415
|
+
marketIds = []
|
|
1416
|
+
parsed = self.parse_orders(orders)
|
|
1417
|
+
for i in range(0, len(parsed)):
|
|
1418
|
+
order = parsed[i]
|
|
1419
|
+
stored.append(order)
|
|
1420
|
+
symbol = order['symbol']
|
|
1421
|
+
market = self.market(symbol)
|
|
1422
|
+
marketIds.append(market['id'])
|
|
1423
|
+
client.resolve(stored, channel)
|
|
1424
|
+
for i in range(0, len(marketIds)):
|
|
1425
|
+
messageHash = channel + ':' + marketIds[i]
|
|
1426
|
+
client.resolve(stored, messageHash)
|
|
1427
|
+
|
|
1428
|
+
def handle_my_trades(self, client: Client, message):
|
|
1429
|
+
#
|
|
1430
|
+
# {
|
|
1431
|
+
# "arg":{
|
|
1432
|
+
# "channel":"orders",
|
|
1433
|
+
# "instType":"SPOT"
|
|
1434
|
+
# },
|
|
1435
|
+
# "data":[
|
|
1436
|
+
# {
|
|
1437
|
+
# "accFillSz":"0",
|
|
1438
|
+
# "amendResult":"",
|
|
1439
|
+
# "avgPx":"",
|
|
1440
|
+
# "cTime":"1634548275191",
|
|
1441
|
+
# "category":"normal",
|
|
1442
|
+
# "ccy":"",
|
|
1443
|
+
# "clOrdId":"e847386590ce4dBC330547db94a08ba0",
|
|
1444
|
+
# "code":"0",
|
|
1445
|
+
# "execType":"",
|
|
1446
|
+
# "fee":"0",
|
|
1447
|
+
# "feeCcy":"USDT",
|
|
1448
|
+
# "fillFee":"0",
|
|
1449
|
+
# "fillFeeCcy":"",
|
|
1450
|
+
# "fillNotionalUsd":"",
|
|
1451
|
+
# "fillPx":"",
|
|
1452
|
+
# "fillSz":"0",
|
|
1453
|
+
# "fillTime":"",
|
|
1454
|
+
# "instId":"ETH-USDT",
|
|
1455
|
+
# "instType":"SPOT",
|
|
1456
|
+
# "lever":"",
|
|
1457
|
+
# "msg":"",
|
|
1458
|
+
# "notionalUsd":"451.4516256",
|
|
1459
|
+
# "ordId":"370257534141235201",
|
|
1460
|
+
# "ordType":"limit",
|
|
1461
|
+
# "pnl":"0",
|
|
1462
|
+
# "posSide":"",
|
|
1463
|
+
# "px":"60000",
|
|
1464
|
+
# "rebate":"0",
|
|
1465
|
+
# "rebateCcy":"ETH",
|
|
1466
|
+
# "reqId":"",
|
|
1467
|
+
# "side":"sell",
|
|
1468
|
+
# "slOrdPx":"",
|
|
1469
|
+
# "slTriggerPx":"",
|
|
1470
|
+
# "state":"live",
|
|
1471
|
+
# "sz":"0.007526",
|
|
1472
|
+
# "tag":"",
|
|
1473
|
+
# "tdMode":"cash",
|
|
1474
|
+
# "tgtCcy":"",
|
|
1475
|
+
# "tpOrdPx":"",
|
|
1476
|
+
# "tpTriggerPx":"",
|
|
1477
|
+
# "tradeId":"",
|
|
1478
|
+
# "uTime":"1634548275191"
|
|
1479
|
+
# }
|
|
1480
|
+
# ]
|
|
1481
|
+
# }
|
|
1482
|
+
#
|
|
1483
|
+
arg = self.safe_value(message, 'arg', {})
|
|
1484
|
+
channel = self.safe_string(arg, 'channel')
|
|
1485
|
+
rawOrders = self.safe_value(message, 'data', [])
|
|
1486
|
+
filteredOrders = []
|
|
1487
|
+
# filter orders with no last trade id
|
|
1488
|
+
for i in range(0, len(rawOrders)):
|
|
1489
|
+
rawOrder = rawOrders[i]
|
|
1490
|
+
tradeId = self.safe_string(rawOrder, 'tradeId', '')
|
|
1491
|
+
if len(tradeId) > 0:
|
|
1492
|
+
order = self.parse_order(rawOrder)
|
|
1493
|
+
filteredOrders.append(order)
|
|
1494
|
+
tradesLength = len(filteredOrders)
|
|
1495
|
+
if tradesLength == 0:
|
|
1496
|
+
return
|
|
1497
|
+
if self.myTrades is None:
|
|
1498
|
+
limit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
|
1499
|
+
self.myTrades = ArrayCacheBySymbolById(limit)
|
|
1500
|
+
myTrades = self.myTrades
|
|
1501
|
+
symbols: dict = {}
|
|
1502
|
+
for i in range(0, len(filteredOrders)):
|
|
1503
|
+
rawTrade = filteredOrders[i]
|
|
1504
|
+
trade = self.order_to_trade(rawTrade)
|
|
1505
|
+
myTrades.append(trade)
|
|
1506
|
+
symbol = trade['symbol']
|
|
1507
|
+
symbols[symbol] = True
|
|
1508
|
+
messageHash = channel + '::myTrades'
|
|
1509
|
+
client.resolve(self.myTrades, messageHash)
|
|
1510
|
+
tradeSymbols = list(symbols.keys())
|
|
1511
|
+
for i in range(0, len(tradeSymbols)):
|
|
1512
|
+
symbolMessageHash = messageHash + '::' + tradeSymbols[i]
|
|
1513
|
+
client.resolve(self.orders, symbolMessageHash)
|
|
1514
|
+
|
|
1515
|
+
async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
|
|
1516
|
+
"""
|
|
1517
|
+
:see: https://www.okx.com/docs-v5/en/#websocket-api-trade-place-order
|
|
1518
|
+
create a trade order
|
|
1519
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1520
|
+
:param str type: 'market' or 'limit'
|
|
1521
|
+
:param str side: 'buy' or 'sell'
|
|
1522
|
+
:param float amount: how much of currency you want to trade in units of base currency
|
|
1523
|
+
:param float|None [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
1524
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1525
|
+
:param boolean params['test']: test order, default False
|
|
1526
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1527
|
+
"""
|
|
1528
|
+
await self.load_markets()
|
|
1529
|
+
await self.authenticate()
|
|
1530
|
+
url = self.get_url('private', 'private')
|
|
1531
|
+
messageHash = str(self.nonce())
|
|
1532
|
+
op = None
|
|
1533
|
+
op, params = self.handle_option_and_params(params, 'createOrderWs', 'op', 'batch-orders')
|
|
1534
|
+
args = self.create_order_request(symbol, type, side, amount, price, params)
|
|
1535
|
+
ordType = self.safe_string(args, 'ordType')
|
|
1536
|
+
if (ordType == 'trigger') or (ordType == 'conditional') or (type == 'oco') or (type == 'move_order_stop') or (type == 'iceberg') or (type == 'twap'):
|
|
1537
|
+
raise BadRequest(self.id + ' createOrderWs() does not support algo trading. self.options["createOrderWs"]["op"] must be either order or batch-order')
|
|
1538
|
+
if (op != 'order') and (op != 'batch-orders'):
|
|
1539
|
+
raise BadRequest(self.id + ' createOrderWs() does not support algo trading. self.options["createOrderWs"]["op"] must be either order or privatePostTradeOrder or privatePostTradeOrderAlgo')
|
|
1540
|
+
request: dict = {
|
|
1541
|
+
'id': messageHash,
|
|
1542
|
+
'op': op,
|
|
1543
|
+
'args': [args],
|
|
1544
|
+
}
|
|
1545
|
+
return await self.watch(url, messageHash, request, messageHash)
|
|
1546
|
+
|
|
1547
|
+
def handle_place_orders(self, client: Client, message):
|
|
1548
|
+
#
|
|
1549
|
+
# batch-orders/order/cancel-order
|
|
1550
|
+
# {
|
|
1551
|
+
# "id": "1689281055",
|
|
1552
|
+
# "op": "batch-orders",
|
|
1553
|
+
# "code": "0",
|
|
1554
|
+
# "msg": '',
|
|
1555
|
+
# "data": [{
|
|
1556
|
+
# "tag": "e847386590ce4dBC",
|
|
1557
|
+
# "ordId": "599823446566084608",
|
|
1558
|
+
# "clOrdId": "e847386590ce4dBCb939511604f394b0",
|
|
1559
|
+
# "sCode": "0",
|
|
1560
|
+
# "sMsg": "Order successfully placed."
|
|
1561
|
+
# },
|
|
1562
|
+
# ...
|
|
1563
|
+
# ]
|
|
1564
|
+
# }
|
|
1565
|
+
#
|
|
1566
|
+
messageHash = self.safe_string(message, 'id')
|
|
1567
|
+
args = self.safe_value(message, 'data', [])
|
|
1568
|
+
# filter out partial errors
|
|
1569
|
+
args = self.filter_by(args, 'sCode', '0')
|
|
1570
|
+
# if empty means request failed and handle error
|
|
1571
|
+
if self.is_empty(args):
|
|
1572
|
+
method = self.safe_string(message, 'op')
|
|
1573
|
+
stringMsg = self.json(message)
|
|
1574
|
+
self.handle_errors(None, None, client.url, method, None, stringMsg, stringMsg, None, None)
|
|
1575
|
+
orders = self.parse_orders(args, None, None, None)
|
|
1576
|
+
first = self.safe_dict(orders, 0, {})
|
|
1577
|
+
client.resolve(first, messageHash)
|
|
1578
|
+
|
|
1579
|
+
async def edit_order_ws(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
|
|
1580
|
+
"""
|
|
1581
|
+
edit a trade order
|
|
1582
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-amend-order
|
|
1583
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-amend-multiple-orders
|
|
1584
|
+
:param str id: order id
|
|
1585
|
+
:param str symbol: unified symbol of the market to create an order in
|
|
1586
|
+
:param str type: 'market' or 'limit'
|
|
1587
|
+
:param str side: 'buy' or 'sell'
|
|
1588
|
+
:param float amount: how much of the currency you want to trade in units of the base currency
|
|
1589
|
+
:param float|None [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
1590
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1591
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1592
|
+
"""
|
|
1593
|
+
await self.load_markets()
|
|
1594
|
+
await self.authenticate()
|
|
1595
|
+
url = self.get_url('private', 'private')
|
|
1596
|
+
messageHash = str(self.nonce())
|
|
1597
|
+
op = None
|
|
1598
|
+
op, params = self.handle_option_and_params(params, 'editOrderWs', 'op', 'amend-order')
|
|
1599
|
+
args = self.edit_order_request(id, symbol, type, side, amount, price, params)
|
|
1600
|
+
request: dict = {
|
|
1601
|
+
'id': messageHash,
|
|
1602
|
+
'op': op,
|
|
1603
|
+
'args': [args],
|
|
1604
|
+
}
|
|
1605
|
+
return await self.watch(url, messageHash, self.extend(request, params), messageHash)
|
|
1606
|
+
|
|
1607
|
+
async def cancel_order_ws(self, id: str, symbol: Str = None, params={}) -> Order:
|
|
1608
|
+
"""
|
|
1609
|
+
:see: https://okx-docs.github.io/apidocs/websocket_api/en/#cancel-order-trade
|
|
1610
|
+
cancel multiple orders
|
|
1611
|
+
:param str id: order id
|
|
1612
|
+
:param str symbol: unified market symbol, default is None
|
|
1613
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1614
|
+
:param str [params.clOrdId]: client order id
|
|
1615
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1616
|
+
"""
|
|
1617
|
+
if symbol is None:
|
|
1618
|
+
raise BadRequest(self.id + ' cancelOrderWs() requires a symbol argument')
|
|
1619
|
+
await self.load_markets()
|
|
1620
|
+
await self.authenticate()
|
|
1621
|
+
url = self.get_url('private', 'private')
|
|
1622
|
+
messageHash = str(self.nonce())
|
|
1623
|
+
clientOrderId = self.safe_string_2(params, 'clOrdId', 'clientOrderId')
|
|
1624
|
+
params = self.omit(params, ['clientOrderId', 'clOrdId'])
|
|
1625
|
+
arg: dict = {
|
|
1626
|
+
'instId': self.market_id(symbol),
|
|
1627
|
+
}
|
|
1628
|
+
if clientOrderId is not None:
|
|
1629
|
+
arg['clOrdId'] = clientOrderId
|
|
1630
|
+
else:
|
|
1631
|
+
arg['ordId'] = id
|
|
1632
|
+
request: dict = {
|
|
1633
|
+
'id': messageHash,
|
|
1634
|
+
'op': 'cancel-order',
|
|
1635
|
+
'args': [self.extend(arg, params)],
|
|
1636
|
+
}
|
|
1637
|
+
return await self.watch(url, messageHash, request, messageHash)
|
|
1638
|
+
|
|
1639
|
+
async def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
|
|
1640
|
+
"""
|
|
1641
|
+
:see: https://www.okx.com/docs-v5/en/#order-book-trading-trade-ws-mass-cancel-order
|
|
1642
|
+
cancel multiple orders
|
|
1643
|
+
:param str[] ids: order ids
|
|
1644
|
+
:param str symbol: unified market symbol, default is None
|
|
1645
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1646
|
+
:returns dict: an list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1647
|
+
"""
|
|
1648
|
+
idsLength = len(ids)
|
|
1649
|
+
if idsLength > 20:
|
|
1650
|
+
raise BadRequest(self.id + ' cancelOrdersWs() accepts up to 20 ids at a time')
|
|
1651
|
+
if symbol is None:
|
|
1652
|
+
raise BadRequest(self.id + ' cancelOrdersWs() requires a symbol argument')
|
|
1653
|
+
await self.load_markets()
|
|
1654
|
+
await self.authenticate()
|
|
1655
|
+
url = self.get_url('private', 'private')
|
|
1656
|
+
messageHash = str(self.nonce())
|
|
1657
|
+
args = []
|
|
1658
|
+
for i in range(0, idsLength):
|
|
1659
|
+
arg: dict = {
|
|
1660
|
+
'instId': self.market_id(symbol),
|
|
1661
|
+
'ordId': ids[i],
|
|
1662
|
+
}
|
|
1663
|
+
args.append(arg)
|
|
1664
|
+
request: dict = {
|
|
1665
|
+
'id': messageHash,
|
|
1666
|
+
'op': 'batch-cancel-orders',
|
|
1667
|
+
'args': args,
|
|
1668
|
+
}
|
|
1669
|
+
return await self.watch(url, messageHash, self.deep_extend(request, params), messageHash)
|
|
1670
|
+
|
|
1671
|
+
async def cancel_all_orders_ws(self, symbol: Str = None, params={}):
|
|
1672
|
+
"""
|
|
1673
|
+
:see: https://docs.okx.com/websockets/#message-cancelAll
|
|
1674
|
+
cancel all open orders of a type. Only applicable to Option in Portfolio Margin mode, and MMP privilege is required.
|
|
1675
|
+
:param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
|
|
1676
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
1677
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
1678
|
+
"""
|
|
1679
|
+
if symbol is None:
|
|
1680
|
+
raise BadRequest(self.id + ' cancelAllOrdersWs() requires a symbol argument')
|
|
1681
|
+
await self.load_markets()
|
|
1682
|
+
await self.authenticate()
|
|
1683
|
+
market = self.market(symbol)
|
|
1684
|
+
if market['type'] != 'option':
|
|
1685
|
+
raise BadRequest(self.id + 'cancelAllOrdersWs is only applicable to Option in Portfolio Margin mode, and MMP privilege is required.')
|
|
1686
|
+
url = self.get_url('private', 'private')
|
|
1687
|
+
messageHash = str(self.nonce())
|
|
1688
|
+
request: dict = {
|
|
1689
|
+
'id': messageHash,
|
|
1690
|
+
'op': 'mass-cancel',
|
|
1691
|
+
'args': [self.extend({
|
|
1692
|
+
'instType': 'OPTION',
|
|
1693
|
+
'instFamily': market['id'],
|
|
1694
|
+
}, params)],
|
|
1695
|
+
}
|
|
1696
|
+
return await self.watch(url, messageHash, request, messageHash)
|
|
1697
|
+
|
|
1698
|
+
def handle_cancel_all_orders(self, client: Client, message):
|
|
1699
|
+
#
|
|
1700
|
+
# {
|
|
1701
|
+
# "id": "1512",
|
|
1702
|
+
# "op": "mass-cancel",
|
|
1703
|
+
# "data": [
|
|
1704
|
+
# {
|
|
1705
|
+
# "result": True
|
|
1706
|
+
# }
|
|
1707
|
+
# ],
|
|
1708
|
+
# "code": "0",
|
|
1709
|
+
# "msg": ""
|
|
1710
|
+
# }
|
|
1711
|
+
#
|
|
1712
|
+
messageHash = self.safe_string(message, 'id')
|
|
1713
|
+
data = self.safe_value(message, 'data', [])
|
|
1714
|
+
client.resolve(data, messageHash)
|
|
1715
|
+
|
|
1716
|
+
def handle_subscription_status(self, client: Client, message):
|
|
1717
|
+
#
|
|
1718
|
+
# {event: 'subscribe', arg: {channel: "tickers", instId: "BTC-USDT"}}
|
|
1719
|
+
#
|
|
1720
|
+
# channel = self.safe_string(message, "channel")
|
|
1721
|
+
# client.subscriptions[channel] = message
|
|
1722
|
+
return message
|
|
1723
|
+
|
|
1724
|
+
def handle_authenticate(self, client: Client, message):
|
|
1725
|
+
#
|
|
1726
|
+
# {event: "login", success: True}
|
|
1727
|
+
#
|
|
1728
|
+
future = self.safe_value(client.futures, 'authenticated')
|
|
1729
|
+
future.resolve(True)
|
|
1730
|
+
|
|
1731
|
+
def ping(self, client):
|
|
1732
|
+
# okex does not support built-in ws protocol-level ping-pong
|
|
1733
|
+
# instead it requires custom text-based ping-pong
|
|
1734
|
+
return 'ping'
|
|
1735
|
+
|
|
1736
|
+
def handle_pong(self, client: Client, message):
|
|
1737
|
+
client.lastPong = self.milliseconds()
|
|
1738
|
+
return message
|
|
1739
|
+
|
|
1740
|
+
def handle_error_message(self, client: Client, message):
|
|
1741
|
+
#
|
|
1742
|
+
# {event: 'error', msg: "Illegal request: {"op":"subscribe","args":["spot/ticker:BTC-USDT"]}", code: "60012"}
|
|
1743
|
+
# {event: 'error", msg: "channel:ticker,instId:BTC-USDT doesn"t exist", code: "60018"}
|
|
1744
|
+
#
|
|
1745
|
+
errorCode = self.safe_string(message, 'code')
|
|
1746
|
+
try:
|
|
1747
|
+
if errorCode and errorCode != '0':
|
|
1748
|
+
feedback = self.id + ' ' + self.json(message)
|
|
1749
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
|
1750
|
+
messageString = self.safe_value(message, 'msg')
|
|
1751
|
+
if messageString is not None:
|
|
1752
|
+
self.throw_broadly_matched_exception(self.exceptions['broad'], messageString, feedback)
|
|
1753
|
+
raise ExchangeError(feedback)
|
|
1754
|
+
except Exception as e:
|
|
1755
|
+
client.reject(e)
|
|
1756
|
+
return False
|
|
1757
|
+
return message
|
|
1758
|
+
|
|
1759
|
+
def handle_message(self, client: Client, message):
|
|
1760
|
+
if not self.handle_error_message(client, message):
|
|
1761
|
+
return
|
|
1762
|
+
#
|
|
1763
|
+
# {event: 'subscribe', arg: {channel: "tickers", instId: "BTC-USDT"}}
|
|
1764
|
+
# {event: 'login", msg: '", code: "0"}
|
|
1765
|
+
#
|
|
1766
|
+
# {
|
|
1767
|
+
# "arg": {channel: "tickers", instId: "BTC-USDT"},
|
|
1768
|
+
# "data": [
|
|
1769
|
+
# {
|
|
1770
|
+
# "instType": "SPOT",
|
|
1771
|
+
# "instId": "BTC-USDT",
|
|
1772
|
+
# "last": "31500.1",
|
|
1773
|
+
# "lastSz": "0.00001754",
|
|
1774
|
+
# "askPx": "31500.1",
|
|
1775
|
+
# "askSz": "0.00998144",
|
|
1776
|
+
# "bidPx": "31500",
|
|
1777
|
+
# "bidSz": "3.05652439",
|
|
1778
|
+
# "open24h": "31697",
|
|
1779
|
+
# "high24h": "32248",
|
|
1780
|
+
# "low24h": "31165.6",
|
|
1781
|
+
# "sodUtc0": "31385.5",
|
|
1782
|
+
# "sodUtc8": "32134.9",
|
|
1783
|
+
# "volCcy24h": "503403597.38138519",
|
|
1784
|
+
# "vol24h": "15937.10781721",
|
|
1785
|
+
# "ts": "1626526618762"
|
|
1786
|
+
# }
|
|
1787
|
+
# ]
|
|
1788
|
+
# }
|
|
1789
|
+
#
|
|
1790
|
+
# {event: 'error', msg: "Illegal request: {"op":"subscribe","args":["spot/ticker:BTC-USDT"]}", code: "60012"}
|
|
1791
|
+
# {event: 'error", msg: "channel:ticker,instId:BTC-USDT doesn"t exist", code: "60018"}
|
|
1792
|
+
# {event: 'error', msg: "Invalid OK_ACCESS_KEY", code: "60005"}
|
|
1793
|
+
# {
|
|
1794
|
+
# "event": "error",
|
|
1795
|
+
# "msg": "Illegal request: {"op":"login","args":["de89b035-b233-44b2-9a13-0ccdd00bda0e","7KUcc8YzQhnxBE3K","1626691289","H57N99mBt5NvW8U19FITrPdOxycAERFMaapQWRqLaSE="]}",
|
|
1796
|
+
# "code": "60012"
|
|
1797
|
+
# }
|
|
1798
|
+
#
|
|
1799
|
+
#
|
|
1800
|
+
#
|
|
1801
|
+
if message == 'pong':
|
|
1802
|
+
self.handle_pong(client, message)
|
|
1803
|
+
return
|
|
1804
|
+
# table = self.safe_string(message, 'table')
|
|
1805
|
+
# if table is None:
|
|
1806
|
+
event = self.safe_string_2(message, 'event', 'op')
|
|
1807
|
+
if event is not None:
|
|
1808
|
+
methods: dict = {
|
|
1809
|
+
# 'info': self.handleSystemStatus,
|
|
1810
|
+
# 'book': 'handleOrderBook',
|
|
1811
|
+
'login': self.handle_authenticate,
|
|
1812
|
+
'subscribe': self.handle_subscription_status,
|
|
1813
|
+
'order': self.handle_place_orders,
|
|
1814
|
+
'batch-orders': self.handle_place_orders,
|
|
1815
|
+
'amend-order': self.handle_place_orders,
|
|
1816
|
+
'batch-amend-orders': self.handle_place_orders,
|
|
1817
|
+
'cancel-order': self.handle_place_orders,
|
|
1818
|
+
'mass-cancel': self.handle_cancel_all_orders,
|
|
1819
|
+
}
|
|
1820
|
+
method = self.safe_value(methods, event)
|
|
1821
|
+
if method is not None:
|
|
1822
|
+
method(client, message)
|
|
1823
|
+
else:
|
|
1824
|
+
arg = self.safe_value(message, 'arg', {})
|
|
1825
|
+
channel = self.safe_string(arg, 'channel')
|
|
1826
|
+
methods: dict = {
|
|
1827
|
+
'bbo-tbt': self.handle_order_book, # newly added channel that sends tick-by-tick Level 1 data, all API users can subscribe, public depth channel, verification not required
|
|
1828
|
+
'books': self.handle_order_book, # all API users can subscribe, public depth channel, verification not required
|
|
1829
|
+
'books5': self.handle_order_book, # all API users can subscribe, public depth channel, verification not required, data feeds will be delivered every 100ms(vs. every 200ms now)
|
|
1830
|
+
'books50-l2-tbt': self.handle_order_book, # only users who're VIP4 and above can subscribe, identity verification required before subscription
|
|
1831
|
+
'books-l2-tbt': self.handle_order_book, # only users who're VIP5 and above can subscribe, identity verification required before subscription
|
|
1832
|
+
'tickers': self.handle_ticker,
|
|
1833
|
+
'positions': self.handle_positions,
|
|
1834
|
+
'index-tickers': self.handle_ticker,
|
|
1835
|
+
'sprd-tickers': self.handle_ticker,
|
|
1836
|
+
'block-tickers': self.handle_ticker,
|
|
1837
|
+
'trades': self.handle_trades,
|
|
1838
|
+
'account': self.handle_balance,
|
|
1839
|
+
'funding-rate': self.handle_funding_rate,
|
|
1840
|
+
# 'margin_account': self.handle_balance,
|
|
1841
|
+
'orders': self.handle_orders,
|
|
1842
|
+
'orders-algo': self.handle_orders,
|
|
1843
|
+
'liquidation-orders': self.handle_liquidation,
|
|
1844
|
+
'balance_and_position': self.handle_balance_and_position,
|
|
1845
|
+
}
|
|
1846
|
+
method = self.safe_value(methods, channel)
|
|
1847
|
+
if method is None:
|
|
1848
|
+
if channel.find('candle') == 0:
|
|
1849
|
+
self.handle_ohlcv(client, message)
|
|
1850
|
+
else:
|
|
1851
|
+
method(client, message)
|