diff --git a/.gitignore b/.gitignore index accb26a..f578a40 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,500 @@ -docs/_build + +# Created by https://www.toptal.com/developers/gitignore/api/linux,jetbrains+all,pycharm+all,pycharm+iml,pycharm,django,python +# Edit at https://www.toptal.com/developers/gitignore?templates=linux,jetbrains+all,pycharm+all,pycharm+iml,pycharm,django,python +*.pyc +db.sqlite3 +venv/ +pyvenv/ +.vscode/ +.env +.idea +static/ +dump.sql + +### Django ### +*.log +*.pot +*.pyc +__pycache__/ +local_settings.py +*.sqlite +db.sqlite3-journal +media + +# If your build process includes running collectstatic, then you probably don't need or want to include staticfiles/ +# in your Git repository. Update and uncomment the following line accordingly. +# /staticfiles/ + +### Django.Python Stack ### +# Byte-compiled / optimized / DLL files +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +pytestdebug.log + +# Translations +*.mo + +# Django stuff: + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ +doc/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +### JetBrains+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### JetBrains+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + +.idea/ + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + +*.iml +modules.xml +.idea/misc.xml +*.ipr + +# Sonarlint plugin +.idea/sonarlint + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### PyCharm ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### PyCharm Patch ### +# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 + +# *.iml +# modules.xml +# .idea/misc.xml +# *.ipr + +# Sonarlint plugin +# https://plugins.jetbrains.com/plugin/7973-sonarlint +.idea/**/sonarlint/ + +# SonarQube Plugin +# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin +.idea/**/sonarIssues.xml + +# Markdown Navigator plugin +# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced +.idea/**/markdown-navigator.xml +.idea/**/markdown-navigator-enh.xml +.idea/**/markdown-navigator/ + +# Cache file creation bug +# See https://youtrack.jetbrains.com/issue/JBR-2257 +.idea/$CACHE_FILE$ + +# CodeStream plugin +# https://plugins.jetbrains.com/plugin/12206-codestream +.idea/codestream.xml + +### PyCharm+all ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### PyCharm+all Patch ### +# Ignores the whole .idea folder and all .iml files +# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360 + + +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + + +# Sonarlint plugin + +### PyCharm+iml ### +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### PyCharm+iml Patch ### +# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023 + + +### Python ### +# Byte-compiled / optimized / DLL files + +# C extensions + +# Distribution / packaging + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. + +# Installer logs + +# Unit test / coverage reports + +# Translations + +# Django stuff: + +# Flask stuff: + +# Scrapy stuff: + +# Sphinx documentation + +# PyBuilder + +# Jupyter Notebook + +# IPython + +# pyenv + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow + +# Celery stuff + +# SageMath parsed files + +# Environments + +# Spyder project settings + +# Rope project settings + +# mkdocs documentation + +# mypy + +# Pyre type checker + +# pytype static type analyzer + +# End of https://www.toptal.com/developers/gitignore/api/linux,jetbrains+all,pycharm+all,pycharm+iml,pycharm,django,python diff --git a/README.rst b/README.rst index f65a56f..87b93f4 100644 --- a/README.rst +++ b/README.rst @@ -1,7 +1,9 @@ =============================== -Welcome to python-kucoin v2.1.1 +Welcome to python-kucoin v2.1.3 =============================== +Last Updated 4th Oct 2021 + .. image:: https://img.shields.io/pypi/v/python-kucoin.svg :target: https://pypi.python.org/pypi/python-kucoin @@ -21,7 +23,7 @@ Welcome to python-kucoin v2.1.1 :target: https://pypi.python.org/pypi/python-kucoin This is an unofficial Python wrapper for the `Kucoin exchanges REST and Websocket API v2 `_. -I am in no way affiliated with Kucoin, use at your own risk. +I am in no way affiliated with `Kucoin `_, use at your own risk. PyPi @@ -158,6 +160,9 @@ Note only for python3.5+ ksm = await KucoinSocketManager.create(loop, client, handle_evt) + # for private topics such as '/account/balance' pass private=True + ksm_private = await KucoinSocketManager.create(loop, client, handle_evt, private=True) + # Note: try these one at a time, if all are on you will see a lot of output # ETH-USDT Market Ticker @@ -175,7 +180,7 @@ Note only for python3.5+ # Level 3 market data await ksm.subscribe('/market/level3:BTC-USDT') # Account balance - must be authenticated - await ksm.subscribe('/account/balance') + await ksm_private.subscribe('/account/balance') while True: print("sleeping to keep loop open") diff --git a/docs/changelog.rst b/docs/changelog.rst index b7f98e3..fd13861 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -1,6 +1,34 @@ Changelog ========= +v2.1.3 - 2021-10-04 +^^^^^^^^^^^^^^^^^^^^ + +**Added** + +- chain to get_deposit_address +- get_accounts to include currency and account_type params +- get_account_activity to use new params +- get_status to retrieve service status +- get and cancel order by orderOid +- trade_type to market and limit orders +- v2 and v3 API version options + +**Deprecated** + +- get_account_holds + +v2.1.2 - 2019-04-17 +^^^^^^^^^^^^^^^^^^^^ + +**Added** + +- exception if using a private websocket topic but not connected with private + +**Removed** + +- removed py3.6 type annotations for py3.5 support + v2.1.1 - 2019-04-17 ^^^^^^^^^^^^^^^^^^^^ diff --git a/docs/index.rst b/docs/index.rst index a244709..0d80449 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -15,6 +15,7 @@ Contents account trading market + sub_accounts websockets exceptions changelog diff --git a/docs/overview.rst b/docs/overview.rst index dac280c..ceeb1d4 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -22,7 +22,7 @@ For previous v1 API install with Register on Kucoin ------------------- -Firstly register an account with `Kucoin `_. +Firstly register an account with `Kucoin `_. To test on the Sandbox register with `Kucoin Sandbox `_. diff --git a/docs/sub_accounts.rst b/docs/sub_accounts.rst new file mode 100644 index 0000000..4adf759 --- /dev/null +++ b/docs/sub_accounts.rst @@ -0,0 +1,6 @@ +Sub Account Endpoints +===================== + +.. autoclass:: kucoin.client.Client + :members: get_symbols, get_ticker, get_24hr_stats, get_markets, get_order_book, get_full_order_book, get_full_order_book_level3, get_trade_histories, get_kline_data, get_historical_orders + :noindex: diff --git a/docs/websockets.rst b/docs/websockets.rst index 619a31b..6c3d394 100644 --- a/docs/websockets.rst +++ b/docs/websockets.rst @@ -1,11 +1,12 @@ Websockets ========== -Note: The websocket client is only available for python3.6+ +Note: The websocket client is only available for python3.5+ This feature is still in development so check the documentation around message topics here https://docs.kucoin.com/#websocket-feed +For private topics such as '/account/balance' pass private=True to the KucoinSocketManager, see example below TODO: ----- @@ -76,6 +77,9 @@ Sample Code ksm = await KucoinSocketManager.create(loop, client, handle_evt) + # for private topics such as '/account/balance' pass private=True + ksm_private = await KucoinSocketManager.create(loop, client, handle_evt, private=True) + # Note: try these one at a time, if all are on you will see a lot of output # ETH-USDT Market Ticker @@ -93,7 +97,7 @@ Sample Code # Level 3 market data await ksm.subscribe('/market/level3:BTC-USDT') # Account balance - must be authenticated - await ksm.subscribe('/account/balance') + await ksm_private.subscribe('/account/balance') while True: print("sleeping to keep loop open") diff --git a/kucoin/__init__.py b/kucoin/__init__.py index 65aa491..7467b1a 100644 --- a/kucoin/__init__.py +++ b/kucoin/__init__.py @@ -4,4 +4,4 @@ """ -__version__ = '2.1.1' +__version__ = '2.1.3' diff --git a/kucoin/client.py b/kucoin/client.py index b597a76..bd4d96a 100644 --- a/kucoin/client.py +++ b/kucoin/client.py @@ -409,7 +409,8 @@ def create_account(self, account_type, currency): return self._post('accounts', True, data=data) - def get_account_activity(self, currency=None, direction=None, biz_type=None, start=None, end=None, page=None, limit=None): + def get_account_activity(self, currency=None, direction=None, biz_type=None, start=None, end=None, page=None, + limit=None): """Get list of account activity https://docs.kucoin.com/#get-account-history @@ -501,6 +502,42 @@ def get_account_activity(self, currency=None, direction=None, biz_type=None, sta return self._get('accounts/ledgers', True, data=data) + def get_transferable(self, currency, account_type): + """Get the transferable balance of a specified account + + https://docs.kucoin.com/#get-the-transferable + + :param currency: Currency code + :type currency: string + :param account_type: Account type - main, trade, margin or pool + :type account_type: string + + .. code:: python + + accounts = client.get_transferable('BTC', 'trade') + + :returns: API Response + + .. code-block:: python + + { + "currency": "BTC", + "balance": "0", + "available": "0", + "holds": "0", + "transferable": "0" + } + + :raises: KucoinResponseException, KucoinAPIException + + """ + + data = { + 'currency': currency, + 'type': account_type.upper(), + } + return self._get('accounts/transferable', True, data=data) + def create_inner_transfer(self, currency, from_type, to_type, amount, order_id=None): """Transfer fund among accounts on the platform @@ -581,17 +618,19 @@ def create_deposit_address(self, currency, chain=None): return self._post('deposit-addresses', True, data=data) - def get_deposit_address(self, currency): + def get_deposit_address(self, currency, chain=None): """Get deposit address for a currency https://docs.kucoin.com/#get-deposit-address :param currency: Name of currency + :param chain: chain name of currency :type currency: string + :type chain: string .. code:: python - address = client.get_deposit_address('USDT') + address = client.get_deposit_address('USDT','TRC20') :returns: ApiResponse @@ -610,8 +649,10 @@ def get_deposit_address(self, currency): data = { 'currency': currency } + if chain is not None: + data['chain'] = chain - return self._get('deposit-addresses', True, api_version=self.API_VERSION2, data=data) + return self._get('deposit-addresses', True, data=data) def get_deposits(self, currency=None, status=None, start=None, end=None, page=None, limit=None): """Get deposit records for a currency @@ -761,14 +802,15 @@ def get_withdrawals(self, currency=None, status=None, start=None, end=None, page return self._get('withdrawals', True, data=data) - def get_withdrawal_quotas(self, currency): + def get_withdrawal_quotas(self, currency, chain=None): """Get withdrawal quotas for a currency https://docs.kucoin.com/#get-withdrawal-quotas :param currency: Name of currency :type currency: string - + :param chain: The chain name of currency, e.g. The available value for USDT are OMNI, ERC20, TRC20, default is ERC20. This only apply for multi-chain currency, and there is no need for single chain currency. + :type chain: string .. code:: python quotas = client.get_withdrawal_quotas('ETH') @@ -796,10 +838,12 @@ def get_withdrawal_quotas(self, currency): data = { 'currency': currency } + if chain: + data['chain'] = chain return self._get('withdrawals/quotas', True, data=data) - def create_withdrawal(self, currency, amount, address, memo=None, is_inner=False, remark=None): + def create_withdrawal(self, currency, amount, address, memo=None, is_inner=False, remark=None, chain=None): """Process a withdrawal https://docs.kucoin.com/#apply-withdraw @@ -812,10 +856,12 @@ def create_withdrawal(self, currency, amount, address, memo=None, is_inner=False :type address: string :param memo: (optional) Remark to the withdrawal address :type memo: string - :param is_inner: (optional) Remark to the withdrawal address + :param is_inner: (optional) Internal withdrawal or not :type is_inner: bool :param remark: (optional) Remark :type remark: string + :param chain: (optional) The chain name of currency, e.g. The available value for USDT are OMNI, ERC20, TRC20, default is ERC20. This only apply for multi-chain currency, and there is no need for single chain currency. + :type chain: string .. code:: python @@ -845,6 +891,8 @@ def create_withdrawal(self, currency, amount, address, memo=None, is_inner=False data['isInner'] = is_inner if remark: data['remark'] = remark + if chain: + data['chain'] = chain return self._post('withdrawals', True, data=data) @@ -871,8 +919,9 @@ def cancel_withdrawal(self, withdrawal_id): # Order Endpoints def create_market_order( - self, symbol, side, size=None, funds=None, client_oid=None, remark=None, stp=None, trade_type=None - ): + self, symbol, side, size=None, funds=None, + client_oid=None, remark=None, stop=None, stop_price=None, + stp=None, trade_type=None): """Create a market order One of size or funds must be set @@ -891,6 +940,10 @@ def create_market_order( :type client_oid: string :param remark: (optional) remark for the order, max 100 utf8 characters :type remark: string + :param stop: (optional) stop type loss or entry - requires stop_price + :type stop: string + :param stop_price: (optional) trigger price for stop order + :type stop_price: string :param stp: (optional) self trade protection CN, CO, CB or DC (default is None) :type stp: string :param trade_type: (optional) The type of trading : TRADE(Spot Trade), MARGIN_TRADE (Margin Trade). Default is TRADE @@ -918,6 +971,12 @@ def create_market_order( if size and funds: raise MarketOrderException('Need size or fund parameter not both') + if stop and not stop_price: + raise LimitOrderException('Stop order needs stop_price') + + if stop_price and not stop: + raise LimitOrderException('Stop order type required with stop_price') + data = { 'side': side, 'symbol': symbol, @@ -934,6 +993,9 @@ def create_market_order( data['clientOid'] = flat_uuid() if remark: data['remark'] = remark + if stop: + data['stop'] = stop + data['stopPrice'] = stop_price if stp: data['stp'] = stp if trade_type: