diff --git a/.github/workflows/_build.yaml b/.github/workflows/_build.yaml index 8c42e2e5..97be70d7 100644 --- a/.github/workflows/_build.yaml +++ b/.github/workflows/_build.yaml @@ -18,12 +18,23 @@ on: type: string required: true -permissions: read-all +permissions: + contents: read jobs: Build: runs-on: ${{ inputs.os }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: @@ -66,7 +77,7 @@ jobs: run: python -m build - name: Store the distribution packages - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 # upload artifacts with the oldest supported version if: runner.os == 'linux' && inputs.python-version == '3.11' with: diff --git a/.github/workflows/_build_doc.yaml b/.github/workflows/_build_doc.yaml index f4d38723..f9ad3a36 100644 --- a/.github/workflows/_build_doc.yaml +++ b/.github/workflows/_build_doc.yaml @@ -17,12 +17,18 @@ on: type: string required: true -permissions: read-all +permissions: + contents: read jobs: Build: runs-on: ${{ inputs.os }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + egress-policy: audit + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -34,9 +40,10 @@ jobs: - name: Install dependencies run: | sudo apt update - sudo apt install -y pandoc - python -m pip install --upgrade pip - python -m pip install -r doc/requirements.txt + DEBIAN_FRONTEND=noninteractive sudo apt install -y pandoc + python -m pip install --user -r doc/requirements.txt + python -m pip install --user --upgrade pip + python -m pip install --user . - name: Build the documentation - run: cd doc && make html + run: make doc diff --git a/.github/workflows/_codecov.yaml b/.github/workflows/_codecov.yaml index 80a3fb21..82dd5bbe 100644 --- a/.github/workflows/_codecov.yaml +++ b/.github/workflows/_codecov.yaml @@ -33,7 +33,8 @@ on: FUTURES_SANDBOX_SECRET: required: true -permissions: read-all +permissions: + contents: read jobs: CodeCov: @@ -44,6 +45,24 @@ jobs: PYTHON: ${{ inputs.python-version }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.codecov.io:443 + api.kraken.com:443 + cli.codecov.io:443 + demo-futures.kraken.com:443 + files.pythonhosted.org:443 + futures.kraken.com:443 + github.com:443 + pypi.org:443 + storage.googleapis.com:443 + ws-auth.kraken.com:443 + ws.kraken.com:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 @@ -56,7 +75,7 @@ jobs: run: python -m pip install --upgrade pip - name: Install package - run: python -m pip install ".[test]" + run: python -m pip install ".[dev,test]" - name: Generate coverage report env: @@ -66,10 +85,16 @@ jobs: FUTURES_SECRET_KEY: ${{ secrets.FUTURES_SECRET_KEY }} FUTURES_SANDBOX_KEY: ${{ secrets.FUTURES_SANDBOX_KEY }} FUTURES_SANDBOX_SECRET: ${{ secrets.FUTURES_SANDBOX_SECRET }} - run: pytest -vv --cov --cov-report=xml:coverage.xml -m "not flaky" tests + run: pytest -vv --cov --cov-report=xml:coverage.xml tests + + - name: Export coverage report + uses: actions/upload-artifact@v4 + with: + name: coverage + path: coverage.xml - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 with: token: ${{ secrets.CODECOV_TOKEN }} files: coverage.xml diff --git a/.github/workflows/_codeql.yaml b/.github/workflows/_codeql.yaml index 6bcdaedc..0d17fbab 100644 --- a/.github/workflows/_codeql.yaml +++ b/.github/workflows/_codeql.yaml @@ -30,12 +30,25 @@ jobs: # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.github.com:443 + github.com:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + - name: "Dependency Review" + if: github.event_name == 'pull_request' + uses: actions/dependency-review-action@0efb1d1d84fc9633afcdaad14c485cbbc90ef46c # v2.5.1 + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 with: languages: python # If you wish to specify custom queries, you can do so here or in a config file. @@ -48,7 +61,7 @@ jobs: # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 # ℹī¸ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun @@ -61,6 +74,6 @@ jobs: # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@23acc5c183826b7a8a97bce3cecc52db901f8251 # v3.25.10 with: category: "/language:python" diff --git a/.github/workflows/_pre_commit.yaml b/.github/workflows/_pre_commit.yaml index 4b35e0b9..5932d972 100644 --- a/.github/workflows/_pre_commit.yaml +++ b/.github/workflows/_pre_commit.yaml @@ -10,12 +10,24 @@ name: Pre-Commit on: workflow_call: -permissions: read-all +permissions: + contents: read jobs: Pre-Commit: runs-on: ubuntu-latest steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + github.com:443 + proxy.golang.org:443 + pypi.org:443 + registry.npmjs.org:443 - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 - - uses: pre-commit/action@v3.0.1 + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 diff --git a/.github/workflows/_pypi_publish.yaml b/.github/workflows/_pypi_publish.yaml index a304e3ba..bfd1426f 100644 --- a/.github/workflows/_pypi_publish.yaml +++ b/.github/workflows/_pypi_publish.yaml @@ -20,23 +20,25 @@ jobs: publish-to-pypi: name: Publish Python distribution to PyPI runs-on: ubuntu-latest - permissions: id-token: write # IMPORTANT: this permission is mandatory for OIDC publishing - environment: name: pypi url: https://pypi.org/p/python-cmethods - steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + egress-policy: audit + - name: Download all the distributions - uses: actions/download-artifact@v4 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: python-package-distributions path: dist/ - name: Publish package distributions to PyPI (optional - testpypi) - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # release/v1 with: password: ${{ secrets.API_TOKEN }} repository-url: https://upload.pypi.org/legacy/ diff --git a/.github/workflows/_pypi_test_publish.yaml b/.github/workflows/_pypi_test_publish.yaml index 454f8a66..93840335 100644 --- a/.github/workflows/_pypi_test_publish.yaml +++ b/.github/workflows/_pypi_test_publish.yaml @@ -26,14 +26,19 @@ jobs: name: testpypi url: https://test.pypi.org/p/python-cmethods steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + egress-policy: audit + - name: Download all the distributions - uses: actions/download-artifact@v4 + uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: python-package-distributions path: dist/ - name: Publish package distributions to PyPI (optional - testpypi) - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@ec4db0b4ddc65acdf4bff5fa45ac92d78b56bdf0 # release/v1 with: password: ${{ secrets.API_TOKEN }} repository-url: https://test.pypi.org/legacy/ diff --git a/.github/workflows/_test_futures_private.yaml b/.github/workflows/_test_futures_private.yaml index eba3c684..755ad35b 100644 --- a/.github/workflows/_test_futures_private.yaml +++ b/.github/workflows/_test_futures_private.yaml @@ -30,13 +30,26 @@ on: FUTURES_SANDBOX_SECRET: required: true -permissions: read-all +permissions: + contents: read jobs: Test-Futures: name: Test ${{ inputs.os }} ${{ inputs.python-version }} runs-on: ${{ inputs.os }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + demo-futures.kraken.com:443 + files.pythonhosted.org:443 + futures.kraken.com:443 + github.com:443 + pypi.org:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/_test_futures_public.yaml b/.github/workflows/_test_futures_public.yaml index ffaf99d3..a6c34b3d 100644 --- a/.github/workflows/_test_futures_public.yaml +++ b/.github/workflows/_test_futures_public.yaml @@ -20,13 +20,25 @@ on: type: string required: true -permissions: read-all +permissions: + contents: read jobs: Test-Futures: name: Test ${{ inputs.os }} ${{ inputs.python-version }} runs-on: ${{ inputs.os }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + files.pythonhosted.org:443 + futures.kraken.com:443 + github.com:443 + pypi.org:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/_test_nft_private.yaml b/.github/workflows/_test_nft_private.yaml index be7306c6..ed8b6439 100644 --- a/.github/workflows/_test_nft_private.yaml +++ b/.github/workflows/_test_nft_private.yaml @@ -22,13 +22,25 @@ on: SPOT_SECRET_KEY: required: true -permissions: read-all +permissions: + contents: read jobs: Test-NFT: name: Test ${{ inputs.os }} ${{ inputs.python-version }} runs-on: ${{ inputs.os }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.kraken.com:443 + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/_test_nft_public.yaml b/.github/workflows/_test_nft_public.yaml index a1a5c05f..30eb816a 100644 --- a/.github/workflows/_test_nft_public.yaml +++ b/.github/workflows/_test_nft_public.yaml @@ -18,13 +18,25 @@ on: type: string required: true -permissions: read-all +permissions: + contents: read jobs: Test-NFT: name: Test ${{ inputs.os }} ${{ inputs.python-version }} runs-on: ${{ inputs.os }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.kraken.com:443 + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/_test_spot_private.yaml b/.github/workflows/_test_spot_private.yaml index c509fb45..e1785c39 100644 --- a/.github/workflows/_test_spot_private.yaml +++ b/.github/workflows/_test_spot_private.yaml @@ -27,13 +27,27 @@ on: SPOT_SECRET_KEY: required: true -permissions: read-all +permissions: + contents: read jobs: Test-Spot: name: Test ${{ inputs.os }} ${{ inputs.python-version }} runs-on: ${{ inputs.os }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.kraken.com:443 + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + ws-auth.kraken.com:443 + ws.kraken.com:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/_test_spot_public.yaml b/.github/workflows/_test_spot_public.yaml index 9a05f260..bdafe495 100644 --- a/.github/workflows/_test_spot_public.yaml +++ b/.github/workflows/_test_spot_public.yaml @@ -20,13 +20,25 @@ on: type: string required: true -permissions: read-all +permissions: + contents: read jobs: Test-Spot: name: Test ${{ inputs.os }} ${{ inputs.python-version }} runs-on: ${{ inputs.os }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + disable-sudo: true + egress-policy: block + allowed-endpoints: > + api.kraken.com:443 + files.pythonhosted.org:443 + github.com:443 + pypi.org:443 + - name: Checkout repository uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 diff --git a/.github/workflows/dependabot_auto_approve.yaml b/.github/workflows/dependabot_auto_merge.yaml similarity index 83% rename from .github/workflows/dependabot_auto_approve.yaml rename to .github/workflows/dependabot_auto_merge.yaml index dc91b0d2..986a0e6d 100644 --- a/.github/workflows/dependabot_auto_approve.yaml +++ b/.github/workflows/dependabot_auto_merge.yaml @@ -20,17 +20,24 @@ jobs: runs-on: ubuntu-latest if: ${{ github.actor == 'dependabot[bot]' }} steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + egress-policy: audit + - name: Dependabot metadata id: dependabot-metadata - uses: dependabot/fetch-metadata@v2.1.0 + uses: dependabot/fetch-metadata@5e5f99653a5b510e8555840e80cbf1514ad4af38 # v2.1.0 with: github-token: "${{ secrets.GITHUB_TOKEN }}" + - name: Approve a PR if: ${{ steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' }} run: gh pr review --approve "$PR_URL" env: PR_URL: ${{ github.event.pull_request.html_url }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Enable auto-merge for Dependabot PRs if: ${{ steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' }} run: gh pr merge --auto --squash "$PR_URL" diff --git a/.github/workflows/manual_build.yaml b/.github/workflows/manual_build.yaml index 52b51242..039781a2 100644 --- a/.github/workflows/manual_build.yaml +++ b/.github/workflows/manual_build.yaml @@ -12,7 +12,8 @@ name: PR Manual Build on: workflow_dispatch: -permissions: read-all +permissions: + contents: read jobs: Build: diff --git a/.github/workflows/manual_codeql.yaml b/.github/workflows/manual_codeql.yaml index 028abe7b..a7ecbf95 100644 --- a/.github/workflows/manual_codeql.yaml +++ b/.github/workflows/manual_codeql.yaml @@ -12,7 +12,11 @@ name: PR Manual CodeQL on: workflow_dispatch: -permissions: read-all +# Don't change this permissions. These must match those of the analyze job. +permissions: + actions: read + contents: read + security-events: write jobs: CodeQL: diff --git a/.github/workflows/manual_pre_commit.yaml b/.github/workflows/manual_pre_commit.yaml index b61d638b..08b29526 100644 --- a/.github/workflows/manual_pre_commit.yaml +++ b/.github/workflows/manual_pre_commit.yaml @@ -13,7 +13,8 @@ name: PR Manual Pre-Commit on: workflow_dispatch: -permissions: read-all +permissions: + contents: read jobs: Pre-Commit: diff --git a/.github/workflows/manual_test_futures.yaml b/.github/workflows/manual_test_futures.yaml index 4fbe3235..3272383a 100644 --- a/.github/workflows/manual_test_futures.yaml +++ b/.github/workflows/manual_test_futures.yaml @@ -27,7 +27,8 @@ name: PR Manual Test Futures on: workflow_dispatch: -permissions: read-all +permissions: + contents: read jobs: Test-Futures-Public: diff --git a/.github/workflows/manual_test_spot.yaml b/.github/workflows/manual_test_spot.yaml index d65e9781..cafbc90c 100644 --- a/.github/workflows/manual_test_spot.yaml +++ b/.github/workflows/manual_test_spot.yaml @@ -35,7 +35,8 @@ name: PR Manual Test Spot on: workflow_dispatch: -permissions: read-all +permissions: + contents: read jobs: Test-Spot-Public: diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 408986d6..eb4c2642 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -32,6 +32,11 @@ jobs: # actions: read steps: + - name: Harden Runner + uses: step-security/harden-runner@17d0e2bd7d51742c71671bd19fa12bdc9d40a3d6 # v2.8.1 + with: + egress-policy: audit + - name: "Checkout code" uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: diff --git a/.gitignore b/.gitignore index ec70b914..745461e4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,14 +2,11 @@ _version.py .vscode/ -# Vale -vale.ini -styles/ - # Byte-compiled / optimized / DLL files __pycache__/ *.py[cod] *$py.class + # C extensions *.so @@ -36,19 +33,14 @@ share/python-wheels/ MANIFEST # Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ .coverage .coverage.* .cache .ruff_cache -nosetests.xml coverage.xml pytest.xml *.cover *.py,cover -.hypothesis/ .pytest_cache/ # Translations @@ -58,9 +50,6 @@ pytest.xml # Sphinx documentation doc/_build/ -# PyBuilder -target/ - # Jupyter Notebook .ipynb_checkpoints @@ -85,6 +74,7 @@ mypy.xml # misc del*.py del/ +todo.md .DS_Store *.csv *.log diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d00cae05..7a8d1dda 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.3.4 + rev: v0.4.2 hooks: - id: ruff args: @@ -21,7 +21,7 @@ repos: - --show-source - --statistics - repo: https://github.com/pycqa/pylint - rev: v3.0.3 + rev: v3.2.3 hooks: - id: pylint name: pylint @@ -32,7 +32,7 @@ repos: - -d=R0801 # ignore duplicate code - -j=4 - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 + rev: v1.10.0 hooks: - id: mypy name: mypy @@ -42,8 +42,16 @@ repos: - --config-file=pyproject.toml - --install-types - --non-interactive + - repo: https://github.com/gitleaks/gitleaks + rev: v8.16.3 + hooks: + - id: gitleaks + - repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shellcheck - repo: https://github.com/codespell-project/codespell - rev: v2.2.6 + rev: v2.3.0 hooks: - id: codespell additional_dependencies: @@ -81,7 +89,7 @@ repos: - id: rst-inline-touching-normal - id: text-unicode-replacement-char - repo: https://github.com/psf/black - rev: 24.2.0 + rev: 24.4.2 hooks: - id: black - repo: https://github.com/pre-commit/mirrors-prettier diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 8c1a91f8..2e693620 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -13,12 +13,13 @@ build: apt_packages: - pandoc -# Build documentation in the docs/ directory with Sphinx +# Build documentation in the doc/ directory with Sphinx sphinx: configuration: doc/conf.py + # If using Sphinx, optionally build your docs in additional formats such as PDF -# formats: -# - pdf +formats: + - pdf # Optionally declare the Python requirements required to build your docs python: diff --git a/CHANGELOG.md b/CHANGELOG.md index fb2c06de..681a7479 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,43 @@ # Changelog -## [Unreleased](https://github.com/btschwertfeger/python-kraken-sdk/tree/HEAD) +## [v2.3.0](https://github.com/btschwertfeger/python-kraken-sdk/tree/v2.3.0) (2024-06-10) -[Full Changelog](https://github.com/btschwertfeger/python-kraken-sdk/compare/v2.1.1...HEAD) +[Full Changelog](https://github.com/btschwertfeger/python-kraken-sdk/compare/v2.2.0...v2.3.0) + +**Implemented enhancements:** + +- Resolve "Add command-line interface" [\#224](https://github.com/btschwertfeger/python-kraken-sdk/pull/224) ([btschwertfeger](https://github.com/btschwertfeger)) + +**Fixed bugs:** + +- Resolve "Subscribing to "balances" channel using KrakenSpotWSClientV2 fails" [\#229](https://github.com/btschwertfeger/python-kraken-sdk/pull/229) ([btschwertfeger](https://github.com/btschwertfeger)) + +Uncategorized merged pull requests: + +- Bump dependabot/fetch-metadata from 1.1.1 to 2.1.0 [\#222](https://github.com/btschwertfeger/python-kraken-sdk/pull/222) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/checkout from 4.1.5 to 4.1.6 [\#221](https://github.com/btschwertfeger/python-kraken-sdk/pull/221) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump ossf/scorecard-action from 2.3.1 to 2.3.3 [\#219](https://github.com/btschwertfeger/python-kraken-sdk/pull/219) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/checkout from 4.1.4 to 4.1.5 [\#218](https://github.com/btschwertfeger/python-kraken-sdk/pull/218) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/upload-artifact from 4.3.2 to 4.3.3 [\#216](https://github.com/btschwertfeger/python-kraken-sdk/pull/216) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/checkout from 4.1.3 to 4.1.4 [\#215](https://github.com/btschwertfeger/python-kraken-sdk/pull/215) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/upload-artifact from 4.3.1 to 4.3.2 [\#214](https://github.com/btschwertfeger/python-kraken-sdk/pull/214) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/checkout from 4.1.2 to 4.1.3 [\#213](https://github.com/btschwertfeger/python-kraken-sdk/pull/213) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/setup-python from 5.0.0 to 5.1.0 [\#211](https://github.com/btschwertfeger/python-kraken-sdk/pull/211) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/checkout from 3.1.0 to 4.1.2 [\#210](https://github.com/btschwertfeger/python-kraken-sdk/pull/210) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump actions/upload-artifact from 3.1.0 to 4.3.1 [\#209](https://github.com/btschwertfeger/python-kraken-sdk/pull/209) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump ossf/scorecard-action from 2.1.2 to 2.3.1 [\#208](https://github.com/btschwertfeger/python-kraken-sdk/pull/208) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Adjust permissions in GitHub Actions [\#207](https://github.com/btschwertfeger/python-kraken-sdk/pull/207) ([btschwertfeger](https://github.com/btschwertfeger)) +- Bump actions/checkout from 4.0.0 to 4.1.2 [\#206](https://github.com/btschwertfeger/python-kraken-sdk/pull/206) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump codecov/codecov-action from 3 to 4 [\#205](https://github.com/btschwertfeger/python-kraken-sdk/pull/205) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Bump pre-commit/action from 3.0.0 to 3.0.1 [\#204](https://github.com/btschwertfeger/python-kraken-sdk/pull/204) ([dependabot[bot]](https://github.com/apps/dependabot)) +- Add dependabot automerge [\#220](https://github.com/btschwertfeger/python-kraken-sdk/pull/220) ([btschwertfeger](https://github.com/btschwertfeger)) +- Update the publishing process [\#217](https://github.com/btschwertfeger/python-kraken-sdk/pull/217) ([btschwertfeger](https://github.com/btschwertfeger)) +- Update ruff and apply new rules [\#212](https://github.com/btschwertfeger/python-kraken-sdk/pull/212) ([btschwertfeger](https://github.com/btschwertfeger)) +- Project Maintenance [\#203](https://github.com/btschwertfeger/python-kraken-sdk/pull/203) ([btschwertfeger](https://github.com/btschwertfeger)) + +## [v2.2.0](https://github.com/btschwertfeger/python-kraken-sdk/tree/v2.2.0) (2024-03-10) + +[Full Changelog](https://github.com/btschwertfeger/python-kraken-sdk/compare/v2.1.1...v2.2.0) **Implemented enhancements:** @@ -14,9 +49,9 @@ Uncategorized merged pull requests: +- adjust CI configuration [\#187](https://github.com/btschwertfeger/python-kraken-sdk/pull/187) ([btschwertfeger](https://github.com/btschwertfeger)) - Resolve "Mark `kraken.spot.KrakenSpotWSClientV1` as deprecated" [\#201](https://github.com/btschwertfeger/python-kraken-sdk/pull/201) ([btschwertfeger](https://github.com/btschwertfeger)) - Resolve "The POST and query parameters of KrakenSpotBaseAPI and KrakenFuturesBaseAPI are not proper encoded in some case" [\#189](https://github.com/btschwertfeger/python-kraken-sdk/pull/189) ([btschwertfeger](https://github.com/btschwertfeger)) -- adjust CI configuration [\#187](https://github.com/btschwertfeger/python-kraken-sdk/pull/187) ([btschwertfeger](https://github.com/btschwertfeger)) - Merge the CI/CD and release workflow + fix scheduled execution [\#186](https://github.com/btschwertfeger/python-kraken-sdk/pull/186) ([btschwertfeger](https://github.com/btschwertfeger)) - Adjust the `kraken.futures.User` documentation [\#185](https://github.com/btschwertfeger/python-kraken-sdk/pull/185) ([btschwertfeger](https://github.com/btschwertfeger)) - Project Housekeeping [\#184](https://github.com/btschwertfeger/python-kraken-sdk/pull/184) ([btschwertfeger](https://github.com/btschwertfeger)) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 961cd577..75ca60fe 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -5,7 +5,7 @@ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, +identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. diff --git a/MANIFEST.in b/MANIFEST.in index 2580a3d7..7e143fe4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -6,7 +6,6 @@ include README.md LICENSE pyproject.toml graft kraken - prune .cache prune .github prune doc diff --git a/README.md b/README.md index 0e2cd10e..8b3fb9da 100644 --- a/README.md +++ b/README.md @@ -53,15 +53,13 @@ General: - extensive example scripts (see `/examples` and `/tests`) - tested using the [pytest](https://docs.pytest.org/en/7.3.x/) framework - releases are permanently archived at [Zenodo](https://zenodo.org/badge/latestdoi/510751854) -- releases before v2.0.0 also support Python 3.7+ Available Clients: -- NFT REST Clients -- Spot REST Clients -- Spot Websocket Clients (Websocket API v1 and v2) -- Spot Orderbook Clients (Websocket API v1 and v2) -- Futures REST Clients +- Spot REST Clients (sync and async; including access to NFT trading) +- Spot Websocket Client (using Websocket API v2) +- Spot Orderbook Client (using Websocket API v2) +- Futures REST Clients (sync and async) - Futures Websocket Client Documentation: @@ -86,17 +84,12 @@ new releases. - [ Installation and setup ](#installation) - [ Command-line interface ](#cliusage) -- [ SDK Usage Hints ](#sdkusage) - [ Spot Clients ](#spotusage) - - [REST API](#spotrest) - - [Websocket API V2](#spotws) - [ Futures Clients ](#futuresusage) - - [REST API](#futuresrest) - - [Websocket API](#futuresws) -- [ NFT Clients ](#nftusage) - [ Troubleshooting ](#trouble) - [ Contributions ](#contribution) - [ Notes ](#notes) +- [ Considerations ](#considerations) - [ References ](#references) @@ -157,158 +150,127 @@ kraken futures --api-key= --secret-key= https://futures.kra ... All endpoints of the Kraken Spot and Futurs API can be accessed like that. - + -# 📍 SDK Usage Hints +# 📍 Spot Clients The python-kraken-sdk provides lots of functions to easily access most of the REST and websocket endpoints of the Kraken Cryptocurrency Exchange API. Since these endpoints and their parameters may change, all implemented endpoints are tested on a regular basis. -If certain parameters or settings are not available, or -specific endpoints are hidden and not implemented, it is always possible to -execute requests to the endpoints directly using the `_request` method provided -by any client. This is demonstrated below. +The Kraken Spot API can be accessed by executing requests to the endpoints +directly using the `request` method provided by any client. This is demonstrated +below. -```python -from kraken.spot import User +See https://docs.kraken.com/api/docs/guides/global-intro for information about +the available endpoints and their usage. -user = User(key="", secret="") -print(user._request(method="POST", uri="/0/private/Balance")) -``` +### `SpotClient` - +The Spot client provides access to all un-and authenticated endpoints of +Kraken's Spot and NFT API. -# 📍 Spot Clients - -A template for Spot trading using both websocket and REST clients can be found -in `examples/spot_trading_bot_template_v2.py`. - -For those who need a realtime order book - a script that demonstrates how to -maintain a valid order book using the Orderbook client can be found in -`examples/spot_orderbook_v2.py`. +```python +from kraken.spot import SpotClient - +client = SpotClient(key="", secret="") +print(client.request("POST", "/0/private/Balance")) +``` -## Spot REST API +### `SpotAsyncClient` -The Kraken Spot REST API offers many endpoints for almost every use-case. The -python-kraken-sdk aims to provide all of them - split in User, Market, Trade, -Funding and Staking (Earn) related clients. +The async Spot client allows for asynchronous access to Kraken's Spot and NFT API endpoints. Below are two examples demonstrating its usage. -The following code block demonstrates how to use some of them. More examples -can be found in `examples/spot_examples.py`. +Using SpotAsyncClient without a context manager; In this example, the client is manually closed after the request is made. ```python -from kraken.spot import Earn, User, Market, Trade, Funding - -def main(): - key = "kraken-public-key" - secret = "kraken-secret-key" +import asyncio +from kraken.spot import SpotAsyncClient - # ____USER________________________ - user = User(key=key, secret=secret) - print(user.get_account_balance()) - print(user.get_open_orders()) - # â€Ļ +async def main(): + client = SpotAsyncClient(key="", secret="") + try: + response = await client.request("POST", "/0/private/Balance") + print(response) + finally: + await client.async_close() - # ____MARKET____ - market = Market() - print(market.get_ticker(pair="BTCUSD")) - # â€Ļ +asyncio.run(main()) +``` - # ____TRADE_________________________ - trade = Trade(key=key, secret=secret) - print(trade.create_order( - ordertype="limit", - side="buy", - volume=1, - pair="BTC/EUR", - price=20000 - )) - # â€Ļ +Using SpotAsyncClient as a context manager; This example demonstrates the use of the context manager, which ensures the client is automatically closed after the request is completed. - # ____FUNDING___________________________ - funding = Funding(key=key, secret=secret) - print( - funding.withdraw_funds( - asset="DOT", key="MyPolkadotWallet", amount=200 - ) - ) - print(funding.cancel_withdraw(asset="DOT", refid="")) - # â€Ļ +```python +import asyncio +from kraken.spot import SpotAsyncClient - # ____EARN________________________ - earn = Earn(key=key, secret=secret) - print(earn.list_earn_strategies(asset="DOT")) - # â€Ļ +async def main(): + async with SpotAsyncClient(key="", secret="")as client: + response = await client.request("POST", "/0/private/Balance") + print(response) -if __name__ == "__main__": - main() +asyncio.run(main()) ``` -## Spot Websocket API V2 +### `SpotWSClient` (Websocket API) Kraken offers two versions of their websocket API (V1 and V2). Since V2 is -offers more possibilities, is way faster and easier to use, only those examples -are shown below. For using the websocket API V1 please have a look into the -`examples/spot_ws_examples_v1.py`. +offers more possibilities, is way faster and easier to use, only the never +version is supported by this SDK. -The documentation for both API versions can be found here: +The official documentation for can be found at: -- https://docs.kraken.com/websockets +- https://docs.kraken.com/api/docs/guides/global-intro - https://docs.kraken.com/websockets-v2 Note that authenticated Spot websocket clients can also un-/subscribe from/to public feeds. The example below can be found in an extended way in -`examples/spot_ws_examples_v2.py`. +`examples/spot_ws_examples.py`. ```python import asyncio -from kraken.spot import KrakenSpotWSClientV2 +from kraken.spot import SpotWSClient + +class Client(SpotWSClient): + """Can be used to create a custom trading strategy""" + + async def on_message(self, message): + """Receives the websocket messages""" + if message.get("method") == "pong" \ + or message.get("channel") == "heartbeat": + return + + print(message) + # Here we can access lots of methods, for example to create an order: + # if self.is_auth: # only if the client is authenticated â€Ļ + # await self.send_message( + # message={ + # "method": "add_order", + # "params": { + # "limit_price": 1234.56, + # "order_type": "limit", + # "order_userref": 123456789, + # "order_qty": 1.0, + # "side": "buy", + # "symbol": "BTC/USD", + # "validate": True, + # }, + # } + # ) + # â€Ļ it is also possible to call regular REST endpoints + # but using the websocket messages is more efficient. + # You can also un-/subscribe here using self.subscribe/self.unsubscribe. async def main(): - key = "spot-api-key" - secret = "spot-secret-key" - - class Client(KrakenSpotWSClientV2): - """Can be used to create a custom trading strategy""" - - async def on_message(self, message): - """Receives the websocket messages""" - if message.get("method") == "pong" \ - or message.get("channel") == "heartbeat": - return - - print(message) - # here we can access lots of methods, for example to create an order: - # if self.is_auth: # only if the client is authenticated â€Ļ - # await self.send_message( - # message={ - # "method": "add_order", - # "params": { - # "limit_price": 1234.56, - # "order_type": "limit", - # "order_userref": 123456789, - # "order_qty": 1.0, - # "side": "buy", - # "symbol": "BTC/USD", - # "validate": True, - # }, - # } - # ) - # â€Ļ it is also possible to call regular REST endpoints - # but using the websocket messages is more efficient. - # You can also un-/subscribe here using self.subscribe/self.unsubscribe. # Public/unauthenticated websocket client client = Client() # only use this one if you don't need private feeds - + await client.start() await client.subscribe( params={"channel": "ticker", "symbol": ["BTC/USD", "DOT/USD"]} ) @@ -323,16 +285,16 @@ async def main(): ) # â€Ļ - # Per default, the authenticated client starts two websocket connections, + # AS default, the authenticated client starts two websocket connections, # one for authenticated and one for public messages. If there is no need # for a public connection, it can be disabled using the ``no_public`` # parameter. - client_auth = Client(key=key, secret=secret, no_public=True) - await client_auth.subscribe(params={"channel": "executions"}) + client_auth = Client(key="api-key", secret="secret-key", no_public=True) + await client_auth.start() + await client_auth.subscribe(params={"channel": "balances"}) while not client.exception_occur and not client_auth.exception_occur: await asyncio.sleep(6) - return if __name__ == "__main__": @@ -345,110 +307,70 @@ if __name__ == "__main__": # individually within your strategy. ``` ---- - -# 📍 Futures Clients +# Futures Clients -Kraken provides a sandbox environment at https://demo-futures.kraken.com for -Futures paper trading. When using these API keys you have to set the `sandbox` -parameter to `True` when instantiating the respective client. +The Kraken Spot API can be accessed by executing requests to the endpoints +directly using the `request` method provided by any client. This is demonstrated +below. -A template for Futures trading using both websocket and REST clients can be -found in `examples/futures_trading_bot_template.py`. +See https://docs.kraken.com/api/docs/guides/global-intro for information about +the available endpoints and their usage. -The Kraken Futures API documentation can be found here: +### `FuturesClient` -- https://docs.futures.kraken.com -- https://support.kraken.com/hc/en-us/sections/360012894412-Futures-API +The simple Futures client provides access to all un-and authenticated endpoints. - +```python +from kraken.futures import FuturesClient -## Futures REST API +client = FuturesClient(key="", secret="") +print(client.request("GET", "/derivatives/api/v3/accounts")) +``` -As the Spot API, Kraken also offers a REST API for Futures. Examples on how to -use the python-kraken-sdk for Futures are shown in -`examples/futures_examples.py` and listed in a shorter ways below. +### `FuturesAsyncClient` -```python -from kraken.futures import Market, User, Trade, Funding +The async Futures client allows for asynchronous access to Kraken's Futures +endpoints. Below are two examples demonstrating its usage. -def main(): +Using FuturesAsyncClient without a context manager; In this example, the client +is manually closed after the request is made. - key = "futures-api-key" - secret = "futures-secret-key" +```python +import asyncio +from kraken.futures import FuturesAsyncClient - # ____USER________________________ - user = User(key=key, secret=secret) # optional: sandbox=True - print(user.get_wallets()) - print(user.get_open_orders()) - print(user.get_open_positions()) - print(user.get_subaccounts()) - # â€Ļ +async def main(): + client = FuturesAsyncClient(key="", secret="") + try: + response = await client.request("GET", "/derivatives/api/v3/accounts") + print(response) + finally: + await client.async_close() - # ____MARKET____ - market = Market() - print(market.get_ohlc(tick_type="trade", symbol="PI_XBTUSD", resolution="5m")) +asyncio.run(main()) +``` - priv_market = Market(key=key, secret=secret) - print(priv_market.get_fee_schedules_vol()) - print(priv_market.get_execution_events()) - # â€Ļ +Using FuturesAsyncClient as context manager; This example demonstrates the use +of the context manager, which ensures the client is automatically closed after +the request is completed. - # ____TRADE_________________________ - trade = Trade(key=key, secret=secret) - print(trade.get_fills()) - print(trade.create_batch_order( - batchorder_list = [{ - "order": "send", - "order_tag": "1", - "orderType": "lmt", - "symbol": "PI_XBTUSD", - "side": "buy", - "size": 1, - "limitPrice": 12000, - "cliOrdId": "some-client-id" - }, { - "order": "send", - "order_tag": "2", - "orderType": "stp", - "symbol": "PI_XBTUSD", - "side": "buy", - "size": 1, - "limitPrice": 10000, - "stopPrice": 11000, - }, { - "order": "cancel", - "order_id": "e35dsdfsdfsddd-8a30-4d5f-a574-b5593esdf0", - }, { - "order": "cancel", - "cliOrdId": "another-client-id", - }], - )) - print(trade.cancel_all_orders()) - print( - trade.create_order( - orderType="lmt", - side="buy", - size=1, - limitPrice=4, - symbol="pf_bchusd" - ) - ) - # â€Ļ +```python +import asyncio +from kraken.futures import FuturesAsyncClient - # ____FUNDING___________________________ - funding = Funding(key=key, secret=secret) - # â€Ļ +async def main(): + async with FuturesAsyncClient(key="", secret="") as client: + response = await client.request("GET", "/derivatives/api/v3/accounts") + print(response) -if __name__ == "__main__": - main() +asyncio.run(main()) ``` -## Futures Websocket API +### `FuturesWSClient` (Websocket API) Not only REST, also the websocket API for Kraken Futures is available. Examples are shown below and demonstrated in `examples/futures_ws_examples.py`. @@ -460,20 +382,17 @@ public feeds. ```python import asyncio -from kraken.futures import KrakenFuturesWSClient +from kraken.futures import FuturesWSClient -async def main(): - - key = "futures-api-key" - secret = "futures-secret-key" +class Client(FuturesWSClient): - class Client(KrakenFuturesWSClient): - - async def on_message(self, event): - print(event) + async def on_message(self, event): + print(event) +async def main(): # Public/unauthenticated websocket connection client = Client() + await client.start() products = ["PI_XBTUSD", "PF_ETHUSD"] @@ -486,7 +405,9 @@ async def main(): # await client.unsubscribe(feed="ticker", products=products) # Private/authenticated websocket connection (+public) - client_auth = Client(key=key, secret=secret) + client_auth = Client(key="key-key", secret="secret-key") + await client_auth.start() + # print(client_auth.get_available_private_subscription_feeds()) # subscribe to a private/authenticated websocket feed @@ -498,7 +419,7 @@ async def main(): # unsubscribe from a private/authenticated websocket feed await client_auth.unsubscribe(feed="fills") - while True: + while not client.exception_occur and not client_auth.exception_occur: await asyncio.sleep(6) if __name__ == "__main__": @@ -511,44 +432,6 @@ if __name__ == "__main__": --- - - -# 📍 NFT REST Clients - -The Kraken NFT REST API offers endpoints for accessing the market and trade API -provided by Kraken. To access the private (trade) endpoints, you have to provide -API keys - same as for the Spot REST API. - -The following code excerpt demonstrates the usage. Please have a look into -`tests/nft/*.py` for more examples. - -```python -from kraken.nft import Market, Trade - -def main(): - key = "kraken-public-key" - secret = "kraken-secret-key" - - market = Market() - print(market.get_nft(nft_id="NT4GUCU-SIJE2-YSQQG2", currency="USD")) - - trade = Trade(key=key, secret=secret) - print(trade.create_auction( - auction_currency="ETH", - nft_id=["NT4EFBO-OWGI5-QLO7AG"], - auction_type="fixed", - auction_params={ - "allow_offers": True, - "ask_price": 100000, - }, - )) - -if __name__ == "__main__": - main() -``` - ---- - # 🆕 Contributions @@ -587,7 +470,8 @@ if __name__ == "__main__": # 📝 Notes -The versioning scheme follows the pattern `v..`. Here's what each part signifies: +The versioning scheme follows the pattern `v..`. Here's +what each part signifies: - **Major**: This denotes significant changes that may introduce new features or modify existing ones. It's possible for these changes to be breaking, meaning @@ -602,13 +486,28 @@ The versioning scheme follows the pattern `v..`. Here's wha Coding standards are not always followed to make arguments and function names as similar as possible to those of the Kraken API documentations. + + +# Considerations + +The tool aims to be fast, easy to use and maintain. In the past, lots of clients +were implemented, that provided functions for almost all available endpoints of +the Kraken API. The effort to maintain this collection grew to a level where it +was not possible to check various changelogs to apply new updates on a regular +basis. Instead, it was decided to concentrate on the `request` functions of +the `SpotClient`, `SpotAsyncClient`, `FuturesClient` and the +`FuturesAsyncClient` (as well as their websocket client implementations). All +those clients named "User", "Trade", "Market", "Funding" and so on will no +longer be extended, but maintained to a certain degree. + # 🔭 References - https://python-kraken-sdk.readthedocs.io/en/stable +- https://docs.kraken.com/api/ +- https://docs.kraken.com/api/docs/guides/global-intro - https://docs.kraken.com/rest -- https://docs.kraken.com/websockets - https://docs.kraken.com/websockets-v2 - https://docs.futures.kraken.com - https://support.kraken.com/hc/en-us/sections/360012894412-Futures-API diff --git a/doc/Makefile b/doc/Makefile index d4bb2cbb..1bd222f3 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -18,3 +18,4 @@ help: # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + rm $(SOURCEDIR)/examples/market_client_example.ipynb diff --git a/doc/base_api/base_api.rst b/doc/base_api/base_api.rst index 98066cfd..419ad238 100644 --- a/doc/base_api/base_api.rst +++ b/doc/base_api/base_api.rst @@ -10,27 +10,32 @@ avoid using them since these are internals and may change without any warning. They are the base classes for Spot and Futures REST and websocket clients. -.. autoclass:: kraken.base_api.KrakenSpotBaseAPI +.. autoclass:: kraken.base_api.SpotClient :members: :show-inheritance: :inherited-members: -.. autoclass:: kraken.base_api.KrakenFuturesBaseAPI +.. autoclass:: kraken.base_api.SpotAsyncClient :members: :show-inheritance: :inherited-members: -.. autoclass:: kraken.spot.websocket.KrakenSpotWSClientBase +.. autoclass:: kraken.base_api.FuturesClient :members: :show-inheritance: :inherited-members: -.. autoclass:: kraken.spot.websocket.connectors.ConnectSpotWebsocketV1 +.. autoclass:: kraken.base_api.FuturesAsyncClient :members: :show-inheritance: :inherited-members: -.. autoclass:: kraken.spot.websocket.connectors.ConnectSpotWebsocketV2 +.. autoclass:: kraken.spot.websocket.SpotWSClientBase + :members: + :show-inheritance: + :inherited-members: + +.. autoclass:: kraken.spot.websocket.connectors.ConnectSpotWebsocket :members: :show-inheritance: :inherited-members: diff --git a/doc/conf.py b/doc/conf.py index 3462ee4c..7f5237d0 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -13,6 +13,8 @@ import sys from pathlib import Path +from shutil import copyfile +from typing import Any # -- Project information ----------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information @@ -30,21 +32,38 @@ with Path("links.rst").open(encoding="utf-8") as f: rst_epilog += f.read() + +def setup(app: Any) -> None: # noqa: ARG001,ANN401 + """Setup function to modify doc building""" + copyfile( + Path("..") / "examples" / "market_client_example.ipynb", + Path("examples") / "market_client_example.ipynb", + ) + + # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ "nbsphinx", + "sphinx_click", "sphinx.ext.autodoc", "sphinx.ext.doctest", "sphinx.ext.intersphinx", "sphinx.ext.coverage", "sphinx.ext.napoleon", "sphinx.ext.autosectionlabel", + "IPython.sphinxext.ipython_console_highlighting", ] templates_path = ["_templates"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", "links.rst"] +exclude_patterns = [ + "_build", + "Thumbs.db", + ".DS_Store", + "links.rst", + "**.ipynb_checkpoints", +] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output diff --git a/doc/examples/command_line_interface.rst b/doc/examples/command_line_interface.rst index f9ccabb8..0aee0ceb 100644 --- a/doc/examples/command_line_interface.rst +++ b/doc/examples/command_line_interface.rst @@ -5,7 +5,7 @@ .. _section-command-line-interface-examples: Command-line Interface -====================== +---------------------- The python-kraken-sdk provides a command-line interface to access the Kraken API using basic instructions while performing authentication tasks in the @@ -36,3 +36,7 @@ Futurs API can be accessed like that. See examples below. # get user's open futures positions kraken futures --api-key= --secret-key= https://futures.kraken.com/derivatives/api/v3/openpositions {'result': 'success', 'openPositions': [], 'serverTime': '2024-05-26T07:15:38.91Z'} + +.. click:: kraken.cli:cli + :prog: kraken + :nested: full diff --git a/doc/examples/market_client_example.ipynb b/doc/examples/market_client_example.ipynb deleted file mode 100644 index ba94fcc3..00000000 --- a/doc/examples/market_client_example.ipynb +++ /dev/null @@ -1,702 +0,0 @@ -{ - "cells": [ - { - "attachments": {}, - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Plotting Market Data " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "from kraken.spot import Market" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "import matplotlib.pyplot as plt\n", - "import numpy as np\n", - "import pandas as pd" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "____\n", - "### 1. Create the unauthenticated market client" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], - "source": [ - "market = Market()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 2. Get the OHLC data of the XBTUSD pair, create the dataframe, and set the time index" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
timeopenhighlowclosevwapvolumecount
02024-03-02 12:00:0061917.862223.761911.462142.462048.615.260659616.0
12024-03-02 13:00:0062142.462142.461900.061900.062006.850.357137727.0
22024-03-02 14:00:0061900.161971.861663.361891.761832.5281.5123031538.0
32024-03-02 15:00:0061891.862032.261810.061836.861941.138.815926886.0
42024-03-02 16:00:0061836.862022.361714.961930.861839.0181.9801021261.0
...........................
7152024-04-01 07:00:0069680.169788.869562.069671.769676.040.187037767.0
7162024-04-01 08:00:0069671.869671.869244.769450.069445.291.3523011017.0
7172024-04-01 09:00:0069450.169613.469448.669448.769510.346.275460731.0
7182024-04-01 10:00:0069448.769604.469353.069601.169454.023.874609556.0
7192024-04-01 11:00:0069601.269850.169601.169666.169732.820.962756455.0
\n", - "

720 rows × 8 columns

\n", - "
" - ], - "text/plain": [ - " time open high low close vwap \\\n", - "0 2024-03-02 12:00:00 61917.8 62223.7 61911.4 62142.4 62048.6 \n", - "1 2024-03-02 13:00:00 62142.4 62142.4 61900.0 61900.0 62006.8 \n", - "2 2024-03-02 14:00:00 61900.1 61971.8 61663.3 61891.7 61832.5 \n", - "3 2024-03-02 15:00:00 61891.8 62032.2 61810.0 61836.8 61941.1 \n", - "4 2024-03-02 16:00:00 61836.8 62022.3 61714.9 61930.8 61839.0 \n", - ".. ... ... ... ... ... ... \n", - "715 2024-04-01 07:00:00 69680.1 69788.8 69562.0 69671.7 69676.0 \n", - "716 2024-04-01 08:00:00 69671.8 69671.8 69244.7 69450.0 69445.2 \n", - "717 2024-04-01 09:00:00 69450.1 69613.4 69448.6 69448.7 69510.3 \n", - "718 2024-04-01 10:00:00 69448.7 69604.4 69353.0 69601.1 69454.0 \n", - "719 2024-04-01 11:00:00 69601.2 69850.1 69601.1 69666.1 69732.8 \n", - "\n", - " volume count \n", - "0 15.260659 616.0 \n", - "1 50.357137 727.0 \n", - "2 281.512303 1538.0 \n", - "3 38.815926 886.0 \n", - "4 181.980102 1261.0 \n", - ".. ... ... \n", - "715 40.187037 767.0 \n", - "716 91.352301 1017.0 \n", - "717 46.275460 731.0 \n", - "718 23.874609 556.0 \n", - "719 20.962756 455.0 \n", - "\n", - "[720 rows x 8 columns]" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "df = pd.DataFrame(\n", - " market.get_ohlc(pair='XBTUSD', interval=60)['XXBTZUSD'],\n", - " columns=['time', 'open', 'high', 'low', 'close', 'vwap', 'volume', 'count']\n", - ").astype(float)\n", - "# df = df.set_index('time')\n", - "df['time'] = pd.to_datetime(df['time'], unit='s')\n", - "df = df.sort_values(by='time')\n", - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## 3. Compute some indicatoes based on the loaded data" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "# compute ema\n", - "df['ema21'] = df['close'].ewm(span=21, adjust=False, min_periods=21).mean()\n", - "df['ema50'] = df['close'].ewm(span=50, adjust=False, min_periods=50).mean()\n", - "df['ema200'] = df['close'].ewm(span=200, adjust=False, min_periods=200).mean()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [], - "source": [ - "def support_and_resistance(df: pd.DataFrame, lookback: int=200, levels: int=3) -> dict:\n", - " ''' Returns up to 3 support and resistance levels by given dataframe '''\n", - " high = df['high'][-lookback:].max()\n", - " low = df['low'][-lookback:].min()\n", - " close = df['close'][-lookback:].iloc[-1]\n", - "\n", - " pp = (high + low + close) / 3\n", - " s1 = 2 * pp - high\n", - " r1 = 2 * pp - low\n", - " if levels >= 2:\n", - " s2 = pp - (high - low)\n", - " r2 = pp + (high - low)\n", - " if levels >= 3:\n", - " s3 = low - 2 * (high -pp)\n", - " r3 = high + 2 * (pp - low)\n", - " return { 's1': s1, 's2': s2, 's3': s3, 'r1': r1, 'r2': r2, 'r3': r3 }\n", - " return { 's1': s1, 's2': s2, 'r1': r1, 'r2': r2 }\n", - " return { 's1': s1, 'r2': r1 }" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
timeopenhighlowclosevwapvolumecountema21ema50ema200s1r1s2r2
02024-03-02 12:00:0061917.862223.761911.462142.462048.615.260659616.0NaNNaNNaNNaNNaNNaNNaN
12024-03-02 13:00:0062142.462142.461900.061900.062006.850.357137727.0NaNNaNNaN61961.30000062273.60000061780.20000062404.800000
22024-03-02 14:00:0061900.161971.861663.361891.761832.5281.5123031538.0NaNNaNNaN61792.10000062115.80000061684.20000062331.600000
32024-03-02 15:00:0061891.862032.261810.061836.861941.138.815926886.0NaNNaNNaN61628.76666762189.16666761365.83333362486.633333
42024-03-02 16:00:0061836.862022.361714.961930.861839.0181.9801021261.0NaNNaNNaN61592.16666762152.56666761347.53333362468.333333
................................................
7152024-04-01 07:00:0069680.169788.869562.069671.769676.040.187037767.070380.08293470315.53109369369.03422768659.50000071012.20000067639.00000072344.400000
7162024-04-01 08:00:0069671.869671.869244.769450.069445.291.3523011017.070295.52994070281.58869769369.83985668653.96666771006.66666767636.23333372341.633333
7172024-04-01 09:00:0069450.169613.469448.669448.769510.346.275460731.070218.54540070248.92639569370.62453468506.16666770858.86666767562.33333372267.733333
7182024-04-01 10:00:0069448.769604.469353.069601.169454.023.874609556.070162.41400070223.52143969372.91782368505.30000070858.00000067561.90000072267.300000
7192024-04-01 11:00:0069601.269850.169601.169666.169732.820.962756455.070117.29454570201.66177469375.83505868606.90000070959.60000067612.70000072318.100000
\n", - "

720 rows × 15 columns

\n", - "
" - ], - "text/plain": [ - " time open high low close vwap \\\n", - "0 2024-03-02 12:00:00 61917.8 62223.7 61911.4 62142.4 62048.6 \n", - "1 2024-03-02 13:00:00 62142.4 62142.4 61900.0 61900.0 62006.8 \n", - "2 2024-03-02 14:00:00 61900.1 61971.8 61663.3 61891.7 61832.5 \n", - "3 2024-03-02 15:00:00 61891.8 62032.2 61810.0 61836.8 61941.1 \n", - "4 2024-03-02 16:00:00 61836.8 62022.3 61714.9 61930.8 61839.0 \n", - ".. ... ... ... ... ... ... \n", - "715 2024-04-01 07:00:00 69680.1 69788.8 69562.0 69671.7 69676.0 \n", - "716 2024-04-01 08:00:00 69671.8 69671.8 69244.7 69450.0 69445.2 \n", - "717 2024-04-01 09:00:00 69450.1 69613.4 69448.6 69448.7 69510.3 \n", - "718 2024-04-01 10:00:00 69448.7 69604.4 69353.0 69601.1 69454.0 \n", - "719 2024-04-01 11:00:00 69601.2 69850.1 69601.1 69666.1 69732.8 \n", - "\n", - " volume count ema21 ema50 ema200 \\\n", - "0 15.260659 616.0 NaN NaN NaN \n", - "1 50.357137 727.0 NaN NaN NaN \n", - "2 281.512303 1538.0 NaN NaN NaN \n", - "3 38.815926 886.0 NaN NaN NaN \n", - "4 181.980102 1261.0 NaN NaN NaN \n", - ".. ... ... ... ... ... \n", - "715 40.187037 767.0 70380.082934 70315.531093 69369.034227 \n", - "716 91.352301 1017.0 70295.529940 70281.588697 69369.839856 \n", - "717 46.275460 731.0 70218.545400 70248.926395 69370.624534 \n", - "718 23.874609 556.0 70162.414000 70223.521439 69372.917823 \n", - "719 20.962756 455.0 70117.294545 70201.661774 69375.835058 \n", - "\n", - " s1 r1 s2 r2 \n", - "0 NaN NaN NaN NaN \n", - "1 61961.300000 62273.600000 61780.200000 62404.800000 \n", - "2 61792.100000 62115.800000 61684.200000 62331.600000 \n", - "3 61628.766667 62189.166667 61365.833333 62486.633333 \n", - "4 61592.166667 62152.566667 61347.533333 62468.333333 \n", - ".. ... ... ... ... \n", - "715 68659.500000 71012.200000 67639.000000 72344.400000 \n", - "716 68653.966667 71006.666667 67636.233333 72341.633333 \n", - "717 68506.166667 70858.866667 67562.333333 72267.733333 \n", - "718 68505.300000 70858.000000 67561.900000 72267.300000 \n", - "719 68606.900000 70959.600000 67612.700000 72318.100000 \n", - "\n", - "[720 rows x 15 columns]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# compute support and resistance levels\n", - "for i, row in enumerate(df.index):\n", - " try:\n", - " srlevels = support_and_resistance(df.iloc[:i], lookback=50, levels=2)\n", - " df.at[row, 's1'] = srlevels['s1']\n", - " df.at[row, 'r1'] = srlevels['r1']\n", - " df.at[row, 's2'] = srlevels['s2']\n", - " df.at[row, 'r2'] = srlevels['r2']\n", - " except:\n", - " df.at[row, 's1'] = np.NaN\n", - " df.at[row, 'r1'] = np.NaN\n", - " df.at[row, 's2'] = np.NaN\n", - " df.at[row, 'r2'] = np.NaN\n", - "\n", - "# isn't that a beauty?:\n", - "df" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### 4. Plot the results" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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aUh8BAAAAAAAAFBkubm5Gj58uEPinSQ9++yz6tKli+V9KlasqM8//9ypf9SoUYaV8fxl2bJluuOOO5z6Y2NjddNNNwUsDk/44prr86677jqnypYpKSm66aablJCQ4NFev/zyi55//nmn/kcffVTh4eFu1z/66KNq1KiRPvjgA6cr1D0xa9YsvfTSS079t956a8CqKx46dEjjxo1T586dtXXrVqfxNm3a6MsvvwxILAAAAAAAACUZiY8AAAAAAAAAiuydd97RH3/84dDXpk0bvfjiix7vdd1112nEiBEOfQkJCX6/8jo5OVm//vqrbrvtNl1++eVKTk52mvPmm2+qUqVKfo3DG7m5uU7Xchcl8dFms+l///ufwsLCHPrXrVunbt26adasWbLb7S73OHv2rJ577jkNGDDAKSG2c+fOGj16tOV4jh07pscff1zVq1fXsGHDtGDBAstVIPft26d77rlHt9xyi7KyshzGYmNjDZMhfSU1NVW///673n33XQ0YMEANGzbUG2+84VR1UpI6duyoJUuWqHz58n6LBwAAAAAAoLSw2d19dwoAAAAAAAAAXNi6das6derkkFQWHh6uNWvWqEOHDl7tmZiYqNatW+vIkSMO/d99951uu+0203UNGjTQgQMHHPratWvn8qyMjAwlJyfr+PHjLpP5HnvsMb3//vsWonevd+/eWr58uUPf0qVL1bt3b6/2W7FihXr16lXQrlmzpo4cOSKbzVaUMPXvf/9bTz75pOFY3bp1dfnll6tdu3aKjY1VdHS0zp49qxMnTmjVqlX6/fffDRP8KleurPXr16tBgwaWYoiKilJmZqZTf3h4uNq3b6+uXbuqXr16io2NVcWKFZWRkaGzZ89q586dWrt2rdatW2e4b3h4uGbMmGEpQdSTz6uMjAwlJSUpKSnJKeHTiM1m03333acPPvjA8pXwAAAAAAAA/3Rh7qcAAAAAAAAAgLHs7GwNHz7cqZLeuHHjvE56lPKvvP7f//6nfv36OfSPHj1al19+uapXr255r7/++svrOCQpMjJSL7zwgsaOHVukffyp8DXX119/fZGTHiXpiSeeUEREhJ544gllZ2c7jB06dEiTJ0/2aL/mzZvrhx9+sJz06Ep2drbWrVtnmtjoSnR0tKZOnaoBAwZ4fX5RP68kqU+fPnrjjTfUvXv3Iu8FAAAAAADwT8JV1wAAAAAAAAC89vrrr2vDhg0OfR07dtS4ceOKvPe1116ru+++26EvISFBDzzwQJH3tiIqKkq33nqrNm/eXKyTHiXnxMeiXHNd2KhRo7Rs2TJ16dLF6z0iIiJ07733au3atWrRooVHa9966y1dcsklCgnxzbezb7zxRu3YsaNISY9F0bBhQz3xxBPatGmTlixZQtIjAAAAAACAF7jqGgAAAAAAAIBXNmzYoG7duiknJ6egLyIiQuvXr1fr1q19ckZSUpJat26tw4cPO/R/++23Gjp0qNN8oyuJ3QkLC1O5cuVUvnx51a1bVx06dFDnzp01YMAAVaxYsSjhm/LlVddbt25VmzZtCtply5bV6dOnFRkZWdQwnSxZskSff/65VqxYoWPHjrmcGxISotatW6tfv34aPXq0atWqVaSzT506pUWLFun333/XypUrtX37duXl5bldFxoaqosuukg33nijhg0bpubNm3t8ttXPK5vNpoiICEVFRalixYqqVq2a6tSpo+bNm6tNmza6+OKLfVLtEgAAAAAA4J+OxEcAAAAAAAAAKMFef/11PffccwXtm266STNnzvT7uXv27NH27dt15swZnTlzRunp6apQoYIqV66s6tWrq3PnzqpQoYLfzs/MzFR8fLz27NmjEydO6Ny5c0pLS1NUVJTKly+v8uXLq0mTJmrVqpXKlCnjtzgAAAAAAAAQeCQ+AgAAAAAAAEAJ1qVLF/35558F7a+//lq33357ECMCAAAAAAAA/IvERwAAAAAAAAAooY4cOaK6devq/Ld5w8LCdPLkSVWqVCnIkQEAAAAAAAD+ExLsAAAAAAAAAAAA3pk3b54u/N32Sy+9lKRHAAAAAAAAlHokPgIAAAAAAABACTV37lyH9sCBA4MUCQAAAAAAABA4XHUNAAAAAAAAAAAAAAAAAABKDCo+AgAAAAAAAAAAAAAAAACAEoPERwAAAAAAAAAAAAAAAAAAUGKQ+AgAAAAAAAAAAAAAAAAAAEoMEh8BAAAAAAAAAAAAAAAAAECJQeIjAAAAAAAAAAAAAAAAAAAoMUh8BAAAAAAAAAAAAAAAAAAAJQaJjwAAAAAAAAAAAAAAAAAAoMQg8REAAAAAAAAAAAAAAAAAAJQYJD4CAAAAAAAAAAAAAAAAAIASg8RHAAAAAAAAAAAAAAAAAABQYpD4CAAAAAAAAAAAAAAAAAAASgwSHwEAAAAAAAAAAAAAAAAAQIlB4iMAAAAAAAAAAAAAAAAAACgxSHwEAAAAAAAAAAAAAAAAAAAlBomPAAAAAAAAAAAAAAAAAACgxCDxEQAAAAAAAAAAAAAAAAAAlBhhwQ4AgP8kJiZq+fLlBe26desqMjIyiBEBAAAAAAAAAAAAAAAACKbMzEwdOnSooN2rVy9VrFgxeAF5gcRHoBRbvny5Bg0aFOwwAAAAAAAAAAAAAAAAABRTc+bM0cCBA4Mdhke46hoAAAAAAAAAAAAAAAAAAJQYJD4CAAAAAAAAAAAAAAAAAIASg6uugVKsbt26Du05c+aoSZMmQYoGAAAAAAAAAAAAAAAAQLDt2bNHgwYNKmgXzjEqCUh8hN9s27ZN69ev17Fjx5Sbm6vY2Fi1bt1a3bp1U1iY7z71zp07p1WrVmn37t1KTk5WmTJlVL9+fV188cWqVauWz86RAveefCUyMtKh3aRJE7Vq1SpI0QAAAAAAAAAAAAAAAAAobgrnGJUExS9Tq5QbMWKEJk+e7JO96tevr/379xdpj19//VV9+/Z16l+6dKl69+7t8X52u10TJ07UW2+9pd27dxvOiY2N1YMPPqgxY8YoJibG4zPO27dvn1544QVNnz5dWVlZTuM2m029evXSyy+/rMsuu8zrcwL5ngAAAAAAAAAAAAAAAAAAroUEOwB4LyIiokjrU1JSdN999/koGikxMVHXXHONRo4caZogKEkJCQl67bXX1LZtW23bts2rs6ZPn67WrVvrm2++MUx6lPITFpctW6bevXtrzJgxstvtHp8TyPcEAAAAAAAAAAAAAAAAAHCPxMcSrH///kVaP2bMGB08eNAnsaSnp+uaa67RokWLHPojIiLUrFkztWnTxqkS4t69e9WnTx/t2bPHo7NmzJih2267TWlpaQ79VatWVceOHVWnTh3ZbLaCfrvdrrfeektPPPFEsX1PAAAAAAAAAAAAAAAAAABruOo6wJ555hndfvvtHq+Li4vTQw895NA3YsQIr+NYtWqVJkyYIEkKCQlRRESEMjIyvN7viSee0Nq1awvaISEhGjdunB5//HFVqlRJkpSVlaXvvvtOTzzxhM6ePStJOnXqlG655RatW7dOoaGhbs+Jj4/XXXfdpby8vIK+du3a6f3331efPn0K+nbt2qWxY8dq9uzZBX0ffPCBLr30Ut14443F6j0BAAAAAAAAAAAAAAAAAKyz2b25/xcBN3bsWI0fP76g3aFDB23YsMGrvTIzM9WuXTvt2rVLkjR69GjNmzdPBw4cKJizdOlS9e7d29J+O3fuVOvWrZWbm1vQ99133+m2224znL9t2zZdcsklSkxMLOj76quvdNddd7k9a+jQoZo6dWpBu0uXLlq8eLHKly/vNNdut+uBBx7Q559/XtDXuHFj7dy5U2FhrnN+A/me/Gnbtm1q3bp1QXvr1q1q1apVECMCAAAAAAAAAAAAAAAAEEylIaeIq65LgLy8PH399dcOfUWp9vjyyy8XJD3WqVNHr7/+elHC04svvuiQIHjHHXeYJghKUqtWrfTuu+86xZSdne3ynG3btun7778vaEdERGjy5MmGSY+SZLPZ9OGHH6pp06YFffHx8Zo4caLLc6TAvScAAAAAAAAAAAAAAAAAgGdIfCwBFi9erMOHDxe0w8PDNXToUK/22rRpk955552C9ieffKJy5cp5HdvZs2cdrpO22Wx66aWX3K676667VL9+/YL2gQMHtHjxYpdrvvrqK4crrocMGaIWLVq4XBMVFaUxY8Y49H3xxRcu1wTyPQEAAAAAAAAAAAAAAAAAPEPiYwkwefJkh3b//v1VpUoVj/fJycnRyJEjlZOTI0m66aabNGDAgCLFNn/+/IL9JKl3795q1KiR23UhISFO10DPmTPH5Zp58+Y5tEeOHGkpxltvvVUxMTEF7XXr1uno0aOm8wP5ngAAAAAAAAAAAAAAAAAAniHxsZhLTk7WDz/84NDn7TXX7777rjZs2CBJqlChgj7++OOihqf58+c7tK+++mrLa6+66iqH9k8//WQ6d9euXdqzZ09BOyYmRhdffLGlcwrPtdvtTnFfKFDvCQAAAAAAAAAAAAAAAADgORIfi7np06crPT29oF2tWjX169fP4312796tl19+uaD95ptvqmbNmkWOb9OmTQ5tq8mIktSpUydFRkYWtI8ePapTp05ZOqdr164KCwuzfFbPnj1d7udqzF/vCQAAAAAAAAAAAAAAAADgORIfi7lJkyY5tIcNG+ZRwp+UX+HwnnvuUUZGhqT8JMD777+/yLFlZ2c7VGGUpJYtW1peHxkZqcaNGzv07dixw3Bu4X5PzjGab3ZOIN8TAAAAAAAAAAAAAAAAAMBzJD4WY3v27NGqVasc+u666y6P9/n000/1+++/S5IiIiL0+eefy2azFTm+vXv3Kicnp6BdpkwZValSxaM96tat69DetWuX4bzC/YXX+eqcQL4nAAAAAAAAAAAAAAAAAIDnPCsdiICaPHmyQ7tjx45q06aNR3scOnRIY8aMKWg/++yzHldLNHPy5EmHdu3atT3eo/Cawnua9depU6dI55hdPx3I9+SpkydPenxtduHqlQAAAAAAAAAAAAAAAABQ0pH4WEzZ7XZNmTLFoW/EiBEe7/PAAw/o3LlzkqTmzZtr3LhxvghPkpSSkuLQjomJ8XiPwmsK7+mrswrPz87OVmZmpiIjI316jtEas/fkqQkTJujll1/2yV4AAAAAAAAAAAAAAAAAUFJx1XUxtWTJEh08eLCgHRERoaFDh3q0xzfffKOff/5ZkmSz2fTZZ585JfoVReGEvqioKI/3KFOmjMs9fXVW4XPMzgrkewIAAAAAAAAAAAAAAAAAeI7Ex2Kq8DXX/fv3V2xsrOX1J0+e1GOPPVbQvvvuu9WrVy9fhSdJysjIcGhHRER4vEfhRMz09HS/nGWU8Gl0ViDfEwAAAAAAAAAAAAAAAADAc1x1XQylpKRo9uzZDn2eXnM9evRoJSQkSJKqV6+ud955x1fhFShcDTErK8vjPTIzM13u6auzCp9jdlYg35OnHnroId18880erdmzZ48GDRrkk/MBAAAAAAAAAAAAAAAAoDgg8bEYmjFjhlJTUwva1atX17XXXmt5/bx58zR9+vSC9gcffKBKlSr5NEZJKlu2rEO7cLVEKwpXQyy8p6/OMqq6aHRWIN+Tp6pVq6Zq1ar5ZC8AAAAAAAAAAAAAAAAAKKm46roYmjRpkkN72LBhCguzlqOalJSkBx98sKB97bXXasiQIb4Mr0DhhL4LkzWtKrzGauKjp2cVnh8WFmZYiTGQ7wkAAAAAAAAAAAAAAAAA4DkSH4uZvXv36vfff3fo8+Sa6/fff19Hjx6VJMXExOjTTz/1ZXgOClcfPHLkiMd7FF5jVtGwcP/hw4eLdE7VqlUtnePP9wQAAAAAAAAAAAAAAAAA8ByJj8XMlClTZLfbC9odO3ZUmzZtLK9PTEws+HNqaqoaNGggm83m9nXgwAGHffr06eMw/thjjzmd1ahRI4dKlOnp6Tp16pT1Nyvp4MGDDu2LLrrIcF7z5s1drvPVOYF8TwAAAAAAAAAAAAAAAAAAz5H4WIzY7XZNmTLFoe+uu+4KUjTuhYeHq3Hjxg5927dvt7w+MzNTe/fudegzSxIs3O/JOZK0Y8cOS+cE8j0BAAAAAAAAAAAAAAAAADxH4mMxsnz5cu3bt6+gHRERoaFDhwYxIvfat2/v0F69erXltevXr1dmZmZBu2bNmqbXQhc+Z926dcrJybF81qpVq1zu52rMX+8JAAAAAAAAAAAAAAAAAOC5MPdTECiTJ092aF9//fWqXLmyR3s89NBD6t+/v8dn33777Tpx4kRB+91331W7du0K2vXq1TNc179/f33//fcF7UWLFulf//qXpTMXLVrk0L7++utN51500UVq3Lix4uPjJeVf47169Wpddtllbs9JTU3V//t//6+gbbPZXH6MAvWeAAAAAAAAAAAAAAAAAACeI/GxmEhNTdXMmTMd+kaMGOHxPs2aNVOzZs08XhcVFeXQ7tSpk3r37u12Xb9+/RQWFlZQfXHZsmXau3evGjVq5HKd3W7XpEmTHPoGDhzocs2AAQP0/vvvF7S//PJLS4mP33//vVJSUgranTt3Vq1atUznB/I9AQAAAAAAAAAAAAAAAAA8w1XXxcSsWbMckvNq1Kihvn37BjEiaypXrqxBgwYVtO12u1566SW367766ivt37+/oF2/fn1deeWVLtfcfffdstlsBe1p06Zpx44dLtdkZGTozTffdOgbOXKkyzWBfE8AAAAAAAAAAAAAAAAAAM+Q+FhMFK4UOGzYMIWFlYyCnC+//LJCQv7+VPr66681depU0/nbt2/XU0895dD3/PPPKyIiwuU5rVu31i233FLQzsrK0vDhw5WcnGw4326367HHHlNcXFxBX6NGjXT33Xe7PEcK3HsCAAAAAAAAAAAAAAAAAHiGxMdi4MCBA1q2bJlDnzfXXAdLy5Ytdc899zj03X777XrhhRd09uzZgr7s7GxNmjRJl1xyiRITEwv627Ztq+HDh1s667XXXlN0dHRBe926dbrsssucPn67d+/W4MGD9dlnnzn0v/nmmwoPDy9W7wkAAAAAAAAAAAAAAAAAYJ3Nbrfbgx3EP92rr76qF154oaDdqVMn/fnnnwGNoUGDBjpw4EBBe+nSperdu7fl9WlpaerVq5dT3BEREWrYsKEiIyO1d+9eh+u8JalKlSpatWqVmjVrZvmsadOmaejQoSr8qVu1alXVq1dPJ0+e1OHDh53GR48erY8++qhYvid/2bZtm1q3bl3Q3rp1q1q1ahXEiAAAAAAAAAAAAAAAAAAEU2nIKaLiYzEwefJkh3ZJqvZ4XnR0tH799VddfvnlDv1ZWVnatWuXNm/e7JQg2KBBAy1ZssTjBMEhQ4bo22+/VZkyZRz6T506pfXr1+vQoUNOSY9PPfWUPvzwQ4/OCeR7AgAAAAAAAAAAAAAAAABYQ+JjkK1cuVLx8fEF7YiICA0dOjSIEXmvcuXKWrRokT7//HM1adLE5byxY8dqy5YtatOmjVdn3Xbbbdq6dauGDh3q8urq89dgv/POO7LZbB6fE8j3BAAAAAAAAAAAAAAAAABwj6uu4TdbtmzRhg0bdOzYMeXm5io2NlatW7dWt27dXCYreio5OVkrV65UXFyczp07p6ioKNWrV089e/ZU7dq1fXaOFLj35CuloSwtAAAAAAAAAAAAAAAAAN8pDTlFYcEOAKVXmzZtAlL9sHz58urXr5/fz5EC954AAAAAAAAAAAAAAAAAAMa46hoAAAAAAAAAAAAAAAAAAJQYJD4CAAAAAAAAAAAAAAAAAIASg8RHAAAAAAAAAAAAAAAAAABQYpD4CAAAAAAAAAAAAAAAAAAASgwSHwEAAAAAAAAAAAAAAAAAQIlB4iMAAAAAAAAAAAAAAAAAACgxSHwEAAAAAAAAAAAAAAAAAAAlBomPAAAAAAAAAAAAAAAAAACgxCDxEQAAAAAAAAAAAAAAAAAAlBgkPgIAAAAAAAAAAAAAAAAAgBKDxEcAAAAAAAAAAAAAAAAAAFBikPgIAAAAAAAAAAAAAAAAAABKDBIfAQAAAAAAoMTERG3cuFHZ2dnBDgUAAAAAAAAAAJdIfAQAAAAAAPgHy8vL01NPPaXY2Fh17NhRsbGxmj9/frDDAgAAAAAAAADAFImPAAAAAAAA/2CTJ0/We++9p7y8PEnSuXPnNGjQIB0/fjzIkQEAAAAAAAAAYIzERwAAAAAAgH+wGTNmOPXl5ORo1qxZQYgGAAAAAAAAAAD3SHwEAAAAAAD4B1uwYIFh/4svvhjgSAAAAAAAAAAAsIbERwAAAAAAADhJSEgIdggAAAAAAAAAABgi8REAAAAAAOAfKjMzM9ghAAAAAAAAAADgMRIfAQAAAAAA/qFOnjwZ7BAAAAAAAAAAAPAYiY8AAAAAAAD/UO4SH3NzcwMUCQAAAAAAAAAA1pH4CAAAAAAA8A914sQJl+NUhAQAAAAAAAAAFEckPgIAAAAAAPxDuUt8PHLkSIAiAQAAAAAAAADAOhIfAQAAAAAA/qHcVXQ8fPhwgCIBAAAAAAAAAMA6Eh8BAAAAAMA/wtKlSzV48GBdddVVGj9+vLKzs4MdUtBR8REAAAAAAAAAUBKFBTsAAAAAAAAAf1u4cKGuu+465eTkSJIWL16s9evXa+bMmUGN69y5c4qOjlZoaGhQzneX+EjFRwAAAAAAAABAcUTFRwAAAAAAUOq98847BUmP582aNUvr1q0LSjx79+5Vjx49VKFCBcXGxuq5555TXl5ewONwd9U1FR8BAAAAAAAAAMURiY8AAAAAAKDUM0twfOuttwIciZSbm6srr7xSf/zxh+x2u5KSkvT666/ro48+CngsVHwEAAAAAAAAAJREJD4CAAAAAIBSLTc3V0lJSYZjs2bNCnA00m+//aZ9+/Y59X/11VcBj8Vd4uORI0e0Y8cOTZgwQdOmTVNiYmJgAgMAAAAAAAAAwIWwYAcAAAAAAADgT8nJyS7HDx8+rDp16gQoGmnKlCmG/Vu2bFFubq5CQ0MDEkdubq5Onz7tcs7u3bvVtm3bgmvCGzVqpF9//VVNmjQJRIgAAAAAAAAAABii4iMAAAAAACjVzp4963J8wYIFAYok39atW03HAnm1dEJCgvLy8tzOO5/0KEl79+7VjTfeqIyMDH+GBgAAAAAAAACASyQ+AgAAAACAUs3d9czz588PTCD/Jy0tzXRs//79AYvD3TXXZrZs2aKxY8f6OBoAAAAAAAAAAKwj8REAAAAAAJRq7io+Ll68WJmZmQGJJS8vT0ePHjUd37dvX0DikKSTJ096vfb999/X4sWLfRgNAAAAAAAAAADWkfgIAAAAAABKNXcVH1NTU7VixYqAxHLo0CGlpqaajpeEio/nDR8+XAkJCT6KBgAAAAAAAAAA60h8BAAAAAAApZq7xEdJ+vnnn/0fiKQdO3a4HA9kxceiJj4ePXpUzzzzjI+iAQAAAAAAAADAOhIfAQAAAABAqebuqmtJmj9/fgAikbZv3+5yPJAVH4ty1fV5U6dOVXJysg+iAQAAAAAAAADAOhIfAQAAAABAqWal4mNcXJzi4uL8HktpqvgoSenp6W6TOQEAAAAAAAAA8DUSHwEAAAAAQKlmpeKjJD322GPKy8vzayzukgQPHz6srKwsv8Zwni8SH6X8K68BAAAAAAAAAAgkEh8BAAAAAECpZqXioyT9/PPPeumll/wWh91ud5v4aLfbdfDgQf3222/68ccfdeDAAb/F46vEx2PHjvlkHwAAAAAAAAAArAoLdgAAAAAAAAD+ZLXioyS9+uqr6tSpkwYOHOjzOE6cOGEpCbNp06YFf46OjtZnn32m22+/3efxnDx50if7UPERAAAAAAAAABBoVHwEAAAAAAClmtWKj+fdcccdOnjwoM/jcFft0UhaWpoefPBBJScne3VmTk6O/vvf/2r48OF69dVXC5IU7XY7FR8BAAAAAAAAACUWiY8AAAAAAKBU86TioySdO3dO77zzjs/j2LFjh1frUlJSNG/ePI/X2e12DRw4UA8++KCmTJmiF154Qd27d9eBAweUlJSkrKwsr+IpjIqPAAAAAAAAAIBAI/ERAAAAAACUamYVHwcPHmy65scff/R5HN5UfDxv6dKlXq35+eefHfoOHTqkjz/+2GfXXEtUfAQAAAAAAAAABB6JjwAAAAAAoFQzq/g4fPhwjRs3znDswIEDPrsK+ryiJD6mpKR4vGb69OmG/T/88INX7+3aa6817KfiIwAAAAAAAAAg0Eh8BAAAAAAApVZGRoYyMzMNxypWrKhRo0aZrl27dq1PY/H2qmtJXlVo/Oyzzwz79+7d61Xi40033WTYf/r0aZ9dmw0AAAAAAAAAgBUkPgIAAAAAgFLL7JprSapUqZJq1KihevXqGY6vWbPGZ3GcOXOmSBUk9+/f77NYJGnLli0er+nevbvp2PHjx4sSDgAAAAAAAAAAHiHxEQAAAAAAlFpm11xL+RUfJalbt26G476s+FiUao+SdOjQIeXk5Fien56e7nJ89erVHp1/8803q1atWqbjx44d82g/AAAAAAAAAACKgsRHAAAAAABQarmr+ChJXbt2NRxfu3at8vLyfBLH9u3bi7Q+NzdXhw8ftjx/9+7dLsfNEh87duyoqKgop/5HHnlEFStWNByTpKNHj1qODQAAAAAAAACAoiLxEQAAAAAAlFpmFR/Dw8NVpkwZSeYVH5OSkhQXF+eTOHbu3FnkPTy57tpdhcm0tDTD/i5duujnn39WkyZNJEmxsbGaPHmyLrnkEtlsNtWsWdNwHRUfAQAAAAAAAACBFBbsAAAAAAAAAPzFrOJjpUqVZLPZJOVXOQwNDVVubq7TvDVr1qh58+ZFjsOTpEVf7OFthclq1aqpT58+iouL05kzZxw+TpJUq1Yt7du3z2kdFR8BAAAAAAAAAIFExUcAAAAAAFBqmVV8rFixYsGfY2Ji1Lp1a8N5a9eu9UkcBw4cKPIevqz4aKZ69eoFf65cubJD0qMkKj4CAAAAAAAAAIoFEh8BAAAAAECpZVbx8cLER8n8uus1a9b4JA6zpMU6depY3sOo0qKZolR8dKVWrVqG/VR8BAAAAAAAAAAEEomPAAAAAACg1DKr+FipUiWHdteuXQ3n/fXXX8rIyChSDKmpqUpISDAc6927t+V9rFZ8zM7OVlxcnOV9L1SjRg2X41R8BAAAAAAAAAAUByQ+AgAAAACAUquoFR+zs7O1adOmIsXg6prrXr16Wd7HauJjfHy8srOzLe97IbMrv8+j4iMAAAAAAAAAoDgg8REAAAAAAJRaZomPhSs+tmjRQmXLljWcu3bt2iLFYJb4aLPZPEp8PHz4sKWERm+vuW7RooXTx6Uws4qPp06d8jrZEgAAAAAAAAAAT5H4CAAAAAAASi2zq64LV3wMDQ1V586dDeeuWbOmSDGYJT7WqlVLTZo0UadOnSztk5eXp8OHD7udt2PHDo/iO+/iiy92O8es4qMkHT9+3KtzAQAAAAAAAADwFImPAAAAAACg1LJa8VGSunbtajjXX4mP9evXl81m0zvvvOO20uJ5+/btczvH24qPVhIfzSo+StKxY8e8OhcAAAAAAAAAAE+FBTsAAAAAAAAAf7Fa8VGSunXrZjg3Pj5eKSkppldhu+Mq8VGS+vTpoy1btmj+/PnKyMjQkCFD1KpVK50+fdppzccff6zZs2erdu3auvfee1WlShWnOf6s+FipUiVFRkYqMzPTaezo0aNenQsAAAAAAAAAgKdIfAQAAAAAAKWWJxUfO3ToYLpPfHy82rVr51UM7hIfJal27dq67777CtoNGjQwTHycM2dOwZ8/+eQTrVixQo0aNSroy8vL086dOz2OsVKlSmrWrJnLOXa7XT/s/EEhw0KkbEmnJR2VdCT/z1R8BAAAAAAAAAAEClddAwAAAACAUikvL8808dGo4mPdunUVHh5uOH/Pnj1ex2El8bGwBg0auN33yJEjevvtt53OSk9P9yg+SerRo4dCQsy/TZSSlaLbZt2mm6bfpPR66VJjSd0k3SBplKRHpdnHZispI8njswEAAAAAAAAA8BSJjwAAAAAAoFQ6d+6c7Ha74ZhRxcewsDCH6okX8iTx0W6369SpU9q3b5+ysrJMr4AuauKjJP30008O7e3bt1uO80KurrneeXqnuv6vq77f9r35BpWkxaGLVef9Onp0waOKPxPvVRwAAAAAAAAAAFhB4iMAAAAAACiVzp49azpmVPFRkpo0aWLYHxcXZ+nMM2fOaPDgwapWrZoaNWqkhg0bmiZf+iLx8ciRI0pISCho+zrx8ee4n9Xlf1204/QOS/ukZKXoo7UfqenHTXXD9zdoxYEVpu8fAAAAAAAAAABvkfgIAAAAAABKJbNrriXjio+SeeKj1YqPY8aM0ezZswvaZtUeJd8kPkrSli1bCv68adMmy+vOCwkJUZcuXZz6f9z1owZNG6SUrBSP97TLrjk756jXpF66ZeYtSstO83gPAAAAAAAAAADMkPgIAAAAAABKJVcVHytUqGDYX5TEx4yMDH3zzTeWYqtSpYpiYmJMxxs2bGhpH0navHmzJCklJUVz5861vO68du3aqWzZsg5983bN003Tb1J2XrbH+xU2c/tMjf99fJH3AQAAAAAAAADgPBIfAQAAAABAqWRW8bFcuXIKCwszHDNLfDxy5IjS0lxXLTx48KDS09Mtxeaq2qOV8QudT3ycMWOGUlNTDefUrVvXdH3ha66nbpmqwdMHW0t6zLMW44Q/JygrN8vaZAAAAAAAAAAA3CDxEQAAAAAAlEpmiY8VK1Y0XdO0aVPTsfj4eJfn7d+/30JU+dwlNrqqBlnY+cTHr776ynC8atWquuOOO0zX9+jRQ5J0POW4Bk8frKGzh7pMerysxmXSm5JekvSepGWSjPMtC5xJP6OF8QtdTwIAAAAAAAAAwCISHwEAAAAAQKlkdtW1q8TH+vXrm1aDdHfdtS8THyWpRYsWlvbaunWrduzYoZUrVxqO33HHHerWrZvp+osvvlhzd85Vy09aataOWS7PGt11tGbeNFPK+L+OVOUnPr4vaa7UuGxj07XfbvnW5d4AAAAAAAAAAFhF4iMAAAAAACiVzCo+VqpUyXRNWFiYGjRoYDgW6MTHNm3aWNorPT1dzz33nOn4XXfdpR49eigyMtJprHnz5orLjdPgGYN1NsM4UfS8R7s9qg/7fqgqsVUUERHhOJgjaaP0buN3NbTNUMP1c3fO1bnMc27fDwAAAAAAAAAA7pD4CAAAAAAASiVvKj5KUpMmTQz7A534OGjQIMv7zZ4927C/a9euat26tapWraoHHnjAafyl11/S/fPvV05ejsv9H+v2mN6/5n3ZbDbZbDbVrFnTcN6aNWs0ot0Iw7H0nHTN3TXX9RsBAAAAAAAAAMACEh8BAAAAAECp5E3FR6n4JD7eeOONuu666yzvaeTuu+8u+PP777+v//3vfxowYIAGDhyoFStWaGulrdqfuN90fYgtRC/1ekn/vubfstlsBf2tWrUynD9jxgz1btBb1WOqG45z3TUAAAAAAAAAwBdIfAQAAAAAAKWSrys+xsXFuVzn68THyMhIzZs3Tz/88IPeeOMNLVq0SDfeeKPlM6KiojRkyJCCts1m0z333KO5c+dqzpw5qtaimt5Z/Y7p+jbV2mjNPWv0Yu8XHZIeJWngwIGGa+Lj47V181YNaT3EcHxR/CKdTD1p+T0AAAAAAAAAAGCExEcAAAAAAFAqeVvxsWnTpob9hw4dUnp6uuFYRkaGjh07ZimusmXLuo3hvJCQEA0aNEj/+te/dOWVV6pDhw6W1knS4MGDVaFCBcMxu92uUQtGKSs3y3D89ra368/7/lTnWp0Nx2+44QaFhoYajs2YMUND2ww1HMu152r6tukWogcAAAAAAAAAwByJjwAAAAAAoFTydcVHSdq3b59h/8GDBy3HVb9+facKila1bdvW8twLr7m+UFZulv7127+0eO9iw/Gq0VX1Ud+PFBEaYbp31apV1adPH8Ox6dOnq3PNzmpS2fjjyHXXAAAAAAAAAICiIvERAAAAAACUSt5WfGzQoIFCQoy/ZbJnzx7Dfk+uua5evbrluYVZTXxs06aNevXq5dS/6fgmdf+iu95a9Zbp2reveluVyrivSHnzzTcb9sfHx+uvv/7S0NbGVR//OPyHDiQecLs/AAAAAAAAAABmSHwEAAAAAAClkrcVHyMiIlS/fn3Dsbi4OMN+TxIf7Xa75bmF1a9fX+XKlXM7b9y4cQXJmztP79TY38aq1YRW6vBZB208vtF03SX1LtGd7e60FIu7666HtR1munbWjlmWzgAAAAAAAAAAwAiJjwAAAAAAoNTJzMxUenq64Zi7io+S+XXXvqj42LdvX8tzC7PZbG6rPjZr1kyDBw+W3W7Xq8tfVZtP22j8yvHafmq7y3WhtlBN6DdBITZr3y6qWrWqevfubTg2fvx4vTPmHdUNq2s4TuIjAAAAAAAAAKAoSHwEAAAAAAClTlJSkumYu4qPktS0aVPDfl8kPvbv39/yXCPuEh/Hjh2r0NBQvbD0Bb2w7AXl5OVY2veDvh+oTfU2HsVyyy23mI598cUXOvTrIcOx1YdW60jyEY/OAgAAAAAAAADgPBIfAQAAAABAqXPkiHlSXTArPt5zzz1q2bKlpblmXCU+NmjQQEOHDtU7q97Ra7+/Zmm/2DKxmj54ukZ1HeVxLK6uu5YkuSgyOXvHbI/PAwAAAAAAAABAksKCHQAAAAAAAICvbdy40bA/MjJSNWrUcLveLPHx4MGDyszMVGRkpEO/WeLjO++8I7vdrsTERHXs2FE33nij27PdcZX4+PQzT+ujdR/pmcXPWNqrf7P++t/1/1ONsu4/JkbOX3f922+/GU9IkHRCUnXnoZk7Zmp0t9FenQsAAAAAAAAA+Gcj8REAAAAAAJQ6ZomPbdq0UViY+2+HmCU+5uXlad++fbrooosK+jIyMnTs2DHT86655hoLEVvXuXNn1a5d26mqZWy3WH1q/1RbF211u0e32t30WPfHdGurW2Wz2YoUz913322e+CjlV300SHz8/cDvOp5y3OukSwAAAAAAAADAPxdXXQMAAAAAgFJn06ZNhv0dOnSwtL5hw4amCYEHDx502b5QgwYNLJ3niYiICL377ruKiIiQKkq6RLI9aFPCtQnaeso86THEFqJ3rnpHR544oj/u+UNDWg8pctKjJA0ZMkQ333yz+QST667tsmvOzjlFPh8AAAAAAAAA8M9D4iMAAAAAAChV8vLyipz4GBUVpQoVKhiOJSUlObTNrrmWpHr16lk6z6p1R9bpyV+f1FfZX6nCKxWkxyRdKdmr292u/WrAV3rq4qdUq1wtn8YUEhKi77//XosXL1avXr2cJ5z6v5eBmdtn+jQWAAAAAAAAAMA/A1ddAwAAAACAUiU+Pl4pKSmGY+3bt7e8T4UKFZSYmOjUbzXxsUaNGipTpozl81xJykjSPT/e43Wi4MfXfqzh7Yf7JBYjNptNV1xxhaKionTJJZc4T9guySAnctn+ZTqddlpVoqv4LTYAAAAAAAAAQOlDxUcAAAAAAFCqbNy40bDfZrOpbdu2lvcpasVHX11zve7IOnX4rINXSY8RoRGa0G+CRnUd5ZNY3ImOjjYe2GHcnWvP1ZJ9S/wXEAAAAAAAAACgVCLxEQAAAAAAlCpm11w3b95cMTExlvcJduJjVm6Wxv8+Xj2/6ql9ifs8Xj+k9RDtfHinHuzyYJHi8IRphcvjUr1yxtd+rzuyzo8RAQAAAAAAAABKI666BgAAAAAApYpZxccOHTp4tE8wEx+X7Fuih39+WDtP7/R47VWNrtLrl7+uLrW7eH2+t0wrPkrqWKWjDp476NS/7iiJjwAAAAAAAAAAz5D4CAAAAAAAShWzxMf27dt7tE8wEh9z83L1yIJHNOHPCR6t61yrs4a0GqJbWt2iuhXqenyur5hWfJR0UfmLDPvXH1uv3LxchYaE+issAAAAAAAAAEApQ+IjAAAAAAAoNY4dO6YTJ04Yjnla8bF8+fKG/RcmPmZkZOjYsWOG87xJfHx28bOWkh6bxTbT/Z3uV+tqrdW2elvVKFvD47P8wVXFxyZlmhj2p2SlaFfCLrWs2tJfYQEAAAAAAAAAShkSHwEAAAAAQKmxadMm0zFfXXWdnJxc8OeDB52vbj7P08TH5fuX69//799u593e9nZ9et2nKhtR1qP9A8FVxce64XUVFhKmnLwcp7F1R9aR+AgAAAAAAAAAsCwk2AEAAAAAAAD4itk113Xq1FGVKlU82svKVddm11xLUr169SyfdS7znEbMHSG77ObxRFbQVwO+0pRBU4pl0qMkhYSEKDIy0nAsNzNXbaq1MRxbd3SdP8MCAAAAAAAAAJQyJD4CAAAAAIBSwyzxsX379h7vZSXx0aziY7Vq1VxWPyzsiV+f0P7E/abjd7a7U7tG7dJdHe6SzWazvG8wmL3vtLQ0danVxXCMxEcAAAAAAAAAgCdIfAQAAAAAAKWGWeKjp9dcS0VLfKxfv77lc37a/ZO+2PiF6fjMm2dq8qDJql62uuU9gyk6OtqwPy0tTV1qGyc+bjq+SVm5Wf4MCwAAAAAAAABQipD4CAAAAAAASoXk5GTFx8cbjgU68dHqNddxCXG644c7TMfv7Xivbmp5k6W9iguzio/p6emmFR+zcrO05cQWf4YFAAAAAAAAAChFSHwEAAAAAAClwl9//WU65svEx6ysLGVkZEiSDh06ZDjHSuJjUkaSBkwboMSMRMPxhhUb6r2r37MWbDHiquJjq2qtVCbMODFy7ZG1/gwLAAAAAAAAAFCKkPgIAAAAAABKhd27dxv2V6hQwaOrpy9cZ+Z81UdvKz7m5uVqyKwh2nl6p+G4TTZNGjRJ5SLLWYy2+HBV8TEsJEwdahonoa47us6fYQEAAAAAAAAAShESHwEAAAAAQKlw6tQpw/5GjRrJZrN5vJ+7xMe8vDyvKz6OWzJOv+z5xXT86Yuf1mX1L7MWaDHjquKjJNPrrkl8BAAAAAAAAABYReIjAAAAAAAoFRISEgz7q1Sp4tV+7hIfT506pczMTMNxV4mP209t19ur3jYdv6bxNXr9itetB1rMmCU+pqenSzJPfNx+artSs1L9FhcAAAAAAAAAoPQg8REAAAAA8I+RkpJSUHUOpc/p06cN+71NfCxXrpxppcikpCTTa64l14mPb658U3bZDceaxTbTtMHTFBYS5lmwxYjZVdcFFR9rGyc+5tnztOHYBr/FBQAAAAAAAAAoPUh8BAAAAACUeseOHdNll12m8uXLq2rVqnrggQeUk5MT7LDgY75OfAwJCVG5cuUMx5KTk00THyMjI1W1alXDsQOJB/Tdlu8MxypEVtC8IfNUMaqiV/EWF+4qPjap3EQVIo2raa49stZvcQEAAAAAAAAASg8SHwEAAAAApd51112n33//XXa7XWlpafrss8/09NNPBzss+JhZ4mNsbKzXe5YvX96w31XFx3r16plWinx39bvKtecajn3S7xM1r9Lcu0CLEXcVH0NsIepcq7PhnF/if/FbXAAAAAAAAACA0oPERwAAAABAqbZjxw5t3LjRqf/jjz/W7t27gxAR/CUhIcGw39uKj5JUoYJxZUJ3iY9GTqae1BcbvzAca1ypsYa0HuJdkMWMWcXHC6+Zv7TepYZzlu1fpsSMRH+EBQAAAAAAAAAoRUh8BAAAAACUart27TLsz83N1csvvxzgaOBPvr7qWvJt4uNHaz5SRk6G4dgzPZ9RaEiod0EWJxmndFmtnfrlWWn/h9KmN6S7e+UPnb/qWpKub3694fKcvBz9soeqjwAAAAAAAAAA10h8BAAAAACUamZVACVp6tSp2rZtm6V90tPTtXbtWv3222/KycnxVXjwkZycHJ09e9ZwzF+Jj4cOHTIcM0p8TM5M1n/W/sdwfs2yNTW83XCvYwy69BNS3H+l366QfqihG2r/omvaSvWrSO3qS1/eJ/34lBSel1SwpEONDqpTvo7hdnN3zQ1U5AAAAAAAAACAEorERwAAAABAqXbmzBnTMbvdrpdeesntHvHx8erSpYu6deumK6+8Uo0bN9bOnTt9GCWKyizpUZJiY2O93tdXFR/fXvW2kjKTDGZLT/R4QpFhkV7HGBT2POngLOm3y6U5taR1D0onluT3G+jfQZp061/Syd8lSTabTQOaDTCc+3Pcz8rKzfJb6AAAAAAAAACAko/ERwAAAABAqeaq4qMkzZw5U23bttXYsWO1evVq2e12pzmjRo1yqAx58OBB3XbbbcrNzfV5vPCO2TXXkn8qPp48eVInTpwwHCuc+Lj37F69u/pdw7kVoyrq/k73ex1fwOVlS3snSfNbSisHSyeWmiY7Fla9XLb0Wx9pzxeSpIEXDTScl5yZrBUHVvgqYgAAAAAAAABAKUTiIwAAAACgVHOX+ChJW7Zs0fjx49WzZ08988wzDsmPiYmJWrhwodOaTZs2aenSpT6NFd5zlfjoj4qPW7duNV1Tt25dh/ZTC59SZm6m4dxRXUapXGQ5r+MLqKQd0oL20h93Scm7vNvDniutvVfa/pZ61e+lchHG733uTq67BgAAAAAAAACYI/ERAAAAAFCqubrq2si7777rkNR25MgR5eUZV7QbP358kWKD75glPkZHR6tMmTJe72uW+Lh//37TNRcmPv629zf9sPMHw3lVo6vqyYuf9Dq2gDr1/6RFl0hJ232z36YxitzynK5t0tdweN7ueYbVVwEAAAAAAAAAkEh8BAAAAACUclYqPha2aNGigj+fOnXKdN7y5ct17tw5r+KCb5n9dy7KNdeSeeKjmSpVqig6OlqSlJOXo0d/edR07htXvKGKURWLEl5gHJkvLblCyrKeRBx3XNpxxM2kHe/qxQpphkMHkw7qrxN/eRAkAAAAAAAAAOCfhMRHAAAAAECp5k3i44XJjq4SH3NzczVz5kyv4oJvmVV8DHTiY7169SRJdrtdTy98WttObTOc17FmR93V/q4ixRYQ+76RVgyUctPdzy3XTGo1Tmsqf6ZmT0odx0mf/eZ6ScvT83VpGeNvT83bNc+LgAEAAAAAAAAA/wQkPgIAAAAASjVPr7qWHJMlXSU+StLkyZM93h++V9wSH19d8ao+WPOB6byP+n6k0JDQooTmf3unSP/vTsmeaz7HFiLVHyr1XS/13ym1e015FdpIkjKypQe+kh6d4vqYz2qXlc2g/8fdP3ofOwAAAAAAAACgVCPxEQAAAABQatntdtOKj6NGjTJdd2GypLvEx+XLl2v//v1exQffMfvvHBsbW6R9vUl8/PCPD/XishdN5wxtM1Q96/UsUlx+t3ey9McISXbzOTWvkfrvlnp+K1XuKNny0xfLlCnjMO2jX6XbJ0g5JvmTLWzJuq2cc//6o+t1KtX13z8AAAAAAAAAwD8TiY8AAAAAgFIrLS1NmZmZhmO33Xab/vWvfxmOeZL4KElff/21dwHCZ/xV8bF8+fIezT9b66we+/Ux8/0iy+utK98qUkx+Fz9R+uMuuUx6bDhc6vWjVK6x01B0dLRT37erpFs/Nt/uzVipTKGyj3bZtWjvIotBAwAAAAAAAAD+SUh8BAAAAACUWmZVACWpcuXKqly5stt1VhIfp0yZIrvdOUksLi5O7733nv7zn/9o3759FiKGt4rFVddlpdlZs02Hw0LCNPWmqapTvk6RYvIbu13a/JK05m65THps+azUfaIUEm44XLji43mz10kpFS83HKsbLj1R0bn/lz2/uAwZAAAAAAAAAPDPROIjAAAAAKDUurByY2GxsbGm1yB7WvFxz549+vPPPx365s+frzZt2uipp57S6NGj1b59ey1btsxa4PBYsUh8vE5KzUs1HLLJpm9u+Eb9mvYrUjx+k5sp/b87pa0vu57X9lWp/ZsF11obMar4eN7hKo9ItjDDsTGVpYaFhn6N/1V59jzXMQEAAAAAAAAA/nFIfAQAAAAAlFquKj5WqlTJtOKjp4mPkrR+/fqCP9vtdo0aNcrhmu3k5GQ98cQThpUhUXRm/63NklutsnzVdUtJLcyHP+v/mW5tfWuRYvGbnDRpaV9p/zeu57V9VWr9nNvtzCo+SlJiXnWp6UOGY2VDpHm1pHIXfLfqZOpJbTq+ye2ZAAAAAAAAAIB/FhIfAQAAAAClllkyXIUKFRQWFmaa+JiWlqaMjAxJ1hMfjxw5UvDnXbt2af/+/U5zNm7cqIMHD1raD9bl5OTo7NmzhmNFrfgYFhammJgY15PKSHJRyPH5y57XvZ3uLVIcfmO3S2vulU4ucz3PYtKjJEVFRZmOpaWlSW1ekCIqGY63jpS+qe74DSuuuwYAAAAAAAAAFEbiIwAAAACg1DK76vp8FUBX1QDPnDmjvLw80yuUC7sw8XHHjh2m83bu3GlpP1jn6krzoiY+Sm6uuw6TdIOkssbD7Wu01/OXPV/kGPxm98fSge9cTLBJHd6znPQoSSEhIabJj+np6VJkrNT6RdP1A8pKr13wV5PERwAAAAAAAABAYSQ+AgAAAABKLXfXH5tVfJTyk+kSExOVm5tr6awLEx/T0tJM5xlVgkTRuLrSvKhXXU/bOk2JgxKl+yX1lXThdmUk3SmpmfHaUFuovhrwlcJDw4sUg9+cXClteNJ8PLSMdOksqcUTHm8dHR1t2F/wd6PZw1L1K0zX/6uydOP/JZOuPrRaSRlJHscAAAAAAAAAACi9SHwEAAAAAJRaRUl8TEhIsHzNteSY+HjixAnTeXFxcZb3hDWuqnIWJfHx7VVv67ZZtymtWppUU1J3SaMkDZU0WNKzkuqZr3+m5zPqULOD1+f7VeohaeXNkj3HeDyqunTlcqnuDV5tb5b4mJ6env+HkDDpkulS2came3xeTaoVKuXac/Xbvt+8igMAAAAAAAAAUDqR+AgAAAAAKLXMrkA+n/AYERGhsmWN7yg+c+aM14mPx48fN51H4qPvmSU+xsTEqEyZMl7t+eOuHzVm8RjnAZvyKzy2dr3+oioX6YVeL3h1tt+d3SQt7C5lmHyehkRKvedLsV28PsLs4+5QDTWystRrnhRWznBubKg0sXr+h3xB3AKvYwEAAAAAAAAAlD4kPgIAAAAASi13FR8l86qPniY+JiYmFiR1uUp83L17t+U9YY1Z4mOVKlW82m/HqR0aNnuY7LJ7tb5cRDlNvWmqosKivFrvV0d+lhZdKqUfNZ/TZYJUuVORjnFb8fG8Ci2lntOUn97o7OoYaXRF6Zf4X2S3e/ffAwAAAAAAAABQ+pD4CAAAAAAotYqS+OjpVdeSdPRofjKZq8THvXv3Kjc316N94ZqV/85WnU0/qwHTBuhc1jmvYqlZtqZW3LVC7Wu092q93+TlStvGSyuul3JSzOc1uV9qfHeRj7NU8fG82v2k1s+Z7vVWrFQh47COp5j/vQIAAAAAAAAA/LOEBTsAAAF05IgUE+PbPevUkcIsPEoOH5Zycnx79nk1akhRFiqpHD8uZWT4J4YqVSSTKxIdnD4tpbj4IWNRVKyY/3InMTH/5Q9ly+Z/LNxJScn/WPhDVFT+54Q7GRn5nxP+EBaW/3fDnZyc/L8b/tKggbV5+/f7LwaeEfl4RuTjGZGPZ8TfeEbk4xmRz0/PiKjjx1XfoL++3V7w+d0yOlpnJWVIOnHBnDNnzig7O9tpbaQksyfJ6T//VJOwMIUcPGh4riQpK0tHV69W3bp1ncd4RvzNg2dEbny84ce7VUyMxzGO+fF+ZcfvUX1Jx8tKmeHu11Q/J0XlSE0qN9bkqyardkZF331sfPGMSD8mrX9cSljjeo+K7aXYx51j9+IZ0dBm0zGDKRFHjxp/bMreIWXPkxL/chqKkvRZlLT5xGbVLFfTdQx8HZGPZ8Tf+DoiH19H5OMZkY9nxN94RuTjGZGPZ0Q+nhF/4xmRj2dEPp4R+XhG/I1nRD6eEfl4RuTjGfE3nhH5eEbkK67PiCNH/BNTINkBlFpbt261Syp4bZXsdl+/9u2zFkz9+r4/+/xr6VJrMfTq5b8YJk60FsPw4f6L4cUXrcXw4ov+i2H4cGsxTJzovxh69bIWw9Kl/ouhfn1rMezb578YJGsx2O3+jYFnRP6LZ0T+i2dE/otnxN8vnhH5L54R+a9i8IxYqr+/dpZkv/fee+2PPvqoQ58key9/fQwknhEXvorBM6LXcNn1kvvX0vp+/DjwjMh/XSr7pN8ecR8DX0fk4xnxN76OyFfanxHF4OsInhEXvKzyZww8I/JfPCPyXzwj8l88I/5+8YzIf/GMyH/xjMh/8Yz4+8UzIv/FMyL/xTMi/8Uz4u8Xz4j8F8+I/FcJf0ZslePPPrZu3Wptr2KEio8AAAAAABhISEhQampqsMNAcbFL0hpJLSRVlpQlKen/XtzAHBANT/0k6cNghwEAAAAAAAAAKAZIfAQAAAAAwMCZM2cUHm7hnmOUerXCa+no7KNSpqS9wY7mn6tbzj4p45QUVTXYoQAAAAAAAAAAgiwk2AEAAAAAAFAcnTlzRqdOnQp2GCgG7q17b37SI4Iq0mZXTtx/gx0GAAAAAAAAAKAYIPERAAAAAAADCQkJQU98TE5O1nfffacJEybo6NGjQY3ln6pr7a66rPZlwQ4D/ydv9ydSXk6wwwAAAAAAAAAABBmJjwAAAAAAGAh24uOOHTvUvn17DRs2TA8//LAaNmyomTNnBi2e4sru5/2fv+x5VaxY0eWcMlFRfo4C50VknpAOzwl2GAAAAAAAAACAILPZ7XZ//4wAQJBs27ZNrVu3Lmhv/fVXtWrWzLeH1KkjhYW5n3f4sJTjp6ocNWpIVn7QePy4lJHhnxiqVJHKlnU/7/RpKSXFPzFUrJj/cicxMf/lD2XL5n8s3ElJyf9Y+ENUVP7nhDsZGfmfE/4QFpb/d8OdnJz8vxv+0qCBtXn79/svBp4R+XhG5OMZkY9nxN94RuTjGZHPD8+IOXPm6LHHH3fqj61cWevXry9or1u3TjffcosyJJ2wsG+kpFcfekifTJjgNBYWGqrHHntM7773ntt9li5ZooYNGxba4O9nxM033+yU6Fi5cmXt2bNHlcqV8+oZkZSUpHbt25uO79u7VzabrUQ9I05v2qTOHToYjv08f75atmzpcv3+xP3qM6mPYQJltcZttGbUX9q7d6+aNGliuseIvn018dNP3cbqFSvPiNwMadFIadd3rufVu1lq/6Zk8/D3YL14RnzyySd65913naZ0aN9eP/zwg9utbvuuryaV2aXI86FGSSr3f3+udpl05XLjhXwdkY+vI/7G1xH5+DoiH8+IfDwj/sYzIh/PiHw8I/LxjPgbz4h8PCPy8YzIxzPibzwj8vGMyMczIh/PiL/xjMjHMyJfMX1GbNu9W62vuaagvXXrVrVq1crXEfqVhb+NAEqN2rWtfzHga1a+EPI3Kw97f6tSxdr/+PzJ6hcA/lS2rLUvhPwpKip4fx/OCwsLfgxS8YiBZ0Q+nhH5eEbk4xnxN54R+XhG5PPgGXEwJEQHDPrLVKvm8Lkdk5ZmOM9MpqQGvXvrgEHio3JztfLwYUv77UhPV0OTv2OZmZmGyWFnzpzR7NmzNXLkSK/+fs788kuXsaVUqaJy5cq5mFFIMXhGnIyIMH1PFdq1y/93kAv/++1/2l/JeOzdK16QzWZThQoVXO5Rt0uX4H0szsVLK2+Wzm6UqrqYV/82qcfXUkio/2K54BmRVauW4X+XCnl5lj5WUa166Nuju3S30Yf+5AopaadU4SLnMb6OyMfXEX/j64h8fB2Rj2dEPp4Rf+MZkY9nRD6eEfl4RvyNZ0Q+nhH5eEbk4xnxN54R+XhG5OMZkY9nxN94RuTjGZGvuD4jUlODEoovcdU1AAAAAKBUSkhIMOyPjY11aFeuXNnjvdu1a2c6tmHDBkt7xMXFmY7t2bNHubm5hmPjx4+3tL+RqVOnuhxPSkryeu9gMfvvLDn/ty4sz56nrzd/bTjWokoL3djiRklym/h4YaX9gDr0g/RLp/ykR1fq3Sz1mOzfpMdCoqOjDfvT09MtrW9bra0+dvXpeGiWF1EBAAAAAAAAAEoLEh8BAAAAAKVKbm6uDh48qFOnThmOF0509DTxMTw8XI0bN1aYyZUmrhIarc7btWuX6Vh8fLxOe3EtxrFjx7R06VKXcxL9deWHH5l9LGJiYhTl5sqX5fuX61DyIcOx0V1HK+T/roQODw93uU+bNm0sROpDOWnSuoek32+Ust0kq7YaK/WcJoW4fg++VqZMGcP+tLQ0S+vb1WinTZnSH2Z5kiQ+AgAAAAAAAMA/GomPAAAAAIBS47///a9iYmJUv359ffrpp4ZzClcBjIiIUFkPrpmoWrWqQkNDVbNmzSLF6irxcefOnS7XGl2D7c706dOVl5fnck5JTHw0+zhWsXCFilm1x4jQCN3a+lbLMTRp0sTy3CI7szG/ymOc8ed3gZAIqccUqd3rki3w3/4xq/hoNfGxbfW2kqTpKSYTzm6UUvZ6ExoAAAAAAAAAoBQg8REAAAAAUCosWLBADz74oDIzM13OM7r+2JOqj1WrVpUk1a5d27MACylK4uP06dM9Ps/dNddSyUp8nD9/vjp37qxnn33WcNxd4mNadppmbJ9hOHZ9s+tVuYz1zwl3FSF9Zs8X0sJuUrLrzw+VqSVdsUxqeEcgojIOwaTio9WrrqtEV1GtcrU02yzxUZIOUvURAAAAAAAAAP6pSHwEAAAAAJQK06ZNszTPKMnRKBnSjK8SHw8cOGCapOku8XHJkiWmV3kb2bt3r9asWeN2XlKSm2uTi4nff/9d/fv31/r1603nuEt8nLNzjlKyjLPq7mx3Z5Hi84ud70tr75Xysl3Pq3GldO1GqWqPwMRlwqziY0ZGhtvKo+e1rd5WB3KkPzNMJnDdNQAAAAAAAAD8Y5H4CAAAAAAoFTZt2mRpXnGp+JiXl6e9e52v6rXb7W4TH/Py8jR79mzLZ1mtEFlSKj6OHTvW7Rx3iY9T/ppi2B9bJlZ9m/R16r/tttsM5//73/92G0uRbX1d2vCEm0k2qc1LUu9fpKhq/o/JDbOKj1J+8qMV7aq3kyTNNKv6mLBGSjvsaWgAAAAAAAAAgFKAxEcAAAAAQKmwefNmS/OKS+KjJMXHxzv1HT9+XOfOnXO71pPrrn/++WdL80pC4uOZM2e0evVqt/MuvfRS07Fj545p0d5FhmO3tb5NEaERzv0GiY9RUVG64w4/Xidtt0t/jZM2P+d6XnQd6YrfpDYvSiGh/ovHA2YVHyUpLS3N0h5tq7eVJM1ydd31IesJwAAAAAAAAACA0oPERwAAAABAqVCxYkVL83x11XWtWrUsrzGTkJDg1Oeu2uN5y5Yt08mTJ93OS0xMtJQoeH5ucbdkyRK3VyV36dJFt99+u+n4d1u+U57deA+za66vv/56ffzxxwWVJBs2bKhFixa5rSzptbxcad2D0rY3XM+rd4vUb7NUvY9/4vCSq4qP6enplvY4X/FxT7a02fhWeK67BgAAAAAAAIB/qLBgB4DASExM1JYtW7R7926dPXtW2dnZqlSpkmrUqKFu3bqpZs2aPj3Pbrdrw4YN2rRpU8EP4qpXr6527dqpY8eOstlsPjsrISFBq1atUnx8vFJTUxUTE6PGjRurZ8+eHv3w0p1AvicAAAAAngsJsfa7fcWp4uPZs2ed+qwmPubl5ennn3/WiBEjXM5bvHixcnNzLe2ZlJRkaV4wLVpkXKlRkvr166frrrtOw4cPV0xMjOm8mTtmGvZfVOUida7V2XTdqFGj9OCDD+rs2bP+S3iUpNxMafXt0iHjOAt0/EBq/ohUDP896ouKj81imykiNEJZuVmalSK1jTSYdPJ3Kf2EVKa6l5ECAAAAAAAAAEoiEh8DbMSIEZo8ebJP9qpfv772799vOJaXl6dly5bpxx9/1OLFi7V161aXe7Vs2VIPP/ywRowY4fKHE+5kZ2frww8/1AcffKAjR44YzqlTp44ee+wxPfLIIwoPD/f6rL/++ksvvPCCfvrpJ8NqH6Ghobruuuv06quvqm3btl6fE8j3BAAAAMA7drtdycnJluaWlsRHSdq9e7fbOQsWLLC8X3Gv+Gi327Vw4ULDsZEjR+qLL75wu8eR5CP64/AfhmN3tL3D7S+1hYaG+jfpMSdNWj5AOvGbi0k2qevnUpN7/BdHEbn63oLVio/hoeFqUrmJtp/arlkp0suGv9tol7a+InX5xLtAAQAAAAAAAAAlElddl2ARERGG/b/++qvq1KmjK664Qh988IHbpEdJ2r59ux5++GG1b99e69at8yqeQ4cOqVu3bnr66adNEwQl6fDhw3rqqafUo0cPl/Nc+fDDD9W5c2fNmzfP9Iqz3NxczZs3T506ddLHH3/s1TmBfE8AAAAAvJeZmamcnBxLc40SH7256toXiY9GiYa7du2yvP706dMux+12u3755ZcixVOcxMfHm/4C4NVXX21pj7m75pqODW452JuwfMdul9bc6zrp0RYi9ZhSrJMeJddXXVut+ChJTSs3lSRty5J2ZZlMipsgnVjuSXgAAAAAAAAAgBKOxMcSrH///ob9cXFxOnbsmOFY5cqV1bJlS3Xp0kX16tUzXNurVy+tWLHCo1hOnjypPn36aOPGjQ79ZcqUUatWrdSiRQtFRUU5jK1fv159+vRx+4O6wv7973/rsccec/qhZs2aNdWpUyena7tzcnL0yCOP6KOPPvLonEC+JwAAAABFY7Xao2SckOVNxceYmBhVqFDB8jojRa346O7fHps3b9bRo0ct71fcr7o2q/Zos9l0xRVXWNpj9o7Zhv2tqrZSs9hmXsfmE7s/lg58Zz4eEiFdMkNqeHvgYvJSZGSkafVMqxUfpb8THyVpiqu/5mtG5lfLBAAAAAAAAAD8I3DVdYA988wzuv12z39AERcXp4ceesihb8SIEW7X2Ww2XXnllRoyZIh69+6tRo0aOYwfPHhQH330kT744APl5uZKyv8BxPXXX68dO3aoVq1aluIbMWKE4uPjC9pRUVF68803de+99xZcb5WamqrPP/9cY8eOVUZGRsH7uvvuuzVv3jxL56xevVrPPPOMQ1/v3r313nvvqWPHjgV9f/75p5566iktX/53xYcnn3xS3bt3V9euXYvVewIAAABQdOfOnSvSem8SH6X8qo9FSRYsnPiYlpamAwcOWF7vLvHRk2uupeJf8XHRokWG/Z06dbJUtTMhLUHL9i8zHLuxxY1FCa3oTq6UNjxpPh5WTuo1V6reJ3AxFYHNZlOZMmUMqzt6VPEx9u/Ex48SpfsqSPXDDSamxEubn5c6vudFtAAAAAAAAACAkobExwBr2bKlWrZs6fG6JUuWOLQ7dOigtm3bms6PiIjQ/fffryeeeEINGjQwnVevXj29++67uvbaa3XdddcpMzNTUn61lH/961+aPHmy29gWLlzo8MO08PBw/frrr7rssssc5sXExOjxxx9Xx44dddVVVyk7O1uS9OOPP2rp0qXq08f9D2+efvrpggRNSbr++us1c+ZMp2u/O3furIULF+rGG2/U/PnzJeVXfnz66acdkiGL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/Pjgx8LjPu4+mHXtLMs2oy03VHosumD6PO8wYMgvwNAVgFewZWs0MlFRUcLjSUlJZgOJpnQP6Y57et0jHMssyUS3z7rh2yPfQqvTKlrn4qVLQOho8WAag49EREREREREREREdQmDj0RERERERORy5oKPpaWlKCwstGjOuljxURY0BAB0BnA3oFPrhMMdm3XEiukr0DxA3IYasDz4GBAgrgp54sQJ9G/SXzhWqavE/635P5RVlVm0limm2hCba3W96+Iu7EvaJxy765q70NRbQXvxK0U/BmSaaGvcpDPQ/2tgygUg4jbL5m6kZBUfAeD48eM2zT1v5Dx4u3kLx9KK0nDv7/ei79d9EZMTU3vQB0ZPxRISEoBQSbvrvOOGSqBEREREREREREREVCcw+EhEREREREQuZyr4CADnzp2zeM56U/FRDWAogBkAPMXXeWo8seKWFfD39IeXl5d0/vbt21u0H1NBzB8f/RGqcpVw7GTGSby87WWL1jLF2oqPmcWZuOPXO6Tjj/R/xLKNpPwJxH0lHw+bZGhr3fFeQCP5n0VGWrZsieBgcVVMW9tdt/JvhScHPmnynGNpx/Ct6lugOwzfa08BmAvgeQB3AhgEoPm/wccWkoqPAJCxw6a9EhEREREREREREZH9MPhIRERERERELmcq+AYAhw4dsnjOulbxceuFrViYthC4H4aw1TgA18EQwhoLQJwxBAB8eN2HuLbltQBgsvKlvVpdGxYC9Bv10uGF+xbi5W0vo1JbadGaIrL//+7u7vDx8RGOaXVa3PHrHUgqSBKOj2w7EteEXqN8E5UFwMH/yscDrwGGLAPUbsrnJACASqWSVn20NfgIAHOHzEWob6jJcyrVlcB0GL7XqjPR7gA6AZgA4BFgUdoilHmFAb5txZNk7rV5r0RERERERERERERkHww+EhERERERkcuZq/h44MABi+esSxUflxxbgvE/jsehvENASxjCVkMADATgZ/ra23vcjvv73F/zcX5+vvTc1q1bW7Qvk8FHADgO4Ix4SA893tz1JoZ9Nwznc85btO7VZK2umzVrBpVKnAh9Zfsr2HJhi3TOZwY/Y9kmjj4LlCSKx7xCgRG/A+51K0xbnzgy+BjgFYDVt65GiG+ITfPEusXi1e2vAsHDxCdkMfhIREREREREREREVFcw+EhEREREREQu54jgY12p+Hg8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GXwkEdnfM1M/sxLRarXYtWsXysrK0KNHD5MftAeUVXwEGqo++vn5SR8C79Wrl8lrExERUctVWVmJgwcP4ty5cygsLER5eTm8vLzg7++PNm3aoH379mjXrp1JXVuJyHEYfHSAvn376rzOzs426fymbZdDQkIs3pMlevfujT/++KPxdWJiIu666y5F52ZmZuLSpUuNr93c3NCtWzfhsd27d4ebmxtqa2sBAJcuXUJmZqbilrw7d+7U27eMvb4mIkeStbkGTAs+rj6zWjo3rZuZba4BIGujeDxsGODCaoJXYsVHIiIiIiIiIrIFU4KPtbW1qK2thZub8pbJ9gw+yni6emJG9xn4/ODnenPrzq5DfkU+Qrxtfw++tLTU7HNLSkosanXdNqCt2WtT8yW7f9f072V9fT327duHCxcuICEhAXFxcQavW1FRgYkTJzZ2GfP19cVXX32Fm2++2aT9mRJ8lH3fcXd31+smRkRERFcfrVaLNWvW4NNPP8XGjRuNfobq5+eHfv364dprr8WECRPQv39/RUHImpoaHD58GHv27MHevXuxd+9enDt3DlqttvGYr7/+GrNnz7b0SyKi/2Hw0QEmTZoEtVoNjUYDAEhKSkJBQQGCg4MVnX/gwAGd103ftE2bNg09evQweV9PPfUUjh492vj6H//4B8aOHdv4Ojw8XHje9ddfj//85z+Nrzdu3AitVguVSmV0zQ0bNui8HjlyJHx9fYXH+vn5Yfjw4di06e8qcH/++SfuvPNOo+totVps3Kgbopo8ebL0eHt9TUSOJAs+ent7w8/PT/F11p5dKxyPj4hHh+AOZu0NdRVA7k7xXORo867Zgjky+MiKj0REREREREQtl6nv7ysqKhAQEKD4eGcIPgIN7a5FwcdaTS1+OvkTHrzmQcVrmcvSio9sdU2mUtLquqKiAjfccEPj5zIqlQoff/wxHnroIel1FyxY0Bh6BICysjLcfffdGD9+vEn3nZW0ugYago+yzjeXC2oQERHR1Ss5ORn33HOPTldWY0pLS7F161Zs3boVCxYswKpVqzBlyhTp8U8//TS2bduGI0eOoKamxhrbJiKFGHx0gPDwcAwZMgTbt29vHFu5ciXuu+8+o+fW1dXhl19+0RkbMWKEzuvWrVujdevWJu8rKChI53W3bt0wZswYo+clJCQgNDS08U3oxYsXsXXrVowc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zjlHn3zyiW6++Wa9/vrrZeP33HOPhg8f7jQgVJnvqTIdPnxYx48ftwtqumL79u167bXXHF4T6hUfvWl1/dOun/TQoodM5//R5x+Ki4rz+GyAKwg+AgAAAAAA2HMUfLRarYbPU9xpdU3FRwAAAKBqGjlypB599NGy4lKFhYV6+umn9eKLLxpef+2112rXrl1O1z106JD69+9vODd69Gi9/fbbHp8ZqG6o+BhAf/vb3+weirz//vsOQ4/lOQqutWzZUmvXrtWsWbMchh7P1rZtW82cOdNu7Mcff3SpZfMjjzxiV93w+uuvd/hezjvvPD377LN2Y4899piKi4sd7rNhwwb95z//KXsdGRmpd955x/ThlcVi0YsvvqgWLVqUjW3btq3C+zRSWe8pEDyp+vjII484fS/btm1TTk6Op8cKqNzcXOXm5hrOOQs+Hj55WFd/erVKbaWG8+2T22tcx3FenxFwxp1W1+5UDQYAAAAAAAhVjlpdR0VFyWKxVBin1TUAAAAAq9WqBx980G7sjTfe0MGDBwN0IgDlEXwMkM8//1yLFi0qe33llVfqyiuv9Nn6LVu2dDnweLbhw4erdevWdmPffWfcuveM48eP27WPtlgsevTRR53udeONN6px48Zlr3ft2qX58+c7vOett96ya3F99dVX69xzz3V4T3R0tO677z67sRkzZji8pzLfUyBs3LjRreuPHDmiDz74wOl1NptN69at8/RYLjl16pSKiop8vq5Zm2vJeavrW76+RftzjKtF1oysqf9c8R+FWymwC/+j4iMAAAAAAIA9RxUfzZ6PmFV8NGp1TfARAAAAqLpGjRql5s2bl73Oz8/X9OnTA3giAGcj+BggZ7delk5X0wsWvXr1snu9e/duh9d//fXXOnXqVNnrPn36qGnTpk73sVqtFdpAz5071+E9X3zxhd3rceNcq6J31VVXKTY2tuz1ihUrTNsaS5X7ngLB3eDj0qVL7QKnjqxZs8bhfEFBgeE3o50pLS3Vgw8+qMTEREVFRal///7atm2b2+uYcfTPg6OKj78d+E1z/phjOj9j2Ay1TGrp1dkAV7lT8ZHgIwAAAAAAqA4cBR/NgolUfAQAAABC286dO2Wz2cr+6tOnj0frhIWFacuWLXZrPffccy7t6clftLkG3EPwMQD27dun77//vux1+/btParO6C/lW2hnZ2c7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uW3bti2ttgCAhMjPz99ibN999y2DTgAAKG2CjwA7ydSpUzPqli1bZrW+8PzC+xXl8ssvTz+x3axZsxg4cGBW5wIAAADsLs4999yMesiQISV6snr48OGxYMGCdH3UUUdtEaIEAMq/iRMnZtSNGjWKypUrb9deX3/9dUyePDkmTpwYX3zxRfp3MQAAlA3BR4CdYO3atTFv3ryMsQYNGmS1R+H506ZN2+aa0aNHx2OPPZau77///qhWrVpW5wIAAADsLjp16hSdO3dO14sWLYquXbvGN998U+SaUaNGxSWXXJKuc3Nz47777tupfQIAu6eHHnoooz799NOz3uPVV1+NevXqRcOGDaNt27Zx0kknRatWraJu3brRpEmT6Nu3b0yaNKm0WgYAoIQqlXUDAOXRkiVLIpVKpevc3NyoW7duVnvUr18/o160aFGx81etWhUXX3xxuv6v//qv6NixY1ZnAgAAAOxuHnvssejQoUN8/vnnERHx5ptvxsEHHxw9e/aMdu3aRd26dWPDhg0xc+bMGDVqVLzxxhvptdWrV49HH300jj322LJqHwAoI6NHj87494KIiD59+mS9z8KFC4v8bM6cOTFs2LAYNmxYnHLKKTF06NBo2LBh1mcAAJA9wUeAnWD16tUZdfXq1SMnJyerPfLy8ords7Brr702vv7664iIqF27dtx5551ZnQcAAACwO6pdu3a88847cf3118fgwYNjw4YNsWrVqhgyZEgMGTJkq2tyc3PjrLPOij/96U9x8MEH7+KOAYCy9u2338ZFF12UMdajR49o27btTjtz7NixceSRR8azzz4bJ5100k47BwCAf/PUNcBOUDikWLVq1az3KPxEdXHBx4kTJ8b999+fru+4446oXbt21mcCAAAA7I7y8vJi0KBBMW7cuGjZsuU25/fs2TOuvPJKoUcA2AMVFBTEBRdcEPPnz0+P1ahRIwYNGpTVPgceeGBccskl8eSTT8bUqVNj+fLlsXHjxliyZElMnjw5/vKXv0TTpk0z1nz77bfRvXv3+PLLL0vluwAAUDTBR4CdYN26dRl15cqVs96jSpUqGfXatWuLPKtfv37pp7U7duwYP//5z7M+DwAAAGB3NXv27OjRo0eccMIJMWXKlG3OHz58eBx77LFxxhlnxIIFC3ZBhwDA7qJ///7x0ksvZYwNHjw4GjRoUKL1NWrUiFGjRsXcuXPjb3/7W5x99tlx6KGHRo0aNaJSpUqx7777Rps2baJ///4xffr0GDhwYFSo8P9/7b58+fK44IIL0r+3AQBg5xB8BNgJCt/wuGHDhqz3WL9+fbF7fm/gwIExY8aMiPj3LZE/vPkRAAAAIOnGjRsXRxxxRDz33HPpAMGpp54aI0eOjHnz5sX69etjxYoV8fHHH8dtt90W9evXT68dPXp0tGnTJv2zEwCgfBs0aFDceeedGWMDBgyIc889t8R71KpVK7p27ZoRZixKxYoV46abbtrizA8++CCeeeaZEp8JAED2BB8BdoK99toroy58A2RJFL7hsfCeEREffvhh3HHHHen6xhtvjGbNmmV9FgAAAMDuaNq0adG1a9dYuXJlRERUqFAhhgwZEq+99lqcc8450aBBg6hcuXLss88+cfjhh8eAAQNiypQp0aVLl/QeCxcujK5du27Xz2cAgOR4/PHH44orrsgY69OnT9x66607/ezLL788Tj755Iyx4cOH7/RzAQD2ZIKPADtB4ZDimjVrsn7S4Lvvvit2z02bNsWFF14YmzdvjoiI1q1bxzXXXLMd3QIAAADsni6++OKMn5HceOON8Ytf/KLYNfvss088/fTTccghh6THpk2bFoMGDdppfQIAZeuFF16I3r17Z/wu5qyzzooHH3wwcnJydkkPV199dUY9duzY2LRp0y45GwBgTyT4CLAT1K5dO+P/SG/cuDEWLVqU1R75+fkZdd26dTPqRx99ND755JOI+PdtBw888EBUqlRpOzsGAAAA2L18+umnMX78+HRdq1at6N+/f4nWVq9ePf7whz9kjA0ZMqQ02wMAdhPjxo2Lc845JyNk2KlTp3jiiSeiYsWKu6yPU045JeN3Q6tWrYqFCxfusvMBAPY0go8AO0G1atWiYcOGGWPz5s3Lao/C8w899NCMevny5el/LigoiGOPPTZycnK2+WfChAkZ+/Tt2zfj8x49emTVJwAAAMDO8Prrr2fUp5xySlSvXr3E688444yM8MHMmTOFDwCgnHn33XejW7dusW7duvTY8ccfH88++2xUrlx5l/aSl5cXtWrVyhhbvHjxLu0BAGBPIvgIsJMUDipOmTIlq/VTp04tdj8AAACA8mz27NkZdZMmTbJaX7NmzS3CB4Vf2AAAkuvTTz+Nn/zkJ7F69er02JFHHhmjR4+OvLy8MukpNzc3o964cWOZ9AEAsCcQfATYSY444oiM+u233y7x2oULF8acOXPSdW5ubrRs2bKUOgMAAADY/a1fvz6jrlSpUtZ7FA4fbN68eYd6AgB2D9OmTYtOnTrFsmXL0mMtWrSIV155JWrUqFEmPW3atCmWLl2aMVanTp0y6QUAYE+Q/U+KACiRM888M2677bZ0/dprr0Uqlcp4Yqkor776akbdoUOH2GuvvTLGfvrTn0arVq2y7uvqq6+OTz/9NF33798/OnfunK7r1q2b9Z4AAAAApW3ffffNqBcsWJDV+vXr1wsfAEA5NHfu3OjYsWMsWrQoPdakSZMYM2ZMmf5v/TvvvBObNm1K15UqVYr999+/zPoBACjvBB8BdpLjjz8+ateuHUuWLImIiK+++irGjx8fHTp02Obav//97xl19+7dt5jToEGDaNCgQdZ9FX7iqWXLltGxY8es9wEAAADYmRo3bpxRjx8/vsR/qTQiYsKECRnhgypVqkT9+vVLs0UAYBdbuHBhnHrqqTF//vz0WP369eP1118v8/+dL/y7neOOOy6qV69eRt0AAJR/nroG2EkqVKgQffr0yRi7+eabI5VKFbvu9ddfj4kTJ6brvffeO372s5/tjBYBAAAAdlunnnpqRj1v3rwYOXJkidamUqm49dZbM8ZOOOGEqFKlSqn1BwDsWt9++2106tQpZs2alR6rU6dOjBkzJpo0aVKGnf37L2gMHz48Y6xHjx5l0wwAwB5C8BFgJ7r22msznqieMGFCxvPXheXn58cvfvGLjLHLL788ateuvdN6BAAAANgdNWvWLI499tiMsUsuuSQ+/fTTYtelUqm4/vrrY9y4cRnjvXv3LvUeAYBdY9WqVdGlS5f44osv0mM1a9aMV199NVq0aFFq54wZMyaGDh2acWv0towdOzbOOuus2Lx5c3rsgAMOiIsvvrjU+gIAYEueugbYiWrXrh033HBD3HDDDemx66+/PubNmxe///3vo169ehERUVBQEKNGjYrLL7885s2bl55br169uPrqq3d53wAAAAAl8dZbb8XatWu3GP/kk08y6nXr1sVrr7221T3q1asXLVu23Opnt956a3To0CH9gsayZcviuOOOi+uuuy5++ctfxv7775+eW1BQEJMmTYo//elP8corr2Ts8+Mf/zjOP//8rL4bALD76NatW0yePDlj7KqrroolS5YU+e8YRTn66KOjVq1aW/0sPz8/LrzwwvjDH/4Q55xzTnTr1i2OOuqoqFGjRsa8zZs3x/vvvx9/+9vf4tFHH42CgoL0ZxUqVIj77rvPM9cAADtZTmpbb64CsEMKCgqie/fu8cILL2SMV6xYMRo1ahQ1atSI2bNnx/LlyzM+r1atWowZMybatWtXqv20b98+JkyYkK6HDh26xZPcAEByFRc+uOaaa9L1fvvtF48++uhW9ygufBARsXDhwowbFn7o6quvzriFqX///tG5c+etzj3hhBOiatWqRZ4DAOz+GjduHHPnzt2hPXr37h3Dhg0r8vPbbrstrrvuuiLPr1u3bqxfvz7mzJkTK1as2GJOnTp14p133ommTZvuUJ8AQNnJyckptb3GjRsX7du33+pnw4YNi759+24xXr9+/fjRj34UeXl5sXLlypg3b16sXr16q33ec8898dvf/rbU+gUAYOvc+Aiwk1WoUCGefPLJ6Nu3b4wYMSI9vnnz5vjqq6+2umbfffeNp556qtRDjwBA+Xf++eeXKHzwzTffRKdOnbb62bbCB6+88spWfwmwNbfffnvcfvvtW/1s9uzZ0bhx4xLtAwDsua699tqoWbNmXHXVVbFmzZqMz+bMmRNz5swpcu3RRx8djz/+uNAjALBD8vPzIz8/v9g5BxxwQDz88MNF/rwFAIDSVaGsGwDYE1StWjWeeOKJeOqpp+KII44ocl5eXl5ceumlMWXKlCL/tiEAAADAnuaiiy6KKVOmxDXXXBN16tQpdm5OTk60bds2hg4dGpMmTYrmzZvvoi4BgKQ75ZRT4uabb4727dvH3nvvvc35FSpUiKOOOiruv//+mDlzptAjAMAu5KlrgDIwc+bMePfddyM/Pz82bNgQNWvWjBYtWkS7du089wgA7JBd8dxkUc8+ZcuNjwDA9kilUjFjxoz46KOPYsmSJbFixYrIzc2NmjVrRsOGDaNt27ZRq1atsm4TAEi4VCoVs2bNipkzZ8bXX38dy5cvj3Xr1kVeXl7UqlUrGjRoEG3bto199tmnrFsFANgjCT4CAAAAAAAAAAAAieGpawAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAASQ/ARAAAAAAAAAAAASAzBRwAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAASQ/ARAAAAAAAAAAAASAzBRwAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAASQ/ARAAAAAAAAAAAASAzBRwAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAASQ/ARAAAAAAAAAAAASAzBRwAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAASQ/ARAAAAAAAAAAAASAzBRwAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAASQ/ARAAAAAAAAAACAPd7LL78cOTk5GX86dOhQ1m2xFYKPAAAAAAAAAAAA7PGG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G2eccUZcccUVcfLJJ+/QubNnz44bb7wxRo4cGRs2bNji85ycnDj55JPj5ptvjpNOOimrvf/1r3/F008/Ha+++mqMHz8+Vq5cWeTcatWqxdlnnx1XXnllHHnkkVl/j5IYPHhwXHzxxVuMz549Oxo3brxTztweOalUKlXWTQAAAAAAAAAAAEBRfv3rX8eDDz641eDhtvz85z+Pe++9N/bZZ5+s144cOTL69u0ba9as2ebcnJycGDBgQPzP//xP5OTkbHN+9+7d44UXXoiCgoKseqpQoUJcddVVccstt0TlypWzWluc+fPnx2GHHbbV8KXgIwAAAAAAAAAAAGShTZs28cEHH2wxXrFixTjggANiv/32i40bN8bcuXNjxYoVW8xr27ZtvP7667HXXnuV+Mwnn3wyevbsuUUwsU6dOtGgQYNYtGhR5OfnR+EI3hVXXBF33XXXNvevXbt2LF26dIvx3NzcqFevXtSpUyfWrVsXX3311VaDl926dYunn346KlUqnYefu3btGi+88MJWP9vdgo8VyroBAAAAAAAAAAAAKKmaNWvGpZdeGi+++GIsW7Ysvv7663j//ffjk08+iaVLl8a4cePixBNPzFjz3nvvRZ8+fUp8xqxZs6Jv374ZocfDDz88xo4dG4sWLYoPPvggvv7665g6dWqcddZZGWvvvvvueOaZZ7L6Tvvtt1/0798/Xn/99Vi5cmXMmTMnJk+eHJ999lksX748Ro0aFT/+8Y8z1owaNSquu+66rM4pyuOPP54OPebl5ZXKnjuTGx8BAAAAAAAAAADYrbVp0yaWLl0av//976NXr15RrVq1Yudv3rw5Lr300njggQcyxseOHRsdOnTY5nm9evWKJ554Il0fc8wx8dprr231uexUKhUXX3xxxlnNmjWLL7/8stjbGGvXrh0HHHBADBw4MHr06LHNmxvXrVsX55xzTsatjLm5ufH5559H8+bNt/mdirJkyZJo0aJFLFmyJCIi7rjjjrj66qsz5uxuNz4KPgIAAAAAAAAAALBbe/HFF6NTp05RuXLlEq/ZvHlzHHvssfH++++nx3r16hWPPfZYseu++OKLaN26dfq2x8qVK8fHH38cLVq0KHLNunXronXr1jFjxoz02AMPPBC//OUvi1zz3HPPRdeuXaNChZI/3Pzdd9/FoYceGvPnz0+P3XDDDXHLLbeUeI/CfhjyPProo+Pdd9/dIoS5uwUfPXUNAAAAAAAAAADAbu2MM87IKvQYEVGxYsUYMGBAxtgrr7yyzXUPPfRQxhPXPXv2LDb0GBFRtWrVLZ6dfvDBB4td071796xCjxH/fob6sssuyxgryXcqygsvvJAOPVasWDGGDBkSFStW3O79dhXBRwAAAAAAAAAAAMqlE088MaNeunRprFmzptg1o0aNyqj79etXorPOPffcyMvLS9eTJ0+OBQsWlLDTkiv8nebNm7dd+6xcuTIuueSSdH3FFVfEkUceuUO97SqCjwAAAAAAAAAAAJRLtWrV2mJsxYoVRc6fNm1azJw5M13n5eXF8ccfX6KzCs9NpVLx4osvZtFtyRT+TsV9n+IMGDAg/WR248aN449//OMO97arCD4CAAAAAAAAAABQLuXn528xtu+++xY5/+OPP86o27ZtG5UqVSrxee3atSt2v9JQ+DsV932KMmHChHjggQfS9f/93/9F9erVd7i3XUXwEQAAAAAAAAAAgHJp4sSJGXWjRo2icuXKRc6fOnVqRt2yZcuszis8v/B+paHwd2revHlW69euXRu//OUvI5VKRUTEeeedF126dCm1/nYFwUcAAAAAAAAAAADKpYceeiijPv3004udP23atIy6QYMGWZ1XeH7h/XbU5s2b45FHHskY29Z3KmzgwIExY8aMiIj40Y9+FHfffXdptbfLCD4CAAAAAAAAAABQ7owePTreeOONjLE+ffoUu2bRokUZ9YEHHpjVmfXr18+oFy9enNX6bRk8eHB89dVX6To3Nzd69epV4vUffPBB3Hnnnen69ttvj7p165Zqj7uC4CMAAAAAAAAAAADlyrfffhsXXXRRxliPHj2ibdu2xa5bvXp1Rp2Xl5fVuYXnb9y4MdavX5/VHkWZNWtWXHfddRljv/71r0sczty4cWP069cvNm/eHBER7du3jwsvvLBUetvVBB8BAAAAAAAAAAAoNwoKCuKCCy6I+fPnp8dq1KgRgwYN2ubawsHHqlWrZnV2tWrVtrnn9lizZk2cffbZsWrVqvRYo0aN4o9//GOJ97jtttvik08+iYiIKlWqxODBg3e4r7Ii+AgAAAAAAAAAAEC50b9//3jppZcyxgYPHhwNGjTY5tp169Zl1JUrV87q7CpVqmwxtnbt2qz2KCyVSkXv3r3j448/To9VqlQpHnvssdh7771LtMfUqVPjz3/+c7r+/e9/H82bN9+hvsqS4CMAAAAAAAAAAADlwqBBg+LOO+/MGBswYECce+65JVpf+IbHDRs2ZHX+1p61zvbWyMKuvvrqeOqppzLG7rnnnmjXrl2J1hcUFES/fv3SvR122GFx7bXX7lBPZU3wEQAAAAAAAAAAgMR7/PHH44orrsgY69OnT9x6660l3mOvvfbKqAvfALktW7vdsfCe2bj11lvjrrvuyhgbOHBgXHrppSXe4957741JkyZFREROTk488MADkZubu9097Q4EHwEAAAAAAAAAAEi0F154IXr37h2pVCo9dtZZZ8WDDz4YOTk5Jd6ncEjxu+++y6qPwvMrVaq03Tc+Dh48OK6//vqMscsuuyxuuummEu8xZ86c+N3vfpeuL7744jj++OO3q5/dieAjAAAAAAAAAAAAiTVu3Lg455xzYtOmTemxTp06xRNPPBEVK1bMaq+6detm1PPnz89qfX5+fkZdp06drNZ/7/HHH9/iVsfevXvH3XffndU+N910UzqMWa9evaxuv9ydCT4CAAAAAAAAAACQSO+++25069Yt40nq448/Pp599tmoXLly1vsdcsghGfW8efOyWl94/qGHHpp1D88991z07t07CgoK0mM//elP4+9//3tWt1dGRCxfvjz9zwsWLIgaNWpETk7ONv8U1qRJk4zPsw1gljbBRwAAAAAAAAAAABLn008/jZ/85CexevXq9NiRRx4Zo0ePjry8vO3as3BQccqUKVmtnzp1arH7bctrr70W5557bsbtlaeddlo8/vjjWd9eWZ4JPgIAAAAAAAAAAJAo06ZNi06dOsWyZcvSYy1atIhXXnklatSosd37HnHEERn15MmTM0KI2/LWW28Vu9+21nbv3j3Wr1+fHjvxxBO3+/bK8iwnlUqlyroJAAAAAAAAAAAAKIm5c+fGCSecEPPnz0+PNWnSJCZOnBj169ff4f0POuigmDVrVrqeMGFCnHTSSdtc991338X++++fvoEyJycn5s+fH/Xq1dvm2g8//DBOOeWUWLFiRXqsTZs28frrr8c+++yzHd/i3z799NNYtGhR1us6deqUUT/66KOx3377petDDjkkGjRosN197ahKZXYyAAAAAAAAAAAAZGHhwoVx6qmnZoQe69evH6+//nqphB4jIrp16xZ33XVXuv773/9e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Y/r06dGlS5f4/PPPo2bNmjFw4MDo3bt31KpVKz3vvffei379+sXnn3+eHjvqqKPigw8+KO4/llizZk20adMmpk6dmh5r0qRJXHfddXHOOedknLFp06Z47bXX4ne/+118+OGH6fEjjjgi3nnnHc9eAwAAALBVgo8AAAAAADtgzpw50aRJk3Tdu3fvGDZsWInX70jwMSKiQoUKMWLEiDjnnHO2uqagoCBOO+20eO2119JjLVq0iKlTp8b+++8fY8eOjRYtWmx17eLFi+Owww6LxYsXp8c++uijOOKII4rs8ZJLLon7778/XXft2jUef/zxLW53/KH169fHeeedF88++2x67M4774wrr7yyyDUAAAAA7Lk8dQ0AAAAAkGD9+/cvMvQY8e9g5J///OeMse9vY3z44YeLDD1GRNSpU2eL8OFLL71U5Pyvv/46HnzwwXTdunXrePLJJ4sNPUZEVKlSJR599NFo3Lhxeuyee+6JzZs3F7sOAAAAgD2T4CMAAAAAQELl5eXFddddt815//Ef/xH77bdfxtgJJ5wQnTt33uba7t27Z9QfffRRkXPvu+++2LRpU7q+/fbbS/xcdfXq1TNClnPnzo3333+/RGsBAAAA2LMIPgIAAAAAJFTHjh2jZs2aJZp72GGHZdRnn312idYdcsghkZubm67nzZtX5NzRo0en/3n//fePjh07luiM7xUOYk6cODGr9QAAAADsGQQfAQAAAAAS6uijjy7x3H333TejPuqoo0q0rmLFihnhypUrV2513rJly+Lzzz/P2L9Chex+BN2wYcOM+vsnuQEAAADghyqVdQMAAAAAAGyfOnXqlHhu9erVS2Xt2rVrtzpn2rRpkUql0vXo0aMjJyenxGdszbfffrtD6wEAAAAon9z4CAAAAACQUFWrVt3la38YbvyhpUuXbncvRVmxYkWp7wkAAABA8gk+AgAAAACww5YvX17qexYUFJT6ngAAAAAkn6euAQAAAADYYYWf0u7QoUPccMMNO7RnrVq1dmg9AAAAAOWT4CMAAAAAADusdu3aGXXVqlWjY8eOZdQNAAAAAOWZp64BAAAAANhhTZo0yahnzpxZRp0AAAAAUN4JPgIAAAAA7IAKFTJ/zJpKpcqok7J14IEHxkEHHZSuZ8yYEV9//XUZdgQAAABAeSX4CAAAAACwA/Ly8jLqNWvWlFEnZa9Lly4Z9f/+7/+WUScAAAAAlGeCjwAAAAAAO2CfffaJihUrpuvZs2eXYTdl68orr4xKlSql63vvvTc+/PDDMuwIAAAAgPJI8BEAAAAAYAfk5uZG8+bN0/XHH38cs2bNKsOOyk7Tpk2jX79+6Xrt2rVx5plnxqRJk7LaZ+zYsfGrX/2qtNsDAAAAoJyotO0pAAAAAAAUp3PnzjF16tSIiNi8eXOcdNJJ8atf/Spat24de+21V+Tk5KTnHnbYYXHAAQeUVas73V133RXvvfdefPTRRxERsXDhwjjppJPiggsuiIsuuijatGmTcStkRMTq1avj448/jpdeeimefvrpmDZtWjRq1Kgs2gcAAAAgAQQfAQAAAAB20KWXXhqDBw+OdevWRUTEggUL4qabbtrq3KFDh0afPn12XXO7WLVq1WLUqFFx+umnx2effRYREZs2bYphw4bFsGHDIi8vLxo0aBA1atSINWvWxLJlyyI/Pz9SqVQZdw4AAABAUnjqGgAAAABgBzVv3jyGDx8ee+21V1m3sls48MADY9KkSXHBBRdk3HYZEfHdd9/Fl19+Ge+++2589tlnMX/+/K2GHhs2bLir2gUAAAAgYQQfAQAAAABKwdlnnx3Tp0+PW2+9NU477bRo0KDBFs9c70ny8vJi+PDh8fHHH8d5550XNWvW3OaaQw89NC6//PJ4++2344033tj5TQIAAACQSDkp74cAAAAAALCTFRQUxIcffhjTp0+PJUuWxMqVK6N69epRs2bNaNasWbRs2TLq1KlT1m0CAAAAkACCjwAAAAAAAAAAAEBieOoaAAAAAAAAAAAASAzBRwAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAASQ/ARAAAAAAAAAAAASAzBRwAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAASQ/ARAAAAAAAAAAAASAzBRwAAAAAAAAAAACAxBB8BAAAAAAAAAACAxBB8BAAAAAAAAAAAABJD8BEAAAAAAAAAAABIDMFHAAAAAAAAAAAAIDEEHwEAAAAAAAAAAIDEEHwEAAAAAAAAAAAAEkPwEQAAAAAAAAAAAEgMwUcAAAAAAAAAAAAgMQQfAQAAAAAAAAAAgMQQfAQAAAAAAAAAAAAS4/8BG+2oyXxkRy4AAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "fig = plt.figure(figsize=(10,5), dpi=300)\n", - "ax = plt.gca()\n", - "df.plot(x='time', y=['close', 'ema21', 'ema50', 'ema200'], ax=ax, color=['black', 'green', 'orange', 'gray'])\n", - "\n", - "xmin, xmax = df['time'].iloc[0], df['time'].iloc[-1]\n", - "ax.hlines(y=df['s1'].iloc[-1], xmin=xmin, xmax=xmax, color='green', linestyle=':', label='S1')\n", - "ax.hlines(y=df['s2'].iloc[-1], xmin=xmin, xmax=xmax, color='green', linestyle='--', label='S2')\n", - "ax.hlines(y=df['r1'].iloc[-1], xmin=xmin, xmax=xmax, color='red', linestyle=':', label='R1')\n", - "ax.hlines(y=df['r2'].iloc[-1], xmin=xmin, xmax=xmax, color='red', linestyle='--', label='R2')\n", - "ax.set_ylabel('Price in Dollar')\n", - "plt.legend()\n", - "plt.title('XBT/USD');" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "â€Ļ Create and combine custom indicators, implement them, and build your own strategies ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "kraken", - "language": "python", - "name": "kraken" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.11.2" - }, - "vscode": { - "interpreter": { - "hash": "bc326337e3c95d7650019b92f82ee601f881f7d791731754deb353f3b8d503be" - } - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/doc/examples/rest_example_usage.rst b/doc/examples/rest_example_usage.rst index 2f23f5dd..2e81dd5e 100644 --- a/doc/examples/rest_example_usage.rst +++ b/doc/examples/rest_example_usage.rst @@ -12,20 +12,6 @@ REST and websocket endpoints of the Kraken Cryptocurrency Exchange API. Since these endpoints and their parameters may change, all implemented endpoints are tested on a regular basis. -If certain parameters or settings are not available, or specific endpoints are -hidden and not implemented, it is always possible to execute requests to the -endpoints directly using the ``_request`` method provided by all clients. This -is demonstrated below. - -.. code-block:: python - :linenos: - :caption: Usage of the basic _request method - - from kraken.spot import User - - user = User(key="", secret="") - print(user._request(method="POST", uri="/0/private/Balance")) - The repository of the `python-kraken-sdk`_ provides some example scripts that demonstrate some of the implemented methods. Please see the sections listed below. diff --git a/doc/examples/rest_ws_samples/futures_rest_examples.rst b/doc/examples/rest_ws_samples/futures_rest_examples.rst index 3388f110..6a4a2b4e 100644 --- a/doc/examples/rest_ws_samples/futures_rest_examples.rst +++ b/doc/examples/rest_ws_samples/futures_rest_examples.rst @@ -3,6 +3,8 @@ .. Copyright (C) 2023 Benjamin Thomas Schwertfeger .. GitHub: https://github.com/btschwertfeger +.. _section-futures-rest-examples: + Futures REST ------------ @@ -12,8 +14,66 @@ REST clients provided by `python-kraken-sdk`_ to access `Kraken`_'s REST API. For questions, feedback, additions, suggestions for improvement or problems `python-kraken-sdk/discussions`_ or `python-kraken-sdk/issues`_ may be helpful. -These examples are not maintained on a regular basis. They serve only for -demonstration purposes - make sure to checkout the documentation of the +See https://docs.kraken.com/api/docs/guides/global-intro for information about +the available endpoints and their usage. + +The Futures client provides access to all un-and authenticated endpoints of +Kraken's Futures API. + +.. code-block:: python + :linenos: + :caption: Example: Spot Client Usage (1) + + from kraken.futures import FuturesClient + + client = FuturesClient(key="", secret="") + print(client.request("GET", "/derivatives/api/v3/accounts")) + +The async Futures client allows for asynchronous access to Kraken's Futures +endpoints. Below are two examples demonstrating its usage. + +Using FuturesAsyncClient without a context manager; In this example, the client +is manually closed after the request is made. + +.. code-block:: python + :linenos: + :caption: Example: Spot Client Usage (2) + + import asyncio + from kraken.futures import FuturesAsyncClient + + async def main(): + client = FuturesAsyncClient(key="", secret="") + try: + response = await client.request("GET", "/derivatives/api/v3/accounts") + print(response) + finally: + await client.async_close() + + asyncio.run(main()) + +Using FuturesAsyncClient as context manager; This example demonstrates the use +of the context manager, which ensures the client is automatically closed after +the request is completed. + +.. code-block:: python + :linenos: + :caption: Example: Spot Client Usage (3) + + import asyncio + from kraken.futures import FuturesAsyncClient + + async def main(): + async with FuturesAsyncClient( + key="", secret="" + ) as client: + response = await client.request("GET", "/derivatives/api/v3/accounts") + print(response) + + asyncio.run(main()) + +The following legacy examples are not maintained on a regular basis. They serve +only for demonstration purposes - make sure to checkout the documentation of the individual functions. .. literalinclude:: ../../../examples/futures_examples.py diff --git a/doc/examples/rest_ws_samples/futures_ws_examples.rst b/doc/examples/rest_ws_samples/futures_ws_examples.rst index 2ece201b..cb187ab8 100644 --- a/doc/examples/rest_ws_samples/futures_ws_examples.rst +++ b/doc/examples/rest_ws_samples/futures_ws_examples.rst @@ -8,7 +8,7 @@ Futures Websocket The examples presented below serve to demonstrate the usage of the Futures websocket clients provided by `python-kraken-sdk`_ to access `Kraken`_'s -Websocket API v1 and v2 . +Websocket API. For questions, feedback, additions, suggestions for improvement or problems `python-kraken-sdk/discussions`_ or `python-kraken-sdk/issues`_ may be helpful. diff --git a/doc/examples/rest_ws_samples/spot_rest_examples.rst b/doc/examples/rest_ws_samples/spot_rest_examples.rst index 0e21446d..1fd7342d 100644 --- a/doc/examples/rest_ws_samples/spot_rest_examples.rst +++ b/doc/examples/rest_ws_samples/spot_rest_examples.rst @@ -2,6 +2,8 @@ .. Copyright (C) 2023 Benjamin Thomas Schwertfeger .. GitHub: https://github.com/btschwertfeger +.. _section-spot-rest-examples: + Spot REST --------- @@ -11,8 +13,66 @@ REST clients provided by `python-kraken-sdk`_ to access `Kraken`_'s REST API. For questions, feedback, additions, suggestions for improvement or problems `python-kraken-sdk/discussions`_ or `python-kraken-sdk/issues`_ may be helpful. -These examples are not maintained on a regular basis. They serve only for -demonstration purposes - make sure to checkout the documentation of the +See https://docs.kraken.com/api/docs/guides/global-intro for information about +the available endpoints and their usage. + +The Spot client provides access to all un-and authenticated endpoints of +Kraken's Spot and NFT API. + +.. code-block:: python + :linenos: + :caption: Example: Spot Client Usage (1) + + from kraken.spot import SpotClient + + client = SpotClient(key="", secret="") + print(client.request("POST", "/0/private/Balance")) + +The async Spot client allows for asynchronous access to Kraken's Spot and NFT +API endpoints. Below are two examples demonstrating its usage. + +Using SpotAsyncClient without a context manager; In this example, the client is +manually closed after the request is made. + +.. code-block:: python + :linenos: + :caption: Example: Spot Client Usage (2) + + import asyncio + from kraken.spot import SpotAsyncClient + + async def main(): + client = SpotAsyncClient(key="", secret="") + try: + response = await client.request("POST", "/0/private/Balance") + print(response) + finally: + await client.async_close() + + asyncio.run(main()) + +Using SpotAsyncClient as context manager; This example demonstrates the use of +the context manager, which ensures the client is automatically closed after the +request is completed. + +.. code-block:: python + :linenos: + :caption: Example: Spot Client Usage (3) + + import asyncio + from kraken.spot import SpotAsyncClient + + async def main(): + async with SpotAsyncClient( + key="", secret="" + ) as client: + response = await client.request("POST", "/0/private/Balance") + print(response) + + asyncio.run(main()) + +The following legacy examples are not maintained on a regular basis. They serve +only for demonstration purposes - make sure to checkout the documentation of the individual functions. .. literalinclude:: ../../../examples/spot_examples.py diff --git a/doc/examples/rest_ws_samples/spot_ws_examples.rst b/doc/examples/rest_ws_samples/spot_ws_examples.rst index 434ffdc8..171d6c22 100644 --- a/doc/examples/rest_ws_samples/spot_ws_examples.rst +++ b/doc/examples/rest_ws_samples/spot_ws_examples.rst @@ -9,17 +9,12 @@ Spot Websocket The examples presented below serve to demonstrate the usage of the Spot websocket clients provided by `python-kraken-sdk`_ to access `Kraken`_'s -Websocket API v1 and v2. +Websocket API v2. For questions, feedback, additions, suggestions for improvement or problems `python-kraken-sdk/discussions`_ or `python-kraken-sdk/issues`_ may be helpful. -.. literalinclude:: ../../../examples/spot_ws_examples_v2.py +.. literalinclude:: ../../../examples/spot_ws_examples.py :language: python :linenos: - :caption: Example access and usage for Kraken Spot Websocket API v2 - -.. literalinclude:: ../../../examples/spot_ws_examples_v1.py - :language: python - :linenos: - :caption: Example access and usage for Kraken Spot Websocket API v1 + :caption: Example access and usage for Kraken Spot Websocket API diff --git a/doc/examples/trading_bot_templates/spot_bot_templates.rst b/doc/examples/trading_bot_templates/spot_bot_templates.rst index 2e5600b0..404fc245 100644 --- a/doc/examples/trading_bot_templates/spot_bot_templates.rst +++ b/doc/examples/trading_bot_templates/spot_bot_templates.rst @@ -15,12 +15,7 @@ The trading strategy can be implemented using the ``TradingBot`` class. This class has access to all REST clients and receives all messages that are sent by the subscribed websocket feeds via the ``on_message`` function. -.. literalinclude:: ../../../examples/spot_trading_bot_template_v2.py +.. literalinclude:: ../../../examples/spot_trading_bot_template.py :language: python :linenos: :caption: Template to build a trading bot using the Kraken Spot Websocket API v2 - -.. literalinclude:: ../../../examples/spot_trading_bot_template_v1.py - :language: python - :linenos: - :caption: Template to build a trading bot using the Kraken Spot Websocket API v1 diff --git a/doc/examples/trading_bot_templates/spot_orderbook.rst b/doc/examples/trading_bot_templates/spot_orderbook.rst index 4ae1beb7..d24974bc 100644 --- a/doc/examples/trading_bot_templates/spot_orderbook.rst +++ b/doc/examples/trading_bot_templates/spot_orderbook.rst @@ -9,21 +9,12 @@ Maintain a valid Spot Orderbook The following examples demonstrate how to use the python-kraken-sdk to retrieve valid realtime orderbooks. The current implementation of the -:class:`kraken.spot.OrderbookClientV2` uses the websocket API v2 and -:class:`kraken.spot.OrderbookClientV1` provides the legacy support for websocket -API v2. +:class:`kraken.spot.SpotOrderBookClient` uses the websocket API v2. -.. literalinclude:: ../../../examples/spot_orderbook_v2.py +.. literalinclude:: ../../../examples/spot_orderbook.py :language: python :linenos: - :caption: Sample on how to maintain a valid orderbook w/ websocket API v2 - - -.. literalinclude:: ../../../examples/spot_orderbook_v1.py - :language: python - :linenos: - :caption: Sample on how to maintain a valid orderbook w/ websocket API v1 - + :caption: Sample on how to maintain a valid orderbook w/ websocket API References: - https://gist.github.com/btschwertfeger/6eea0eeff193f7cd1b262cfce4f0eb51 diff --git a/doc/futures/rest.rst b/doc/futures/rest.rst index 6a0b4903..6b97523a 100644 --- a/doc/futures/rest.rst +++ b/doc/futures/rest.rst @@ -2,8 +2,13 @@ .. Copyright (C) 2023 Benjamin Thomas Schwertfeger .. GitHub: https://github.com/btschwertfeger -Futures REST -============ +.. _section-futures-rest-clients: + +Futures REST Clients +==================== + +The recommended way to execute requests against the Kraken Futures API is +described in :ref:`section-futures-rest-examples`. .. autoclass:: kraken.futures.User :members: diff --git a/doc/futures/websockets.rst b/doc/futures/websockets.rst index 95eb0caa..90549e04 100644 --- a/doc/futures/websockets.rst +++ b/doc/futures/websockets.rst @@ -5,7 +5,7 @@ Futures Websockets ================== -.. autoclass:: kraken.futures.KrakenFuturesWSClient +.. autoclass:: kraken.futures.FuturesWSClient :members: :show-inheritance: :inherited-members: diff --git a/doc/introduction.rst b/doc/introduction.rst index 2d724b55..2bd6f6f7 100644 --- a/doc/introduction.rst +++ b/doc/introduction.rst @@ -30,20 +30,19 @@ and documented. - The output in the examples may differ, as these are only intended as examples and may change in the future. - If a certain endpoint is not reachable, the function - :func:`kraken.base_api.KrakenSpotBaseAPI._request` or - :func:`kraken.base_api.KrakenFuturesBaseAPI._request`, + :func:`kraken.spot.SpotClient.request` or + :func:`kraken.futures.FuturesClient.request`, which is also available in all derived REST clients, can be used to reach an endpoint with the appropriate parameters. Here private content can also be accessed, provided that either the base class or one of the clients has been initialized with valid credentials. -- For Futures there is only one websocket client - - :class:`kraken.futures.KrakenFuturesWSClient`. For Spot there are two: - :class:`kraken.spot.KrakenSpotWSClientV1` (for API version 1) and - :class:`kraken.spot.KrakenSpotWSClientV2` (for API version 2). +- For Futures there is the websocket client + :class:`kraken.futures.FuturesWSClient` and for Spot + :class:`kraken.spot.SpotWSClient`. Disclaimer -------------- +---------- There is no guarantee that this software will work flawlessly at this or later times. Of course, no responsibility is taken for possible profits or losses. @@ -64,19 +63,18 @@ General: - extensive examples - tested using the `pytest `_ framework - releases are permanently archived at `Zenodo `_ -- releases before v2.0.0 also support Python 3.7+ Available Clients: -- NFT REST Clients -- Spot REST Clients -- Spot Websocket Clients (Websocket API v1 and v2) -- Spot Orderbook Clients (Websocket API v1 and v2) -- Futures REST Clients +- Spot REST Clients (sync and async; including access to NFT trading) +- Spot Websocket Client (Websocket API v2) +- Spot Orderbook Client (Websocket API v2) +- Futures REST Clients (sync and async) - Futures Websocket Client Important Notice ----------------- + **ONLY tagged releases are available at PyPI**. The content of the master branch may not match with the content of the latest release. - Please have a look at the release specific READMEs and changelogs. @@ -84,6 +82,7 @@ the release specific READMEs and changelogs. It is also recommended to **pin the used version** to avoid unexpected behavior on new releases. + .. _section-troubleshooting: Troubleshooting @@ -105,8 +104,9 @@ References ---------- - https://python-kraken-sdk.readthedocs.io/en/stable +- https://docs.kraken.com/api/ +- https://docs.kraken.com/api/docs/guides/global-intro - https://docs.kraken.com/rest -- https://docs.kraken.com/websockets - https://docs.kraken.com/websockets-v2 - https://docs.futures.kraken.com - https://support.kraken.com/hc/en-us/sections/360012894412-Futures-API diff --git a/doc/nft/rest.rst b/doc/nft/rest.rst index fecd64ea..25b5a624 100644 --- a/doc/nft/rest.rst +++ b/doc/nft/rest.rst @@ -5,6 +5,9 @@ NFT REST ========= +The recommended way to execute requests against the Kraken Futures API is +described in :ref:`section-spot-rest-examples`. + .. autoclass:: kraken.nft.Market :members: :show-inheritance: diff --git a/doc/requirements.txt b/doc/requirements.txt index c9f50229..48593d4f 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,7 +1,13 @@ +aiohttp asyncio>=3.4 +click +cloup +ipython nbsphinx +orjson requests setuptools_scm sphinx +sphinx-click sphinx-rtd-theme websockets diff --git a/doc/spot/rest.rst b/doc/spot/rest.rst index 562defbf..8455e965 100644 --- a/doc/spot/rest.rst +++ b/doc/spot/rest.rst @@ -2,8 +2,13 @@ .. Copyright (C) 2023 Benjamin Thomas Schwertfeger .. GitHub: https://github.com/btschwertfeger -Spot REST -========= +.. _section-spot-rest-clients: + +Spot REST Clients +================== + +The recommended way to execute requests against the Kraken Futures API is +described in :ref:`section-spot-rest-examples`. .. autoclass:: kraken.spot.User :members: @@ -29,8 +34,3 @@ Spot REST :members: :show-inheritance: :inherited-members: - -.. autoclass:: kraken.spot.Staking - :members: - :show-inheritance: - :inherited-members: diff --git a/doc/spot/websockets.rst b/doc/spot/websockets.rst index b888d2bf..51fa2d96 100644 --- a/doc/spot/websockets.rst +++ b/doc/spot/websockets.rst @@ -5,22 +5,12 @@ Spot Websockets =============== -.. autoclass:: kraken.spot.KrakenSpotWSClientV2 +.. autoclass:: kraken.spot.SpotWSClient :members: :show-inheritance: :inherited-members: -.. autoclass:: kraken.spot.KrakenSpotWSClientV1 - :members: - :show-inheritance: - :inherited-members: - -.. autoclass:: kraken.spot.OrderbookClientV2 - :members: - :show-inheritance: - :inherited-members: - -.. autoclass:: kraken.spot.OrderbookClientV1 +.. autoclass:: kraken.spot.SpotOrderBookClient :members: :show-inheritance: :inherited-members: diff --git a/examples/futures_trading_bot_template.py b/examples/futures_trading_bot_template.py index 208e15d7..1b676dac 100644 --- a/examples/futures_trading_bot_template.py +++ b/examples/futures_trading_bot_template.py @@ -21,7 +21,7 @@ import urllib3 from kraken.exceptions import KrakenAuthenticationError -from kraken.futures import Funding, KrakenFuturesWSClient, Market, Trade, User +from kraken.futures import FuturesWSClient, User logging.basicConfig( format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s", @@ -32,7 +32,7 @@ logging.getLogger("urllib3").setLevel(logging.WARNING) -class TradingBot(KrakenFuturesWSClient): +class TradingBot(FuturesWSClient): """ Class that implements the trading strategy @@ -55,29 +55,16 @@ def __init__(self: TradingBot, config: dict) -> None: key=config["key"], secret=config["secret"], ) - self.__config: dict = config - - self.__user: User = User(key=config["key"], secret=config["secret"]) - self.__trade: Trade = Trade(key=config["key"], secret=config["secret"]) - self.__market: Market = Market(key=config["key"], secret=config["secret"]) - self.__funding: Funding = Funding(key=config["key"], secret=config["secret"]) async def on_message(self: TradingBot, message: list | dict) -> None: """Receives all messages that came form the websocket feed(s)""" logging.info(message) # == apply your trading strategy here == - - # Call functions of `self.__trade` and other clients if conditions met â€Ļ - # print( - # self.__trade.create_order( - # orderType='lmt', - # size=2, - # symbol='PI_XBTUSD', - # side='buy', - # limitPrice=10000 - # ) - # ) + # Hint: You can execute requests using the `request` function directly: + # print(await self.request( + # "GET", "/api/charts/v1/spot/PI_XBTUSD/1d", + # )) # You can also un-/subscribe here using `self.subscribe(...)` or # `self.unsubscribe(...)` @@ -139,6 +126,7 @@ async def __main(self: ManagedBot) -> None: exit the asyncio loop - but you can also apply your own reconnect rules. """ self.__trading_strategy = TradingBot(config=self.__config) + await self.__trading_strategy.start() await self.__trading_strategy.subscribe( feed="ticker", diff --git a/examples/futures_ws_examples.py b/examples/futures_ws_examples.py index 33c429e6..6f6f011d 100644 --- a/examples/futures_ws_examples.py +++ b/examples/futures_ws_examples.py @@ -16,7 +16,7 @@ import time from contextlib import suppress -from kraken.futures import KrakenFuturesWSClient +from kraken.futures import FuturesWSClient logging.basicConfig( format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s", @@ -27,24 +27,26 @@ logging.getLogger("urllib3").setLevel(logging.WARNING) +# Custom client +class Client(FuturesWSClient): + """Can be used to create a custom trading strategy""" + + async def on_message(self: Client, message: list | dict) -> None: + """Receives the websocket messages""" + logging.info(message) + # â€Ļ apply your trading strategy in this class + # â€Ļ you can also combine this with the Futures REST clients + + async def main() -> None: """Create a client and subscribe to channels/feeds""" key = os.getenv("FUTURES_API_KEY") secret = os.getenv("FUTURES_SECRET_KEY") - # Custom client - class Client(KrakenFuturesWSClient): - """Can be used to create a custom trading strategy""" - - async def on_message(self: Client, message: list | dict) -> None: - """Receives the websocket messages""" - logging.info(message) - # â€Ļ apply your trading strategy here - # â€Ļ you can also combine this with the Futures REST clients - # _____Public_Websocket_Feeds___________________ client = Client() + await client.start() # print(client.get_available_public_subscription_feeds()) products = ["PI_XBTUSD", "PF_SOLUSD"] @@ -66,6 +68,7 @@ async def on_message(self: Client, message: list | dict) -> None: # _____Private_Websocket_Feeds_________________ if key and secret: client_auth = Client(key=key, secret=secret) + await client_auth.start() # print(client_auth.get_available_private_subscription_feeds()) # subscribe to a private/authenticated websocket feed diff --git a/examples/market_client_example.ipynb b/examples/market_client_example.ipynb index ba94fcc3..9cc0e34b 100644 --- a/examples/market_client_example.ipynb +++ b/examples/market_client_example.ipynb @@ -265,7 +265,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 3. Compute some indicatoes based on the loaded data" + "### 3. Compute some indicatoes based on the loaded data" ] }, { diff --git a/examples/spot_orderbook_v2.py b/examples/spot_orderbook.py similarity index 88% rename from examples/spot_orderbook_v2.py rename to examples/spot_orderbook.py index 35f526dc..09410c2d 100644 --- a/examples/spot_orderbook_v2.py +++ b/examples/spot_orderbook.py @@ -40,7 +40,7 @@ import logging from typing import Any -from kraken.spot import OrderbookClientV2 +from kraken.spot import SpotOrderBookClient logging.basicConfig( format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s", @@ -51,12 +51,12 @@ logging.getLogger("requests").setLevel(logging.WARNING) -class Orderbook(OrderbookClientV2): +class Orderbook(SpotOrderBookClient): """ This is a wrapper class that is used to overload the :func:`on_book_update` function. It can also be used as a base for trading strategy. Since the - :class:`kraken.spot.OrderbookClientV2` is derived from - :class:`kraken.spot.KrakenSpotWSClientV2` it can also be used to access the + :class:`kraken.spot.SpotOrderBookClient` is derived from + :class:`kraken.spot.SpotWSClient` it can also be used to access the :func:`subscribe` function and any other provided utility. """ @@ -104,14 +104,14 @@ async def main() -> None: Finally we need some "game loop" - so we create a while loop that runs as long as there is no error. """ - orderbook: Orderbook = Orderbook(depth=10) - await orderbook.add_book( - pairs=["BTC/USD"], # we can also subscribe to more currency pairs - ) + async with Orderbook(depth=10) as orderbook: + await orderbook.add_book( + pairs=["BTC/USD"], # we can also subscribe to more currency pairs + ) - while not orderbook.exception_occur: - await asyncio.sleep(10) + while not orderbook.exception_occur: + await asyncio.sleep(10) if __name__ == "__main__": diff --git a/examples/spot_orderbook_v1.py b/examples/spot_orderbook_v1.py deleted file mode 100644 index ec1a48b5..00000000 --- a/examples/spot_orderbook_v1.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# - -""" - -**For websocket API v1** - -This module provides an example on how to use the Spot Orderbook client of the -python-kraken-sdk (https://github.com/btschwertfeger/python-kraken-sdk) to -retrieve and maintain a valid Spot order book for (a) specific asset pair(s). -It can be run directly without any credentials if the python-kraken-sdk is -installed. - - python3 -m pip install python-kraken-sdk - -The output when running this snippet looks like the following table and updates -the book as soon as Kraken sent any order book update. - -Bid Volume Ask Volume -27076.00000 (8.28552127) 27076.10000 (2.85897056) -27075.90000 (3.75748052) 27077.30000 (0.57243521) -27074.40000 (0.57249652) 27080.80000 (0.00100000) -27072.90000 (0.01200917) 27081.00000 (0.00012345) -27072.80000 (0.25000000) 27081.70000 (0.30000000) -27072.30000 (4.89735970) 27082.70000 (0.05539777) -27072.20000 (2.65896716) 27082.80000 (0.00400000) -27072.10000 (2.77037635) 27082.90000 (0.57231684) -27072.00000 (0.81770000) 27083.00000 (0.38934000) -27071.50000 (0.07194657) 27083.80000 (2.76918992) - -This can be the basis of an order book based trading strategy where realtime -data and fast price movements are considered. -""" - -from __future__ import annotations - -import asyncio -from typing import Any - -from kraken.spot import OrderbookClientV1 - - -class Orderbook(OrderbookClientV1): - """ - This is a wrapper class that is used to overload the :func:`on_book_update` - function. It can also be used as a base for trading strategy. Since the - :class:`kraken.spot.OrderbookClientV1` is derived from - :class:`kraken.spot.KrakenSpotWSClientV1` it can also be used to access the - :func:`subscribe` function and any other provided utility. - """ - - async def on_book_update( - self: Orderbook, - pair: str, - message: list, # noqa: ARG002 - ) -> None: - """ - This function is called every time the order book of ``pair`` gets - updated. - - The ``pair`` parameter can be used to access the updated order book as - shown in the function body below. - - :param pair: The currency pair of the updated order book - :type pair: str - :param message: The message sent by Kraken (not needed in most cases) - :type message: list - """ - - book: dict[str, Any] = self.get(pair=pair) - bid: list[tuple[str, str]] = list(book["bid"].items()) - ask: list[tuple[str, str]] = list(book["ask"].items()) - - print("Bid Volume\t\t Ask Volume") - for level in range(self.depth): - print( - f"{bid[level][0]} ({bid[level][1][0]}) \t {ask[level][0]} ({ask[level][1][0]})", - ) - # assert book["valid"] # ensure that the checksum is valid (will be - # false after reconnect -- but the client handles the removal and - # resubscription of the book) - - -async def main() -> None: - """ - Here we depth of the order book and also a pair. We could - subscribe to multiple pairs, but for simplicity only XBT/USD is chosen. - - The Orderbook class can be instantiated, which receives the order - book-related messages, after we subscribed to the book feed. - - Finally we need some "game loop" - so we create a while loop - that runs as long as there is no error. - """ - orderbook: Orderbook = Orderbook() - - await orderbook.add_book( - pairs=["XBT/USD"], # we can also subscribe to more currency pairs - ) - - while not orderbook.exception_occur: - await asyncio.sleep(10) - - -if __name__ == "__main__": - try: - asyncio.run(main()) - except KeyboardInterrupt: - print("KeyboardInterrupt!") diff --git a/examples/spot_trading_bot_template_v2.py b/examples/spot_trading_bot_template.py similarity index 93% rename from examples/spot_trading_bot_template_v2.py rename to examples/spot_trading_bot_template.py index f9825184..617939ed 100644 --- a/examples/spot_trading_bot_template_v2.py +++ b/examples/spot_trading_bot_template.py @@ -20,7 +20,7 @@ import urllib3 from kraken.exceptions import KrakenAuthenticationError # , KrakenPermissionDeniedError -from kraken.spot import Funding, KrakenSpotWSClientV2, Market, Staking, Trade, User +from kraken.spot import Funding, Market, SpotWSClient, Trade, User logging.basicConfig( format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s", @@ -31,7 +31,7 @@ logging.getLogger("urllib3").setLevel(logging.WARNING) -class TradingBot(KrakenSpotWSClientV2): +class TradingBot(SpotWSClient): """ Class that implements the trading strategy @@ -54,7 +54,7 @@ def __init__( config: dict, **kwargs: object | dict | set | tuple | list | str | float | None, ) -> None: - super().__init__( # initialize the KrakenSpotWSClientV2 + super().__init__( key=config["key"], secret=config["secret"], **kwargs, @@ -65,7 +65,6 @@ def __init__( self.__trade: Trade = Trade(key=config["key"], secret=config["secret"]) self.__market: Market = Market(key=config["key"], secret=config["secret"]) self.__funding: Funding = Funding(key=config["key"], secret=config["secret"]) - self.__staking: Staking = Staking(key=config["key"], secret=config["secret"]) async def on_message(self: TradingBot, message: dict) -> None: """Receives all messages of the websocket connection(s)""" @@ -168,12 +167,13 @@ async def __main(self: Manager) -> None: websocket feeds. While no exception within the strategy occur run the loop. - The variable `exception_occur` which is an attribute of the - KrakenSpotWSClientV2 can be set individually but is also being set to - `True` if the websocket connection has some fatal error. This is used to - exit the asyncio loop - but you can also apply your own reconnect rules. + The variable `exception_occur` which is an attribute of the SpotWSClient + can be set individually but is also being set to `True` if the websocket + connection has some fatal error. This is used to exit the asyncio loop - + but you can also apply your own reconnect rules. """ self.__trading_strategy = TradingBot(config=self.__config) + await self.__trading_strategy.start() await self.__trading_strategy.subscribe( params={"channel": "ticker", "symbol": self.__config["pairs"]}, diff --git a/examples/spot_trading_bot_template_v1.py b/examples/spot_trading_bot_template_v1.py deleted file mode 100644 index 35d435d2..00000000 --- a/examples/spot_trading_bot_template_v1.py +++ /dev/null @@ -1,241 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# ruff: noqa: RUF027 - -""" -Module that provides a template to build a Spot trading algorithm using the -python-kraken-sdk and Kraken Spot websocket API v1. -""" - -from __future__ import annotations - -import asyncio -import logging -import logging.config -import os -import sys -import traceback - -import requests -import urllib3 - -from kraken.exceptions import KrakenAuthenticationError # , KrakenPermissionDeniedError -from kraken.spot import Funding, KrakenSpotWSClientV1, Market, Staking, Trade, User - -logging.basicConfig( - format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s", - datefmt="%Y/%m/%d %H:%M:%S", - level=logging.INFO, -) -logging.getLogger("requests").setLevel(logging.WARNING) -logging.getLogger("urllib3").setLevel(logging.WARNING) - - -class TradingBot(KrakenSpotWSClientV1): - """ - Class that implements the trading strategy - - * The on_message function gets all messages sent by the websocket feeds. - * Decisions can be made based on these messages - * Can place trades using the self.__trade client or self.send_message - * Do everything you want - - ====== P A R A M E T E R S ====== - config: dict - configuration like: { - "key": "kraken-spot-key", - "secret": "kraken-spot-secret", - "pairs": ["DOT/USD", "BTC/USD"], - } - """ - - def __init__(self: TradingBot, config: dict) -> None: - super().__init__( # initialize the KrakenSpotWSClientV1 - key=config["key"], - secret=config["secret"], - ) - self.__config: dict = config - - self.__user: User = User(key=config["key"], secret=config["secret"]) - self.__trade: Trade = Trade(key=config["key"], secret=config["secret"]) - self.__market: Market = Market(key=config["key"], secret=config["secret"]) - self.__funding: Funding = Funding(key=config["key"], secret=config["secret"]) - self.__staking: Staking = Staking(key=config["key"], secret=config["secret"]) - - async def on_message(self: TradingBot, message: dict | list) -> None: - """Receives all messages of the websocket connection(s)""" - if isinstance(message, dict) and "event" in message: - if message["event"] in {"heartbeat", "pong"}: - return - if "error" in message: - # handle exceptions/errors sent by websocket connection â€Ļ - pass - - logging.info(message) - - # == apply your trading strategy here == - - # Call functions of `self.__trade` and other clients if conditions met â€Ļ - # try: - # print(self.__trade.create_order( - # ordertype='limit', - # side='buy', - # volume=2, - # pair='XBTUSD', - # price=12000 - # )) - # except KrakenPermissionDeniedError: - # # â€Ļ handle exceptions - # pass - - # The spot websocket client also allow sending orders via websockets - # this is way faster than using REST endpoints. - # await self.create_order( - # ordertype='limit', - # side='buy', - # pair='BTC/EUR', - # price=20000, - # volume=200 - # ) - - # You can also un-/subscribe here using `self.subscribe(...)` or - # `self.unsubscribe(...)`. - # - # â€Ļ more can be found in the documentation - # (https://python-kraken-sdk.readthedocs.io/en/stable/) - - # Add more functions to customize the trading strategy â€Ļ - - def save_exit(self: TradingBot, reason: str | None = "") -> None: - """controlled shutdown of the strategy""" - logging.warning( - "Save exit triggered, reason: {reason}", - extra={"reason": reason}, - ) - # some ideas: - # * save the bots data - # * maybe close trades - # * enable dead man's switch - sys.exit(1) - - -class Manager: - """ - Class to manage the trading strategy - - â€Ļ subscribes to desired feeds, instantiates the strategy and runs as long - as there is no error. - - ====== P A R A M E T E R S ====== - config: dict - configuration like: { - "key": "kraken-spot-key", - "secret": "kraken-spot-secret", - "pairs": ["DOT/USD", "BTC/USD"], - } - """ - - def __init__(self: Manager, config: dict) -> None: - self.__config: dict = config - self.__trading_strategy: TradingBot | None = None - - def run(self: Manager) -> None: - """Starts the event loop and bot""" - if not self.__check_credentials(): - sys.exit(1) - - try: - asyncio.run(self.__main()) - except KeyboardInterrupt: - self.save_exit(reason="KeyboardInterrupt") - else: - self.save_exit(reason="Asyncio loop left") - - async def __main(self: Manager) -> None: - """ - Instantiates the trading strategy (bot) and subscribes to the - desired websocket feeds. While no exception within the strategy occur - run the loop. - - This variable `exception_occur` which is an attribute of the - KrakenSpotWSClientV1 can be set individually but is also being set to - `True` if the websocket connection has some fatal error. This is used to - exit the asyncio loop - but you can also apply your own reconnect rules. - """ - self.__trading_strategy = TradingBot(config=self.__config) - - await self.__trading_strategy.subscribe( - subscription={"name": "ticker"}, - pair=self.__config["pairs"], - ) - await self.__trading_strategy.subscribe( - subscription={"name": "ohlc", "interval": 15}, - pair=self.__config["pairs"], - ) - - await self.__trading_strategy.subscribe(subscription={"name": "ownTrades"}) - await self.__trading_strategy.subscribe(subscription={"name": "openOrders"}) - - while not self.__trading_strategy.exception_occur: - try: - # check if the algorithm feels good - # maybe send a status update every day via Telegram or Mail - # ..â€Ļ - pass - - except Exception as exc: - message: str = f"Exception in main: {exc} {traceback.format_exc()}" - logging.error(message) - self.__trading_strategy.save_exit(reason=message) - - await asyncio.sleep(6) - self.__trading_strategy.save_exit( - reason="Left main loop because of exception in strategy.", - ) - - def __check_credentials(self: Manager) -> bool: - """Checks the user credentials and the connection to Kraken""" - try: - User(self.__config["key"], self.__config["secret"]).get_account_balance() - logging.info("Client credentials are valid.") - return True - except urllib3.exceptions.MaxRetryError: - logging.error("MaxRetryError, cannot connect.") - return False - except requests.exceptions.ConnectionError: - logging.error("ConnectionError, Kraken not available.") - return False - except KrakenAuthenticationError: - logging.error("Invalid credentials!") - return False - - def save_exit(self: Manager, reason: str = "") -> None: - """Invoke the save exit function of the trading strategy""" - print(f"Save exit triggered - {reason}") - if self.__trading_strategy is not None: - self.__trading_strategy.save_exit(reason=reason) - else: - sys.exit(1) - - -def main() -> None: - """Example main - load environment variables and run the strategy.""" - manager: Manager = Manager( - config={ - "key": os.getenv("SPOT_API_KEY"), - "secret": os.getenv("SPOT_SECRET_KEY"), - "pairs": ["DOT/USD", "XBT/USD"], - }, - ) - - try: - manager.run() - except Exception: - manager.save_exit( - reason=f"manageBot.run() has ended: {traceback.format_exc()}", - ) - - -if __name__ == "__main__": - main() diff --git a/examples/spot_ws_examples_v2.py b/examples/spot_ws_examples.py similarity index 69% rename from examples/spot_ws_examples_v2.py rename to examples/spot_ws_examples.py index 38edbe0e..e3b302b1 100644 --- a/examples/spot_ws_examples_v2.py +++ b/examples/spot_ws_examples.py @@ -16,7 +16,7 @@ import os from contextlib import suppress -from kraken.spot import KrakenSpotWSClientV2 +from kraken.spot import SpotWSClient logging.basicConfig( format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s", @@ -27,41 +27,43 @@ logging.getLogger("urllib3").setLevel(logging.WARNING) +class Client(SpotWSClient): + """Can be used to create a custom trading strategy""" + + async def on_message(self: Client, message: dict) -> None: + """Receives the websocket messages""" + if message.get("method") == "pong" or message.get("channel") == "heartbeat": + return + + print(message) + # now you can access lots of methods, for example to create an order: + # if self._is_auth: # only if the client is authenticated â€Ļ + # await self.send_message( + # message={ + # "method": "add_order", + # "params": { + # "limit_price": 1234.56, + # "order_type": "limit", + # "order_userref": 123456789, + # "order_qty": 1.0, + # "side": "buy", + # "symbol": "BTC/USD", + # "validate": True, + # }, + # } + # ) + # ... it is also possible to call regular REST endpoints + # but using the websocket messages is more efficient. + # You can also un-/subscribe here using self.subscribe/self.unsubscribe. + + async def main() -> None: key: str = os.getenv("SPOT_API_KEY") secret: str = os.getenv("SPOT_SECRET_KEY") - class Client(KrakenSpotWSClientV2): - """Can be used to create a custom trading strategy""" - - async def on_message(self: Client, message: dict) -> None: - """Receives the websocket messages""" - if message.get("method") == "pong" or message.get("channel") == "heartbeat": - return - - print(message) - # now you can access lots of methods, for example to create an order: - # if self._is_auth: # only if the client is authenticated â€Ļ - # await self.send_message( - # message={ - # "method": "add_order", - # "params": { - # "limit_price": 1234.56, - # "order_type": "limit", - # "order_userref": 123456789, - # "order_qty": 1.0, - # "side": "buy", - # "symbol": "BTC/USD", - # "validate": True, - # }, - # } - # ) - # ... it is also possible to call regular REST endpoints - # but using the websocket messages is more efficient. - # You can also un-/subscribe here using self.subscribe/self.unsubscribe. - # Public/unauthenticated websocket client client: Client = Client() # only use this one if you don't need private feeds + await client.start() # print(client.public_channel_names) # list public subscription names await client.subscribe( @@ -95,6 +97,7 @@ async def on_message(self: Client, message: dict) -> None: # for a public connection, it can be disabled using the ``no_public`` # parameter. client_auth = Client(key=key, secret=secret, no_public=True) + await client_auth.start() # print(client_auth.private_channel_names) # â€Ļ list private channel names # when using the authenticated client, you can also subscribe to public feeds await client_auth.subscribe(params={"channel": "executions"}) @@ -116,7 +119,7 @@ async def on_message(self: Client, message: dict) -> None: # ============================================================ # Alternative - as ContextManager: -# from kraken.spot import KrakenSpotWSClientV2 +# from kraken.spot import SpotWSClient # import asyncio @@ -125,7 +128,7 @@ async def on_message(self: Client, message: dict) -> None: # async def main() -> None: -# async with KrakenSpotWSClientV2(callback=on_message) as session: +# async with SpotWSClient(callback=on_message) as session: # await session.subscribe(params={"channel": "ticker", "symbol": ["BTC/USD"]}) # while True: diff --git a/examples/spot_ws_examples_v1.py b/examples/spot_ws_examples_v1.py deleted file mode 100644 index 0eabad16..00000000 --- a/examples/spot_ws_examples_v1.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# - -""" -Module that provides an example usage for the KrakenSpotWebsocketClient. -It uses the Kraken Websocket API v1. -""" - -from __future__ import annotations - -import asyncio -import logging -import logging.config -import os -from contextlib import suppress - -from kraken.spot import KrakenSpotWSClientV1 - -logging.basicConfig( - format="%(asctime)s %(module)s,line: %(lineno)d %(levelname)8s | %(message)s", - datefmt="%Y/%m/%d %H:%M:%S", - level=logging.INFO, -) -logging.getLogger("requests").setLevel(logging.WARNING) -logging.getLogger("urllib3").setLevel(logging.WARNING) - - -async def main() -> None: - """Create a client and subscribe to channels/feeds""" - - key: str = os.getenv("SPOT_API_KEY") - secret: str = os.getenv("SPOT_SECRET_KEY") - - class Client(KrakenSpotWSClientV1): - """Can be used to create a custom trading strategy""" - - async def on_message(self: Client, message: list | dict) -> None: - """Receives the websocket messages""" - if isinstance(message, dict) and "event" in message: - topic = message["event"] - if topic in {"heartbeat", "pong"}: - return - - print(message) - # if condition: - # await self.create_order( - # ordertype="limit", - # side="buy", - # pair="BTC/USD", - # price=20000, - # volume=200 - # ) - # ... it is also possible to call regular REST endpoints - # but using the websocket messages is more efficient. - # You can also un-/subscribe here using self.subscribe/self.unsubscribe. - - # ___Public_Websocket_Feed_____ - client: Client = Client() # only use this one if you don't need private feeds - # print(client.public_channel_names) # list public subscription names - - await client.subscribe(subscription={"name": "ticker"}, pair=["XBT/USD", "DOT/USD"]) - await client.subscribe(subscription={"name": "spread"}, pair=["XBT/USD", "DOT/USD"]) - await client.subscribe(subscription={"name": "book"}, pair=["BTC/USD"]) - # await client.subscribe(subscription={ "name": "book", "depth": 25}, pair=["BTC/USD"]) - # await client.subscribe(subscription={ "name": "ohlc" }, pair=["BTC/USD"]) - # await client.subscribe(subscription={ "name": "ohlc", "interval": 15}, pair=["XBT/USD", "DOT/USD"]) - # await client.subscribe(subscription={ "name": "trade" }, pair=["BTC/USD"]) - # await client.subscribe(subscription={ "name": "*"} , pair=["BTC/USD"]) - - await asyncio.sleep(2) # wait because unsubscribing is faster than subscribing ... - # print(client.active_public_subscriptions) - await client.unsubscribe( - subscription={"name": "ticker"}, - pair=["XBT/USD", "DOT/USD"], - ) - await client.unsubscribe(subscription={"name": "spread"}, pair=["XBT/USD"]) - await client.unsubscribe(subscription={"name": "spread"}, pair=["DOT/USD"]) - # ... - - if key and secret: - client_auth = Client(key=key, secret=secret) - # print(client_auth.active_private_subscriptions) - # print(client_auth.private_channel_names) # list private channel names - # when using the authenticated client, you can also subscribe to public feeds - await client_auth.subscribe(subscription={"name": "ownTrades"}) - await client_auth.subscribe(subscription={"name": "openOrders"}) - - await asyncio.sleep(2) - await client_auth.unsubscribe(subscription={"name": "ownTrades"}) - await client_auth.unsubscribe(subscription={"name": "openOrders"}) - - while not client.exception_occur: # and not client_auth.exception_occur: - await asyncio.sleep(6) - - -if __name__ == "__main__": - with suppress(KeyboardInterrupt): - asyncio.run(main()) - # The websocket client will send {'event': 'asyncio.CancelledError'} - # via on_message so you can handle the behavior/next actions - # individually within your strategy. - -# ============================================================ -# Alternative - as ContextManager: - -# from kraken.spot import KrakenSpotWSClientV1 -# import asyncio - -# async def on_message(message): -# print(message) - -# async def main() -> None: -# async with KrakenSpotWSClientV1(callback=on_message) as session: -# await session.subscribe(subscription={"name": "ticker"}, pair=["XBT/USD"]) - -# while True: -# await asyncio.sleep(6) - -# if __name__ == "__main__": -# try: -# asyncio.run(main()) -# except KeyboardInterrupt: -# pass diff --git a/kraken/base_api/__init__.py b/kraken/base_api/__init__.py index 90656a5a..f5332257 100644 --- a/kraken/base_api/__init__.py +++ b/kraken/base_api/__init__.py @@ -11,17 +11,20 @@ import hmac import json import time +from copy import deepcopy from functools import wraps -from typing import TYPE_CHECKING, Any, Final, TypeVar +from typing import TYPE_CHECKING, Any, TypeVar from urllib.parse import urlencode, urljoin from uuid import uuid1 +import aiohttp import requests from kraken.exceptions import _get_exception if TYPE_CHECKING: - from collections.abc import Callable + from collections.abc import Awaitable, Callable, Coroutine + from typing import Final Self = TypeVar("Self") @@ -87,7 +90,7 @@ def wrapper( return decorator -class KrakenErrorHandler: +class ErrorHandler: """ Class that checks if the response of a request contains error messages and returns either message if there is no error or raises a custom @@ -95,7 +98,7 @@ class KrakenErrorHandler: """ def __get_exception( - self: KrakenErrorHandler, + self: ErrorHandler, data: str, ) -> Any | None: # noqa: ANN401 """ @@ -104,7 +107,7 @@ def __get_exception( """ return _get_exception(data=data) - def check(self: KrakenErrorHandler, data: dict) -> dict | Any: # noqa: ANN401 + def check(self: ErrorHandler, data: dict) -> dict | Any: # noqa: ANN401 """ Check if the error message is a known KrakenError response and than raise a custom exception or return the data containing the "error". @@ -127,7 +130,7 @@ def check(self: KrakenErrorHandler, data: dict) -> dict | Any: # noqa: ANN401 raise exception(data) return data - def check_send_status(self: KrakenErrorHandler, data: dict) -> dict: + def check_send_status(self: ErrorHandler, data: dict) -> dict: """ Checks the responses of Futures REST endpoints @@ -147,7 +150,7 @@ def check_send_status(self: KrakenErrorHandler, data: dict) -> dict: return data return data - def check_batch_status(self: KrakenErrorHandler, data: dict) -> dict: + def check_batch_status(self: ErrorHandler, data: dict) -> dict: """ Used to check the Futures batch order responses for errors @@ -170,9 +173,9 @@ def check_batch_status(self: KrakenErrorHandler, data: dict) -> dict: return data -class KrakenSpotBaseAPI: +class SpotClient: """ - This class the the base for all Spot clients, handles un-/signed + This class is the base for all Spot clients, handles un-/signed requests and returns exception handled results. If you are facing timeout errors on derived clients, you can make use of the @@ -184,91 +187,46 @@ class KrakenSpotBaseAPI: :type secret: str, optional :param url: URL to access the Kraken API (default: https://api.kraken.com) :type url: str, optional - :param sandbox: Use the sandbox (not supported for Spot trading so far, - default: ``False``) - :type sandbox: bool, optional """ URL: str = "https://api.kraken.com" TIMEOUT: int = 10 + HEADERS: Final[dict] = { + "User-Agent": "python-kraken-sdk" + " (https://github.com/btschwertfeger/python-kraken-sdk)", + } def __init__( - self: KrakenSpotBaseAPI, + self: SpotClient, key: str = "", secret: str = "", url: str = "", *, - sandbox: bool = False, use_custom_exceptions: bool = True, ) -> None: - if sandbox: - raise ValueError("Sandbox not available for Kraken Spot trading.") if url: self.URL = url - self.__key: str = key - self.__secret: str = secret - self.__use_custom_exceptions: bool = use_custom_exceptions - - self.__err_handler: KrakenErrorHandler = KrakenErrorHandler() + self._key: str = key + self._secret: str = secret + self._use_custom_exceptions: bool = use_custom_exceptions + self._err_handler: ErrorHandler = ErrorHandler() self.__session: requests.Session = requests.Session() - self.__session.headers.update( - { - "User-Agent": "python-kraken-sdk" - " (https://github.com/btschwertfeger/python-kraken-sdk)", - }, - ) + self.__session.headers.update(self.HEADERS) - def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments - self: KrakenSpotBaseAPI, + def _prepare_request( + self: SpotClient, + *, method: str, uri: str, params: dict | None = None, - timeout: int = 10, - *, auth: bool = True, do_json: bool = False, - return_raw: bool = False, query_str: str | None = None, extra_params: str | dict | None = None, - ) -> dict[str, Any] | list[str] | list[dict[str, Any]] | requests.Response: - """ - Handles the requested requests, by sending the request, handling the - response, and returning the message or in case of an error the - respective Exception. - - :param method: The request method, e.g., ``GET``, ``POST``, and ``PUT`` - :type method: str - :param uri: The endpoint to send the message - :type uri: str - :param auth: If the requests needs authentication (default: ``True``) - :type auth: bool - :param params: The query or post parameter of the request (default: - ``None``) - :type params: dict, optional - :param extra_params: Additional query or post parameter of the request - (default: ``None``) - :type extra_params: str | dict, optional - :param timeout: Timeout for the request (default: ``10``) - :type timeout: int - :param do_json: If the ``params`` must be "jsonified" - in case of - nested dict style - :type do_json: bool - :param return_raw: If the response should be returned without parsing. - This is used for example when requesting an export of the trade - history as .zip archive. - :type return_raw: bool, optional - :param query_str: Add custom values to the query - /0/public/Nfts?filter%5Bcollection_id%5D=NCQNABO-XYCA7-JMMSDF&page_size=10 - :type query_str: str, optional - :raise kraken.exceptions.KrakenException.*: If the response contains - errors - :return: The response - :rtype: dict[str, Any] | list[str] | list[dict[str, Any]] | - requests.Response - """ - METHOD: str = method.upper() - URL: str = urljoin(self.URL, uri) + ) -> tuple[str, str, dict, dict, str]: + method: str = method.upper() # type: ignore[no-redef] + url: str = urljoin(self.URL, uri) if not defined(params): params = {} @@ -280,7 +238,7 @@ def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments ) query_params: str = ( urlencode(params, doseq=True) - if METHOD in {"GET", "DELETE"} and params + if method in {"GET", "DELETE"} and params else "" ) @@ -289,14 +247,13 @@ def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments elif query_str: query_params = query_str - TIMEOUT: int = self.TIMEOUT if timeout != 10 else timeout - HEADERS: dict = {} + headers: dict = deepcopy(self.HEADERS) if auth: - if not self.__key or not self.__secret: + if not self._key or not self._secret: raise ValueError("Missing credentials.") - params["nonce"] = str(int(time.time() * 100_000_000)) + params["nonce"] = self.get_nonce() content_type: str sign_data: str @@ -307,10 +264,10 @@ def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments content_type = "application/x-www-form-urlencoded; charset=utf-8" sign_data = urlencode(params, doseq=True) - HEADERS.update( + headers.update( { "Content-Type": content_type, - "API-Key": self.__key, + "API-Key": self._key, "API-Sign": self._get_kraken_signature( url_path=f"{uri}{query_params}", data=sign_data, @@ -318,14 +275,73 @@ def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments ), }, ) + return method, url, headers, params, query_params + + def request( # noqa: PLR0913 # pylint: disable=too-many-arguments + self: SpotClient, + method: str, + uri: str, + params: dict | None = None, + timeout: int = 10, + *, + auth: bool = True, + do_json: bool = False, + return_raw: bool = False, + query_str: str | None = None, + extra_params: str | dict | None = None, + ) -> dict[str, Any] | list[str] | list[dict[str, Any]] | requests.Response: + """ + Handles the requested requests, by sending the request, handling the + response, and returning the message or in case of an error the + respective Exception. + + :param method: The request method, e.g., ``GET``, ``POST``, ``PUT``, ... + :type method: str + :param uri: The endpoint to send the message + :type uri: str + :param auth: If the requests needs authentication (default: ``True``) + :type auth: bool + :param params: The query or post parameter of the request (default: + ``None``) + :type params: dict, optional + :param extra_params: Additional query or post parameter of the request + (default: ``None``) + :type extra_params: str | dict, optional + :param timeout: Timeout for the request (default: ``10``) + :type timeout: int + :param do_json: If the ``params`` must be "jsonified" - in case of + nested dict style + :type do_json: bool + :param return_raw: If the response should be returned without parsing. + This is used for example when requesting an export of the trade + history as .zip archive. + :type return_raw: bool, optional + :param query_str: Add custom values to the query + /0/public/Nfts?filter%5Bcollection_id%5D=NCQNABO-XYCA7-JMMSDF&page_size=10 + :type query_str: str, optional + :raise kraken.exceptions.KrakenException.*: If the response contains + errors + :return: The response + :rtype: dict | list | requests.Response + """ + method, url, headers, params, query_params = self._prepare_request( + method=method, + uri=uri, + params=params, + auth=auth, + do_json=do_json, + query_str=query_str, + extra_params=extra_params, + ) + timeout: int = self.TIMEOUT if timeout != 10 else timeout # type: ignore[no-redef] - if METHOD in {"GET", "DELETE"}: + if method in {"GET", "DELETE"}: return self.__check_response_data( response=self.__session.request( - method=METHOD, - url=f"{URL}?{query_params}" if query_params else URL, - headers=HEADERS, - timeout=TIMEOUT, + method=method, + url=f"{url}?{query_params}" if query_params else url, + headers=headers, + timeout=timeout, ), return_raw=return_raw, ) @@ -333,28 +349,28 @@ def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments if do_json: return self.__check_response_data( response=self.__session.request( - method=METHOD, - url=URL, - headers=HEADERS, + method=method, + url=url, + headers=headers, json=params, - timeout=TIMEOUT, + timeout=timeout, ), return_raw=return_raw, ) return self.__check_response_data( response=self.__session.request( - method=METHOD, - url=URL, - headers=HEADERS, + method=method, + url=url, + headers=headers, data=params, - timeout=TIMEOUT, + timeout=timeout, ), return_raw=return_raw, ) def _get_kraken_signature( - self: KrakenSpotBaseAPI, + self: SpotClient, url_path: str, data: str, nonce: int, @@ -374,7 +390,7 @@ def _get_kraken_signature( """ return base64.b64encode( hmac.new( - base64.b64decode(self.__secret), + base64.b64decode(self._secret), url_path.encode() + hashlib.sha256((str(nonce) + data).encode()).digest(), hashlib.sha512, @@ -382,7 +398,7 @@ def _get_kraken_signature( ).decode() def __check_response_data( - self: KrakenSpotBaseAPI, + self: SpotClient, response: requests.Response, *, return_raw: bool = False, @@ -397,7 +413,7 @@ def __check_response_data( :return: The response in raw or parsed to dict :rtype: dict | list | requests.Response """ - if not self.__use_custom_exceptions: + if not self._use_custom_exceptions: return response if response.status_code in {"200", 200}: @@ -410,13 +426,17 @@ def __check_response_data( if "error" in data: # can only be dict if error is present: - return self.__err_handler.check(data) # type: ignore[arg-type] + return self._err_handler.check(data) # type: ignore[arg-type] return data raise Exception(f"{response.status_code} - {response.text}") + def get_nonce(self: SpotClient) -> str: + """Return a new nonce""" + return str(int(time.time() * 100_000_000)) + @property - def return_unique_id(self: KrakenSpotBaseAPI) -> str: + def return_unique_id(self: SpotClient) -> str: """Returns a unique uuid string :return: uuid @@ -428,18 +448,186 @@ def __enter__(self: Self) -> Self: return self def __exit__( - self: KrakenSpotBaseAPI, + self: SpotClient, *exc: object, **kwargs: dict[str, Any], ) -> None: pass -class KrakenNFTBaseAPI(KrakenSpotBaseAPI): - """Inherits from KrakenSpotBaseAPI""" +class SpotAsyncClient(SpotClient): + """ + This class provides the base client for accessing the Kraken Spot and NFT + API using asynchronous requests. + + If you are facing timeout errors on derived clients, you can make use of the + ``TIMEOUT`` attribute to deviate from the default ``10`` seconds. + + :param key: Spot API public key (default: ``""``) + :type key: str, optional + :param secret: Spot API secret key (default: ``""``) + :type secret: str, optional + :param url: URL to access the Kraken API (default: https://api.kraken.com) + :type url: str, optional + """ + + def __init__( + self: SpotAsyncClient, + key: str = "", + secret: str = "", + url: str = "", + *, + use_custom_exceptions: bool = True, + ) -> None: + super().__init__( + key=key, + secret=secret, + url=url, + use_custom_exceptions=use_custom_exceptions, + ) + self.__session = aiohttp.ClientSession(headers=self.HEADERS) + + async def request( # type: ignore[override] # pylint: disable=invalid-overridden-method,too-many-arguments # noqa: PLR0913 + self: SpotAsyncClient, + method: str, + uri: str, + params: dict | None = None, + timeout: int = 10, + *, + auth: bool = True, + do_json: bool = False, + return_raw: bool = False, + query_str: str | None = None, + extra_params: str | dict | None = None, + ) -> Coroutine: + """ + Handles the requested requests, by sending the request, handling the + response, and returning the message or in case of an error the + respective Exception. + + :param method: The request method, e.g., ``GET``, ``POST``, ``PUT``, ... + :type method: str + :param uri: The endpoint to send the message + :type uri: str + :param auth: If the requests needs authentication (default: ``True``) + :type auth: bool + :param params: The query or post parameter of the request (default: + ``None``) + :type params: dict, optional + :param timeout: Timeout for the request (default: ``10``) + :type timeout: int + :param do_json: If the ``params`` must be "jsonified" - in case of + nested dict style + :type do_json: bool + :param return_raw: If the response should be returned without parsing. + This is used for example when requesting an export of the trade + history as .zip archive. + :type return_raw: bool, optional + :param query_str: Add custom values to the query + /0/public/Nfts?filter%5Bcollection_id%5D=NCQNABO-XYCA7-JMMSDF&page_size=10 + :type query_str: str, optional + :raise kraken.exceptions.KrakenException.*: If the response contains + errors + :return: The response + :rtype: dict | list | aiohttp.ClientResponse + """ + method, url, headers, params, query_params = self._prepare_request( + method=method, + uri=uri, + params=params, + auth=auth, + do_json=do_json, + query_str=query_str, + extra_params=extra_params, + ) + timeout: int = self.TIMEOUT if timeout != 10 else timeout # type: ignore[no-redef] + + if method in {"GET", "DELETE"}: + return await self.__check_response_data( # type: ignore[return-value] + response=await self.__session.request( # type: ignore[misc] + method=method, + url=f"{url}?{query_params}" if query_params else url, + headers=headers, + timeout=timeout, + ), + return_raw=return_raw, + ) + + if do_json: + return await self.__check_response_data( # type: ignore[return-value] + response=await self.__session.request( # type: ignore[misc] + method=method, + url=url, + headers=headers, + json=params, + timeout=timeout, + ), + return_raw=return_raw, + ) + + return await self.__check_response_data( # type: ignore[return-value] + response=await self.__session.request( # type: ignore[misc] + method=method, + url=url, + headers=headers, + data=params, + timeout=timeout, + ), + return_raw=return_raw, + ) + + async def __check_response_data( # pylint: disable=invalid-overridden-method + self: SpotAsyncClient, + response: aiohttp.ClientResponse, + *, + return_raw: bool = False, + ) -> dict | list | aiohttp.ClientResponse: + """ + Checks the response, handles the error (if exists) and returns the + response data. + + :param response: The response of a request, requested by the requests + module + :type response: aiohttp.ClientResponse + :param return_raw: Defines if the return should be the raw response if + there is no error + :type data: bool, optional + :return: The response in raw or parsed to dict + :rtype: dict | list | aiohttp.ClientResponse + """ + if not self._use_custom_exceptions: + return response + + if response.status in {"200", 200}: + if return_raw: + return response + try: + data: dict | list = await response.json() + except ValueError as exc: + raise ValueError(response.content) from exc + + if "error" in data: + return self._err_handler.check(data) # type: ignore[arg-type] + return data + + raise Exception(f"{response.status} - {response.text}") + + async def async_close(self: SpotAsyncClient) -> None: + """Closes the aiohttp session""" + await self.__session.close() # type: ignore[func-returns-value] + async def __aenter__(self: Self) -> Self: + return self -class KrakenFuturesBaseAPI: + async def __aexit__(self: SpotAsyncClient, *args: object) -> None: + await self.async_close() + + +class NFTClient(SpotClient): + """Inherits from SpotClient""" + + +class FuturesClient: """ The base class for all Futures clients handles un-/signed requests and returns exception handled results. @@ -463,9 +651,13 @@ class KrakenFuturesBaseAPI: URL: str = "https://futures.kraken.com" SANDBOX_URL: str = "https://demo-futures.kraken.com" TIMEOUT: int = 10 + HEADERS: Final[dict] = { + "User-Agent": "python-kraken-sdk" + " (https://github.com/btschwertfeger/python-kraken-sdk)", + } def __init__( - self: KrakenFuturesBaseAPI, + self: FuturesClient, key: str = "", secret: str = "", url: str = "", @@ -482,11 +674,11 @@ def __init__( else: self.url = self.URL - self.__key: str = key - self.__secret: str = secret - self.__use_custom_exceptions: bool = use_custom_exceptions + self._key: str = key + self._secret: str = secret + self._use_custom_exceptions: bool = use_custom_exceptions - self.__err_handler: KrakenErrorHandler = KrakenErrorHandler() + self._err_handler: ErrorHandler = ErrorHandler() self.__session: requests.Session = requests.Session() self.__session.headers.update( { @@ -495,8 +687,61 @@ def __init__( }, ) - def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments - self: KrakenFuturesBaseAPI, + def _prepare_request( + self: FuturesClient, + method: str, + uri: str, + post_params: dict, + query_params: str | dict, + extra_params: str | dict | None = None, + auth: bool = True, # noqa: FBT001,FBT002 + ) -> tuple[str, str, dict, str, str]: + + method: str = method.upper() # type: ignore[no-redef] + url: Final[str] = urljoin(self.url, uri) + + if defined(extra_params): + extra_params = ( + json.loads(extra_params) + if isinstance(extra_params, str) + else extra_params + ) + else: + extra_params = {} + + if post_params is None: + post_params = {} + post_params |= extra_params + + encoded_payload: Final[str] = urlencode(post_params, doseq=True) + + query_string = ( + "" if query_params is None else urlencode(query_params, doseq=True) # type: ignore[arg-type] + ) + + headers: dict = deepcopy(self.HEADERS) + + if auth: + if not self._key or not self._secret: + raise ValueError("Missing credentials") + nonce: str = self.get_nonce() + headers.update( + { + "Content-Type": "application/x-www-form-urlencoded; charset=utf-8", + "Nonce": nonce, + "APIKey": self._key, + "Authent": self._get_kraken_futures_signature( + uri, + query_string + encoded_payload, + nonce, + ), + }, + ) + + return method, url, headers, encoded_payload, query_string + + def request( # noqa: PLR0913 # pylint: disable=too-many-arguments + self: FuturesClient, method: str, uri: str, post_params: dict | None = None, @@ -506,7 +751,7 @@ def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments auth: bool = True, return_raw: bool = False, extra_params: str | dict | None = None, - ) -> dict[str, Any] | list[dict[str, Any]] | list[str] | requests.Response: + ) -> dict | list | requests.Response: """ Handles the requested requests, by sending the request, handling the response, and returning the message or in case of an error the @@ -536,86 +781,55 @@ def _request( # noqa: PLR0913 # pylint: disable=too-many-arguments :raise kraken.exceptions.*: If the response contains errors :return: The response - :rtype: dict[str, Any] | list[dict[str, Any]] | list[str] | requests.Response + :rtype: dict | list | requests.Response """ - METHOD: Final[str] = method.upper() - URL: Final[str] = urljoin(self.url, uri) - - if defined(extra_params): - extra_params = ( - json.loads(extra_params) - if isinstance(extra_params, str) - else extra_params - ) - else: - extra_params = {} - - if post_params is None: - post_params = {} - post_params |= extra_params - - encoded_payload: Final[str] = urlencode(post_params, doseq=True) - - # post_string: Final[str] = json.dumps(post_params) if post_params else "" - query_string = ( - "" if query_params is None else urlencode(query_params, doseq=True) + method, url, headers, encoded_payload, query_string = self._prepare_request( + method=method, + uri=uri, + post_params=post_params, + query_params=query_params, + auth=auth, + extra_params=extra_params, ) + timeout: int = self.TIMEOUT if timeout == 10 else timeout # type: ignore[no-redef] - TIMEOUT: int = self.TIMEOUT if timeout == 10 else timeout - HEADERS: dict = {} - if auth: - if not self.__key or not self.__secret: - raise ValueError("Missing credentials") - nonce: str = str(int(time.time() * 100_000_000)) - HEADERS.update( - { - "Content-Type": "application/x-www-form-urlencoded; charset=utf-8", - "Nonce": nonce, - "APIKey": self.__key, - "Authent": self._get_kraken_futures_signature( - uri, - query_string + encoded_payload, - nonce, - ), - }, - ) - if METHOD in {"GET", "DELETE"}: + if method in {"GET", "DELETE"}: return self.__check_response_data( response=self.__session.request( - method=METHOD, - url=URL, + method=method, + url=url, params=query_string, - headers=HEADERS, - timeout=TIMEOUT, + headers=headers, + timeout=timeout, ), return_raw=return_raw, ) - if METHOD == "PUT": + if method == "PUT": return self.__check_response_data( response=self.__session.request( - method=METHOD, - url=URL, + method=method, + url=url, params=encoded_payload, - headers=HEADERS, - timeout=TIMEOUT, + headers=headers, + timeout=timeout, ), return_raw=return_raw, ) return self.__check_response_data( response=self.__session.request( - method=METHOD, - url=URL, + method=method, + url=url, data=encoded_payload, - headers=HEADERS, - timeout=TIMEOUT, + headers=headers, + timeout=timeout, ), return_raw=return_raw, ) def _get_kraken_futures_signature( - self: KrakenFuturesBaseAPI, + self: FuturesClient, endpoint: str, data: str, nonce: str, @@ -640,14 +854,14 @@ def _get_kraken_futures_signature( sha256_hash.update((data + nonce + endpoint).encode("utf8")) return base64.b64encode( hmac.new( - base64.b64decode(self.__secret), + base64.b64decode(self._secret), sha256_hash.digest(), hashlib.sha512, ).digest(), ).decode() def __check_response_data( - self: KrakenFuturesBaseAPI, + self: FuturesClient, response: requests.Response, *, return_raw: bool = False, @@ -667,7 +881,7 @@ def __check_response_data( :return: The signed string :rtype: dict | requests.Response """ - if not self.__use_custom_exceptions: + if not self._use_custom_exceptions: return response if response.status_code in {"200", 200}: @@ -679,15 +893,19 @@ def __check_response_data( raise ValueError(response.content) from exc if "error" in data: - return self.__err_handler.check(data) + return self._err_handler.check(data) if "sendStatus" in data: - return self.__err_handler.check_send_status(data) + return self._err_handler.check_send_status(data) if "batchStatus" in data: - return self.__err_handler.check_batch_status(data) + return self._err_handler.check_batch_status(data) return data raise Exception(f"{response.status_code} - {response.text}") + def get_nonce(self: FuturesClient) -> str: + """Return a new nonce""" + return str(int(time.time() * 100_000_000)) + def __enter__(self: Self) -> Self: return self @@ -695,4 +913,161 @@ def __exit__(self, *exc: object, **kwargs: dict[str, Any]) -> None: pass -__all__ = ["defined", "ensure_string", "KrakenSpotBaseAPI", "KrakenFuturesBaseAPI"] +class FuturesAsyncClient(FuturesClient): + """ + This class provides the base client for accessing the Kraken Futures API + using asynchronous requests. + + If you are facing timeout errors on derived clients, you can make use of the + ``TIMEOUT`` attribute to deviate from the default ``10`` seconds. + + If the sandbox environment is chosen, the keys must be generated from here: + https://demo-futures.kraken.com/settings/api + + :param key: Futures API public key (default: ``""``) + :type key: str, optional + :param secret: Futures API secret key (default: ``""``) + :type secret: str, optional + :param url: The URL to access the Futures Kraken API (default: + https://futures.kraken.com) + :type url: str, optional + :param sandbox: If set to ``True`` the URL will be + https://demo-futures.kraken.com (default: ``False``) + :type sandbox: bool, optional + """ + + def __init__( + self: FuturesAsyncClient, + key: str = "", + secret: str = "", + url: str = "", + *, + sandbox: bool = False, + use_custom_exceptions: bool = True, + ) -> None: + super().__init__( + key=key, + secret=secret, + url=url, + sandbox=sandbox, + use_custom_exceptions=use_custom_exceptions, + ) + self.__session = aiohttp.ClientSession(headers=self.HEADERS) + + async def request( # type: ignore[override] # pylint: disable=arguments-differ,invalid-overridden-method + self: FuturesAsyncClient, + method: str, + uri: str, + post_params: dict | None = None, + query_params: dict | None = None, + timeout: int = 10, + *, + auth: bool = True, + return_raw: bool = False, + ) -> dict | list | aiohttp.ClientResponse | Awaitable: + method, url, headers, encoded_payload, query_string = self._prepare_request( + method=method, + uri=uri, + post_params=post_params, + query_params=query_params, + auth=auth, + ) + timeout: int = self.TIMEOUT if timeout != 10 else timeout # type: ignore[no-redef] + + if method in {"GET", "DELETE"}: + return await self.__check_response_data( + response=await self.__session.request( # type: ignore[misc] + method=method, + url=url, + params=query_string, + headers=headers, + timeout=timeout, + ), + return_raw=return_raw, + ) + + if method == "PUT": + return await self.__check_response_data( + response=await self.__session.request( # type: ignore[misc] + method=method, + url=url, + params=encoded_payload, + headers=headers, + timeout=timeout, + ), + return_raw=return_raw, + ) + + return await self.__check_response_data( + response=await self.__session.request( # type: ignore[misc] + method=method, + url=url, + data=encoded_payload, + headers=headers, + timeout=timeout, + ), + return_raw=return_raw, + ) + + async def __check_response_data( # pylint: disable=invalid-overridden-method + self: FuturesAsyncClient, + response: aiohttp.ClientResponse, + *, + return_raw: bool = False, + ) -> dict | aiohttp.ClientResponse: + """ + Checks the response, handles the error (if exists) and returns the + response data. + + :param response: The response of a request, requested by the requests + module + :type response: requests.Response + :param return_raw: Defines if the return should be the raw response if + there is no error + :type return_raw: dict, optional + :raise kraken.exceptions.KrakenException.*: If the response contains the + error key + :return: The signed string + :rtype: dict | aiohttp.ClientResponse + """ + if not self._use_custom_exceptions: + return response + + if response.status in {"200", 200}: + if return_raw: + return response + try: + data: dict = await response.json() + except ValueError as exc: + raise ValueError(response.content) from exc + + if "error" in data: + return self._err_handler.check(data) + if "sendStatus" in data: + return self._err_handler.check_send_status(data) + if "batchStatus" in data: + return self._err_handler.check_batch_status(data) + return data + + raise Exception(f"{response.status} - {response.text}") + + async def async_close(self: FuturesAsyncClient) -> None: + """Closes the aiohttp session""" + await self.__session.close() # type: ignore[func-returns-value] + + async def __aenter__(self: Self) -> Self: + return self + + async def __aexit__(self: FuturesAsyncClient, *args: object) -> None: + return await self.async_close() + + +__all__ = [ + "defined", + "ensure_string", + "SpotClient", + "SpotAsyncClient", + "NFTClient", + "FuturesClient", + "FuturesAsyncClient", +] diff --git a/kraken/cli.py b/kraken/cli.py index 8bf6167d..5667b913 100644 --- a/kraken/cli.py +++ b/kraken/cli.py @@ -125,21 +125,23 @@ def cli(ctx: Context, **kwargs: dict) -> None: @pass_context def spot(ctx: Context, url: str, **kwargs: dict) -> None: # noqa: ARG001 """Access the Kraken Spot REST API""" - from kraken.base_api import KrakenSpotBaseAPI # noqa: PLC0415 + from kraken.base_api import SpotClient # noqa: PLC0415 logging.debug("Initialize the Kraken client") - client = KrakenSpotBaseAPI( + client = SpotClient( key=kwargs["api_key"], # type: ignore[arg-type] secret=kwargs["secret_key"], # type: ignore[arg-type] ) try: - response = client._request( # noqa: SLF001 # pylint: disable=protected-access,no-value-for-parameter - method=kwargs["x"], # type: ignore[arg-type] - uri=(uri := re_sub(r"https://.*.com", "", url)), - params=orloads(kwargs.get("data") or "{}"), - timeout=kwargs["timeout"], # type: ignore[arg-type] - auth="private" in uri.lower(), + response = ( + client.request( # pylint: disable=protected-access,no-value-for-parameter + method=kwargs["x"], # type: ignore[arg-type] + uri=(uri := re_sub(r"https://.*.com", "", url)), + params=orloads(kwargs.get("data") or "{}"), + timeout=kwargs["timeout"], # type: ignore[arg-type] + auth="private" in uri.lower(), + ) ) except JSONDecodeError as exc: logging.error(f"Could not parse the passed data. {exc}") # noqa: G004 @@ -199,22 +201,24 @@ def spot(ctx: Context, url: str, **kwargs: dict) -> None: # noqa: ARG001 @pass_context def futures(ctx: Context, url: str, **kwargs: dict) -> None: # noqa: ARG001 """Access the Kraken Futures REST API""" - from kraken.base_api import KrakenFuturesBaseAPI # noqa: PLC0415 + from kraken.base_api import FuturesClient # noqa: PLC0415 logging.debug("Initialize the Kraken client") - client = KrakenFuturesBaseAPI( + client = FuturesClient( key=kwargs["api_key"], # type: ignore[arg-type] secret=kwargs["secret_key"], # type: ignore[arg-type] ) try: - response = client._request( # noqa: SLF001 # pylint: disable=protected-access,no-value-for-parameter - method=kwargs["x"], # type: ignore[arg-type] - uri=(uri := re_sub(r"https://.*.com", "", url)), - post_params=orloads(kwargs.get("data") or "{}"), - query_params=orloads(kwargs.get("query") or "{}"), - timeout=kwargs["timeout"], # type: ignore[arg-type] - auth="derivatives" in uri.lower(), + response = ( + client.request( # pylint: disable=protected-access,no-value-for-parameter + method=kwargs["x"], # type: ignore[arg-type] + uri=(uri := re_sub(r"https://.*.com", "", url)), + post_params=orloads(kwargs.get("data") or "{}"), + query_params=orloads(kwargs.get("query") or "{}"), + timeout=kwargs["timeout"], # type: ignore[arg-type] + auth="derivatives" in uri.lower(), + ) ) except JSONDecodeError as exc: logging.error(f"Could not parse the passed data. {exc}") # noqa: G004 diff --git a/kraken/futures/__init__.py b/kraken/futures/__init__.py index 1a318b1c..62a585c7 100644 --- a/kraken/futures/__init__.py +++ b/kraken/futures/__init__.py @@ -5,10 +5,18 @@ """This module provides the Kraken Futures clients""" +from kraken.base_api import FuturesAsyncClient from kraken.futures.funding import Funding from kraken.futures.market import Market from kraken.futures.trade import Trade from kraken.futures.user import User -from kraken.futures.ws_client import KrakenFuturesWSClient +from kraken.futures.ws_client import FuturesWSClient -__all__ = ["Funding", "KrakenFuturesWSClient", "Market", "Trade", "User"] +__all__ = [ + "Funding", + "FuturesAsyncClient", + "FuturesWSClient", + "Market", + "Trade", + "User", +] diff --git a/kraken/futures/funding.py b/kraken/futures/funding.py index 329deef9..5713d544 100644 --- a/kraken/futures/funding.py +++ b/kraken/futures/funding.py @@ -8,12 +8,12 @@ from typing import TypeVar -from kraken.base_api import KrakenFuturesBaseAPI +from kraken.base_api import FuturesClient Self = TypeVar("Self") -class Funding(KrakenFuturesBaseAPI): +class Funding(FuturesClient): """ Class that implements the Kraken Futures Funding client @@ -99,7 +99,7 @@ def get_historical_funding_rates( ] } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v4/historicalfundingrates", query_params={"symbol": symbol}, @@ -151,7 +151,7 @@ def initiate_wallet_transfer( 'serverTime': '2023-04-07T15:23:45.196Z" } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/transfer", post_params={ @@ -209,7 +209,7 @@ def initiate_subaccount_transfer( ... unit='XBT' ... )) """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/transfer/subaccount", post_params={ @@ -270,7 +270,7 @@ def initiate_withdrawal_to_spot_wallet( if sourceWallet is not None: params["sourceWallet"] = sourceWallet - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/withdrawal", post_params=params, diff --git a/kraken/futures/market.py b/kraken/futures/market.py index 5383f5a2..fa863bc9 100644 --- a/kraken/futures/market.py +++ b/kraken/futures/market.py @@ -10,12 +10,12 @@ from functools import lru_cache from typing import TypeVar -from kraken.base_api import KrakenFuturesBaseAPI, defined, ensure_string +from kraken.base_api import FuturesClient, defined, ensure_string Self = TypeVar("Self") -class Market(KrakenFuturesBaseAPI): +class Market(FuturesClient): """ Class that implements the Kraken Futures market client @@ -129,7 +129,7 @@ def get_ohlc( params["from"] = from_ if defined(to): params["to"] = to - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri=f"/api/charts/v1/{tick_type}/{symbol}/{resolution}", query_params=params, @@ -164,7 +164,7 @@ def get_tick_types( >>> Market().get_tick_types() ['mark', 'spot', 'trade'] """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/api/charts/v1/", auth=False, @@ -201,7 +201,7 @@ def get_tradeable_products( >>> Market().get_tradeable_products(tick_type="trade") ["PI_XBTUSD", "PF_XBTUSD", "PF_SOLUSD", ...] """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri=f"/api/charts/v1/{tick_type}", auth=False, @@ -241,7 +241,7 @@ def get_resolutions( >>> Market().get_resolutions(tick_type="mark", tradeable="PI_XBTUSD") ['1h', '12h', '1w', '15m', '1d', '5m', '30m', '4h', '1m'] """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri=f"/api/charts/v1/{tick_type}/{tradeable}", auth=False, @@ -292,7 +292,7 @@ def get_fee_schedules( ] } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/feeschedules", auth=False, @@ -328,7 +328,7 @@ def get_fee_schedules_vol( } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/feeschedules/volumes", auth=True, @@ -386,7 +386,7 @@ def get_orderbook( if defined(symbol): params["symbol"] = symbol - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/orderbook", query_params=params, @@ -440,7 +440,7 @@ def get_tickers( }, ...] } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/tickers", auth=False, @@ -530,7 +530,7 @@ def get_instruments( } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/instruments", auth=False, @@ -570,13 +570,13 @@ def get_instruments_status( } """ if instrument: - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri=f"/derivatives/api/v3/instruments/{instrument}/status", auth=False, ) - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/instruments/status", auth=False, @@ -635,7 +635,7 @@ def get_trade_history( if defined(lastTime): params["lastTime"] = lastTime - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/history", query_params=params, @@ -683,7 +683,7 @@ def get_historical_funding_rates( ] } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v4/historicalfundingrates", query_params={"symbol": symbol}, @@ -721,7 +721,7 @@ def get_leverage_preference( ] } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/leveragepreferences", auth=True, @@ -763,7 +763,7 @@ def set_leverage_preference( if defined(maxLeverage): params["maxLeverage"] = maxLeverage - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="PUT", uri="/derivatives/api/v3/leveragepreferences", post_params=params, @@ -797,7 +797,7 @@ def get_pnl_preference( >>> market.get_pnl_preference() {'result': 'success', 'serverTime': '2023-04-04T15:21:29.413Z', 'preferences': []} """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/pnlpreferences", auth=True, @@ -837,7 +837,7 @@ def set_pnl_preference( >>> market.set_pnl_preference(symbol="PF_XBTUSD", pnlPreference="USD") {'result': 'success', 'serverTime': '2023-04-04T15:24:18.406Z'} """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="PUT", uri="/derivatives/api/v3/pnlpreferences", post_params={"symbol": symbol, "pnlPreference": pnlPreference}, @@ -891,7 +891,7 @@ def _get_historical_events( if defined(tradeable): params["tradeable"] = tradeable - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri=endpoint, post_params=params, diff --git a/kraken/futures/trade.py b/kraken/futures/trade.py index ad4fd631..8eaefa2d 100644 --- a/kraken/futures/trade.py +++ b/kraken/futures/trade.py @@ -9,12 +9,12 @@ from typing import TypeVar -from kraken.base_api import KrakenFuturesBaseAPI, defined +from kraken.base_api import FuturesClient, defined Self = TypeVar("Self") -class Trade(KrakenFuturesBaseAPI): +class Trade(FuturesClient): """ Class that implements the Kraken Futures trade client @@ -107,7 +107,7 @@ def get_fills( query_params: dict = {} if defined(lastFillTime): query_params["lastFillTime"] = lastFillTime - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/fills", query_params=query_params, @@ -229,7 +229,7 @@ def create_batch_order( if processBefore: params["processBefore"] = processBefore - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/batchorder", post_params=params, @@ -284,7 +284,7 @@ def cancel_all_orders( params: dict = {} if defined(symbol): params["symbol"] = symbol - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/cancelallorders", post_params=params, @@ -330,7 +330,7 @@ def dead_mans_switch( } } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/cancelallordersafter", post_params={"timeout": timeout}, @@ -391,7 +391,7 @@ def cancel_order( else: raise ValueError("Either order_id or cliOrdId must be set!") - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/cancelorder", post_params=params, @@ -470,7 +470,7 @@ def edit_order( if defined(processBefore): params["processBefore"] = processBefore - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/editorder", post_params=params, @@ -519,7 +519,7 @@ def get_orders_status( elif defined(cliOrdIds): params["cliOrdIds"] = cliOrdIds - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/orders/status", post_params=params, @@ -743,7 +743,7 @@ def create_order( # pylint: disable=too-many-arguments # noqa: PLR0913, PLR0917 if defined(processBefore): params["processBefore"] = processBefore - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/derivatives/api/v3/sendorder", post_params=params, @@ -781,7 +781,7 @@ def get_max_order_size( if defined(limitPrice) and orderType == "lmt": params["limitPrice"] = limitPrice - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/initialmargin/maxordersize", query_params=params, diff --git a/kraken/futures/user.py b/kraken/futures/user.py index b9544247..13d127db 100644 --- a/kraken/futures/user.py +++ b/kraken/futures/user.py @@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, TypeVar -from kraken.base_api import KrakenFuturesBaseAPI, defined +from kraken.base_api import FuturesClient, defined if TYPE_CHECKING: import requests @@ -17,7 +17,7 @@ Self = TypeVar("Self") -class User(KrakenFuturesBaseAPI): +class User(FuturesClient): """ Class that implements the Kraken Futures user client @@ -153,7 +153,7 @@ def get_wallets( 'serverTime': '2023-04-04T17:56:49.027Z' } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/accounts", auth=True, @@ -190,7 +190,7 @@ def get_subaccounts( 'subaccounts': [] } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/subaccounts", auth=True, @@ -229,7 +229,7 @@ def get_unwind_queue( ] } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/unwindqueue", auth=True, @@ -269,7 +269,7 @@ def get_notifications( 'serverTime': '2023-04-04T18:01:39.729Z' } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/notifications", auth=True, @@ -367,7 +367,7 @@ def get_account_log( # noqa: PLR0913 # pylint: disable=too-many-arguments if defined(to): params["to"] = to - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/api/history/v2/account-log", query_params=params, @@ -402,7 +402,7 @@ def get_account_log_csv( ... file.write(chunk) """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/api/history/v2/accountlogcsv", auth=True, @@ -456,7 +456,7 @@ def _get_historical_events( if defined(tradeable): params["tradeable"] = tradeable - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri=endpoint, query_params=params, @@ -806,7 +806,7 @@ def get_open_positions( 'serverTime': '2023-04-06T16:12:15.410Z' } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/openpositions", auth=True, @@ -896,7 +896,7 @@ def get_open_orders( 'serverTime': '2023-04-07T15:30:29.911Z' } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/derivatives/api/v3/openorders", auth=True, @@ -936,7 +936,7 @@ def check_trading_enabled_on_subaccount( "tradingEnabled": False } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri=f"/derivatives/api/v3/subaccount/{subaccountUid}/trading-enabled", auth=True, @@ -978,7 +978,7 @@ def set_trading_on_subaccount( "tradingEnabled": True } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="PUT", uri=f"/derivatives/api/v3/subaccount/{subaccountUid}/trading-enabled", post_params={"tradingEnabled": trading_enabled}, diff --git a/kraken/futures/websocket/__init__.py b/kraken/futures/websocket/__init__.py index f6bf994c..f9893b5a 100644 --- a/kraken/futures/websocket/__init__.py +++ b/kraken/futures/websocket/__init__.py @@ -2,6 +2,7 @@ # Copyright (C) 2023 Benjamin Thomas Schwertfeger # GitHub: https://github.com/btschwertfeger # +# pylint: disable=attribute-defined-outside-init """Module that implements the Kraken Futures websocket client""" @@ -22,17 +23,17 @@ if TYPE_CHECKING: from collections.abc import Callable - from kraken.futures import KrakenFuturesWSClient + from kraken.futures import FuturesWSClient -class ConnectFuturesWebsocket: +class ConnectFuturesWebsocket: # pylint: disable=too-many-instance-attributes """ This class is only called by the - :class:`kraken.futures.KrakenFuturesWSClient` to establish the websocket + :class:`kraken.futures.FuturesWSClient` to establish the websocket connection. :param client: The Futures websocket client that instantiates this class - :type client: :class:`kraken.futures.KrakenFuturesWSClient` + :type client: :class:`kraken.futures.FuturesWSClient` :param endpoint: The endpoint to access (either the live Kraken API or the sandbox environment) :type endpoint: str @@ -44,11 +45,11 @@ class ConnectFuturesWebsocket: def __init__( self: ConnectFuturesWebsocket, - client: KrakenFuturesWSClient, + client: FuturesWSClient, endpoint: str, callback: Callable, ) -> None: - self.__client: KrakenFuturesWSClient = client + self.__client: FuturesWSClient = client self.__ws_endpoint: str = endpoint self.__callback: Any = callback @@ -58,21 +59,34 @@ def __init__( self.__new_challenge: str | None = None self.__challenge_ready: bool = False - self.__socket: Any = None + self.socket: Any = None self.__subscriptions: list[dict] = [] - - self.task = asyncio.ensure_future( - self.__run_forever(), - loop=asyncio.get_running_loop(), - ) + self.keep_alive = True + self.exception_occur = False @property def subscriptions(self: ConnectFuturesWebsocket) -> list[dict]: """Returns the active subscriptions""" return self.__subscriptions + async def start(self: ConnectFuturesWebsocket) -> None: + """Starts the websocket connection""" + if ( + hasattr(self, "task") + and not self.task.done() # pylint: disable=access-member-before-definition + ): + return + self.task: asyncio.Task = asyncio.create_task( + self.__run_forever(), + ) + + async def stop(self: ConnectFuturesWebsocket) -> None: + """Stops the websocket connection""" + self.keep_alive = False + if hasattr(self, "task") and not self.task.done(): + await self.task + async def __run(self: ConnectFuturesWebsocket, event: asyncio.Event) -> None: - keep_alive: bool = True self.__new_challenge = None self.__last_challenge = None @@ -81,15 +95,15 @@ async def __run(self: ConnectFuturesWebsocket, event: asyncio.Event) -> None: ping_interval=30, ) as socket: logging.info("Websocket connected!") - self.__socket = socket + self.socket = socket if not event.is_set(): event.set() self.__reconnect_num = 0 - while keep_alive: + while self.keep_alive: try: - _message = await asyncio.wait_for(self.__socket.recv(), timeout=15) + _message = await asyncio.wait_for(self.socket.recv(), timeout=10) except TimeoutError: logging.debug( # important "Timeout error in %s", @@ -97,7 +111,7 @@ async def __run(self: ConnectFuturesWebsocket, event: asyncio.Event) -> None: ) except asyncio.CancelledError: logging.exception("asyncio.CancelledError") - keep_alive = False + self.keep_alive = False await self.__callback({"error": "asyncio.CancelledError"}) else: try: @@ -119,21 +133,23 @@ async def __run(self: ConnectFuturesWebsocket, event: asyncio.Event) -> None: await self.__callback(message) async def __run_forever(self: ConnectFuturesWebsocket) -> None: + self.keep_alive = True + self.exception_occur = False try: - while True: + while self.keep_alive: await self.__reconnect() except MaxReconnectError: await self.__callback( {"error": "kraken.exceptions.MaxReconnectError"}, ) + self.exception_occur = True except Exception: logging.exception(traceback.format_exc()) - finally: - self.__client.exception_occur = True + self.exception_occur = True async def close_connection(self: ConnectFuturesWebsocket) -> None: """Closes the connection -/ will force reconnect""" - await self.__socket.close() + await self.socket.close() async def __reconnect(self: ConnectFuturesWebsocket) -> None: logging.info("Websocket start connect/reconnect") @@ -159,12 +175,12 @@ async def __reconnect(self: ConnectFuturesWebsocket) -> None: asyncio.ensure_future(self.__run(event)): self.__run, } - while set(tasks.keys()): + while self.keep_alive: finished, pending = await asyncio.wait( tasks.keys(), return_when=asyncio.FIRST_EXCEPTION, ) - exception_occur: bool = False + exception_occur = False for task in finished: if task.exception(): exception_occur = True @@ -222,7 +238,7 @@ async def send_message( :type private: bool, optional :rtype: Coroutine """ - while not self.__socket: + while not self.socket: await asyncio.sleep(0.4) if private: @@ -237,7 +253,7 @@ async def send_message( message["original_challenge"] = self.__last_challenge message["signed_challenge"] = self.__new_challenge - await self.__socket.send(json.dumps(message)) + await self.socket.send(json.dumps(message)) def __handle_new_challenge(self: ConnectFuturesWebsocket, message: dict) -> None: self.__last_challenge = message["message"] @@ -245,7 +261,7 @@ def __handle_new_challenge(self: ConnectFuturesWebsocket, message: dict) -> None self.__challenge_ready = True async def __check_challenge_ready(self: ConnectFuturesWebsocket) -> None: - await self.__socket.send( + await self.socket.send( json.dumps({"event": "challenge", "api_key": self.__client.key}), ) diff --git a/kraken/futures/ws_client.py b/kraken/futures/ws_client.py index 58fe6a30..7eab7905 100644 --- a/kraken/futures/ws_client.py +++ b/kraken/futures/ws_client.py @@ -11,23 +11,25 @@ import hashlib import hmac import logging +from asyncio import sleep as async_sleep from copy import deepcopy -from typing import TYPE_CHECKING, Any, TypeVar +from typing import TYPE_CHECKING, TypeVar -from kraken.base_api import KrakenFuturesBaseAPI +from kraken.base_api import FuturesAsyncClient from kraken.exceptions import KrakenAuthenticationError from kraken.futures.websocket import ConnectFuturesWebsocket if TYPE_CHECKING: from collections.abc import Callable + from typing import Any Self = TypeVar("Self") -class KrakenFuturesWSClient(KrakenFuturesBaseAPI): +class FuturesWSClient(FuturesAsyncClient): """ - Class to access public and (optional) - private/authenticated websocket connection. + Class to access public and (optional) private/authenticated websocket + connection. So far there are no trade endpoints that can be accessed using the Futures Kraken API. If this has changed and is not implemented yet, please open an @@ -50,21 +52,24 @@ class KrakenFuturesWSClient(KrakenFuturesBaseAPI): :caption: Futures Websocket: Create the websocket client import asyncio - from kraken.futures import KrakenFuturesWSClient + from kraken.futures import FuturesWSClient - async def main() -> None: - - # Create the custom client - class Client(KrakenFuturesWSClient): - async def on_message(self, event: dict) -> None: - print(event) + # Create the custom client + class Client(FuturesWSClient): + async def on_message(self, event: dict) -> None: + print(event) + async def main() -> None: client = Client() # unauthenticated auth_client = Client( # authenticated key="api-key", secret="secret-key" ) + # open the websocket connections + await client.start() + await auth_client.start() + # now you can subscribe to channels using await client.subscribe( feed='ticker', @@ -86,34 +91,30 @@ async def on_message(self, event: dict) -> None: :caption: Futures Websocket: Create the websocket client as context manager import asyncio - from kraken.futures import KrakenFuturesWSClient + from kraken.futures import FuturesWSClient - async def on_messageessage): + async def on_message(message): print(message) async def main() -> None: - async with KrakenFuturesWSClient(callback=on_message) as session: + async with FuturesWSClient(callback=on_message) as session: await session.subscribe(feed="ticker", products=["PF_XBTUSD"]) while True: await asyncio.sleep(6) if __name__ == "__main__": - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) try: asyncio.run(main()) except KeyboardInterrupt: pass - finally: - loop.close() """ PROD_ENV_URL: str = "futures.kraken.com/ws/v1" DEMO_ENV_URL: str = "demo-futures.kraken.com/ws/v1" def __init__( - self: KrakenFuturesWSClient, + self: FuturesWSClient, key: str = "", secret: str = "", url: str = "", @@ -123,25 +124,44 @@ def __init__( ) -> None: super().__init__(key=key, secret=secret, url=url, sandbox=sandbox) - self.__key: str = key - self.__secret: str = secret + self._key: str = key - self.exception_occur: bool = False self.__callback: Any = callback self._conn: ConnectFuturesWebsocket = ConnectFuturesWebsocket( client=self, - endpoint=( - url if url else self.DEMO_ENV_URL if sandbox else self.PROD_ENV_URL - ), + endpoint=(url or (self.DEMO_ENV_URL if sandbox else self.PROD_ENV_URL)), callback=self.on_message, ) @property - def key(self: KrakenFuturesBaseAPI) -> str: + def exception_occur(self: FuturesWSClient) -> bool: + """Returns True if the connection was stopped due to an exception.""" + return self._conn.exception_occur + + async def start(self: FuturesWSClient) -> None: + """Method to start the websocket connection.""" + await self._conn.start() + + # Wait for the connection(s) to be established ... + while (timeout := 0.0) < 10: + if self._conn.socket is not None: + break + await async_sleep(0.2) + timeout += 0.2 + else: + raise TimeoutError("Could not connect to the Kraken API!") + + async def stop(self: FuturesWSClient) -> None: + """Method to stop the websocket connection.""" + if self._conn: + await self._conn.stop() + + @property + def key(self: FuturesWSClient) -> str: """Returns the API key""" - return self.__key + return self._key - def get_sign_challenge(self: KrakenFuturesWSClient, challenge: str) -> str: + def get_sign_challenge(self: FuturesWSClient, challenge: str) -> str: """ Sign the challenge/message using the secret key @@ -159,20 +179,20 @@ def get_sign_challenge(self: KrakenFuturesWSClient, challenge: str) -> str: sha256_hash.update(challenge.encode("utf-8")) return base64.b64encode( hmac.new( - base64.b64decode(self.__secret), + base64.b64decode(self._secret), sha256_hash.digest(), hashlib.sha512, ).digest(), ).decode("utf-8") - async def on_message(self: KrakenFuturesWSClient, message: dict) -> None: + async def on_message(self: FuturesWSClient, message: dict) -> None: """ Method that serves as the default callback function Calls the defined callback function (if defined) or overload this function. This is the default method which just logs the messages. In production you want to overload this with your custom methods, as shown in the - Example of :class:`kraken.futures.KrakenFuturesWSClient`. + Example of :class:`kraken.futures.FuturesWSClient`. :param message: The message that was send by Kraken via the websocket connection. @@ -186,7 +206,7 @@ async def on_message(self: KrakenFuturesWSClient, message: dict) -> None: logging.info(message) async def subscribe( - self: KrakenFuturesWSClient, + self: FuturesWSClient, feed: str, products: list[str] | None = None, ) -> None: @@ -204,7 +224,7 @@ async def subscribe( the Kraken API Initialize your client as described in - :class:`kraken.futures.KrakenFuturesWSClient` to run the following + :class:`kraken.futures.FuturesWSClient` to run the following example: .. code-block:: python @@ -215,7 +235,7 @@ async def subscribe( Success or failures are sent over the websocket connection and can be received via the default - :func:`kraken.futures.KrakenFuturesWSClient.on_message` or a custom + :func:`kraken.futures.FuturesWSClient.on_message` or a custom callback function. """ @@ -245,7 +265,7 @@ async def subscribe( raise ValueError(f"Feed: {feed} not found. Not subscribing to it.") async def unsubscribe( - self: KrakenFuturesWSClient, + self: FuturesWSClient, feed: str, products: list[str] | None = None, ) -> None: @@ -263,7 +283,7 @@ async def unsubscribe( by the Kraken API Initialize your client as described in - :class:`kraken.futures.KrakenFuturesWSClient` to run the following + :class:`kraken.futures.FuturesWSClient` to run the following example: .. code-block:: python @@ -274,7 +294,7 @@ async def unsubscribe( Success or failures are sent over the websocket connection and can be received via the default - :func:`kraken.futures.KrakenFuturesWSClient.on_message`` or a custom + :func:`kraken.futures.FuturesWSClient.on_message`` or a custom callback function. """ @@ -316,8 +336,8 @@ def get_available_public_subscription_feeds() -> list[str]: :linenos: :caption: Futures Websocket: Get the available public subscription feeds - >>> from kraken.futures import KrakenFuturesWSClient - >>> KrakenFuturesWSClient.get_available_private_subscription_feeds() + >>> from kraken.futures import FuturesWSClient + >>> FuturesWSClient.get_available_private_subscription_feeds() [ "trade", "book", "ticker", "ticker_lite", "heartbeat" @@ -338,8 +358,8 @@ def get_available_private_subscription_feeds() -> list[str]: :linenos: :caption: Futures Websocket: Get the available private subscription feeds - >>> from kraken.futures import KrakenFuturesWSClient - >>> KrakenFuturesWSClient.get_available_private_subscription_feeds() + >>> from kraken.futures import FuturesWSClient + >>> FuturesWSClient.get_available_private_subscription_feeds() [ "fills", "open_positions", "open_orders", "open_orders_verbose", "balances", @@ -360,7 +380,7 @@ def get_available_private_subscription_feeds() -> list[str]: ] @property - def is_auth(self: KrakenFuturesWSClient) -> bool: + def is_auth(self: FuturesWSClient) -> bool: """ Checks if key and secret are set. @@ -371,13 +391,13 @@ def is_auth(self: KrakenFuturesWSClient) -> bool: :linenos: :caption: Futures Websocket: Check if the credentials are set - >>> from kraken.futures import KrakenFuturesWSClient - >>> KrakenFuturesWSClient().is_auth() + >>> from kraken.futures import FuturesWSClient + >>> FuturesWSClient().is_auth() False """ - return bool(self.__key and self.__secret) + return bool(self._key and self._secret) - def get_active_subscriptions(self: KrakenFuturesWSClient) -> list[dict]: + def get_active_subscriptions(self: FuturesWSClient) -> list[dict]: """ Returns the list of active subscriptions. @@ -385,16 +405,16 @@ def get_active_subscriptions(self: KrakenFuturesWSClient) -> list[dict]: and additional information. :rtype: list[dict] - Initialize your client as described in :class:`kraken.futures.KrakenFuturesWSClient` to + Initialize your client as described in :class:`kraken.futures.FuturesWSClient` to run the following example: .. code-block:: python :linenos: :caption: Futures Websocket: Get the active subscriptions - >>> from kraken.futures import KrakenFuturesWSClient + >>> from kraken.futures import FuturesWSClient ... - >>> KrakenFuturesWSClient.get_active_subscriptions() + >>> FuturesWSClient.get_active_subscriptions() [ { "event": "subscribe", @@ -409,14 +429,19 @@ def get_active_subscriptions(self: KrakenFuturesWSClient) -> list[dict]: return self._conn.get_active_subscriptions() async def __aenter__(self: Self) -> Self: + """Entrypoint for use as context manager""" + await super().__aenter__() + await self.start() # type: ignore[attr-defined] return self async def __aexit__( - self: KrakenFuturesWSClient, + self: FuturesWSClient, *exc: object, **kwargs: dict[str, Any], ) -> None: - pass + """Exit if used as context manager""" + await super().__aexit__() + await self.stop() -__all__ = ["KrakenFuturesWSClient"] +__all__ = ["FuturesWSClient"] diff --git a/kraken/nft/market.py b/kraken/nft/market.py index b4bff443..4d03e61b 100644 --- a/kraken/nft/market.py +++ b/kraken/nft/market.py @@ -8,12 +8,12 @@ from typing import TypeVar -from kraken.base_api import KrakenNFTBaseAPI, defined +from kraken.base_api import NFTClient, defined Self = TypeVar("Self") -class Market(KrakenNFTBaseAPI): +class Market(NFTClient): """ Class that implements the Kraken NFT Market client. Can be used to access the Kraken NFT market data. @@ -105,7 +105,7 @@ def get_nft( params: dict = {"nft_id": nft_id} if defined(currency): params["currency"] = currency - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/Nft", params=params, @@ -153,7 +153,7 @@ def list_nfts( if defined(sort): params["sort"] = sort - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/Nfts", params=params, @@ -203,7 +203,7 @@ def get_nft_provenance( } if defined(currency): params["currency"] = currency - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftProvenance", params=params, @@ -242,7 +242,7 @@ def get_collection( if defined(currency): params["currency"] = currency - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftCollection", params=params, @@ -297,7 +297,7 @@ def list_collections( if defined(sort): params["sort"] = sort - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftCollections", params=params, @@ -328,7 +328,7 @@ def get_creator( >>> market = Market() >>> market.get_creator(creator_id="NA7NELE-FOQFZ-ODWOTV") """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftCreator", params={"creator_id": creator_id}, @@ -383,7 +383,7 @@ def list_creators( if defined(sort): params["sort"] = sort - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftCreators", params=params, @@ -410,7 +410,7 @@ def list_blockchains( >>> market = Market() >>> market.list_blockchains() """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftBlockchains", auth=False, @@ -448,7 +448,7 @@ def get_auctions( params: dict = {} if defined(status): params["status"] = status - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftAuctions", params=params, @@ -479,7 +479,7 @@ def get_offers( >>> market = Market() >>> market.get_offers(nft_id="NT4GUCU-SIJE2-YSQQG2") """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftOffers", params={"nft_id": nft_id}, @@ -519,7 +519,7 @@ def get_nft_quotes( if defined(count): params["count"] = count - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/NftQuotes", query_str=filter_, diff --git a/kraken/nft/trade.py b/kraken/nft/trade.py index 0ac608a1..792e5912 100644 --- a/kraken/nft/trade.py +++ b/kraken/nft/trade.py @@ -8,12 +8,12 @@ from typing import TypeVar -from kraken.base_api import KrakenNFTBaseAPI, defined +from kraken.base_api import NFTClient, defined Self = TypeVar("Self") -class Trade(KrakenNFTBaseAPI): +class Trade(NFTClient): """ Class that implements the Kraken NFT Trade client. Can be used to access the Kraken NFT market data. @@ -115,7 +115,7 @@ def create_auction( # noqa: PLR0913 # pylint: disable=too-many-arguments if defined(start_time): params["start_time"] = start_time - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftCreateAuction", params=params, @@ -167,7 +167,7 @@ def modify_auction( if defined(reserve_price): params["reserve_price"] = reserve_price - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftModifyAuction", params=params, @@ -204,7 +204,7 @@ def cancel_auction( if defined(otp): params["otp"] = otp - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftCancelAuction", params=params, @@ -266,7 +266,7 @@ def place_offer( if defined(otp): params["otp"] = otp - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftPlaceOffer", params=params, @@ -323,7 +323,7 @@ def counter_offer( if defined(otp): params["otp"] = otp - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftCounterOffer", params=params, @@ -360,7 +360,7 @@ def accept_offer( if defined(otp): params["otp"] = otp - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftAcceptOffer", params=params, @@ -414,7 +414,7 @@ def get_auction_trades( if defined(otp): params["otp"] = otp - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftAuctionTrades", params=params, @@ -510,7 +510,7 @@ def get_user_offers( # noqa: PLR0913,PLR0917 # pylint: disable=too-many-argumen if defined(otp): params["otp"] = otp - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftUserOffers", params=params, @@ -599,7 +599,7 @@ def get_nft_wallet( # noqa: PLR0913,PLR0917 # pylint: disable=too-many-argument if defined(otp): params[otp] = otp - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftWallet", params=params, @@ -668,7 +668,7 @@ def list_nft_transactions( # noqa: PLR0913 # pylint: disable=too-many-arguments if defined(type_): params[type_] = type_ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/NftTransactions", params=params, diff --git a/kraken/spot/__init__.py b/kraken/spot/__init__.py index 7a172933..ea94f2db 100644 --- a/kraken/spot/__init__.py +++ b/kraken/spot/__init__.py @@ -5,26 +5,23 @@ """Module that provides the Spot REST clients.""" +from kraken.base_api import SpotAsyncClient, SpotClient from kraken.spot.earn import Earn from kraken.spot.funding import Funding from kraken.spot.market import Market -from kraken.spot.orderbook_v1 import OrderbookClientV1 -from kraken.spot.orderbook_v2 import OrderbookClientV2 -from kraken.spot.staking import Staking +from kraken.spot.orderbook import SpotOrderBookClient from kraken.spot.trade import Trade from kraken.spot.user import User -from kraken.spot.websocket_v1 import KrakenSpotWSClientV1 -from kraken.spot.websocket_v2 import KrakenSpotWSClientV2 +from kraken.spot.ws_client import SpotWSClient __all__ = [ "Earn", "Funding", - "KrakenSpotWSClientV1", - "KrakenSpotWSClientV2", + "SpotWSClient", "Market", - "OrderbookClientV1", - "OrderbookClientV2", - "Staking", + "SpotOrderBookClient", + "SpotClient", + "SpotAsyncClient", "Trade", "User", ] diff --git a/kraken/spot/earn.py b/kraken/spot/earn.py index 9b318f07..53b4fb19 100644 --- a/kraken/spot/earn.py +++ b/kraken/spot/earn.py @@ -9,17 +9,16 @@ from typing import TypeVar -from kraken.base_api import KrakenSpotBaseAPI, defined +from kraken.base_api import SpotClient, defined Self = TypeVar("Self") -class Earn(KrakenSpotBaseAPI): +class Earn(SpotClient): """ Class that implements the Kraken Spot Earn client. Currently there are no - earn endpoints that could be accesses without authentication. The earn - endpoints replace the past staking endpoints. + earn endpoints that could be accesses without authentication. - https://docs.kraken.com/rest/#tag/Earn @@ -94,7 +93,7 @@ def allocate_earn_funds( """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Earn/Allocate", params={"amount": amount, "strategy_id": strategy_id}, @@ -136,7 +135,7 @@ def deallocate_earn_funds( """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Earn/Deallocate", params={"amount": amount, "strategy_id": strategy_id}, @@ -173,7 +172,7 @@ def get_allocation_status( {'pending': False} """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Earn/AllocateStatus", params={"strategy_id": strategy_id}, @@ -210,7 +209,7 @@ def get_deallocation_status( {'pending': False} """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Earn/DeallocateStatus", params={"strategy_id": strategy_id}, @@ -313,7 +312,7 @@ def list_earn_strategies( if defined(cursor): params["cursor"] = cursor - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Earn/Strategies", params=params, @@ -376,7 +375,7 @@ def list_earn_allocations( if defined(converted_asset): params["converted_asset"] = converted_asset - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Earn/Allocations", params=params, diff --git a/kraken/spot/funding.py b/kraken/spot/funding.py index f7be60ae..dbbdb71b 100644 --- a/kraken/spot/funding.py +++ b/kraken/spot/funding.py @@ -9,12 +9,12 @@ from typing import TypeVar -from kraken.base_api import KrakenSpotBaseAPI, defined +from kraken.base_api import SpotClient, defined Self = TypeVar("Self") -class Funding(KrakenSpotBaseAPI): +class Funding(SpotClient): """ Class that implements the Spot Funding client. Currently there are no funding endpoints that could be accesses without authentication. @@ -93,7 +93,7 @@ def get_deposit_methods( } ] """ - return self._request( + return self.request( method="POST", uri="/0/private/DepositMethods", params={"asset": asset}, # type: ignore[return-value] @@ -146,7 +146,7 @@ def get_deposit_address( }, ... ] """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/DepositAddresses", params={"asset": asset, "method": method, "new": new}, @@ -239,7 +239,7 @@ def get_recent_deposits_status( if defined(end): params["end"] = end - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/DepositStatus", params=params, @@ -292,7 +292,7 @@ def get_withdrawal_info( 'fee': '0.05000000' } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/WithdrawInfo", params={"asset": asset, "key": str(key), "amount": str(amount)}, @@ -345,7 +345,7 @@ def withdraw_funds( if defined(max_fee): params["max_fee"] = max_fee - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Withdraw", params=params, @@ -415,7 +415,7 @@ def get_recent_withdraw_status( params["end"] = end if defined(cursor): params["cursor"] = cursor - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/WithdrawStatus", params=params, @@ -453,7 +453,7 @@ def cancel_withdraw( >>> funding.cancel_withdraw(asset="DOT", refid="I7KGS6-UFMTTQ-AGBSO6T") { 'result': True } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/WithdrawCancel", params={"asset": asset, "refid": str(refid)}, @@ -501,7 +501,7 @@ def wallet_transfer( ... ) { 'refid': "ANS1EE5-SKACR4-PENGVP" } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/WalletTransfer", params={"asset": asset, "from": from_, "to": to_, "amount": str(amount)}, @@ -538,7 +538,7 @@ def withdraw_methods( params["network"] = aclass if defined(network): params["network"] = network - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/WithdrawMethods", params=params, @@ -585,7 +585,7 @@ def withdraw_addresses( params["key"] = key if defined(verified): params["verified"] = verified - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/WithdrawMethods", params=params, diff --git a/kraken/spot/market.py b/kraken/spot/market.py index ca0ae172..266dd56f 100644 --- a/kraken/spot/market.py +++ b/kraken/spot/market.py @@ -10,12 +10,12 @@ from functools import lru_cache from typing import TypeVar -from kraken.base_api import KrakenSpotBaseAPI, defined, ensure_string +from kraken.base_api import SpotClient, defined, ensure_string Self = TypeVar("Self") -class Market(KrakenSpotBaseAPI): +class Market(SpotClient): """ Class that implements the Kraken Spot Market client. Can be used to access the Kraken Spot market data. @@ -125,7 +125,7 @@ def get_assets( params["asset"] = assets if defined(aclass): params["aclass"] = aclass - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/Assets", params=params, @@ -209,7 +209,7 @@ def get_asset_pairs( params["pair"] = pair if defined(info): params["info"] = info - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/AssetPairs", params=params, @@ -259,7 +259,7 @@ def get_ticker( params: dict = {} if defined(pair): params["pair"] = pair - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/Ticker", params=params, @@ -314,7 +314,7 @@ def get_ohlc( params: dict = {"pair": pair, "interval": interval} if defined(since): params["since"] = since - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/OHLC", params=params, @@ -362,7 +362,7 @@ def get_order_book( } } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/Depth", params={"pair": pair, "count": count}, @@ -413,7 +413,7 @@ def get_recent_trades( params["since"] = since if defined(count): params["count"] = count - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/Trades", params=params, @@ -458,7 +458,7 @@ def get_recent_spreads( params: dict = {"pair": pair} if defined(since): params["since"] = since - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/Spread", params=params, @@ -487,7 +487,7 @@ def get_system_status( >>> Market().get_system_status() {'status': 'online', 'timestamp': '2023-04-05T17:12:31Z'} """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="GET", uri="/0/public/SystemStatus", auth=False, diff --git a/kraken/spot/orderbook_v2.py b/kraken/spot/orderbook.py similarity index 88% rename from kraken/spot/orderbook_v2.py rename to kraken/spot/orderbook.py index 8312e8cc..cb84ca88 100644 --- a/kraken/spot/orderbook_v2.py +++ b/kraken/spot/orderbook.py @@ -19,13 +19,13 @@ from typing import TYPE_CHECKING from kraken.spot import Market -from kraken.spot.websocket_v2 import KrakenSpotWSClientV2 +from kraken.spot.ws_client import SpotWSClient if TYPE_CHECKING: from collections.abc import Callable -class OrderbookClientV2: +class SpotOrderBookClient(SpotWSClient): """ **This client is using the Kraken Websocket API v2** @@ -54,10 +54,10 @@ class OrderbookClientV2: :caption: Example: Create and maintain a Spot orderbook as custom class from typing import Any - from kraken.spot import OrderbookClientV2 + from kraken.spot import SpotOrderBookClient import asyncio - class OrderBook(OrderbookClientV2): + class OrderBook(SpotOrderBookClient): async def on_book_update(self: "OrderBook", pair: str, message: list) -> None: '''This function must be overloaded to get the recent updates.''' @@ -73,7 +73,10 @@ async def on_book_update(self: "OrderBook", pair: str, message: ) async def main() -> None: - orderbook: OrderBook = OrderBook(depth=10) await orderbook.add_book( + orderbook: OrderBook = OrderBook(depth=10) + await orderbook.start() + + await orderbook.add_book( pairs=["XBT/USD"] # we can also subscribe to more currency pairs ) @@ -93,7 +96,7 @@ async def main() -> None: :caption: Example: Create and maintain a Spot orderbook using a callback from typing import Any - from kraken.spot import OrderbookClientV2 + from kraken.spot import SpotOrderBookClient import asyncio async def my_callback(self: "OrderBook", pair: str, message: dict) -> None: @@ -102,6 +105,8 @@ async def my_callback(self: "OrderBook", pair: str, message: dict) -> None: async def main() -> None: orderbook: OrderBook = OrderBook(depth=100, callback=my_callback) + await orderbook.start() + await orderbook.add_book( pairs=["XBT/USD"] # we can also subscribe to more currency pairs @@ -120,7 +125,7 @@ async def main() -> None: LOG: logging.Logger = logging.getLogger(__name__) def __init__( - self: OrderbookClientV2, + self: SpotOrderBookClient, depth: int = 10, callback: Callable | None = None, ) -> None: @@ -130,11 +135,8 @@ def __init__( self.__callback: Callable | None = callback self.__market: Market = Market() - self.ws_client: KrakenSpotWSClientV2 = KrakenSpotWSClientV2( - callback=self.on_message, - ) - async def on_message(self: OrderbookClientV2, message: list | dict) -> None: + async def on_message(self: SpotOrderBookClient, message: list | dict) -> None: """ *This function must not be overloaded - it would break this client!* @@ -223,7 +225,11 @@ async def on_message(self: OrderbookClientV2, message: list | dict) -> None: await asyncio_sleep(3) await self.add_book(pairs=[pair]) - async def on_book_update(self: OrderbookClientV2, pair: str, message: dict) -> None: + async def on_book_update( + self: SpotOrderBookClient, + pair: str, + message: dict, + ) -> None: """ This function will be called every time the orderbook gets updated. It needs to be overloaded if no callback function was defined during the @@ -243,7 +249,7 @@ async def on_book_update(self: OrderbookClientV2, pair: str, message: dict) -> N else: print(message) # noqa: T201 - async def add_book(self: OrderbookClientV2, pairs: list[str]) -> None: + async def add_book(self: SpotOrderBookClient, pairs: list[str]) -> None: """ Add an orderbook to this client. The feed will be subscribed and updates will be published to the :func:`on_book_update` function. @@ -253,11 +259,11 @@ async def add_book(self: OrderbookClientV2, pairs: list[str]) -> None: :param depth: The book depth :type depth: int """ - await self.ws_client.subscribe( + await self.subscribe( params={"channel": "book", "depth": self.__depth, "symbol": pairs}, ) - async def remove_book(self: OrderbookClientV2, pairs: list[str]) -> None: + async def remove_book(self: SpotOrderBookClient, pairs: list[str]) -> None: """ Unsubscribe from a subscribed orderbook. @@ -266,32 +272,18 @@ async def remove_book(self: OrderbookClientV2, pairs: list[str]) -> None: :param depth: The book depth :type depth: int """ - await self.ws_client.unsubscribe( + await self.unsubscribe( params={"channel": "book", "depth": self.__depth, "symbol": pairs}, ) @property - def depth(self: OrderbookClientV2) -> int: + def depth(self: SpotOrderBookClient) -> int: """ Return the fixed depth of this orderbook client. """ return self.__depth - @property - def exception_occur(self: OrderbookClientV2) -> bool: - """ - Can be used to determine if any critical error occurred within the - websocket connection. If so, the function will return ``True`` and the - client instance is most likely not usable anymore. So this is the - switch lets the user know, when to delete the current one and create a - new one. - - :return: ``True`` if any critical error occurred else ``False`` - :rtype: bool - """ - return bool(self.ws_client.exception_occur) - - def get(self: OrderbookClientV2, pair: str) -> dict | None: + def get(self: SpotOrderBookClient, pair: str) -> dict | None: """ Returns the orderbook for a specific ``pair``. @@ -305,7 +297,7 @@ def get(self: OrderbookClientV2, pair: str) -> dict | None: :caption: Orderbook: Get ask and bid â€Ļ - class Orderbook(OrderbookClientV2): + class Orderbook(SpotOrderBookClient): async def on_book_update( self: "Orderbook", @@ -321,7 +313,7 @@ async def on_book_update( return self.__book.get(pair) def __update_book( - self: OrderbookClientV2, + self: SpotOrderBookClient, orders: list[dict], side: str, symbol: str, @@ -367,7 +359,11 @@ def __update_book( )[: self.__depth], ) - def __validate_checksum(self: OrderbookClientV2, pair: str, checksum: int) -> None: + def __validate_checksum( + self: SpotOrderBookClient, + pair: str, + checksum: int, + ) -> None: """ Function that validates the checksum of the order book as described here https://docs.kraken.com/websockets-v2/#calculate-book-checksum. @@ -411,4 +407,4 @@ def get_first(values: tuple) -> float: return float(values[0]) -__all__ = ["OrderbookClientV2"] +__all__ = ["SpotOrderBookClient"] diff --git a/kraken/spot/orderbook_v1.py b/kraken/spot/orderbook_v1.py deleted file mode 100644 index ac22a8f4..00000000 --- a/kraken/spot/orderbook_v1.py +++ /dev/null @@ -1,400 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# - -"""Module that implements the Kraken Spot Orderbook client""" - -from __future__ import annotations - -import logging -from asyncio import sleep as asyncio_sleep -from binascii import crc32 -from collections import OrderedDict -from inspect import iscoroutinefunction -from typing import TYPE_CHECKING - -from kraken.spot.websocket_v1 import KrakenSpotWSClientV1 - -if TYPE_CHECKING: - from collections.abc import Callable - - -class OrderbookClientV1: - """ - **This client is using the Kraken Websocket API v1** - - Please use :class:`kraken.spot.OrderbookClientV2` to access the Kraken - Websocket API v2. - - The orderbook client can be used for instantiation and maintaining one or - multiple orderbooks for Spot trading on the Kraken cryptocurrency exchange. - It connects to the websocket feed(s) and receives the book updates, - calculates the checksum and will publish the changes to the - :func:`on_book_update` function or to the specified callback - function. - - The :func:`get` function can be used to access a specific - book of this client. - - The client will resubscribe to the book feed(s) if any errors occur and - publish the changes to the mentioned function(s). - - This class has a fixed book depth. Available depths are: {10, 25, 50, 100} - - - https://support.kraken.com/hc/en-us/articles/360027821131-WebSocket-API-v1-How-to-maintain-a-valid-order-book - - - https://docs.kraken.com/websockets/#book-checksum - - .. code-block:: python - :linenos: - :caption: Example: Create and maintain a Spot orderbook as custom class - - from typing import Any - from kraken.spot import OrderbookClientV1 - import asyncio - - class OrderBook(OrderbookClientV1): - async def on_book_update(self: "OrderBook", pair: str, message: list) -> None: - '''This function must be overloaded to get the recent - updates.''' book: Dict[str, Any] = self.get(pair=pair) bid: - list[tuple[str, str]] = list(book["bid"].items()) ask: - list[tuple[str, str]] = list(book["ask"].items()) - - print("Bid Volume\t\t Ask Volume") for level in - range(self.depth): - print( - f"{bid[level][0]} ({bid[level][1]}) \t {ask[level][0]} - ({ask[level][1]})" - ) - - async def main() -> None: - orderbook: OrderBook = OrderBook(depth=10) await orderbook.add_book( - pairs=["XBT/USD"] # we can also subscribe to more currency - pairs - ) - - while not orderbook.exception_occur: - await asyncio.sleep(10) - - if __name__ == "__main__": - try: - asyncio.run(main()) - except KeyboardInterrupt: - pass - - - .. code-block:: python - :linenos: - :caption: Example: Create and maintain a Spot orderbook using a callback - - from typing import Any - from kraken.spot import OrderbookClientV1 - import asyncio - - # â€Ļ use the Orderbook class defined in the example before - async def my_callback(self: "OrderBook", pair: str, message: list) -> None: - '''This function do not need to be async.''' print(message) - - async def main() -> None: - orderbook: OrderBook = OrderBook(depth=100, callback=my_callback) - await orderbook.add_book( - pairs=["XBT/USD"] # we can also subscribe to more currency - pairs - ) - - while not orderbook.exception_occur: - await asyncio.sleep(10) - - if __name__ == "__main__": - try: - asyncio.run(main()) - except KeyboardInterrupt: - pass - """ - - LOG: logging.Logger = logging.getLogger(__name__) - - def __init__( - self: OrderbookClientV1, - depth: int = 10, - callback: Callable | None = None, - ) -> None: - super().__init__() - self.__book: dict[str, dict] = {} - self.__depth: int = depth - self.__callback: Callable | None = callback - - self.ws_client: KrakenSpotWSClientV1 = KrakenSpotWSClientV1( - callback=self.on_message, - ) - - async def on_message(self: OrderbookClientV1, message: list | dict) -> None: - """ - *This function should not be overloaded - this would break this client!* - - It receives and processes the book related websocket messages and is - only publicly visible for those who understand and are willing to mock - it. - """ - if "errorMessage" in message: - self.LOG.warning(message) - - if ( - isinstance(message, dict) - and message.get("event", "") == "subscriptionStatus" - and message.get("status", "") in {"subscribed", "unsubscribed"} - and message.get("pair", "") in self.__book - ): - del self.__book[message["pair"]] - return - - if not isinstance(message, list): - # The orderbook feed only sends messages of type list, - # so we can ignore anything else. - return - - pair: str = message[-1] - if pair not in self.__book: - self.__book[pair] = { - "bid": {}, - "ask": {}, - "valid": True, - } - - if "as" in message[1]: - # Will be triggered initially when the first message comes in that - # provides the initial snapshot of the current orderbook. - self.__update_book(pair=pair, side="ask", snapshot=message[1]["as"]) - self.__update_book(pair=pair, side="bid", snapshot=message[1]["bs"]) - else: - checksum: str | None = None - # Executed every time a new update comes in. - for data in message[1 : len(message) - 2]: - if "a" in data: - self.__update_book(pair=pair, side="ask", snapshot=data["a"]) - elif "b" in data: - self.__update_book(pair=pair, side="bid", snapshot=data["b"]) - if "c" in data: - checksum = data["c"] - - self.__validate_checksum(pair=pair, checksum=checksum) - - if not self.__book[pair]["valid"]: - await self.on_book_update( - pair=pair, - message=[ - { - "error": f"Checksum mismatch - resubscribe to the orderbook {pair}", - }, - ], - ) - # If the orderbook's checksum is invalid, we need re-add the - # orderbook. - await self.remove_book(pairs=[pair]) - - await asyncio_sleep(3) - await self.add_book(pairs=[pair]) - - else: - await self.on_book_update(pair=pair, message=message) - - async def on_book_update(self: OrderbookClientV1, pair: str, message: list) -> None: - """ - This function will be called every time the orderbook gets updated. It - needs to be overloaded if no callback function was defined during the - instantiation of this class. - - :param pair: The currency pair of the orderbook that has been updated. - :type pair: str - :param message: The message sent by Kraken causing the orderbook to - update. - :type message: str - """ - - if self.__callback: - if iscoroutinefunction(self.__callback): - await self.__callback(pair=pair, message=message) - else: - self.__callback(pair=pair, message=message) - else: - logging.info(message) - - async def add_book(self: OrderbookClientV1, pairs: list[str]) -> None: - """ - Add an orderbook to this client. The feed will be subscribed and updates - will be published to the :func:`on_book_update` function. - - :param pairs: The pair(s) to subscribe to - :type pairs: list[str] - :param depth: The book depth - :type depth: int - """ - await self.ws_client.subscribe( - subscription={"name": "book", "depth": self.__depth}, - pair=pairs, - ) - - async def remove_book(self: OrderbookClientV1, pairs: list[str]) -> None: - """ - Unsubscribe from a subscribed orderbook. - - :param pairs: The pair(s) to unsubscribe from - :type pairs: list[str] - :param depth: The book depth - :type depth: int - """ - await self.ws_client.unsubscribe( - subscription={"name": "book", "depth": self.__depth}, - pair=pairs, - ) - - @property - def depth(self: OrderbookClientV1) -> int: - """ - Return the fixed depth of this orderbook client. - """ - return self.__depth - - @property - def exception_occur(self: OrderbookClientV1) -> bool: - """ - Can be used to determine if any critical error occurred within the - websocket connection. If so, the function will return ``True`` and the - client instance is most likely not usable anymore. So this is the - switch lets the user know, when to delete the current one and create a - new one. - - :return: ``True`` if any critical error occurred else ``False`` - :rtype: bool - """ - return bool(self.ws_client.exception_occur) - - def get(self: OrderbookClientV1, pair: str) -> dict | None: - """ - Returns the orderbook for a specific ``pair``. - - :param pair: The pair to get the orderbook from - :type pair: str - :return: The orderbook of that ``pair``. - :rtype: dict - - .. code-block:: python - :linenos: - :caption: OrderbookClientV1: Get ask and bid - - # â€Ļ - class Orderbook(OrderbookClientV1): - - async def on_book_update( - self: "Orderbook", - pair: str, - message: list - ) -> None: - book: dict[str, Any] = self.get(pair="XBT/USD") - ask: list[tuple[str, str]] = list(book["ask"].items()) - bid: list[tuple[str, str]] = list(book["bid"].items()) - # ask and bid are now in format [price, (volume, timestamp)] - # â€Ļ and include the whole orderbook - """ - return self.__book.get(pair) - - def __update_book( - self: OrderbookClientV1, - pair: str, - side: str, - snapshot: list, - ) -> None: - """ - This functions updates the local orderbook based on the information - provided in ``data`` and assigns/update the asks and bids in book. - - The ``data`` here looks like: - [ - ['25026.00000', '2.77183035', '1684658128.013525'], - ['25028.50000', '0.04725650', '1684658121.180535'], - ['25030.20000', '0.29527502', '1684658128.018182'], - ['25030.40000', '2.77134976', '1684658131.751539'], - ['25032.20000', '0.13978808', '1684658131.751577'] - ] - â€Ļ where the first value is the ask or bid price, the second - represents the volume and the last one is the timestamp. - - :param side: The side to assign the data to, either ``ask`` or ``bid`` - :type side: str - :param data: The data that needs to be assigned. - :type data: list - """ - for entry in snapshot: - price: str = entry[0] - volume: str = entry[1] - timestamp: str = entry[2] - - if float(volume) > 0.0: - # Price level exist or is new - self.__book[pair][side][price] = (volume, timestamp) - else: - # Price level moved out of range - self.__book[pair][side].pop(price) - - if side == "ask": - self.__book[pair]["ask"] = OrderedDict( - sorted(self.__book[pair]["ask"].items(), key=self.get_first)[ - : self.__depth - ], - ) - - elif side == "bid": - self.__book[pair]["bid"] = OrderedDict( - sorted( - self.__book[pair]["bid"].items(), - key=self.get_first, - reverse=True, - )[: self.__depth], - ) - - def __validate_checksum(self: OrderbookClientV1, pair: str, checksum: str) -> None: - """ - Function that validates the checksum of the orderbook as described here - https://docs.kraken.com/websockets/#book-checksum. - - :param pair: The pair that's orderbook checksum should be validated. - :type pair: str - :param checksum: The checksum sent by the Kraken API - :type checksum: str - """ - book: dict = self.__book[pair] - ask = list(book["ask"].items()) - bid = list(book["bid"].items()) - - local_checksum: str = "" - for price_level, (volume, _) in ask[:10]: - local_checksum += price_level.replace(".", "").lstrip("0") + volume.replace( - ".", - "", - ).lstrip("0") - - for price_level, (volume, _) in bid[:10]: - local_checksum += price_level.replace(".", "").lstrip("0") + volume.replace( - ".", - "", - ).lstrip("0") - - self.__book[pair]["valid"] = checksum == str(crc32(local_checksum.encode())) - - @staticmethod - def get_first(values: tuple) -> float: - """ - This function is used as callback for the ``sorted`` method to sort a - tuple/list by its first value and while ensuring that the values are - floats and comparable. - - :param values: A tuple of string values - :type values: tuple - :return: The first value of ``values`` as float. - :rtype: float - """ - return float(values[0]) - - -__all__ = ["OrderbookClientV1"] diff --git a/kraken/spot/staking.py b/kraken/spot/staking.py deleted file mode 100644 index 1ebcf3f3..00000000 --- a/kraken/spot/staking.py +++ /dev/null @@ -1,335 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# - -"""Module that implements the Kraken Spot Staking client""" - -from __future__ import annotations - -from typing import TypeVar - -from kraken.base_api import KrakenSpotBaseAPI, defined -from kraken.utils import deprecated - -Self = TypeVar("Self") - - -class Staking(KrakenSpotBaseAPI): - """ - .. deprecated:: v2.2.0 - - Class that implements the Kraken Spot Staking client. Currently there are no - staking endpoints that could be accesses without authentication. - - :param key: Spot API public key (default: ``""``) - :type key: str, optional - :param secret: Spot API secret key (default: ``""``) - :type secret: str, optional - :param url: Alternative URL to access the Kraken API (default: - https://api.kraken.com) - :type url: str, optional - :param sandbox: Use the sandbox (not supported for Spot trading so far, - default: ``False``) - :type sandbox: bool, optional - - .. code-block:: python - :linenos: - :caption: Spot Staking: Create the staking client - - >>> from kraken.spot import Staking - >>> staking = Staking() # unauthenticated - >>> auth_staking = Staking(key="api-key", secret="secret-key") # authenticated - - .. code-block:: python - :linenos: - :caption: Spot Staking: Create the staking client as context manager - - >>> from kraken.spot import Staking - >>> with Staking(key="api-key", secret="secret-key") as staking: - ... print(staking.stake_asset(asset="XLM", amount=200, method="Lumen Staked")) - """ - - def __init__( - self, - key: str = "", - secret: str = "", - url: str = "", - ) -> None: - super().__init__(key=key, secret=secret, url=url) - - @deprecated - def __enter__(self: Self) -> Self: - super().__enter__() - return self - - @deprecated - def stake_asset( - self: Staking, - asset: str, - amount: str | float, - method: str, - *, - extra_params: dict | None = None, - ) -> dict: - """ - .. deprecated:: v2.2.0 - - Stake the specified asset from the Spot wallet. - - Requires the ``Withdraw funds`` permission in the API key settings. - - Have a look at :func:`kraken.spot.Staking.list_stakeable_assets` to get - information about the stakable assets and methods. - - - https://docs.kraken.com/rest/#operation/stake - - :param asset: The asset to stake - :type asset: str - :param amount: The amount to stake - :type amount: str | float - :param method: The staking method - :type method: str - :return: The reference id of the staking transaction - :rtype: dict - - .. code-block:: python - :linenos: - :caption: Spot Staking: Stake an asset - - >>> from kraken.spot import Staking - >>> staking = Staking(key="api-key", secret="secret-key") - >>> staking.stake_asset( - ... asset="DOT", - ... amount=2000, - ... method="polkadot-staked" - ... ) - { 'refid': 'BOG5AE5-KSCNR4-VPNPEV' } - """ - return self._request( # type: ignore[return-value] - method="POST", - uri="/0/private/Stake", - params={"asset": asset, "amount": amount, "method": method}, - auth=True, - extra_params=extra_params, - ) - - @deprecated - def unstake_asset( - self: Staking, - asset: str, - amount: str | float, - method: str | None = None, - *, - extra_params: dict | None = None, - ) -> dict: - """ - .. deprecated:: v2.2.0 - - Unstake an asset and transfer the amount to the Spot wallet. - - Requires the ``Withdraw funds`` permission in the API key settings. - - Have a look at :func:`kraken.spot.Staking.list_stakeable_assets` to get - information about the stakeable assets and methods. - - - https://docs.kraken.com/rest/#operation/unstake - - :param asset: The asset to stake - :type asset: str - :param amount: The amount to stake - :type amount: str | float - :param method: Filter by staking method (default: ``None``) - :type method: str, optional - :return: The reference id of the unstaking transaction - :rtype: dict - - .. code-block:: python - :linenos: - :caption: Spot Staking: Unstake a staked asset - - >>> from kraken.spot import Staking - >>> staking = Staking(key="api-key", secret="secret-key") - >>> staking.unstake_asset( - ... asset="DOT", - ... amount=2000, - ... method="polkadot-staked" - ... ) - { 'refid': 'BOG5AE5-KSCNR4-VPNPEV' } - """ - params: dict = {"asset": asset, "amount": amount} - if defined(method): - params["method"] = method - - return self._request( # type: ignore[return-value] - method="POST", - uri="/0/private/Unstake", - params=params, - auth=True, - extra_params=extra_params, - ) - - @deprecated - def list_stakeable_assets( - self: Staking, - *, - extra_params: dict | None = None, - ) -> list[dict]: - """ - .. deprecated:: v2.2.0 - - Get a list of stakeable assets. Only assets that the user is able to - stake will be shown. - - Requires the ``Withdraw funds`` and ``Query funds`` API key permissions. - - https://docs.kraken.com/rest/#operation/getStakingAssetInfo - - :return: Information for all assets that can be staked on Kraken - :rtype: list[dict] - - .. code-block:: python - :linenos: - :caption: Spot Staking: List the stakeable assets - - >>> from kraken.spot import Staking - >>> staking = Staking(key="api-key", secret="secret-key") - >>> staking.list_stakeable_assets() - [ - { - "method": "polkadot-staked", - "asset": "DOT", - "staking_asset": "DOT.S", - "rewards": { - "type": "percentage", - "reward": "7-11" - }, - "on_chain": True, - "can_stake": True, - "can_unstake": True, - "minimum_amount": { - "staking": "0.0000000100", - "unstaking": "0.0000000100" - } - }, { - "method": "polygon-staked", - "asset": "MATIC", - "staking_asset": "MATIC.S", - "rewards": { - "type": "percentage", - "reward": "1-2" - }, - "on_chain": True, - "can_stake": True, - "can_unstake": True, - "minimum_amount": { - "staking": "0.0000000000", - "unstaking": "0.0000000000" - } - }, ... - ] - """ - return self._request( # type: ignore[return-value] - method="POST", - uri="/0/private/Staking/Assets", - auth=True, - extra_params=extra_params, - ) - - @deprecated - def get_pending_staking_transactions( - self: Staking, - *, - extra_params: dict | None = None, - ) -> list[dict]: - """ - .. deprecated:: v2.2.0 - - Get the list of pending staking transactions of the user. - - Requires the ``Withdraw funds`` and ``Query funds`` API key permissions. - - - https://docs.kraken.com/rest/#operation/getStakingPendingDeposits - - :return: List of pending staking transactions - :rtype: list[dict] - - .. code-block:: python - :linenos: - :caption: Spot Staking: Get the pending staking transactions - - >>> from kraken.spot import Staking - >>> staking = Staking(key="api-key", secret="secret-key") - >>> staking.get_pending_staking_transactions() - [ - { - 'method': 'polkadot-staked', - 'aclass': 'currency', - 'asset': 'DOT.S', - 'refid': 'BOG5AE5-KSCNR4-VPNPEV', - 'amount': '1982.17316', - 'fee': '0.00000000', - 'time': 1623653613, - 'status': 'Initial', - 'type': 'bonding' - }, ... - ] - """ - return self._request( # type: ignore[return-value] - method="POST", - uri="/0/private/Staking/Pending", - auth=True, - extra_params=extra_params, - ) - - @deprecated - def list_staking_transactions( - self: Staking, - *, - extra_params: dict | None = None, - ) -> list[dict]: - """ - .. deprecated:: v2.2.0 - - List the last 1000 staking transactions of the past 90 days. - - Requires the ``Query funds`` API key permission. - - - https://docs.kraken.com/rest/#operation/getStakingTransactions - - :return: List of historical staking transactions - :rtype: list[dict] - - .. code-block:: python - :linenos: - :caption: Spot Staking: List the historical staking transactions - - >>> from kraken.spot import Staking - >>> staking = Staking(key="api-key", secret="secret-key") - >>> staking.list_staking_transactions() - [ - { - 'method': 'polkadot-staked', - 'aclass': 'currency', - 'asset': 'DOT.S', - 'refid': 'POLZN7T-RWBL2YD-3HAPL1', - 'amount': '121.1', - 'fee': '1.0000000000', - 'time': 1622971496, - 'status': 'Success'. - 'type': 'bonding', - 'bond_start': 1623234684, - 'bond_end': 1632345316 - }, ... - ] - - """ - return self._request( # type: ignore[return-value] - method="POST", - uri="/0/private/Staking/Transactions", - auth=True, - extra_params=extra_params, - ) - - -__all__ = ["Staking"] diff --git a/kraken/spot/trade.py b/kraken/spot/trade.py index cf41aaef..36d18718 100644 --- a/kraken/spot/trade.py +++ b/kraken/spot/trade.py @@ -12,13 +12,13 @@ from math import floor from typing import TypeVar -from kraken.base_api import KrakenSpotBaseAPI, defined, ensure_string +from kraken.base_api import SpotClient, defined, ensure_string from kraken.spot.market import Market Self = TypeVar("Self") -class Trade(KrakenSpotBaseAPI): +class Trade(SpotClient): """ Class that implements the Kraken Trade Spot client. @@ -355,7 +355,7 @@ def create_order( # pylint: disable=too-many-branches,too-many-arguments # noqa if defined(displayvol): params["displayvol"] = str(displayvol) - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/AddOrder", params=params, @@ -435,7 +435,7 @@ def create_order_batch( params: dict = {"orders": orders, "pair": pair, "validate": validate} if defined(deadline): params["deadline"] = deadline - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/AddOrderBatch", params=params, @@ -542,7 +542,7 @@ def edit_order( # pylint: disable=too-many-arguments # noqa: PLR0913, PLR0917 params["cancel_response"] = cancel_response if defined(deadline): params["deadline"] = deadline - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] "POST", uri="/0/private/EditOrder", params=params, @@ -579,7 +579,7 @@ def cancel_order( >>> trade.cancel_order(txid="OAUHYR-YCVK6-P22G6P") { 'count': 1 } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/CancelOrder", params={"txid": txid}, @@ -611,7 +611,7 @@ def cancel_all_orders( >>> trade.cancel_all_orders() { 'count': 2 } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/CancelAll", extra_params=extra_params, @@ -648,7 +648,7 @@ def cancel_all_orders_after_x( 'triggerTime': '2023-04-06T06:52:56Z' } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/CancelAllOrdersAfter", params={"timeout": timeout}, @@ -685,7 +685,7 @@ def cancel_order_batch( ... ) { count': 2 } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/CancelOrderBatch", params={"orders": orders}, diff --git a/kraken/spot/user.py b/kraken/spot/user.py index 87c5aa08..ebdcc4df 100644 --- a/kraken/spot/user.py +++ b/kraken/spot/user.py @@ -12,12 +12,12 @@ from decimal import Decimal from typing import TypeVar -from kraken.base_api import KrakenSpotBaseAPI, defined, ensure_string +from kraken.base_api import SpotClient, defined, ensure_string Self = TypeVar("Self") -class User(KrakenSpotBaseAPI): +class User(SpotClient): """ Class that implements the Kraken Spot User client @@ -93,7 +93,7 @@ def get_account_balance( ... } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Balance", extra_params=extra_params, @@ -139,7 +139,7 @@ def get_balances( ... } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/BalanceEx", extra_params=extra_params, @@ -228,7 +228,7 @@ def get_trade_balance( params: dict = {} if defined(asset): params["asset"] = asset - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/TradeBalance", params=params, @@ -302,7 +302,7 @@ def get_open_orders( params: dict = {"trades": trades} if defined(userref): params["userref"] = userref - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/OpenOrders", params=params, @@ -397,7 +397,7 @@ def get_closed_orders( if defined(ofs): params["ofs"] = ofs - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/ClosedOrders", params=params, @@ -510,7 +510,7 @@ def get_orders_info( } if defined(userref): params["userref"] = userref - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/QueryOrders", params=params, @@ -598,7 +598,7 @@ def get_trades_history( # noqa: PLR0913 # pylint: disable=too-many-arguments params["end"] = end if defined(ofs): params["ofs"] = ofs - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/TradesHistory", params=params, @@ -655,7 +655,7 @@ def get_trades_info( } } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/QueryTrades", params={ @@ -726,7 +726,7 @@ def get_open_positions( params: dict = {"docalcs": docalcs, "consolidation": consolidation} if defined(txid): params["txid"] = txid - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/OpenPositions", params=params, @@ -802,7 +802,7 @@ def get_ledgers_info( params["end"] = end if defined(ofs): params["ofs"] = ofs - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/Ledgers", params=params, @@ -853,7 +853,7 @@ def get_ledgers( } } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/QueryLedgers", params={"trades": trades, "id": id_}, @@ -924,7 +924,7 @@ def get_trade_volume( params: dict = {"fee-info": fee_info} if defined(pair): params["pair"] = pair - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/TradeVolume", params=params, @@ -994,7 +994,7 @@ def request_export_report( # noqa: PLR0913 # pylint: disable=too-many-arguments params["starttm"] = starttm if defined(endtm): params["endtm"] = endtm - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/AddExport", params=params, @@ -1058,7 +1058,7 @@ def get_export_report_status( """ if report not in {"trades", "ledgers"}: raise ValueError('report must be one of "trades", "ledgers"') - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/ExportStatus", params={"report": report}, @@ -1106,7 +1106,7 @@ def retrieve_export( ... file.write(chunk) """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/RetrieveExport", params={"id": id_}, @@ -1149,7 +1149,7 @@ def delete_export_report( >>> user.delete_export_report(id_="GEHI", type_="delete") { 'delete': True } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/RemoveExport", params={"id": id_, "type": type_}, @@ -1185,7 +1185,7 @@ def create_subaccount( >>> user.create_subaccount(username="user", email="user@domain.com") { 'result': True } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/CreateSubaccount", params={"username": username, "email": email}, @@ -1238,7 +1238,7 @@ def account_transfer( } } """ - return self._request( # type: ignore[return-value] + return self.request( # type: ignore[return-value] method="POST", uri="/0/private/AccountTransfer", params={"asset": asset, "amount": amount, "from": from_, "to": to_}, diff --git a/kraken/spot/websocket/__init__.py b/kraken/spot/websocket/__init__.py index 856ba835..8c4aeb98 100644 --- a/kraken/spot/websocket/__init__.py +++ b/kraken/spot/websocket/__init__.py @@ -4,19 +4,17 @@ # """ -Module that provides the base class for the Kraken Websocket clients v1 and v2. +Module that provides the base class for the Kraken Websocket clients v2. """ from __future__ import annotations import logging +from asyncio import sleep as async_sleep from typing import TYPE_CHECKING, Any, TypeVar -from kraken.base_api import KrakenSpotBaseAPI -from kraken.spot.websocket.connectors import ( - ConnectSpotWebsocketV1, - ConnectSpotWebsocketV2, -) +from kraken.spot import SpotAsyncClient +from kraken.spot.websocket.connectors import ConnectSpotWebsocket if TYPE_CHECKING: from collections.abc import Callable @@ -24,12 +22,11 @@ Self = TypeVar("Self") -class KrakenSpotWSClientBase(KrakenSpotBaseAPI): +class SpotWSClientBase(SpotAsyncClient): """ - This is the base class for :class:`kraken.spot.KrakenSpotWSClientV1` and - :class:`kraken.spot.KrakenSpotWSClientV2`. It extends the REST API base - class and is used to provide the base functionalities that are used - for Kraken Websocket API v1 and v2. + This is the base class for :class:`kraken.spot.SpotWSClient`. It extends + the REST API base class and is used to provide the base functionalities that + are used for Kraken Websocket API v2. **This is an internal class and should not be used outside.** @@ -39,76 +36,59 @@ class and is used to provide the base functionalities that are used :type secret: str, optional :param url: Set a specific URL to access the Kraken REST API :type url: str, optional - :param no_public: Disables public connection (default: ``False``). - If not set or set to ``False``, the client will create a public and - a private connection per default. If only a private connection is - required, this parameter should be set to ``True``. + :param no_public: Disables public connection (default: ``False``). If not + set or set to ``False``, the client will create a public and a private + connection per default. If only a private connection is required, this + parameter should be set to ``True``. :param beta: Use the beta websocket channels (maybe not supported anymore, default: ``False``) :type beta: bool """ LOG: logging.Logger = logging.getLogger(__name__) - PROD_ENV_URL: str = "ws.kraken.com" AUTH_PROD_ENV_URL: str = "ws-auth.kraken.com" - BETA_ENV_URL: str = "beta-ws.kraken.com" - AUTH_BETA_ENV_URL: str = "beta-ws-auth.kraken.com" def __init__( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, key: str = "", secret: str = "", callback: Callable | None = None, - api_version: str = "v2", *, no_public: bool = False, - beta: bool = False, ) -> None: - super().__init__(key=key, secret=secret, sandbox=beta) + super().__init__(key=key, secret=secret) self._is_auth: bool = bool(key and secret) self.__callback: Callable | None = callback - self.exception_occur: bool = False - self._pub_conn: ConnectSpotWebsocketV1 | ConnectSpotWebsocketV2 | None = None - self._priv_conn: ConnectSpotWebsocketV1 | ConnectSpotWebsocketV2 | None = None + self._pub_conn: ConnectSpotWebsocket | None = None + self._priv_conn: ConnectSpotWebsocket | None = None + self.__prepare_connect(no_public=no_public) - self.__connect(version=api_version, beta=beta, no_public=no_public) + @property + def exception_occur(self: SpotWSClientBase) -> bool: + """Returns True if any connection was stopped due to an exception.""" + return (self._pub_conn is not None and self._pub_conn.exception_occur) or ( + self._priv_conn is not None and self._priv_conn.exception_occur + ) # -------------------------------------------------------------------------- # Internals - def __connect( - self: KrakenSpotWSClientBase, - version: str, + def __prepare_connect( + self: SpotWSClientBase, *, - beta: bool, no_public: bool, ) -> None: - """ - Set up functions and attributes based on the API version. + """Set up functions and attributes based on the API version.""" - :param version: The Websocket API version to use (one of ``v1``, ``v2``) - :type version: str - """ - ConnectSpotWebsocket: type[ConnectSpotWebsocketV1 | ConnectSpotWebsocketV2] - - if version == "v1": - ConnectSpotWebsocket = ConnectSpotWebsocketV1 - - elif version == "v2": - # pylint: disable=invalid-name - self.PROD_ENV_URL += "/v2" - self.AUTH_PROD_ENV_URL += "/v2" - self.BETA_ENV_URL += "/v2" - self.AUTH_BETA_ENV_URL += "/v2" - ConnectSpotWebsocket = ConnectSpotWebsocketV2 - else: - raise ValueError("Websocket API version must be one of ``v1``, ``v2``") + # pylint: disable=invalid-name + self.PROD_ENV_URL += "/v2" + self.AUTH_PROD_ENV_URL += "/v2" self._pub_conn = ( ConnectSpotWebsocket( client=self, - endpoint=self.PROD_ENV_URL if not beta else self.BETA_ENV_URL, + endpoint=self.PROD_ENV_URL, is_auth=False, callback=self.on_message, ) @@ -119,7 +99,7 @@ def __connect( self._priv_conn = ( ConnectSpotWebsocket( client=self, - endpoint=self.AUTH_PROD_ENV_URL if not beta else self.AUTH_BETA_ENV_URL, + endpoint=self.AUTH_PROD_ENV_URL, is_auth=True, callback=self.on_message, ) @@ -127,8 +107,45 @@ def __connect( else None ) + async def start(self: SpotWSClientBase) -> None: + """Method to start the websocket connection.""" + if self._pub_conn: + await self._pub_conn.start() + if self._priv_conn: + await self._priv_conn.start() + + # Wait for the connection(s) to be established ... + while (timeout := 0.0) < 10: + public_conntection_waiting = True + if self._pub_conn: + if self._pub_conn.socket is not None: + public_conntection_waiting = False + else: + public_conntection_waiting = False + + private_conection_waiting = True + if self._priv_conn: + if self._priv_conn.socket is not None: + private_conection_waiting = False + else: + private_conection_waiting = False + + if not public_conntection_waiting and not private_conection_waiting: + break + await async_sleep(0.2) + timeout += 0.2 + else: + raise TimeoutError("Could not connect to the Kraken API!") + + async def stop(self: SpotWSClientBase) -> None: + """Method to stop the websocket connection.""" + if self._pub_conn: + await self._pub_conn.stop() + if self._priv_conn: + await self._priv_conn.stop() + async def on_message( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, message: dict | list, ) -> None: """ @@ -136,8 +153,7 @@ async def on_message( have to overwrite this function since it will receive all incoming messages that will be sent by Kraken. - See :class:`kraken.spot.KrakenSpotWSClientV1` and - :class:`kraken.spot.KrakenSpotWSClientV2` for examples to use this + See :class:`kraken.spot.SpotWSClient` for examples to use this function. :param message: The message received sent by Kraken via the websocket connection @@ -157,16 +173,20 @@ async def on_message( async def __aenter__(self: Self) -> Self: """Entrypoint for use as context manager""" + await super().__aenter__() + await self.start() # type: ignore[attr-defined] return self async def __aexit__( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, *exc: object, **kwargs: Any, # noqa: ANN401 ) -> None: """Exit if used as context manager""" + await super().__aexit__() + await self.stop() - def get_ws_token(self: KrakenSpotWSClientBase) -> dict: + async def get_ws_token(self: SpotWSClientBase) -> dict: """ Get the authentication token to establish the authenticated websocket connection. This is used internally and in most cases not @@ -177,13 +197,13 @@ def get_ws_token(self: KrakenSpotWSClientBase) -> dict: :returns: The authentication token :rtype: dict """ - return self._request( # type: ignore[return-value] + return await self.request( # type: ignore[return-value] method="POST", uri="/0/private/GetWebSocketsToken", ) def _get_socket( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, *, private: bool, ) -> Any | None: # noqa: ANN401 @@ -202,7 +222,7 @@ def _get_socket( @property def active_public_subscriptions( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, ) -> list[dict]: """ Returns the active public subscriptions @@ -217,7 +237,7 @@ def active_public_subscriptions( @property def active_private_subscriptions( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, ) -> list[dict]: """ Returns the active private subscriptions @@ -234,7 +254,7 @@ def active_private_subscriptions( # Functions and attributes to overload async def send_message( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, *args: Any, # noqa: ANN401 **kwargs: Any, # noqa: ANN401 ) -> None: @@ -245,7 +265,7 @@ async def send_message( raise NotImplementedError("Must be overloaded!") # coverage: disable async def subscribe( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, *args: Any, # noqa: ANN401 **kwargs: Any, # noqa: ANN401 ) -> None: @@ -256,7 +276,7 @@ async def subscribe( raise NotImplementedError("Must be overloaded!") # coverage: disable async def unsubscribe( - self: KrakenSpotWSClientBase, + self: SpotWSClientBase, *args: Any, # noqa: ANN401 **kwargs: Any, # noqa: ANN401 ) -> None: @@ -267,7 +287,7 @@ async def unsubscribe( raise NotImplementedError("Must be overloaded!") # coverage: disable @property - def public_channel_names(self: KrakenSpotWSClientBase) -> list[str]: + def public_channel_names(self: SpotWSClientBase) -> list[str]: """ This function must be overloaded and return a list of names that can be subscribed to (for unauthenticated connections). @@ -275,7 +295,7 @@ def public_channel_names(self: KrakenSpotWSClientBase) -> list[str]: raise NotImplementedError("Must be overloaded!") # coverage: disable @property - def private_channel_names(self: KrakenSpotWSClientBase) -> list[str]: + def private_channel_names(self: SpotWSClientBase) -> list[str]: """ This function must be overloaded and return a list of names that can be subscribed to (for authenticated connections). @@ -283,4 +303,4 @@ def private_channel_names(self: KrakenSpotWSClientBase) -> list[str]: raise NotImplementedError("Must be overloaded!") # coverage: disable -__all__ = ["KrakenSpotWSClientBase"] +__all__ = ["SpotWSClientBase"] diff --git a/kraken/spot/websocket/connectors.py b/kraken/spot/websocket/connectors.py index b8f78178..a48abe3b 100644 --- a/kraken/spot/websocket/connectors.py +++ b/kraken/spot/websocket/connectors.py @@ -2,12 +2,13 @@ # Copyright (C) 2023 Benjamin Thomas Schwertfeger # GitHub: https://github.com/btschwertfeger # +# pylint: disable=attribute-defined-outside-init """ This module provides the base class that is used to create and maintain websocket connections to Kraken. -It also provides derived classes for using the Kraken Websocket API v1 and v2. +It also provides derived classes for using the Kraken Websocket API v2. """ from __future__ import annotations @@ -28,24 +29,21 @@ if TYPE_CHECKING: from collections.abc import Callable - from kraken.spot.websocket import KrakenSpotWSClientBase + from kraken.spot.websocket import SpotWSClientBase -class ConnectSpotWebsocketBase: +class ConnectSpotWebsocketBase: # pylint: disable=too-many-instance-attributes """ This class serves as the base for - :class:`kraken.spot.websocket.connectors.ConnectSpotWebsocket` and - :class:`kraken.spot.websocket.connectors.ConnectSpotWebsocketV2`. + :class:`kraken.spot.websocket.connectors.ConnectSpotWebsocket`. It creates and holds a websocket connection, reconnects and handles - errors. Its functions only serve as base for the classes mentioned above, - since it combines the functionalities that is used for both Websocket API v1 - and v2. + errors. **This is an internal class and should not be used outside.** :param client: The websocket client that wants to connect - :type client: :class:`kraken.spot.KrakenSpotWSClientBase` + :type client: :class:`kraken.spot.SpotWSClientBase` :param endpoint: The websocket endpoint :type endpoint: str :param callback: Callback function that receives the websocket messages @@ -61,13 +59,13 @@ class ConnectSpotWebsocketBase: def __init__( self: ConnectSpotWebsocketBase, - client: KrakenSpotWSClientBase, + client: SpotWSClientBase, endpoint: str, callback: Callable, *, is_auth: bool = False, ) -> None: - self.__client: KrakenSpotWSClientBase = client + self.__client: SpotWSClientBase = client self.__ws_endpoint: str = endpoint self.__callback: Callable = callback @@ -79,7 +77,8 @@ def __init__( self._last_ping: int | float | None = None self.socket: Any | None = None self._subscriptions: list[dict] = [] - self.task: asyncio.Task = asyncio.create_task(self.__run_forever()) + self.exception_occur: bool = False + self.keep_alive: bool = True @property def is_auth(self: ConnectSpotWebsocketBase) -> bool: @@ -87,7 +86,7 @@ def is_auth(self: ConnectSpotWebsocketBase) -> bool: return self.__is_auth @property - def client(self: ConnectSpotWebsocketBase) -> KrakenSpotWSClientBase: + def client(self: ConnectSpotWebsocketBase) -> SpotWSClientBase: """Return the websocket client""" return self.__client @@ -96,6 +95,23 @@ def subscriptions(self: ConnectSpotWebsocketBase) -> list[dict]: """Returns a copy of active subscriptions""" return deepcopy(self._subscriptions) + async def start(self: ConnectSpotWebsocketBase) -> None: + """Starts the websocket connection""" + if ( + hasattr(self, "task") + and not self.task.done() # pylint: disable=access-member-before-definition + ): + return + self.task: asyncio.Task = asyncio.create_task( + self.__run_forever(), + ) + + async def stop(self: ConnectSpotWebsocketBase) -> None: + """Stops the websocket connection""" + self.keep_alive = False + if hasattr(self, "task") and not self.task.done(): + await self.task + async def __run(self: ConnectSpotWebsocketBase, event: asyncio.Event) -> None: """ This function establishes the websocket connection and runs until @@ -104,10 +120,9 @@ async def __run(self: ConnectSpotWebsocketBase, event: asyncio.Event) -> None: :param event: Event used to control the information flow :type event: asyncio.Event """ - keep_alive: bool = True self._last_ping = time() self.ws_conn_details = ( - None if not self.__is_auth else self.__client.get_ws_token() + None if not self.__is_auth else await self.__client.get_ws_token() ) self.LOG.debug( "Websocket token: %s", @@ -127,16 +142,16 @@ async def __run(self: ConnectSpotWebsocketBase, event: asyncio.Event) -> None: event.set() self.__reconnect_num = 0 - while keep_alive: + while self.keep_alive: if time() - self._last_ping > self.PING_INTERVAL: await self.send_ping() try: - _message = await asyncio.wait_for(self.socket.recv(), timeout=15) + _message = await asyncio.wait_for(self.socket.recv(), timeout=10) except TimeoutError: # important await self.send_ping() except asyncio.CancelledError: self.LOG.exception("asyncio.CancelledError") - keep_alive = False + self.keep_alive = False await self.__callback({"error": "asyncio.CancelledError"}) else: try: @@ -149,20 +164,17 @@ async def __run(self: ConnectSpotWebsocketBase, event: asyncio.Event) -> None: await self.__callback(message) async def __run_forever(self: ConnectSpotWebsocketBase) -> None: - """ - This function ensures the reconnects. - - todo: This is stupid. There must be a better way for passing - the raised exception to the client class - not - through this ``exception_occur`` flag - """ + """This function ensures the reconnects.""" + self.keep_alive = True + self.exception_occur = False try: - while True: + while self.keep_alive: await self.__reconnect() except MaxReconnectError: await self.__callback( {"error": "kraken.exceptions.MaxReconnectError"}, ) + self.exception_occur = True except Exception as exc: traceback_: str = traceback.format_exc() logging.exception( @@ -171,11 +183,7 @@ async def __run_forever(self: ConnectSpotWebsocketBase) -> None: traceback_, ) await self.__callback({"error": traceback_}) - finally: - await self.__callback( - {"error": "Exception stopped the Kraken Spot Websocket Client!"}, - ) - self.__client.exception_occur = True + self.exception_occur = True async def close_connection(self: ConnectSpotWebsocketBase) -> None: """Closes the websocket connection and thus forces a reconnect""" @@ -211,7 +219,7 @@ async def __reconnect(self: ConnectSpotWebsocketBase) -> None: asyncio.create_task(self.__run(event)), ] - while True: + while self.keep_alive: finished, pending = await asyncio.wait( tasks, return_when=asyncio.FIRST_EXCEPTION, @@ -291,172 +299,7 @@ async def _recover_subscriptions( ) -class ConnectSpotWebsocketV1(ConnectSpotWebsocketBase): - """ - This class extends the - :class:`kraken.spot.websocket.connectors.ConnectSpotWebsocketBase` and - can be instantiated to create and maintain a websocket connection using - the Kraken Websocket API v1. - - **This is an internal class and should not be used outside.** - - :param client: The websocket client that wants to connect - :type client: :class:`kraken.spot.KrakenSpotWSClientBase` - :param endpoint: The websocket endpoint - :type endpoint: str - :param callback: Callback function that receives the websocket messages - :type callback: function - :param is_auth: If the websocket connects to endpoints that - require authentication (default: ``False``) - :type is_auth: bool, optional - """ - - def __init__( - self: ConnectSpotWebsocketV1, - client: KrakenSpotWSClientBase, - endpoint: str, - callback: Callable | None, - *, - is_auth: bool = False, - ) -> None: - super().__init__( - client=client, - endpoint=endpoint, - callback=callback, - is_auth=is_auth, - ) - - async def send_ping(self: ConnectSpotWebsocketV1) -> None: - """Sends ping to Kraken""" - await self.socket.send( - json.dumps( - { - "event": "ping", - "reqid": int(time() * 1000), - }, - ), - ) - self._last_ping = time() - - async def _recover_subscriptions( - self: ConnectSpotWebsocketV1, - event: asyncio.Event, - ) -> None: - """ - Executes the subscribe function for all subscriptions that were tracked - locally. This function is called when the connection was closed to - recover the subscriptions. - - :param event: Event to wait for (so this is only executed when - it is set to ``True`` - which is when the connection is ready) - :type event: asyncio.Event - """ - log_msg: str = ( - f'Recover {"authenticated" if self.is_auth else "public"} subscriptions {self._subscriptions}' - ) - self.LOG.info("%s: waiting", log_msg) - await event.wait() - - for sub in self._subscriptions: - cpy = deepcopy(sub) - private = False - if ( - "subscription" in sub - and "name" in sub["subscription"] - and sub["subscription"]["name"] in self.client.private_channel_names - ): - cpy["subscription"]["token"] = self.ws_conn_details["token"] - private = True - - await self.client.send_message(cpy, private=private) - self.LOG.info("%s: OK", sub) - - self.LOG.info("%s: done", log_msg) - - def _manage_subscriptions( - self: ConnectSpotWebsocketV1, - message: dict | list, - ) -> None: - """ - Checks if the message contains events about un-/subscriptions - to add or remove these from the list of current tracked subscriptions. - - :param message: The message to check for subscriptions - :type message: dict | list - """ - if ( - isinstance(message, dict) - and message.get("event") == "subscriptionStatus" - and message.get("status") - ): - if message["status"] == "subscribed": - self.__append_subscription(message=message) - elif message["status"] == "unsubscribed": - self.__remove_subscription(message=message) - elif message["status"] == "error": - self.LOG.warning(message) - - def __append_subscription(self: ConnectSpotWebsocketV1, message: dict) -> None: - """ - Appends a subscription to the local list of tracked subscriptions. - - :param subscription: The subscription to append - :type subscription: dict - """ - # remove from list, to avoid duplicate entries - self.__remove_subscription(message) - self._subscriptions.append(self.__build_subscription(message)) - - def __remove_subscription(self: ConnectSpotWebsocketV1, message: dict) -> None: - """ - Removes a subscription from the list of locally tracked subscriptions. - - :param subscription: The subscription to remove. - :type subscription: dict - """ - subscription: dict = self.__build_subscription(message=message) - self._subscriptions = [ - sub for sub in self._subscriptions if sub != subscription - ] - - def __build_subscription(self: ConnectSpotWebsocketV1, message: dict) -> dict: - """ - Builds a subscription dictionary that can be used to subscribe to a - feed. This is also used to prepare the local active subscription list. - - :param message: The information to build the subscription from - :type message: dict - :raises ValueError: If attributes are missing - :return: The built subscription - :rtype: dict - """ - sub: dict = {"event": "subscribe"} - - if "subscription" not in message or "name" not in message["subscription"]: - raise ValueError("Cannot remove subscription with missing attributes.") - if ( - message["subscription"]["name"] in self.client.public_channel_names - ): # public endpoint - if message.get("pair"): - sub["pair"] = ( - message["pair"] - if isinstance(message["pair"], list) - else [message["pair"]] - ) - sub["subscription"] = message["subscription"] - elif ( - message["subscription"]["name"] in self.client.private_channel_names - ): # private endpoint - sub["subscription"] = {"name": message["subscription"]["name"]} - else: - self.LOG.warning( - "Feed not implemented. Please contact the python-kraken-sdk " - "package maintainer.", - ) - return sub - - -class ConnectSpotWebsocketV2(ConnectSpotWebsocketBase): +class ConnectSpotWebsocket(ConnectSpotWebsocketBase): """ This class extends the :class:`kraken.spot.websocket.connectors.ConnectSpotWebsocketBase` and can @@ -466,7 +309,7 @@ class ConnectSpotWebsocketV2(ConnectSpotWebsocketBase): **This is an internal class and should not be used outside.** :param client: The websocket client that wants to connect - :type client: :class:`kraken.spot.KrakenSpotWSClientBase` + :type client: :class:`kraken.spot.SpotWSClientBase` :param endpoint: The websocket endpoint :type endpoint: str :param callback: Callback function that receives the websocket messages @@ -477,8 +320,8 @@ class ConnectSpotWebsocketV2(ConnectSpotWebsocketBase): """ def __init__( - self: ConnectSpotWebsocketV2, - client: KrakenSpotWSClientBase, + self: ConnectSpotWebsocket, + client: SpotWSClientBase, endpoint: str, callback: Callable | None, *, @@ -491,13 +334,13 @@ def __init__( is_auth=is_auth, ) - async def send_ping(self: ConnectSpotWebsocketV2) -> None: + async def send_ping(self: ConnectSpotWebsocket) -> None: """Sends ping to Kraken""" await self.socket.send(json.dumps({"method": "ping"})) self._last_ping = time() async def _recover_subscriptions( - self: ConnectSpotWebsocketV2, + self: ConnectSpotWebsocket, event: asyncio.Event, ) -> None: """ @@ -521,7 +364,7 @@ async def _recover_subscriptions( self.LOG.info("%s: done", log_msg) - def _manage_subscriptions(self: ConnectSpotWebsocketV2, message: dict) -> None: # type: ignore[override] + def _manage_subscriptions(self: ConnectSpotWebsocket, message: dict) -> None: # type: ignore[override] """ Checks if the message contains events about un-/subscriptions to add or remove these from the list of current tracked subscriptions. @@ -543,7 +386,7 @@ def _manage_subscriptions(self: ConnectSpotWebsocketV2, message: dict) -> None: else: self.LOG.warning(message) - def __append_subscription(self: ConnectSpotWebsocketV2, subscription: dict) -> None: + def __append_subscription(self: ConnectSpotWebsocket, subscription: dict) -> None: """ Appends a subscription to the local list of tracked subscriptions. @@ -553,7 +396,7 @@ def __append_subscription(self: ConnectSpotWebsocketV2, subscription: dict) -> N self.__remove_subscription(subscription=subscription) self._subscriptions.append(subscription) - def __remove_subscription(self: ConnectSpotWebsocketV2, subscription: dict) -> None: + def __remove_subscription(self: ConnectSpotWebsocket, subscription: dict) -> None: """ Removes a subscription from the list of locally tracked subscriptions. @@ -569,7 +412,7 @@ def __remove_subscription(self: ConnectSpotWebsocketV2, subscription: dict) -> N return def __transform_subscription( - self: ConnectSpotWebsocketV2, + self: ConnectSpotWebsocket, subscription: dict, ) -> dict: """ @@ -620,6 +463,5 @@ def __transform_subscription( __all__ = [ "ConnectSpotWebsocketBase", - "ConnectSpotWebsocketV1", - "ConnectSpotWebsocketV2", + "ConnectSpotWebsocket", ] diff --git a/kraken/spot/websocket_v1.py b/kraken/spot/websocket_v1.py deleted file mode 100644 index 9fb5ecbe..00000000 --- a/kraken/spot/websocket_v1.py +++ /dev/null @@ -1,758 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# - -""" -This module provides the Spot websocket client (Websocket API V1 as -documented in https://docs.kraken.com/websockets). -""" - -from __future__ import annotations - -import asyncio -import json -import warnings -from copy import deepcopy -from typing import TYPE_CHECKING, Any - -from kraken.base_api import defined, ensure_string -from kraken.exceptions import KrakenAuthenticationError -from kraken.spot.trade import Trade -from kraken.spot.websocket import KrakenSpotWSClientBase - -if TYPE_CHECKING: - from collections.abc import Callable - - -class KrakenSpotWSClientV1(KrakenSpotWSClientBase): - """ - .. deprecated:: v2.2.0 - - Class to access public and private/authenticated websocket connections. - - **This client only supports the Kraken Websocket API v1.** - - - https://docs.kraken.com/websockets - - â€Ļ please use :class:`KrakenSpotWSClientV2` for accessing the Kraken - Websockets API v2. - - This class holds up to two websocket connections, one private and one - public. - - When accessing private endpoints that need authentication make sure, that - the ``Access WebSockets API`` API key permission is set in the user's - account. To place or cancel orders, querying ledger information or accessing - live portfolio changes (fills, new orders, ...) there are separate - permissions that must be enabled if required. - - :param key: API Key for the Kraken Spot API (default: ``""``) - :type key: str, optional - :param secret: Secret API Key for the Kraken Spot API (default: ``""``) - :type secret: str, optional - :param url: Set a specific URL to access the Kraken REST API - :type url: str, optional - :param no_public: Disables public connection (default: ``False``). If not - set or set to ``False``, the client will create a public and a private - connection per default. If only a private connection is required, this - parameter should be set to ``True``. - :param beta: Use the beta websocket channels (maybe not supported anymore, - default: ``False``) - :type beta: bool - - .. code-block:: python - :linenos: - :caption: HowTo: Use the Kraken Spot websocket client (v1) - - import asyncio - from kraken.spot import KrakenSpotWSClientV1 - - - class Client(KrakenSpotWSClientV1): - - async def on_message(self, message): - print(message) - - - async def main(): - - client = Client() # unauthenticated - client_auth = Client( # authenticated - key="kraken-api-key", - secret="kraken-secret-key" - ) - - # subscribe to the desired feeds: - await client.subscribe( - subscription={"name": ticker}, - pair=["XBTUSD", "DOT/EUR"] - ) - # from now on the on_message function receives the ticker feed - - while not client.exception_occur: - await asyncio.sleep(6) - - if __name__ == "__main__": - try: - asyncio.run(main()) - except KeyboardInterrupt: - pass - - .. code-block:: python - :linenos: - :caption: HowTo: Use the websocket client (v1) as instance - - import asyncio - from kraken.spot import KrakenSpotWSClientV1 - - - async def main() -> None: - async def on_message(message) -> None: - print(message) - - client = KrakenSpotWSClientV1(callback=on_message) - await client.subscribe( - subscription={"name": "ticker"}, - pair=["XBT/USD"] - ) - - while not client.exception_occur: - await asyncio.sleep(10) - - - if __name__ == "__main__": - try: - asyncio.run(main()) - except KeyboardInterrupt: - pass - - - .. code-block:: python - :linenos: - :caption: HowTo: Use the websocket client (v1) as context manager - - import asyncio - from kraken.spot import KrakenSpotWSClientV1 - - async def on_message(message): - print(message) - - async def main() -> None: - async with KrakenSpotWSClientV1( - key="api-key", - secret="secret-key", - callback=on_message - ) as session: - await session.subscribe( - subscription={"name": "ticker"}, - pair=["XBT/USD"] - ) - - while True - await asyncio.sleep(6) - - - if __name__ == "__main__": - try: - asyncio.run(main()) - except KeyboardInterrupt: - pass - """ - - def __init__( - self: KrakenSpotWSClientV1, - key: str = "", - secret: str = "", - callback: Callable | None = None, - *, - no_public: bool = False, - beta: bool = False, - ) -> None: - warnings.warn( - "The Kraken websocket API v1 is marked as deprecated and " - "its support could be removed in the future. " - "Please migrate to websocket API v2.", - category=DeprecationWarning, - stacklevel=2, - ) - super().__init__( - key=key, - secret=secret, - callback=callback, - no_public=no_public, - beta=beta, - api_version="v1", - ) - - async def send_message( # pylint: disable=arguments-differ - self: KrakenSpotWSClientV1, - message: dict, - *, - private: bool = False, - raw: bool = False, - ) -> None: - """ - Sends a message via the websocket connection. For private messages the - authentication token will be assigned automatically if ``raw=False``. - - The user can specify a ``reqid`` within the message to identify - corresponding responses via websocket feed. - - :param message: The content to send - :type message: dict - :param private: Use authentication (default: ``False``) - :type private: bool, optional - :param raw: If set to ``True`` the ``message`` will be sent directly. - :type raw: bool, optional - """ - - if private and not self._is_auth: - raise KrakenAuthenticationError - - socket: Any = self._get_socket(private=private) - while not socket: - socket = self._get_socket(private=private) - await asyncio.sleep(0.4) - - if raw: - await socket.send(json.dumps(message)) - return - - if private and "subscription" in message: - message["subscription"]["token"] = self._priv_conn.ws_conn_details["token"] - elif private: - message["token"] = self._priv_conn.ws_conn_details["token"] - await socket.send(json.dumps(message)) - - async def subscribe( # pylint: disable=arguments-differ - self: KrakenSpotWSClientV1, - subscription: dict, - pair: list[str] | None = None, - ) -> None: - """ - Subscribe to a channel - - Success or failures are sent over the websocket connection and can be - received via the on_message callback function. - - When accessing private endpoints and subscription feeds that need - authentication make sure, that the ``Access WebSockets API`` API key - permission is set in the users Kraken account. - - - https://docs.kraken.com/websockets/#message-subscribe - - :param subscription: The subscription message - :type subscription: dict - :param pair: The pair to subscribe to - :type pair: list[str], optional - - Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV1` to run the following example: - - .. code-block:: python - :linenos: - :caption: Spot Websocket v1: Subscribe to a websocket feed - - >>> await client.subscribe( - ... subscription={"name": ticker}, - ... pair=["XBTUSD", "DOT/EUR"] - ... ) - """ - - if "name" not in subscription: - raise AttributeError('Subscription requires a "name" key."') - private: bool = bool(subscription["name"] in self.private_channel_names) - - payload: dict = {"event": "subscribe", "subscription": subscription} - if pair is not None: - if not isinstance(pair, list): - raise TypeError( - 'Parameter pair must be type of list[str] (e.g. pair=["XBTUSD"])', - ) - payload["pair"] = pair - - if private: # private == without pair - if not self._is_auth: - raise KrakenAuthenticationError( - "Cannot subscribe to private feeds without valid credentials!", - ) - if pair is not None: - raise ValueError( - "Cannot subscribe to private endpoint with specific pair!", - ) - await self.send_message(payload, private=True) - - elif pair is not None: # public with pair - for symbol in pair: - sub = deepcopy(payload) - sub["pair"] = [symbol] - await self.send_message(sub, private=False) - - else: - raise ValueError( - "At least one pair must be specified when subscribing to public feeds.", - ) - # Currently there is no possibility to public subscribe without a - # pair (July 2023). - # await self.send_message(payload, private=False) - - async def unsubscribe( # pylint: disable=arguments-differ - self: KrakenSpotWSClientV1, - subscription: dict, - pair: list[str] | None = None, - ) -> None: - """ - Unsubscribe from a feed - - Success or failures are sent via the websocket connection and can be - received via the on_message or callback function. - - When accessing private endpoints and subscription feeds that need - authentication make sure, that the ``Access WebSockets API`` API key - permission is set in the users Kraken account. - - - https://docs.kraken.com/websockets/#message-unsubscribe - - :param subscription: The subscription to unsubscribe from - :type subscription: dict - :param pair: The pair or list of pairs to unsubscribe - :type pair: list[str], optional - - Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV1` to run the following example: - - .. code-block:: python - :linenos: - :caption: Spot Websocket v1: Unsubscribe from a websocket feed - - >>> await client.unsubscribe( - ... subscription={"name": ticker}, - ... pair=["XBTUSD", "DOT/EUR"] - ... ) - """ - if "name" not in subscription: - raise AttributeError('Subscription requires a "name" key.') - private: bool = bool(subscription["name"] in self.private_channel_names) - - payload: dict = {"event": "unsubscribe", "subscription": subscription} - if pair is not None: - if not isinstance(pair, list): - raise TypeError( - 'Parameter pair must be type of list[str] (e.g. pair=["XBTUSD"])', - ) - payload["pair"] = pair - - if private: # private == without pair - if not self._is_auth: - raise KrakenAuthenticationError( - "Cannot unsubscribe from private feeds without valid credentials!", - ) - if pair is not None: - raise ValueError( - "Cannot unsubscribe from private endpoint with specific pair!", - ) - await self.send_message(payload, private=True) - - elif pair is not None: # public with pair - for symbol in pair: - sub = deepcopy(payload) - sub["pair"] = [symbol] - await self.send_message(sub, private=False) - - else: - raise ValueError( - "At least one pair must be specified when unsubscribing " - "from public feeds.", - ) - # Currently there is no possibility to public unsubscribe without a - # pair (July 2023). - # await self.send_message(payload, private=False) - - @property - def public_channel_names(self: KrakenSpotWSClientV1) -> list[str]: - """ - Returns the public subscription names - - :return: List of public subscription names (``ticker``, - ``spread``, ``book``, ``ohlc``, ``trade``, ``*``) - :rtype: list[str] - """ - return ["ticker", "spread", "book", "ohlc", "trade", "*"] - - @property - def private_channel_names(self: KrakenSpotWSClientV1) -> list[str]: - """ - Returns the private subscription names - - :return: List of private subscription names (``ownTrades``, - ``openOrders``) - :rtype: list[str] - """ - return ["ownTrades", "openOrders"] - - @ensure_string("oflags") - async def create_order( # pylint: disable=too-many-arguments # noqa: PLR0913, PLR0917 - self: KrakenSpotWSClientV1, - ordertype: str, - side: str, - pair: str, - volume: str | float, - price: str | float | None = None, - price2: str | float | None = None, - leverage: str | float | None = None, - oflags: str | list[str] | None = None, - starttm: str | int | None = None, - expiretm: str | int | None = None, - deadline: str | None = None, - userref: str | int | None = None, - close_ordertype: str | None = None, - close_price: str | float | None = None, - close_price2: str | float | None = None, - timeinforce: str | int | None = None, - *, - truncate: bool = False, - validate: bool = False, - ) -> None: - """ - Create an order and submit it. - - Requires the ``Access WebSockets API`` and ``Create and modify orders`` - API key permissions. - - - https://docs.kraken.com/websockets/#message-addOrder - - :param ordertype: The type of order, one of: ``limit``, ``market``, - ``stop-loss``, ``take-profit``, ``stop-loss-limit``, - ``settle-position``, ``take-profit-limit`` (see: - https://support.kraken.com/hc/en-us/sections/200577136-Order-types) - :type ordertype: str - :param side: The side - one of ``buy``, ``sell`` - :type side: str - :param pair: The asset pair to trade - :type pair: str - :param volume: The volume of the order that is being created - :type volume: str | float - :param price: The limit price for ``limit`` orders or the trigger price - for orders with ``ordertype`` one of ``stop-loss``, - ``stop-loss-limit``, ``take-profit``, and ``take-profit-limit`` - :type price: str | float, optional - :param price2: The second price for ``stop-loss-limit`` and - ``take-profit-limit`` orders (see the referenced Kraken - documentation for more information) - :type price2: str | float, optional - :param leverage: The leverage - :type leverage: str | float, optional - :param oflags: Order flags like ``post``, ``fcib``, ``fciq``, ``nomp``, - ``viqc`` (see the referenced Kraken documentation for more - information) - :type oflags: str | list[str], optional - :param starttm: Unix timestamp or seconds defining the start time - (default: ``"0"``) - :type starttm: str | int, optional - :param expiretim: Unix timestamp or time in seconds defining the - expiration of the order (default: ``"0"`` - i.e., no expiration) - :type expiretim: str - :param deadline: RFC3339 timestamp + {0..60} seconds that defines when - the matching engine should reject the order. - :type deadline: str - :param userref: User reference id for example to group orders - :type userref: int - :param close_ordertype: Conditional close order type, one of: - ``limit``, ``stop-loss``, ``take-profit``, ``stop-loss-limit``, - ``take-profit-limit`` - :type close_ordertype: str, optional - :param close_price: Conditional close price - :type close_price: str | float, optional - :param close_price2: Second conditional close price - :type close_price2: str | float, optional - :param timeinforce: How long the order remains in the orderbook, one of: - ``GTC``, ``IOC``, ``GTD`` (see the referenced Kraken documentation - for more information) - :type timeinforce: str, optional - :param truncate: If enabled: round the ``price`` and ``volume`` to - Kraken's maximum allowed decimal places. See - https://support.kraken.com/hc/en-us/articles/4521313131540 fore more - information about decimals. - :type truncate: bool, optional - :param validate: Validate the order without placing on the market - (default: ``False``) - :type validate: bool, optional - :raises KrakenAuthenticationError: If the websocket is not connected or - the connection is not authenticated - :raises ValueError: If input is not correct - - Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV1` to run the following example: - - .. code-block:: python - :linenos: - :caption: Spot Websocket: Create an order - - >>> await client_auth.create_order( - ... ordertype="market", - ... pair="XBTUSD", - ... side="buy", - ... volume=0.001 - ... ) - >>> await client_auth.create_order( - ... ordertype="limit", - ... side="buy", - ... pair="XBTUSD", - ... volume=0.02, - ... price=23000, - ... expiretm=120, - ... oflags=["post", "fcib"] - ... ) - - """ - if not self._priv_conn or not self._priv_conn.is_auth: - raise KrakenAuthenticationError( - "Can't place order - Authenticated websocket not connected!", - ) - - payload: dict = { - "event": "addOrder", - "ordertype": str(ordertype), - "type": str(side), - "pair": str(pair), - "volume": ( - str(volume) - if not truncate - else Trade().truncate(amount=volume, amount_type="volume", pair=pair) - ), - "validate": str(validate), - } - if defined(price): - payload["price"] = ( - str(price) - if not truncate - else Trade().truncate(amount=price, amount_type="price", pair=pair) - ) - if defined(price2): - payload["price2"] = str(price2) - if defined(oflags): - if not isinstance(oflags, str): - raise ValueError( - "oflags must be a comma delimited list of order flags as " - "str. Available flags: {viqc, fcib, fciq, nompp, post}", - ) - payload["oflags"] = oflags - if defined(starttm): - payload["starttm"] = str(starttm) - if defined(expiretm): - payload["expiretm"] = str(expiretm) - if defined(deadline): - payload["deadline"] = str(deadline) - if defined(userref): - payload["userref"] = str(userref) - if defined(leverage): - payload["leverage"] = str(leverage) - if defined(close_ordertype): - payload["close[ordertype]"] = close_ordertype - if defined(close_price): - payload["close[price]"] = str(close_price) - if defined(close_price2): - payload["close[price2]"] = str(close_price2) - if defined(timeinforce): - payload["timeinforce"] = timeinforce - - await self.send_message(message=payload, private=True) - - @ensure_string("oflags") - async def edit_order( # pylint: disable=too-many-arguments # noqa: PLR0913 - self: KrakenSpotWSClientV1, - orderid: str, - reqid: str | int | None = None, - pair: str | None = None, - price: str | float | None = None, - price2: str | float | None = None, - volume: str | float | None = None, - oflags: str | list[str] | None = None, - newuserref: str | int | None = None, - *, - truncate: bool = False, - validate: bool = False, - ) -> None: - """ - Edit an open order that was placed on the Spot market. - - Requires the ``Access WebSockets API`` and ``Create and modify orders`` - API key permissions. - - - https://docs.kraken.com/websockets/#message-editOrder - - :param orderId: The orderId of the order to edit - :type orderId: str - :param reqid: Filter by reqid - :type reqid: str | int, optional - :param pair: Filter by pair - :type pair: str, optional - :param price: Set a new price - :type price: str | int | float, optional - :param price2: Set a new second price - :type price2: str | int | float, optional - :param volume: Set a new volume - :type volume: str | int | float, optional - :param oflags: Set new oflags (overwrite old ones) - :type oflags: str | list[str], optional - :param newuserref: Set a new user reference id - :type newuserref: str | int, optional - :param truncate: If enabled: round the ``price`` and ``volume`` to - Kraken's maximum allowed decimal places. See - https://support.kraken.com/hc/en-us/articles/4521313131540 fore more - information about decimals. - :type truncate: bool, optional - :param validate: Validate the input without applying the changes - (default: ``False``) - :type validate: bool, optional - :raises KrakenAuthenticationError: If the websocket is not connected or - the connection is not authenticated - :raises ValueError: If input is not correct - - Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV1` to run the following example: - - .. code-block:: python - :linenos: - :caption: Spot Websocket: Edit an order - - >>> await client_auth.edit_order( - ... orderId="OBGFYP-XVQNL-P4GMWF", - ... volume=0.75, - ... pair="XBTUSD", - ... price=20000 - ... ) - """ - if not self._priv_conn or not self._priv_conn.is_auth: - raise KrakenAuthenticationError( - "Can't edit order - Authenticated websocket not connected!", - ) - - payload: dict = { - "event": "editOrder", - "orderid": orderid, - "validate": str(validate), - } - if defined(reqid): - payload["reqid"] = reqid - if defined(pair): - payload["pair"] = pair - if defined(price): - payload["price"] = ( - str(price) - if not truncate - else Trade().truncate(amount=price, amount_type="price", pair=pair) - ) - if defined(price2): - payload["price2"] = str(price2) - if defined(volume): - payload["volume"] = ( - str(volume) - if not truncate - else Trade().truncate(amount=volume, amount_type="volume", pair=pair) - ) - if defined(oflags): - payload["oflags"] = oflags - if defined(newuserref): - payload["newuserref"] = str(newuserref) - - await self.send_message(message=payload, private=True) - - async def cancel_order(self: KrakenSpotWSClientV1, txid: list[str]) -> None: - """ - Cancel a specific order or a list of orders. - - Requires the ``Access WebSockets API`` and ``Cancel/close orders`` API - key permissions. - - - https://docs.kraken.com/websockets/#message-cancelOrder - - :param txid: A single or multiple transaction ids as list - :type txid: list[str] - :raises KrakenAuthenticationError: If the websocket is not connected or - the connection is not authenticated - - Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV1` to run the following example: - - .. code-block:: python - :linenos: - :caption: Spot Websocket: Cancel an order - - >>> await client_auth.cancel_order(txid=["OBGFYP-XVQNL-P4GMWF"]) - """ - if not self._priv_conn or not self._priv_conn.is_auth: - raise KrakenAuthenticationError( - "Can't cancel order - Authenticated websocket not connected!", - ) - await self.send_message( - message={"event": "cancelOrder", "txid": txid}, - private=True, - ) - - async def cancel_all_orders(self: KrakenSpotWSClientV1) -> None: - """ - Cancel all open Spot orders. - - Requires the ``Access WebSockets API`` and ``Cancel/close orders`` API - key permissions. - - - https://docs.kraken.com/websockets/#message-cancelAll - - :raises KrakenAuthenticationError: If the websocket is not connected or - the connection is not authenticated - - Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV1` to run the following example: - - .. code-block:: python - :linenos: - :caption: Spot Websocket: Cancel all Orders - - >>> await client_auth.cancel_all_orders() - """ - if not self._priv_conn or not self._priv_conn.is_auth: - raise KrakenAuthenticationError( - "Can't cancel all orders - Authenticated websocket not connected!", - ) - await self.send_message(message={"event": "cancelAll"}, private=True) - - async def cancel_all_orders_after( - self: KrakenSpotWSClientV1, - timeout: int = 0, - ) -> None: - """ - Set a Death Man's Switch - - Requires the ``Access WebSockets API`` and ``Cancel/close orders`` API - key permissions. - - - https://docs.kraken.com/websockets/#message-cancelAllOrdersAfter - - :param timeout: Set the timeout in seconds to cancel the orders after, - set to ``0`` to reset. - :type timeout: int - :raises KrakenAuthenticationError: If the websocket is not connected or - the connection is not authenticated - - Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV1` to run the following example: - - .. code-block:: python - :linenos: - :caption: Spot Websocket: Death Man's Switch - - >>> await client_auth.cancel_all_orders_after(timeout=60) - """ - if not self._priv_conn or not self._priv_conn.is_auth: - raise KrakenAuthenticationError( - "Can't cancel all orders after - Authenticated websocket not connected!", - ) - await self.send_message( - message={"event": "cancelAllOrdersAfter", "timeout": timeout}, - private=True, - ) - - -__all__ = ["KrakenSpotWSClientV1"] diff --git a/kraken/spot/websocket_v2.py b/kraken/spot/ws_client.py similarity index 87% rename from kraken/spot/websocket_v2.py rename to kraken/spot/ws_client.py index 14f7f117..6b69c7f4 100644 --- a/kraken/spot/websocket_v2.py +++ b/kraken/spot/ws_client.py @@ -4,7 +4,7 @@ # """ -This module provides the Spot websocket client (Websocket API V2 as +This module provides the Spot websocket client (Websocket API as documented in - https://docs.kraken.com/websockets-v2). """ @@ -16,13 +16,13 @@ from kraken.base_api import defined from kraken.exceptions import KrakenAuthenticationError -from kraken.spot.websocket import KrakenSpotWSClientBase +from kraken.spot.websocket import SpotWSClientBase if TYPE_CHECKING: from collections.abc import Callable -class KrakenSpotWSClientV2(KrakenSpotWSClientBase): +class SpotWSClient(SpotWSClientBase): """ **This client only supports the Kraken Websocket API v2.** @@ -30,13 +30,10 @@ class KrakenSpotWSClientV2(KrakenSpotWSClientBase): - https://docs.kraken.com/websockets-v2 - â€Ļ please use :class:`kraken.spot.KrakenSpotWSClientV1` for accessing the - Kraken's Websocket API v1. - This class holds up to two websocket connections, one private and one public. The core functionalities are un-/subscribing to websocket feeds and - sending messages. See :func:`kraken.spot.KrakenSpotWSClientV2.subscribe` and - :func:`kraken.spot.KrakenSpotWSClientV2.send_message` for more information. + sending messages. See :func:`kraken.spot.SpotWSClient.subscribe` and + :func:`kraken.spot.SpotWSClientV.send_message` for more information. When accessing private endpoints that need authentication make sure, that the ``Access WebSockets API`` API key permission is set in the user's @@ -60,25 +57,27 @@ class KrakenSpotWSClientV2(KrakenSpotWSClientBase): .. code-block:: python :linenos: - :caption: HowTo: Use the Kraken Spot websocket client (v2) + :caption: HowTo: Use the Kraken Spot websocket client import asyncio - from kraken.spot import KrakenSpotWSClientV2 + from kraken.spot import SpotWSClient - class Client(KrakenSpotWSClientV2): + class Client(SpotWSClient): async def on_message(self, message): print(message) async def main(): - client = Client() # unauthenticated client_auth = Client( # authenticated key="kraken-api-key", secret="kraken-secret-key" ) + # open the websocket connections + await client.start() + await auth_client.start() # subscribe to the desired feeds: await client.subscribe( @@ -97,17 +96,19 @@ async def main(): .. code-block:: python :linenos: - :caption: HowTo: Use the websocket client (v2) as instance + :caption: HowTo: Use the websocket client as instance import asyncio - from kraken.spot import KrakenSpotWSClientV2 + from kraken.spot import SpotWSClient + + async def on_message(message): + print(message) async def main(): - async def on_message(message): - print(message) - client = KrakenSpotWSClientV2(callback=on_message) + client = SpotWSClient(callback=on_message) + await client.start() await client.subscribe( params={"channel": "ticker", "symbol": ["BTC/USD"]} ) @@ -125,16 +126,16 @@ async def on_message(message): .. code-block:: python :linenos: - :caption: HowTo: Use the websocket client (v2) as context manager + :caption: HowTo: Use the websocket client as context manager import asyncio - from kraken.spot import KrakenSpotWSClientV2 + from kraken.spot import SpotWSClient async def on_message(message): print(message) async def main(): - async with KrakenSpotWSClientV2( + async with SpotWSClient( key="api-key", secret="secret-key", callback=on_message @@ -155,25 +156,22 @@ async def main(): """ def __init__( - self: KrakenSpotWSClientV2, + self: SpotWSClient, key: str = "", secret: str = "", callback: Callable | None = None, *, no_public: bool = False, - beta: bool = False, ) -> None: super().__init__( key=key, secret=secret, callback=callback, no_public=no_public, - beta=beta, - api_version="v2", ) async def send_message( # pylint: disable=arguments-differ - self: KrakenSpotWSClientV2, + self: SpotWSClient, message: dict, *, raw: bool = False, @@ -192,9 +190,9 @@ async def send_message( # pylint: disable=arguments-differ :type raw: bool, optional The following examples demonstrate how to use the - :func:`kraken.spot.KrakenSpotWSClientV2.send_message` function. The + :func:`kraken.spot.SpotWSClient.send_message` function. The client must be instantiated as described in - :class:`kraken.spot.KrakenSpotWSClientV2` where ``client`` uses + :class:`kraken.spot.SpotWSClient` where ``client`` uses public connections (without authentication) and ``client_auth`` must be instantiated using valid credentials since only this way placing or canceling orders can be done. @@ -210,7 +208,7 @@ async def send_message( # pylint: disable=arguments-differ .. code-block:: python :linenos: - :caption: Spot Websocket v2: Place a new order + :caption: Spot Websocket: Place a new order >>> await client_auth.send_message( ... message={ @@ -232,7 +230,7 @@ async def send_message( # pylint: disable=arguments-differ .. code-block:: python :linenos: - :caption: Spot Websocket v2: Placing orders as batch + :caption: Spot Websocket: Placing orders as batch >>> await client_auth.send_message( ... message={ @@ -267,7 +265,7 @@ async def send_message( # pylint: disable=arguments-differ .. code-block:: python :linenos: - :caption: Spot Websocket v2: Cancel orders as batch + :caption: Spot Websocket: Cancel orders as batch >>> await client_auth.send_message( ... message={ @@ -288,7 +286,7 @@ async def send_message( # pylint: disable=arguments-differ .. code-block:: python :linenos: - :caption: Spot Websocket v2: Cancel all orders + :caption: Spot Websocket: Cancel all orders >>> await client_auth.send_message( ... message={ @@ -297,14 +295,14 @@ async def send_message( # pylint: disable=arguments-differ ... ) **Death Man's Switch** is a useful utility to reduce the risk of losses - due to network fuckups since it will cancel all orders if the call + due to network fuck-ups since it will cancel all orders if the call was not received by Kraken within a certain amount of time. See https://docs.kraken.com/websockets-v2/#cancel-all-orders-after for more information. .. code-block:: python :linenos: - :caption: Spot Websocket v2: Death Man's Switch / cancel_all_orders_after + :caption: Spot Websocket: Death Man's Switch / cancel_all_orders_after >>> await client_auth.send_message( ... message={ @@ -318,7 +316,7 @@ async def send_message( # pylint: disable=arguments-differ .. code-block:: python :linenos: - :caption: Spot Websocket v2: Cancel order(s) + :caption: Spot Websocket: Cancel order(s) >>> await client_auth.send_message( ... message={ @@ -334,7 +332,7 @@ async def send_message( # pylint: disable=arguments-differ .. code-block:: python :linenos: - :caption: Spot Websocket v2: Cancel order(s) + :caption: Spot Websocket: Cancel order(s) >>> await client_auth.send_message( ... message={ @@ -349,11 +347,11 @@ async def send_message( # pylint: disable=arguments-differ **Subscribing** to websocket feeds can be done using the send_message function but it is recommended to use - :func:`kraken.spot.KrakenSpotWSClientV2.subscribe` instead. + :func:`kraken.spot.SpotWSClient.subscribe` instead. .. code-block:: python :linenos: - :caption: Spot Websocket v2: Subscribe to a websocket feed + :caption: Spot Websocket: Subscribe to a websocket feed >>> await client.send_message( ... message={ @@ -424,7 +422,7 @@ async def send_message( # pylint: disable=arguments-differ await socket.send(json.dumps(message)) async def subscribe( # pylint: disable=arguments-differ - self: KrakenSpotWSClientV2, + self: SpotWSClient, params: dict, req_id: int | None = None, ) -> None: @@ -453,11 +451,11 @@ async def subscribe( # pylint: disable=arguments-differ :type req_id: int, optional Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV2` to run the following example: + :class:`kraken.spot.SpotWSClient` to run the following example: .. code-block:: python :linenos: - :caption: Spot Websocket v2: Subscribe to a websocket feed + :caption: Spot Websocket: Subscribe to a websocket feed >>> await client.subscribe( ... params={"channel": "ticker", "symbol": ["BTC/USD"]} @@ -473,7 +471,7 @@ async def subscribe( # pylint: disable=arguments-differ await self.send_message(message=payload) async def unsubscribe( # pylint: disable=arguments-differ - self: KrakenSpotWSClientV2, + self: SpotWSClient, params: dict, req_id: int | None = None, ) -> None: @@ -489,15 +487,15 @@ async def unsubscribe( # pylint: disable=arguments-differ - https://docs.kraken.com/websockets-v2/#unsubscribe - :param params: The unsubscription message (only the params part) + :param params: The un-subscription message (only the params part) :type params: dict Initialize your client as described in - :class:`kraken.spot.KrakenSpotWSClientV2` to run the following example: + :class:`kraken.spot.SpotWSClient` to run the following example: .. code-block:: python :linenos: - :caption: Spot Websocket v2: Unsubscribe from a websocket feed + :caption: Spot Websocket: Unsubscribe from a websocket feed >>> await client.unsubscribe( ... params={"channel": "ticker", "symbol": ["BTC/USD"]} @@ -512,7 +510,7 @@ async def unsubscribe( # pylint: disable=arguments-differ await self.send_message(message=payload) @property - def public_channel_names(self: KrakenSpotWSClientV2) -> list[str]: + def public_channel_names(self: SpotWSClient) -> list[str]: """ Returns the list of valid values for ``channel`` when un-/subscribing from/to public feeds without authentication. @@ -533,7 +531,7 @@ def public_channel_names(self: KrakenSpotWSClientV2) -> list[str]: return ["book", "instrument", "ohlc", "ticker", "trade"] @property - def private_channel_names(self: KrakenSpotWSClientV2) -> list[str]: + def private_channel_names(self: SpotWSClient) -> list[str]: """ Returns the list of valid values for ``channel`` when un-/subscribing from/to private feeds that need authentication. @@ -550,7 +548,7 @@ def private_channel_names(self: KrakenSpotWSClientV2) -> list[str]: return ["executions", "balances"] @property - def private_methods(self: KrakenSpotWSClientV2) -> list[str]: + def private_methods(self: SpotWSClient) -> list[str]: """ Returns the list of available methods - parameters are similar to the REST API trade methods. @@ -580,4 +578,4 @@ def private_methods(self: KrakenSpotWSClientV2) -> list[str]: ] -__all__ = ["KrakenSpotWSClientV2"] +__all__ = ["SpotWSClient"] diff --git a/pyproject.toml b/pyproject.toml index 862ba860..c358a984 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ dependencies = [ "click", "cloup", "orjson", + "aiohttp", ] keywords = ["crypto", "trading", "kraken", "exchange", "api"] classifiers = [ @@ -56,12 +57,15 @@ kraken = "kraken.cli:cli" [project.optional-dependencies] dev = [ + "debugpy", # building "build", # documentation "sphinx", + "sphinx-click", "sphinx-rtd-theme", "nbsphinx", + "ipython", # to visualize notebooks in doc # formatting "black", # typing @@ -95,9 +99,9 @@ junit_family = "xunit2" testpaths = ["tests"] [tool.pytest.ini_options] -filterwarnings = [ - "ignore:The Kraken websocket API v1 is marked as deprecated*:DeprecationWarning", -] +# filterwarnings = [ +# "ignore:The Kraken websocket API v1 is marked as deprecated*:DeprecationWarning", +# ] cache_dir = ".cache/pytest" markers = [ @@ -110,10 +114,7 @@ markers = [ "spot_user: â€Ļ Spot User endpoint.", "spot_market: â€Ļ Spot Market endpoint.", "spot_funding: â€Ļ Spot Funding endpoint.", - "spot_staking: â€Ļ Spot Staking endpoint.", - "spot_websocket: â€Ļ Spot Websocket clients (v1 + v2) + Spot Orderbook client.", - "spot_websocket_v1: â€Ļ Spot Websocket client v1.", - "spot_websocket_v2: â€Ļ Spot Websocket client v2.", + "spot_websocket: â€Ļ Spot Websocket client + Spot Orderbook client.", "spot_orderbook: â€Ļ Spot Orderbook client.", "futures: â€Ļ Futures endpoint.", "futures_auth: â€Ļ authenticated Futures endpoint.", @@ -139,7 +140,6 @@ skip_empty = true skip = "CHANGELOG.md,examples/market_client_example.ipynb,doc/examples/market_client_example.ipynb" check-filenames = true - # ========= T Y P I N G ======================================================== # [tool.mypy] @@ -161,7 +161,7 @@ disallow_any_explicit = false disallow_any_generics = false disallow_subclassing_any = false -# # Untyped definitions and calls +# Untyped definitions and calls check_untyped_defs = true disallow_untyped_calls = true disallow_untyped_defs = true @@ -303,7 +303,7 @@ ignore = [ "RUF022", # `__all__` is not sorted ] -task-tags = ["todo", "TODO"] +task-tags = ["todo", "TODO", "fixme", "FIXME"] [tool.ruff.lint.per-file-ignores] "examples/*.py" = [ @@ -313,9 +313,6 @@ task-tags = ["todo", "TODO"] "S110", # try-catch-pass without logging "T201", # print ] -"examples/spot_trading_bot_template_v2.py" = [ - "RUF027", # Possible f-string without an `f` prefix -] "tests/*.py" = [ "ASYNC101", # no open call on async function "E501", # line to long @@ -456,7 +453,7 @@ ignore-patterns = ["^\\.#"] # Use multiple processes to speed up PyLint. Specifying 0 will auto-detect the # number of processors available to use, and will cap the count on Windows to # avoid hangs. -jobs = 2 +jobs = 0 # Control the amount of potential inferred values when inferring a single object. # This can help the performance when dealing with large functions or complex, diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index cfff85a6..00000000 --- a/requirements.txt +++ /dev/null @@ -1,3 +0,0 @@ -asyncio>=3.4 -requests -websockets diff --git a/tests/cli/__init__.py b/tests/cli/__init__.py new file mode 100644 index 00000000..057aad23 --- /dev/null +++ b/tests/cli/__init__.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python +# Copyright (C) 2024 Benjamin Thomas Schwertfeger +# GitHub: https://github.com/btschwertfeger +# +# This file is required for collecting coverage information. diff --git a/tests/futures/conftest.py b/tests/futures/conftest.py index dd4638f9..9356298e 100644 --- a/tests/futures/conftest.py +++ b/tests/futures/conftest.py @@ -13,7 +13,6 @@ FUTURES_SECRET_KEY: str = os.getenv("FUTURES_SECRET_KEY") FUTURES_SANDBOX_KEY: str = os.getenv("FUTURES_SANDBOX_KEY") FUTURES_SANDBOX_SECRET_KEY: str = os.getenv("FUTURES_SANDBOX_SECRET") - FUTURES_EXTENDED_TIMEOUT: int = 30 diff --git a/tests/futures/helper.py b/tests/futures/helper.py index 9d2b30dd..02101857 100644 --- a/tests/futures/helper.py +++ b/tests/futures/helper.py @@ -6,11 +6,9 @@ from __future__ import annotations import logging -from asyncio import sleep from pathlib import Path -from time import time -from kraken.futures import KrakenFuturesWSClient +from kraken.futures import FuturesWSClient CACHE_DIR: Path = Path(__file__).resolve().parent.parent.parent / ".cache" / "tests" CACHE_DIR.mkdir(parents=True, exist_ok=True) @@ -32,16 +30,9 @@ def is_not_error( return isinstance(value, dict) and "error" not in value -async def async_wait(seconds: float = 1.0) -> None: - """Function that realizes the wait for ``seconds``.""" - start: float = time() - while time() - seconds < start: - await sleep(0.2) - - -class FuturesWebsocketClientTestWrapper(KrakenFuturesWSClient): +class FuturesWebsocketClientTestWrapper(FuturesWSClient): """ - Class that creates an instance to test the KrakenFuturesWSClient. + Class that creates an instance to test the FuturesWSClient. It writes the messages to the log and a file. The log is used within the tests, the log file is for local debugging. diff --git a/tests/futures/test_futures_base_api.py b/tests/futures/test_futures_base_api.py index bdbdc803..d287b44c 100644 --- a/tests/futures/test_futures_base_api.py +++ b/tests/futures/test_futures_base_api.py @@ -5,9 +5,11 @@ """Module that checks the general Futures Base API class.""" +from asyncio import run + import pytest -from kraken.base_api import KrakenFuturesBaseAPI +from kraken.base_api import FuturesAsyncClient, FuturesClient from kraken.exceptions import KrakenRequiredArgumentMissingError from kraken.futures import Funding, Market, Trade, User @@ -23,14 +25,14 @@ def test_KrakenFuturesBaseAPI_without_exception() -> None: the same request and the returned response gets evaluated. """ with pytest.raises(KrakenRequiredArgumentMissingError): - KrakenFuturesBaseAPI( + FuturesClient( key="fake", secret="fake", - )._request(method="POST", uri="/derivatives/api/v3/sendorder", auth=True) + ).request(method="POST", uri="/derivatives/api/v3/sendorder", auth=True) result: dict = ( - KrakenFuturesBaseAPI(key="fake", secret="fake", use_custom_exceptions=False) # type: ignore[union-attr] - ._request(method="POST", uri="/derivatives/api/v3/sendorder", auth=True) + FuturesClient(key="fake", secret="fake", use_custom_exceptions=False) # type: ignore[union-attr] + .request(method="POST", uri="/derivatives/api/v3/sendorder", auth=True) .json() ) @@ -60,3 +62,60 @@ def test_futures_rest_contextmanager( with futures_demo_trade as trade: assert is_success(trade.get_fills()) + + +# ============================================================================== +# Futures async client + + +@pytest.mark.futures() +def test_futures_async_rest_contextmanager() -> None: + """ + Checks if the clients can be used as context manager. + """ + + async def check() -> None: + async with FuturesAsyncClient() as client: + assert isinstance( + await client.request( + "GET", + "/api/charts/v1/spot/PI_XBTUSD/1h", + auth=False, + post_params={"from": "1668989233", "to": "1668999233"}, + ), + dict, + ) + + run(check()) + + +@pytest.mark.futures() +@pytest.mark.futures_auth() +def test_futures_rest_async_client_post( + futures_api_key: str, + futures_secret_key: str, +) -> None: + """ + Check the instantiation as well as a simple request using the async client. + """ + + async def check() -> None: + client = FuturesAsyncClient(futures_api_key, futures_secret_key) + try: + assert isinstance( + await client.request( + "POST", + "/derivatives/api/v3/orders/status", + post_params={ + "orderIds": [ + "bcaaefce-27a3-44b4-b13a-19df21e3f087", + "685d5a1a-23eb-450c-bf17-1e4ab5c6fe8a", + ], + }, + ), + dict, + ) + finally: + await client.async_close() + + run(check()) diff --git a/tests/futures/test_futures_websocket.py b/tests/futures/test_futures_websocket.py index 073645b2..dff65107 100644 --- a/tests/futures/test_futures_websocket.py +++ b/tests/futures/test_futures_websocket.py @@ -14,9 +14,11 @@ if TYPE_CHECKING: from pytest_mock import MockerFixture +from asyncio import sleep as async_sleep + import pytest -from .helper import FuturesWebsocketClientTestWrapper, async_wait +from .helper import FuturesWebsocketClientTestWrapper @pytest.mark.futures() @@ -28,10 +30,12 @@ def test_create_public_client(caplog: pytest.LogCaptureFixture) -> None: """ async def instantiate_client() -> None: - client: FuturesWebsocketClientTestWrapper = FuturesWebsocketClientTestWrapper() - await async_wait(5) - + client = FuturesWebsocketClientTestWrapper() + await client.start() + await async_sleep(4) assert not client.is_auth + await client.stop() + await async_sleep(2) asyncio.run(instantiate_client()) @@ -52,12 +56,12 @@ def test_create_private_client( """ async def instantiate_client() -> None: - client: FuturesWebsocketClientTestWrapper = FuturesWebsocketClientTestWrapper( + async with FuturesWebsocketClientTestWrapper( key=futures_api_key, secret=futures_secret_key, - ) - assert client.is_auth - await async_wait(5) + ) as client: + assert client.is_auth + await async_sleep(4) asyncio.run(instantiate_client()) @@ -116,26 +120,25 @@ def test_subscribe_public(caplog: pytest.LogCaptureFixture) -> None: """ async def check_subscription() -> None: - client: FuturesWebsocketClientTestWrapper = FuturesWebsocketClientTestWrapper() - await async_wait(2) - - with pytest.raises( - TypeError, - match=r"Parameter products must be type of list\[str\] \(e.g. products=\[\"PI_XBTUSD\"\]\)", - ): - await client.subscribe(feed="ticker", products="PI_XBTUSD") # type: ignore[arg-type] - - await client.subscribe(feed="ticker", products=["PI_XBTUSD", "PF_SOLUSD"]) - await async_wait(seconds=2) - - subs: list[dict] = client.get_active_subscriptions() - assert isinstance(subs, list) - - expected_subscriptions: list[dict] = [ - {"event": "subscribe", "feed": "ticker", "product_ids": ["PI_XBTUSD"]}, - {"event": "subscribe", "feed": "ticker", "product_ids": ["PF_SOLUSD"]}, - ] - assert all(sub in subs for sub in expected_subscriptions) + async with FuturesWebsocketClientTestWrapper() as client: + with pytest.raises( + TypeError, + match=r"Parameter products must be type of list\[str\] \(e.g. products=\[\"PI_XBTUSD\"\]\)", + ): + await client.subscribe(feed="ticker", products="PI_XBTUSD") # type: ignore[arg-type] + + async with FuturesWebsocketClientTestWrapper() as client: + await client.subscribe(feed="ticker", products=["PI_XBTUSD", "PF_SOLUSD"]) + await async_sleep(2) + + subs: list[dict] = client.get_active_subscriptions() + assert isinstance(subs, list) + + expected_subscriptions: list[dict] = [ + {"event": "subscribe", "feed": "ticker", "product_ids": ["PI_XBTUSD"]}, + {"event": "subscribe", "feed": "ticker", "product_ids": ["PF_SOLUSD"]}, + ] + assert all(sub in subs for sub in expected_subscriptions) asyncio.run(check_subscription()) @@ -160,22 +163,26 @@ def test_subscribe_private( """ async def submit_subscription() -> None: - client: FuturesWebsocketClientTestWrapper = FuturesWebsocketClientTestWrapper( + async with FuturesWebsocketClientTestWrapper( key=futures_api_key, secret=futures_secret_key, - ) + ) as client: - with pytest.raises( - ValueError, - match=r"There is no private feed that accepts products!", - ): - await client.subscribe(feed="fills", products=["PI_XBTUSD"]) + with pytest.raises( + ValueError, + match=r"There is no private feed that accepts products!", + ): + await client.subscribe(feed="fills", products=["PI_XBTUSD"]) - await client.subscribe(feed="open_orders") - await async_wait(seconds=2) + async with FuturesWebsocketClientTestWrapper( + key=futures_api_key, + secret=futures_secret_key, + ) as client: + + await client.subscribe(feed="open_orders") + await async_sleep(2) - assert len(client.get_active_subscriptions()) == 1 - await async_wait(seconds=1) + assert len(client.get_active_subscriptions()) == 1 asyncio.run(submit_subscription()) @@ -195,20 +202,22 @@ def test_unsubscribe_public(caplog: pytest.LogCaptureFixture) -> None: """ async def execute_unsubscribe() -> None: - client: FuturesWebsocketClientTestWrapper = FuturesWebsocketClientTestWrapper() products: list[str] = ["PI_XBTUSD", "PF_SOLUSD"] + async with FuturesWebsocketClientTestWrapper() as client: - await client.subscribe(feed="ticker", products=products) - await async_wait(seconds=2) + await client.subscribe(feed="ticker", products=products) + await async_sleep(2) - with pytest.raises( - TypeError, - match=r"Parameter products must be type of list\[str\]", - ): - await client.unsubscribe(feed="ticker", products="PI_XBTUSD") # type: ignore[arg-type] + await client.unsubscribe(feed="ticker", products=products) + await async_sleep(2) # need to get the message before error - await client.unsubscribe(feed="ticker", products=products) - await async_wait(seconds=2) + with pytest.raises( + TypeError, + match=r"Parameter products must be type of list\[str\]", + ): + await client.unsubscribe(feed="ticker", products="PI_XBTUSD") # type: ignore[arg-type] + + await async_sleep(4) asyncio.run(execute_unsubscribe()) @@ -235,21 +244,22 @@ def test_unsubscribe_private( """ async def execute_unsubscribe() -> None: - client: FuturesWebsocketClientTestWrapper = FuturesWebsocketClientTestWrapper( + async with FuturesWebsocketClientTestWrapper( key=futures_api_key, secret=futures_secret_key, - ) - await client.subscribe(feed="open_orders") + ) as client: + await client.subscribe(feed="open_orders") + + await async_sleep(2) + await client.unsubscribe(feed="open_orders") - await async_wait(seconds=2) - with pytest.raises( - ValueError, - match=r"There is no private feed that accepts products!", - ): - await client.unsubscribe(feed="open_orders", products=["PI_XBTUSD"]) + with pytest.raises( + ValueError, + match=r"There is no private feed that accepts products!", + ): + await client.unsubscribe(feed="open_orders", products=["PI_XBTUSD"]) - await client.unsubscribe(feed="open_orders") - await async_wait(seconds=2) + await async_sleep(2) asyncio.run(execute_unsubscribe()) @@ -268,17 +278,16 @@ def test_get_active_subscriptions(caplog: pytest.LogCaptureFixture) -> None: """ async def check_subscriptions() -> None: - client: FuturesWebsocketClientTestWrapper = FuturesWebsocketClientTestWrapper() - assert client.get_active_subscriptions() == [] - await async_wait(seconds=1) + async with FuturesWebsocketClientTestWrapper() as client: + assert client.get_active_subscriptions() == [] - await client.subscribe(feed="ticker", products=["PI_XBTUSD"]) - await async_wait(seconds=1) - assert len(client.get_active_subscriptions()) == 1 + await client.subscribe(feed="ticker", products=["PI_XBTUSD"]) + await async_sleep(1) + assert len(client.get_active_subscriptions()) == 1 - await client.unsubscribe(feed="ticker", products=["PI_XBTUSD"]) - await async_wait(seconds=1) - assert client.get_active_subscriptions() == [] + await client.unsubscribe(feed="ticker", products=["PI_XBTUSD"]) + await async_sleep(1) + assert client.get_active_subscriptions() == [] asyncio.run(check_subscriptions()) @@ -305,27 +314,27 @@ def test_resubscribe( caplog.set_level(logging.INFO) async def check_resubscribe() -> None: - client: FuturesWebsocketClientTestWrapper = FuturesWebsocketClientTestWrapper( + async with FuturesWebsocketClientTestWrapper( key=futures_api_key, secret=futures_secret_key, - ) + ) as client: - assert client.get_active_subscriptions() == [] - await async_wait(seconds=1) + assert client.get_active_subscriptions() == [] + await async_sleep(1) - await client.subscribe(feed="open_orders") - await async_wait(seconds=2) - assert len(client.get_active_subscriptions()) == 1 + await client.subscribe(feed="open_orders") + await async_sleep(2) + assert len(client.get_active_subscriptions()) == 1 - mocker.patch.object( - client._conn, - "_ConnectFuturesWebsocket__get_reconnect_wait", - return_value=2, - ) + mocker.patch.object( + client._conn, + "_ConnectFuturesWebsocket__get_reconnect_wait", + return_value=2, + ) - await client._conn.close_connection() - await async_wait(seconds=5) - assert len(client.get_active_subscriptions()) == 1 + await client._conn.close_connection() + await async_sleep(5) + assert len(client.get_active_subscriptions()) == 1 asyncio.run(check_resubscribe()) for phrase in ( diff --git a/tests/nft/__init__.py b/tests/nft/__init__.py index bc8e830d..057aad23 100644 --- a/tests/nft/__init__.py +++ b/tests/nft/__init__.py @@ -1,3 +1,5 @@ #!/usr/bin/env python # Copyright (C) 2024 Benjamin Thomas Schwertfeger # GitHub: https://github.com/btschwertfeger +# +# This file is required for collecting coverage information. diff --git a/tests/spot/__init__.py b/tests/spot/__init__.py index a7c2bce3..fe5cedeb 100644 --- a/tests/spot/__init__.py +++ b/tests/spot/__init__.py @@ -2,4 +2,4 @@ # Copyright (C) 2023 Benjamin Thomas Schwertfeger # GitHub: https://github.com/btschwertfeger # -# This file is required for the CI/CD codecov workflow. +# This file is required for collecting coverage information. diff --git a/tests/spot/conftest.py b/tests/spot/conftest.py index fa5de928..0189c396 100644 --- a/tests/spot/conftest.py +++ b/tests/spot/conftest.py @@ -11,7 +11,7 @@ import pytest -from kraken.spot import Earn, Funding, Market, Staking, Trade, User +from kraken.spot import Earn, Funding, Market, Trade, User SPOT_API_KEY: str = os.getenv("SPOT_API_KEY") SPOT_SECRET_KEY: str = os.getenv("SPOT_SECRET_KEY") @@ -92,11 +92,3 @@ def spot_auth_funding() -> Funding: Fixture providing an authenticated Spot funding client. """ return Funding(key=SPOT_API_KEY, secret=SPOT_SECRET_KEY) - - -@pytest.fixture() -def spot_auth_staking() -> Staking: - """ - Fixture providing an authenticated Spot staking client. - """ - return Staking(key=SPOT_API_KEY, secret=SPOT_SECRET_KEY) diff --git a/tests/spot/helper.py b/tests/spot/helper.py index 89d2cc2d..5f0caaca 100644 --- a/tests/spot/helper.py +++ b/tests/spot/helper.py @@ -4,7 +4,7 @@ # """ -Module that implements the unit tests for the Kraken Spot Websocket API v1 +Module that implements the unit tests for the Kraken Spot Websocket API v2 client. """ @@ -12,16 +12,9 @@ import json import logging -from asyncio import sleep from pathlib import Path -from time import time -from kraken.spot import ( - KrakenSpotWSClientV1, - KrakenSpotWSClientV2, - OrderbookClientV1, - OrderbookClientV2, -) +from kraken.spot import SpotOrderBookClient, SpotWSClient FIXTURE_DIR: Path = Path(__file__).resolve().parent / "fixture" CACHE_DIR: Path = Path(__file__).resolve().parent.parent.parent / ".cache" / "tests" @@ -35,48 +28,9 @@ def is_not_error( return isinstance(value, dict) and "error" not in value -async def async_wait(seconds: float = 1.0) -> None: - """Function that waits for ``seconds`` - asynchronous.""" - start: float = time() - while time() - seconds < start: - await sleep(0.2) - - -class SpotWebsocketClientV1TestWrapper(KrakenSpotWSClientV1): - """ - Class that creates an instance to test the KrakenSpotWSClientV1. - - It writes the messages to the log and a file. The log is used - within the tests, the log file is for local debugging. - """ - - LOG: logging.Logger = logging.getLogger(__name__) - - def __init__( - self: SpotWebsocketClientV1TestWrapper, - key: str = "", - secret: str = "", - ) -> None: - super().__init__(key=key, secret=secret, callback=self.on_message) - self.LOG.setLevel(logging.INFO) - fh = logging.FileHandler(filename=CACHE_DIR / "spot_ws-v1.log", mode="a") - fh.setLevel(logging.INFO) - self.LOG.addHandler(fh) - - async def on_message( - self: SpotWebsocketClientV1TestWrapper, - message: list | dict, - ) -> None: - """ - This is the callback function that must be implemented - to handle custom websocket messages. - """ - self.LOG.info(message) # the log is read within the tests - - -class SpotWebsocketClientV2TestWrapper(KrakenSpotWSClientV2): +class SpotWebsocketClientTestWrapper(SpotWSClient): """ - Class that creates an instance to test the KrakenSpotWSClientV2. + Class that creates an instance to test the SpotWSClient. It writes the messages to the log and a file. The log is used within the tests, the log file is for local debugging. @@ -85,7 +39,7 @@ class SpotWebsocketClientV2TestWrapper(KrakenSpotWSClientV2): LOG: logging.Logger = logging.getLogger(__name__) def __init__( - self: SpotWebsocketClientV2TestWrapper, + self: SpotWebsocketClientTestWrapper, key: str = "", secret: str = "", **kwargs: dict | str | float | bool | None, @@ -96,7 +50,7 @@ def __init__( fh.setLevel(logging.INFO) self.LOG.addHandler(fh) - async def on_message(self: SpotWebsocketClientV2TestWrapper, message: dict) -> None: + async def on_message(self: SpotWebsocketClientTestWrapper, message: dict) -> None: """ This is the callback function that must be implemented to handle custom websocket messages. @@ -104,67 +58,9 @@ async def on_message(self: SpotWebsocketClientV2TestWrapper, message: dict) -> N self.LOG.info(json.dumps(message)) # the log is read within the tests -class OrderbookClientV1Wrapper(OrderbookClientV1): - """ - This class is used for testing the Spot OrderbookClientV1. - - It writes the messages to the log and a file. The log is used - within the tests, the log file is for local debugging. - """ - - LOG: logging.Logger = logging.getLogger(__name__) - - def __init__(self: OrderbookClientV1Wrapper) -> None: - super().__init__() - self.LOG.setLevel(logging.INFO) - - async def on_message( - self: OrderbookClientV1Wrapper, - message: list | dict, - ) -> None: - self.ensure_log(message) - await super().on_message(message=message) - - async def on_book_update( - self: OrderbookClientV1Wrapper, - pair: str, - message: list, - ) -> None: - """ - This is the callback function that must be implemented - to handle custom websocket messages. - """ - self.ensure_log((pair, message)) - - @classmethod - def ensure_log(cls, content: dict | list | str) -> None: - """ - Ensures that the messages are logged. - Into a file for debugging and general to the log - to read the logs within the unit tests. - """ - cls.LOG.info(content) - - log: str = "" - try: - with Path(CACHE_DIR / "spot_orderbook-v1.log").open( - mode="r", - encoding="utf-8", - ) as logfile: - log = logfile.read() - except FileNotFoundError: - pass - - with Path(CACHE_DIR / "spot_orderbook.log").open( - mode="w", - encoding="utf-8", - ) as logfile: - logfile.write(f"{log}\n{content}") - - -class OrderbookClientV2Wrapper(OrderbookClientV2): +class SpotOrderBookClientWrapper(SpotOrderBookClient): """ - This class is used for testing the Spot OrderbookClientV2. + This class is used for testing the Spot SpotOrderBookClient. It writes the messages to the log and a file. The log is used within the tests, the log file is for local debugging. @@ -172,16 +68,16 @@ class OrderbookClientV2Wrapper(OrderbookClientV2): LOG: logging.Logger = logging.getLogger(__name__) - def __init__(self: OrderbookClientV2Wrapper) -> None: + def __init__(self: SpotOrderBookClientWrapper) -> None: super().__init__() self.LOG.setLevel(logging.INFO) - async def on_message(self: OrderbookClientV2Wrapper, message: dict) -> None: + async def on_message(self: SpotOrderBookClientWrapper, message: dict) -> None: self.ensure_log(message) await super().on_message(message=message) async def on_book_update( - self: OrderbookClientV2Wrapper, + self: SpotOrderBookClientWrapper, pair: str, message: dict, ) -> None: diff --git a/tests/spot/test_spot_base_api.py b/tests/spot/test_spot_base_api.py index 5da09f0a..2ad60937 100644 --- a/tests/spot/test_spot_base_api.py +++ b/tests/spot/test_spot_base_api.py @@ -3,14 +3,26 @@ # GitHub: https://github.com/btschwertfeger # -"""Module that checks the general Spot Base API class.""" +"""Module that checks the general Spot Base API class as well as the Async Client.""" + +from __future__ import annotations + +import random +import tempfile +from asyncio import run +from contextlib import suppress +from datetime import datetime +from pathlib import Path +from time import sleep +from typing import TYPE_CHECKING import pytest -from kraken.base_api import KrakenSpotBaseAPI from kraken.exceptions import KrakenInvalidAPIKeyError, KrakenPermissionDeniedError -from kraken.spot import Funding, Market, Trade, User +from kraken.spot import SpotAsyncClient, SpotClient +if TYPE_CHECKING: + from kraken.spot import Funding, Market, Trade, User from .helper import is_not_error @@ -23,16 +35,16 @@ def test_KrakenSpotBaseAPI_without_exception() -> None: gets evaluated. """ with pytest.raises(KrakenInvalidAPIKeyError): - KrakenSpotBaseAPI( + SpotClient( key="fake", secret="fake", - )._request(method="POST", uri="/0/private/AddOrder", auth=True) + ).request(method="POST", uri="/0/private/AddOrder", auth=True) - assert KrakenSpotBaseAPI( + assert SpotClient( key="fake", secret="fake", use_custom_exceptions=False, - )._request(method="POST", uri="/0/private/AddOrder", auth=True).json() == { + ).request(method="POST", uri="/0/private/AddOrder", auth=True).json() == { "error": ["EAPI:Invalid key"], } @@ -44,7 +56,6 @@ def test_spot_rest_contextmanager( spot_auth_funding: Funding, spot_auth_trade: Trade, spot_auth_user: User, - # spot_auth_staking: Staking, ) -> None: """ Checks if the clients can be used as context manager. @@ -59,13 +70,158 @@ def test_spot_rest_contextmanager( with spot_auth_user as user: assert is_not_error(user.get_account_balance()) - # FIXME: does not work; deprecated - # with spot_auth_staking as staking: - # assert isinstance(staking.get_pending_staking_transactions(), list) - - # Disabled since there is no Earn support in CI - # with spot_auth_earn as earn: - # assert isinstance(earn.list_earn_allocations(), dict) - with spot_auth_trade as trade, pytest.raises(KrakenPermissionDeniedError): trade.cancel_order(txid="OB6JJR-7NZ5P-N5SKCB") + + +# ============================================================================== +# Spot async client + + +@pytest.mark.spot() +def test_spot_rest_async_client_get() -> None: + """ + Check the instantiation as well as a simple request using the async client. + """ + + async def check() -> None: + client = SpotAsyncClient() + try: + assert is_not_error( + await client.request( + "GET", + "/0/public/OHLC", + params={"pair": "XBTUSD"}, + auth=False, + ), + ) + finally: + await client.async_close() + + run(check()) + + +@pytest.mark.spot() +def test_spot_async_rest_contextmanager( + spot_api_key: str, + spot_secret_key: str, +) -> None: + """ + Checks if the clients can be used as context manager. + """ + + async def check() -> None: + async with SpotAsyncClient(spot_api_key, spot_secret_key) as client: + result = await client.request("GET", "/0/public/Time", auth=False) + assert is_not_error(result), result + + run(check()) + + +@pytest.mark.spot() +@pytest.mark.spot_auth() +def test_spot_rest_async_client_post_report( + spot_api_key: str, + spot_secret_key: str, +) -> None: + """ + Check the authenticated async client using multiple request to retrieve a + the user-specific order report. + """ + + async def check() -> None: + client = SpotAsyncClient(spot_api_key, spot_secret_key) + + first_of_current_month = int(datetime.now().replace(day=1).timestamp()) + try: + for report in ("trades", "ledgers"): + if report == "trades": + fields = [ + "ordertxid", + "time", + "ordertype", + "price", + "cost", + "fee", + "vol", + "margin", + "misc", + "ledgers", + ] + else: + fields = [ + "refid", + "time", + "type", + "aclass", + "asset", + "amount", + "fee", + "balance", + ] + + export_descr = f"{report}-export-{random.randint(0, 10000)}" + response = await client.request( + "POST", + "/0/private/AddExport", + params={ + "format": "CSV", + "fields": fields, + "report": report, + "description": export_descr, + "endtm": first_of_current_month + 100 * 100, + }, + timeout=30, + ) + assert is_not_error(response) + assert "id" in response + sleep(2) + + status = await client.request( + "POST", + "/0/private/ExportStatus", + params={"report": report}, + ) + assert isinstance(status, list) + sleep(5) + + result = await client.request( + "POST", + "/0/private/RetrieveExport", + params={"id": response["id"]}, + timeout=30, + return_raw=True, + ) + + with tempfile.TemporaryDirectory() as tmp_dir: + file_path = Path(tmp_dir) / f"{export_descr}.zip" + + with file_path.open("wb") as file: + async for chunk in result.content.iter_chunked(1024): + file.write(chunk) + + status = await client.request( + "POST", + "/0/private/ExportStatus", + params={"report": report}, + ) + assert isinstance(status, list) + for response in status: + assert "id" in response + with suppress(Exception): + assert isinstance( + await client.request( + "POST", + "/0/private/RemoveExport", + params={ + "id": response["id"], + "type": "delete", + }, + ), + dict, + ) + sleep(2) + finally: + await client.async_close() + + run(check()) diff --git a/tests/spot/test_spot_orderbook_v2.py b/tests/spot/test_spot_orderbook.py similarity index 79% rename from tests/spot/test_spot_orderbook_v2.py rename to tests/spot/test_spot_orderbook.py index 676ea109..715f1cf8 100644 --- a/tests/spot/test_spot_orderbook_v2.py +++ b/tests/spot/test_spot_orderbook.py @@ -11,15 +11,16 @@ import asyncio import json +from asyncio import sleep as async_sleep from collections import OrderedDict from typing import TYPE_CHECKING from unittest import mock import pytest -from kraken.spot import OrderbookClientV2 +from kraken.spot import SpotOrderBookClient -from .helper import FIXTURE_DIR, OrderbookClientV2Wrapper, async_wait +from .helper import FIXTURE_DIR, SpotOrderBookClientWrapper if TYPE_CHECKING: from pathlib import Path @@ -34,10 +35,11 @@ def test_create_public_bot(caplog: pytest.LogCaptureFixture) -> None: """ async def create_bot() -> None: - orderbook: OrderbookClientV2Wrapper = OrderbookClientV2Wrapper() - await async_wait(seconds=10) + async with SpotOrderBookClientWrapper() as orderbook: - assert orderbook.depth == 10 + await async_sleep(10) + + assert orderbook.depth == 10 asyncio.run(create_bot()) @@ -60,25 +62,25 @@ def test_get_first() -> None: assert ( float(10) - == OrderbookClientV2Wrapper.get_first(("10", "5")) - == OrderbookClientV2Wrapper.get_first((10, 5)) + == SpotOrderBookClientWrapper.get_first(("10", "5")) + == SpotOrderBookClientWrapper.get_first((10, 5)) ) @pytest.mark.spot() @pytest.mark.spot_orderbook() -@mock.patch("kraken.spot.orderbook_v2.KrakenSpotWSClientV2", return_value=None) +@mock.patch("kraken.spot.orderbook.SpotWSClient", return_value=None) @mock.patch( - "kraken.spot.orderbook_v2.OrderbookClientV2.remove_book", + "kraken.spot.orderbook.SpotOrderBookClient.remove_book", return_value=mock.AsyncMock(), ) @mock.patch( - "kraken.spot.orderbook_v2.OrderbookClientV2.add_book", + "kraken.spot.orderbook.SpotOrderBookClient.add_book", return_value=mock.AsyncMock(), ) def test_passing_msg_and_validate_checksum( mock_add_book: mock.MagicMock, # noqa: ARG001 - mock_remove_bookv: mock.MagicMock, # noqa: ARG001 + mock_remove_book: mock.MagicMock, # noqa: ARG001 mock_ws_client: mock.MagicMock, # noqa: ARG001 ) -> None: """ @@ -91,7 +93,8 @@ def test_passing_msg_and_validate_checksum( orderbook: dict = json.load(json_file) async def assign() -> None: - client: OrderbookClientV2 = OrderbookClientV2(depth=10) + client: SpotOrderBookClient = SpotOrderBookClient(depth=10) + # await client.start() # not required here await client.on_message(message=orderbook["init"]) assert client.get(pair="BTC/USD")["valid"] @@ -129,10 +132,11 @@ def test_add_book(caplog: pytest.LogCaptureFixture) -> None: """ async def execute_add_book() -> None: - orderbook: OrderbookClientV2Wrapper = OrderbookClientV2Wrapper() + orderbook = SpotOrderBookClientWrapper() + await orderbook.start() await orderbook.add_book(pairs=["BTC/USD"]) - await async_wait(seconds=2) + await async_sleep(2) book: dict | None = orderbook.get(pair="BTC/USD") assert isinstance(book, dict) @@ -168,13 +172,13 @@ def test_remove_book(caplog: pytest.LogCaptureFixture) -> None: """ async def execute_remove_book() -> None: - orderbook: OrderbookClientV2Wrapper = OrderbookClientV2Wrapper() + async with SpotOrderBookClientWrapper() as orderbook: - await orderbook.add_book(pairs=["BTC/USD"]) - await async_wait(seconds=2) + await orderbook.add_book(pairs=["BTC/USD"]) + await async_sleep(2) - await orderbook.remove_book(pairs=["BTC/USD"]) - await async_wait(seconds=2) + await orderbook.remove_book(pairs=["BTC/USD"]) + await async_sleep(2) asyncio.run(execute_remove_book()) diff --git a/tests/spot/test_spot_orderbook_v1.py b/tests/spot/test_spot_orderbook_v1.py deleted file mode 100644 index a42d10e9..00000000 --- a/tests/spot/test_spot_orderbook_v1.py +++ /dev/null @@ -1,180 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# - -""" -Module that implements the unit tests regarding the Spot OrderbookClientV1. -""" - -from __future__ import annotations - -import asyncio -import json -from collections import OrderedDict -from typing import TYPE_CHECKING -from unittest import mock - -import pytest - -from kraken.spot import OrderbookClientV1 - -from .helper import FIXTURE_DIR, OrderbookClientV1Wrapper, async_wait - -if TYPE_CHECKING: - from pathlib import Path - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_orderbook() -def test_create_public_bot(caplog: pytest.LogCaptureFixture) -> None: - """Checks if the websocket client can be instantiated.""" - - async def create_bot() -> None: - orderbook: OrderbookClientV1Wrapper = OrderbookClientV1Wrapper() - await async_wait(seconds=10) - - assert orderbook.depth == 10 - - asyncio.run(create_bot()) - - for expected in ( - "'connectionID", - "'event': 'systemStatus', 'status': 'online'", - "'event': 'pong'", - ): - assert expected in caplog.text - assert "Kraken websockets at full capacity, try again later" not in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_orderbook() -def test_get_first() -> None: - """ - Checks the ``get_first`` method. - """ - - assert ( - float(10) - == OrderbookClientV1Wrapper.get_first(("10", "5")) - == OrderbookClientV1Wrapper.get_first((10, 5)) - ) - - -@pytest.mark.spot() -@pytest.mark.spot_orderbook() -@mock.patch("kraken.spot.orderbook_v1.KrakenSpotWSClientV1", return_value=None) -@mock.patch( - "kraken.spot.orderbook_v1.OrderbookClientV1.remove_book", - return_value=mock.AsyncMock(), -) -@mock.patch( - "kraken.spot.orderbook_v1.OrderbookClientV1.add_book", - return_value=mock.AsyncMock(), -) -def test_assign_msg_and_validate_checksum( - mock_add_book: mock.MagicMock, # noqa: ARG001 - mock_remove_book: mock.MagicMock, # noqa: ARG001 - mock_ws_client: mock.MagicMock, # noqa: ARG001 -) -> None: - """ - This function checks if the initial snapshot and the book updates are - assigned correctly so that the checksum calculation can validate the - assigned book updates and values. - """ - json_file_path: Path = FIXTURE_DIR / "orderbook-v1.json" - - with json_file_path.open("r", encoding="utf-8") as json_file: - orderbook: dict = json.load(json_file) - - async def assign() -> None: - client: OrderbookClientV1 = OrderbookClientV1(depth=10) - - for message in orderbook["init"]: - await client.on_message(message=message) - - for message in orderbook["updates"]: - await client.on_message(message=message) - assert client.get(pair="XBT/USD")["valid"] - - # NOTE: The price must be higher than the last one to trigger an - # invalid orderbook in this case. - bad_message: list = [ - 336, - { - "b": [["29131.30000", "17.39936238", "1693415483.413309"]], - "c": "3842386424", - }, - "book-10", - "XBT/USD", - ] - await client.on_message(message=bad_message) - assert not client.get(pair="XBT/USD")["valid"] - - asyncio.run(assign()) - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_orderbook() -def test_add_book(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks if the orderbook client is able to add a book by subscribing. - The logs are then checked for the expected results. - """ - - async def execute_add_book() -> None: - orderbook: OrderbookClientV1Wrapper = OrderbookClientV1Wrapper() - - await orderbook.add_book(pairs=["XBT/USD"]) - await async_wait(seconds=2) - - book: dict | None = orderbook.get(pair="XBT/USD") - assert isinstance(book, dict) - - assert all(key in book for key in ("ask", "bid", "valid")), book - - assert isinstance(book["ask"], OrderedDict) - assert isinstance(book["bid"], OrderedDict) - - for ask, bid in zip(book["ask"], book["bid"], strict=True): - assert isinstance(ask, str) - assert isinstance(bid, str) - - asyncio.run(execute_add_book()) - - for expected in ( - "'channelName': 'book-10', 'event': 'subscriptionStatus', 'pair': 'XBT/USD'", - "'status': 'subscribed', 'subscription': {'depth': 10, 'name': 'book'}}", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_orderbook() -def test_remove_book(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks if the orderbook client is able to add a book by subscribing to a book - and unsubscribing right after + validating using the logs. - """ - - async def execute_remove_book() -> None: - orderbook: OrderbookClientV1Wrapper = OrderbookClientV1Wrapper() - - await orderbook.add_book(pairs=["XBT/USD"]) - await async_wait(seconds=2) - - await orderbook.remove_book(pairs=["XBT/USD"]) - await async_wait(seconds=2) - - asyncio.run(execute_remove_book()) - - for expected in ( - "'channelName': 'book-10', 'event': 'subscriptionStatus', 'pair': 'XBT/USD'", - "'status': 'subscribed', 'subscription': {'depth': 10, 'name': 'book'}}", - "'status': 'unsubscribed', 'subscription': {'depth': 10, 'name': 'book'}}", - ): - assert expected in caplog.text diff --git a/tests/spot/test_spot_staking.py b/tests/spot/test_spot_staking.py deleted file mode 100644 index 269a070d..00000000 --- a/tests/spot/test_spot_staking.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# - -"""Module that implements the unit tests for the Spot staking client.""" - -import pytest - -from kraken.spot import Staking - -from .helper import is_not_error # noqa: F401 - -# todo: Mock skipped tests - or is this to dangerous? - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_staking() -@pytest.mark.skip(reason="CI does not have withdraw/stake permission") -def test_list_stakeable_assets(spot_auth_staking: Staking) -> None: - """ - Checks if the ``list_stakeable_assets`` endpoint returns the - expected data type or raises the KrakenPermissionDeniedError. - - The error will be raised if some permissions of the API keys are not set. - """ - assert isinstance(spot_auth_staking.list_stakeable_assets(), list) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_staking() -@pytest.mark.skip(reason="CI does not have withdraw/stake permission") -def test_stake_asset(spot_auth_staking: Staking) -> None: # noqa: ARG001 - """ - Checks the ``stake_asset`` endpoint by requesting a stake. - - This test is skipped since staking is not the desired result. - """ - # assert is_not_error( - # spot_auth_staking.stake_asset( - # asset="DOT", - # amount="4500000", - # method="polkadot-staked", - # ), - # ) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_staking() -@pytest.mark.skip(reason="CI does not have withdraw/stake permission") -def test_unstake_asset(spot_auth_staking: Staking) -> None: # noqa: ARG001 - """ - Checks if the ``unstake_asset`` endpoints returns a response that does - not contain the error key. - - This test is skipped since unstaking is not wanted in the CI. - """ - # with pytest.raises(KrakenException.KrakenPermissionDeniedError, "API key doesn't have permission to make this request."): - # assert is_not_error( - # spot_auth_staking.unstake_asset(asset="DOT", amount="4500000"), - # ) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_staking() -@pytest.mark.skip(reason="CI does not have withdraw/stake permission") -def test_get_pending_staking_transactions(spot_auth_staking: Staking) -> None: - """ - Checks the ``get_pending_staking_transactions`` endpoint by validating - that the response is of type list. This test is also skipped since - the withdraw/stake permission is not set on the CI api keys. - """ - assert isinstance(spot_auth_staking.get_pending_staking_transactions(), list) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_staking() -@pytest.mark.skip(reason="CI does not have withdraw/stake permission") -def test_list_staking_transactions(spot_auth_staking: Staking) -> None: - """ - Checks the ``list_staking_transactions`` endpoint by performing a regular - request. This test is skipped since the CI API keys do not have the - withdraw/stake permission. - """ - assert isinstance(spot_auth_staking.list_staking_transactions(), list) diff --git a/tests/spot/test_spot_user.py b/tests/spot/test_spot_user.py index d2038fe2..5281a7d2 100644 --- a/tests/spot/test_spot_user.py +++ b/tests/spot/test_spot_user.py @@ -315,7 +315,7 @@ def test_request_save_export_report(spot_auth_user: User) -> None: description="this is an invalid report type", ) - first_of_currrent_month = int(datetime.now().replace(day=1).timestamp()) + first_of_current_month = int(datetime.now().replace(day=1).timestamp()) for report in ("trades", "ledgers"): if report == "trades": fields = [ @@ -348,8 +348,8 @@ def test_request_save_export_report(spot_auth_user: User) -> None: description=export_descr, fields=fields, format_="CSV", - starttm=first_of_currrent_month, - endtm=first_of_currrent_month + 100 * 100, + starttm=first_of_current_month, + endtm=first_of_current_month + 100 * 100, timeout=30, ) assert is_not_error(response) diff --git a/tests/spot/test_spot_websocket_v2.py b/tests/spot/test_spot_websocket.py similarity index 62% rename from tests/spot/test_spot_websocket_v2.py rename to tests/spot/test_spot_websocket.py index 214f3f3f..37496fe2 100644 --- a/tests/spot/test_spot_websocket_v2.py +++ b/tests/spot/test_spot_websocket.py @@ -8,7 +8,7 @@ (Kraken Spot Websocket API v2) NOTE: -* The custom SpotWebsocketClientV2TestWrapper class is used that wraps around +* The custom SpotWebsocketClientTestWrapper class is used that wraps around the websocket client. To validate the functions the responses are logged and finally the logs are read out and its input is checked for the expected output. @@ -19,6 +19,7 @@ import logging from asyncio import run as asyncio_run +from asyncio import sleep as async_sleep from copy import deepcopy from typing import TYPE_CHECKING @@ -28,22 +29,23 @@ from pytest_mock import MockerFixture from kraken.exceptions import KrakenAuthenticationError -from kraken.spot.websocket.connectors import ConnectSpotWebsocketV2 +from kraken.spot.websocket.connectors import ConnectSpotWebsocket -from .helper import SpotWebsocketClientV2TestWrapper, async_wait +from .helper import SpotWebsocketClientTestWrapper @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_create_public_client(caplog: pytest.LogCaptureFixture) -> None: """ Checks if the websocket client can be instantiated. """ async def create_client() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper() - await async_wait(seconds=5) + client = SpotWebsocketClientTestWrapper() + await client.start() + await async_sleep(5) + await client.stop() asyncio_run(create_client()) @@ -58,7 +60,6 @@ async def create_client() -> None: @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_create_public_client_as_context_manager( caplog: pytest.LogCaptureFixture, ) -> None: @@ -67,8 +68,8 @@ def test_create_public_client_as_context_manager( """ async def create_client_as_context_manager() -> None: - with SpotWebsocketClientV2TestWrapper() as client: - await async_wait(seconds=5) + async with SpotWebsocketClientTestWrapper(): + await async_sleep(5) asyncio_run(create_client_as_context_manager()) @@ -83,7 +84,6 @@ async def create_client_as_context_manager() -> None: @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_access_public_client_attributes() -> None: """ Checks the ``access_public_client_attributes`` function @@ -91,29 +91,28 @@ def test_access_public_client_attributes() -> None: """ async def check_access() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper() - - assert client.public_channel_names == [ - "book", - "instrument", - "ohlc", - "ticker", - "trade", - ] - assert client.active_public_subscriptions == [] - await async_wait(seconds=1) - with pytest.raises(ConnectionError): - # can't access private subscriptions on unauthenticated client - assert isinstance(client.active_private_subscriptions, list) - - await async_wait(seconds=1.5) + async with SpotWebsocketClientTestWrapper() as client: + + assert client.public_channel_names == [ + "book", + "instrument", + "ohlc", + "ticker", + "trade", + ] + assert client.active_public_subscriptions == [] + await async_sleep(1) + with pytest.raises(ConnectionError): + # can't access private subscriptions on unauthenticated client + assert isinstance(client.active_private_subscriptions, list) + + await async_sleep(1.5) asyncio_run(check_access()) @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_access_public_subscriptions_no_conn_failing() -> None: """ Checks if ``active_public_subscriptions`` fails, because there is no @@ -121,13 +120,13 @@ def test_access_public_subscriptions_no_conn_failing() -> None: """ async def check_access() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper( + async with SpotWebsocketClientTestWrapper( no_public=True, - ) - with pytest.raises(ConnectionError): - assert isinstance(client.active_public_subscriptions, list) + ) as client: + with pytest.raises(ConnectionError): + assert isinstance(client.active_public_subscriptions, list) - await async_wait(seconds=1.5) + await async_sleep(1.5) asyncio_run(check_access()) @@ -135,7 +134,6 @@ async def check_access() -> None: @pytest.mark.spot() @pytest.mark.spot_auth() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_access_private_client_attributes( spot_api_key: str, spot_secret_key: str, @@ -146,28 +144,28 @@ def test_access_private_client_attributes( """ async def check_access() -> None: - auth_client: SpotWebsocketClientV2TestWrapper = ( - SpotWebsocketClientV2TestWrapper(key=spot_api_key, secret=spot_secret_key) - ) - assert auth_client.private_channel_names == ["executions", "balances"] - assert auth_client.private_methods == [ - "add_order", - "batch_add", - "batch_cancel", - "cancel_all", - "cancel_all_orders_after", - "cancel_order", - "edit_order", - ] - assert auth_client.active_private_subscriptions == [] - await async_wait(seconds=2.5) + async with SpotWebsocketClientTestWrapper( + key=spot_api_key, + secret=spot_secret_key, + ) as auth_client: + assert auth_client.private_channel_names == ["executions", "balances"] + assert auth_client.private_methods == [ + "add_order", + "batch_add", + "batch_cancel", + "cancel_all", + "cancel_all_orders_after", + "cancel_order", + "edit_order", + ] + assert auth_client.active_private_subscriptions == [] + await async_sleep(2.5) asyncio_run(check_access()) @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_send_message_missing_method_failing() -> None: """ Checks if the send_message function fails when specific keys or values @@ -175,43 +173,42 @@ def test_send_message_missing_method_failing() -> None: """ async def create_client() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper() - with pytest.raises(TypeError): # wrong message format - await client.send_message(message=[]) - with pytest.raises(TypeError): # method value not string - await client.send_message(message={"method": 1}) - with pytest.raises(TypeError): # missing params for '*subscribe' - await client.send_message(message={"method": "subscribe"}) - with pytest.raises(TypeError): # params not dict - await client.send_message(message={"method": "subscribe", "params": []}) - with pytest.raises(TypeError): # params missing channel key - await client.send_message( - message={"method": "subscribe", "params": {"test": 1}}, - ) - with pytest.raises(TypeError): # channel key must be str - await client.send_message( - message={"method": "subscribe", "params": {"channel": 1}}, - ) - await async_wait(seconds=1) + async with SpotWebsocketClientTestWrapper() as client: + with pytest.raises(TypeError): # wrong message format + await client.send_message(message=[]) + with pytest.raises(TypeError): # method value not string + await client.send_message(message={"method": 1}) + with pytest.raises(TypeError): # missing params for '*subscribe' + await client.send_message(message={"method": "subscribe"}) + with pytest.raises(TypeError): # params not dict + await client.send_message(message={"method": "subscribe", "params": []}) + with pytest.raises(TypeError): # params missing channel key + await client.send_message( + message={"method": "subscribe", "params": {"test": 1}}, + ) + with pytest.raises(TypeError): # channel key must be str + await client.send_message( + message={"method": "subscribe", "params": {"channel": 1}}, + ) + await async_sleep(1) asyncio_run(create_client()) @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_send_message_raw(caplog: pytest.LogCaptureFixture) -> None: """ Checks if the send_message function fails when the socket is not available. """ async def create_client() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper() - await client.send_message( - message={"method": "ping", "req_id": 123456789}, - raw=True, - ) - await async_wait(seconds=1) + async with SpotWebsocketClientTestWrapper() as client: + await client.send_message( + message={"method": "ping", "req_id": 123456789}, + raw=True, + ) + await async_sleep(1) asyncio_run(create_client()) @@ -220,7 +217,6 @@ async def create_client() -> None: @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_public_subscribe(caplog: pytest.LogCaptureFixture) -> None: """ Function that checks if the websocket client is able to subscribe to public @@ -228,25 +224,25 @@ def test_public_subscribe(caplog: pytest.LogCaptureFixture) -> None: """ async def test_subscription() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper() - await client.subscribe( - params={"channel": "ticker", "symbol": ["BTC/USD"]}, - req_id=12345678, - ) - await async_wait(seconds=2) + async with SpotWebsocketClientTestWrapper() as client: + await client.subscribe( + params={"channel": "ticker", "symbol": ["BTC/USD"]}, + req_id=12345678, + ) + await async_sleep(3) asyncio_run(test_subscription()) assert ( - '{"method": "subscribe", "req_id": 12345678, "result": {"channel": "ticker", "event_trigger": "trades", "snapshot": true, "symbol": "BTC/USD"}, "success": true, "time_in":' - in caplog.text + '{"method": "subscribe", "req_id": 12345678, "result": {"channel":' + ' "ticker", "event_trigger": "trades", "snapshot": true, "symbol":' + ' "BTC/USD"}, "success": true, "time_in":' in caplog.text ) @pytest.mark.spot() @pytest.mark.spot_auth() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_private_subscribe_failing_on_public_connection() -> None: """ Ensures that the public websocket connection can't subscribe to private @@ -254,11 +250,14 @@ def test_private_subscribe_failing_on_public_connection() -> None: """ async def test_subscription() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper() - with pytest.raises(KrakenAuthenticationError): - await client.subscribe(params={"channel": "executions"}, req_id=123456789) + async with SpotWebsocketClientTestWrapper() as client: + with pytest.raises(KrakenAuthenticationError): + await client.subscribe( + params={"channel": "executions"}, + req_id=123456789, + ) - await async_wait(seconds=2) + await async_sleep(2) asyncio_run(test_subscription()) @@ -266,7 +265,6 @@ async def test_subscription() -> None: @pytest.mark.spot() @pytest.mark.spot_auth() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_private_subscribe( spot_api_key: str, spot_secret_key: str, @@ -277,18 +275,20 @@ def test_private_subscribe( """ async def test_subscription() -> None: - auth_client: SpotWebsocketClientV2TestWrapper = ( - SpotWebsocketClientV2TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - no_public=True, + async with SpotWebsocketClientTestWrapper( + key=spot_api_key, + secret=spot_secret_key, + no_public=True, + ) as auth_client: + await auth_client.subscribe( + params={"channel": "executions"}, + req_id=123456789, ) - ) - await auth_client.subscribe(params={"channel": "executions"}, req_id=123456789) - await async_wait(seconds=2) + await async_sleep(2) asyncio_run(test_subscription()) + for phrase in ( '{"method": "subscribe", "req_id": 123456789, "result": {"channel": "executions", "maxratecount": 180, "snapshot": true,', # for some reason they provide a "warnings" key '"success": true, "time_in": ', @@ -298,21 +298,20 @@ async def test_subscription() -> None: @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_public_unsubscribe(caplog: pytest.LogCaptureFixture) -> None: """ Checks if the websocket client can unsubscribe from public feeds. """ async def test_unsubscribe() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper() + async with SpotWebsocketClientTestWrapper() as client: - params: dict = {"channel": "ticker", "symbol": ["BTC/USD"]} - await client.subscribe(params=params, req_id=123456789) - await async_wait(seconds=3) + params: dict = {"channel": "ticker", "symbol": ["BTC/USD"]} + await client.subscribe(params=params, req_id=123456789) + await async_sleep(3) - await client.unsubscribe(params=params, req_id=987654321) - await async_wait(seconds=2) + await client.unsubscribe(params=params, req_id=987654321) + await async_sleep(2) asyncio_run(test_unsubscribe()) @@ -326,7 +325,6 @@ async def test_unsubscribe() -> None: @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_public_unsubscribe_failure(caplog: pytest.LogCaptureFixture) -> None: """ Checks if the websocket client responses with failures @@ -334,16 +332,16 @@ def test_public_unsubscribe_failure(caplog: pytest.LogCaptureFixture) -> None: """ async def check_unsubscribe_fail() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper() + async with SpotWebsocketClientTestWrapper() as client: - # We did not subscribed to this ticker but it will work, - # and the response will inform us that there is no such subscription. - await client.unsubscribe( - params={"channel": "ticker", "symbol": ["BTC/USD"]}, - req_id=123456789, - ) + # We did not subscribed to this ticker but it will work, + # and the response will inform us that there is no such subscription. + await client.unsubscribe( + params={"channel": "ticker", "symbol": ["BTC/USD"]}, + req_id=123456789, + ) - await async_wait(seconds=2) + await async_sleep(2) asyncio_run(check_unsubscribe_fail()) @@ -356,7 +354,6 @@ async def check_unsubscribe_fail() -> None: @pytest.mark.spot() @pytest.mark.spot_auth() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_private_unsubscribe( spot_api_key: str, spot_secret_key: str, @@ -367,18 +364,18 @@ def test_private_unsubscribe( """ async def check_unsubscribe() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper( + async with SpotWebsocketClientTestWrapper( key=spot_api_key, secret=spot_secret_key, no_public=True, - ) + ) as client: - await client.subscribe(params={"channel": "executions"}, req_id=123456789) - await async_wait(seconds=2) + await client.subscribe(params={"channel": "executions"}, req_id=123456789) + await async_sleep(2) - await client.unsubscribe(params={"channel": "executions"}, req_id=987654321) - await async_wait(seconds=2) - # todo: check if subs are removed from known list - Dec 2023: obsolete? + await client.unsubscribe(params={"channel": "executions"}, req_id=987654321) + await async_sleep(2) + # todo: check if subs are removed from known list - Dec 2023: obsolete? asyncio_run(check_unsubscribe()) @@ -392,7 +389,6 @@ async def check_unsubscribe() -> None: @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test___transform_subscription() -> None: """ Checks if the subscription transformation works properly by checking @@ -421,8 +417,8 @@ def test___transform_subscription() -> None: target_subscription["result"]["symbol"] = ["BTC/USD"] assert ( - ConnectSpotWebsocketV2._ConnectSpotWebsocketV2__transform_subscription( - ConnectSpotWebsocketV2, + ConnectSpotWebsocket._ConnectSpotWebsocket__transform_subscription( + ConnectSpotWebsocket, subscription=incoming_subscription, ) == target_subscription @@ -431,7 +427,6 @@ def test___transform_subscription() -> None: @pytest.mark.spot() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test___transform_subscription_no_change() -> None: """ Similar to the test above -- but verifying that messages that don't need an @@ -457,8 +452,8 @@ def test___transform_subscription_no_change() -> None: } assert ( - ConnectSpotWebsocketV2._ConnectSpotWebsocketV2__transform_subscription( - ConnectSpotWebsocketV2, + ConnectSpotWebsocket._ConnectSpotWebsocket__transform_subscription( + ConnectSpotWebsocket, subscription=incoming_subscription, ) == incoming_subscription @@ -468,7 +463,6 @@ def test___transform_subscription_no_change() -> None: @pytest.mark.spot() @pytest.mark.spot_auth() @pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() def test_reconnect( spot_api_key: str, spot_secret_key: str, @@ -481,26 +475,26 @@ def test_reconnect( caplog.set_level(logging.INFO) async def check_reconnect() -> None: - client: SpotWebsocketClientV2TestWrapper = SpotWebsocketClientV2TestWrapper( + async with SpotWebsocketClientTestWrapper( key=spot_api_key, secret=spot_secret_key, - ) - await async_wait(seconds=2) - - await client.subscribe(params={"channel": "ticker", "symbol": ["BTC/USD"]}) - await client.subscribe(params={"channel": "executions"}) - await async_wait(seconds=2) - - for obj in (client._priv_conn, client._pub_conn): - mocker.patch.object( - obj, - "_ConnectSpotWebsocketBase__get_reconnect_wait", - return_value=2, - ) - await client._pub_conn.close_connection() - await client._priv_conn.close_connection() - - await async_wait(seconds=5) + ) as client: + await async_sleep(2) + + await client.subscribe(params={"channel": "ticker", "symbol": ["BTC/USD"]}) + await client.subscribe(params={"channel": "executions"}) + await async_sleep(2) + + for obj in (client._priv_conn, client._pub_conn): + mocker.patch.object( + obj, + "_ConnectSpotWebsocketBase__get_reconnect_wait", + return_value=2, + ) + await client._pub_conn.close_connection() + await client._priv_conn.close_connection() + + await async_sleep(5) asyncio_run(check_reconnect()) diff --git a/tests/spot/test_spot_websocket_internals.py b/tests/spot/test_spot_websocket_internals.py index a27b2cbb..09045682 100644 --- a/tests/spot/test_spot_websocket_internals.py +++ b/tests/spot/test_spot_websocket_internals.py @@ -8,26 +8,11 @@ from __future__ import annotations from asyncio import run as asyncio_run +from asyncio import sleep as async_sleep import pytest -from kraken.spot.websocket import KrakenSpotWSClientBase - -from .helper import async_wait - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -def test_ws_base_client_invalid_api_version() -> None: - """ - Checks that the KrakenSpotWSClientBase raises an error when an invalid API - version was specified. - """ - with pytest.raises( - ValueError, - match=r"Websocket API version must be one of ``v1``, ``v2``", - ): - client = KrakenSpotWSClientBase(api_version="10") +from kraken.spot.websocket import SpotWSClientBase @pytest.mark.spot() @@ -39,15 +24,15 @@ def test_ws_base_client_context_manager() -> None: """ async def check_it() -> None: - class TestClient(KrakenSpotWSClientBase): + class TestClient(SpotWSClientBase): async def on_message(self: TestClient, message: dict) -> None: if message == {"error": "yes"}: raise ValueError("Test Error") - with TestClient(api_version="v2", no_public=True) as client: + with TestClient(no_public=True) as client: with pytest.raises(ValueError, match=r"Test Error"): await client.on_message(message={"error": "yes"}) - await async_wait(seconds=5) + await async_sleep(5) asyncio_run(check_it()) @@ -61,6 +46,10 @@ def test_ws_base_client_on_message_no_callback( Checks that the KrakenSpotWSClientBase logs a message when no callback was defined. """ - client = KrakenSpotWSClientBase(api_version="v2", no_public=True) - asyncio_run(client.on_message({"event": "testing"})) + + async def run() -> None: + client = SpotWSClientBase(no_public=True) + await client.on_message({"event": "testing"}) + + asyncio_run(run()) assert "Received message but no callback is defined!" in caplog.text diff --git a/tests/spot/test_spot_websocket_v1.py b/tests/spot/test_spot_websocket_v1.py deleted file mode 100644 index 5a849745..00000000 --- a/tests/spot/test_spot_websocket_v1.py +++ /dev/null @@ -1,931 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2023 Benjamin Thomas Schwertfeger -# GitHub: https://github.com/btschwertfeger -# - -""" -Module that tests the Kraken Spot websocket client -(Kraken Spot Websocket API v1) - -NOTE: -* Since there is no sandbox environment for the Spot trading API, - some tests are adjusted, so that there is a `validate` switch to not risk - funds. -* The custom SpotWebsocketClientV1TestWrapper class is used that wraps around - the websocket client. To validate the functions the responses are logged and - finally the logs are read out and its input is checked for the expected - output. - -todo: check also if reqid matches -""" - -from __future__ import annotations - -import logging -from asyncio import run as asyncio_run -from typing import TYPE_CHECKING - -import pytest - -if TYPE_CHECKING: - from pytest_mock import MockerFixture - -from kraken.exceptions import KrakenAuthenticationError - -from .helper import SpotWebsocketClientV1TestWrapper, async_wait - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_create_public_client(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks if the websocket client can be instantiated. - """ - - async def create_client() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - await async_wait(seconds=5) - - asyncio_run(create_client()) - - for expected in ( - "'connectionID", - "'event': 'systemStatus', 'status': 'online'", - "'version': '1.", - "'event': 'pong'", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v2() -def test_create_public_client_as_context_manager( - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks if the websocket client can be instantiated as context manager. - """ - - async def create_client_as_context_manager() -> None: - with SpotWebsocketClientV1TestWrapper() as client: - await async_wait(seconds=5) - - asyncio_run(create_client_as_context_manager()) - - for expected in ( - "'connectionID", - "'event': 'systemStatus', 'status': 'online'", - "'version': '1.", - "'event': 'pong'", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_create_private_client( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks if the authenticated websocket client can be instantiated. - """ - - async def create_client() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - await async_wait(seconds=5) - - asyncio_run(create_client()) - for expected in ( - "'connectionID", - "'event': 'systemStatus', 'status': 'online'", - "'event': 'pong'", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_access_public_client_attributes() -> None: - """ - Checks the ``access_public_client_attributes`` function - works as expected. - """ - - async def check_access() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - - assert client.public_channel_names == [ - "ticker", - "spread", - "book", - "ohlc", - "trade", - "*", - ] - assert client.active_public_subscriptions == [] - await async_wait(seconds=1) - with pytest.raises(ConnectionError): - # cannot access private subscriptions on unauthenticated client - assert isinstance(client.active_private_subscriptions, list) - - await async_wait(seconds=1.5) - - asyncio_run(check_access()) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_access_private_client_attributes( - spot_api_key: str, - spot_secret_key: str, -) -> None: - """ - Checks the ``access_private_client_attributes`` function - works as expected. - """ - - async def check_access() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - assert client.private_channel_names == ["ownTrades", "openOrders"] - assert client.active_private_subscriptions == [] - await async_wait(seconds=2.5) - - asyncio_run(check_access()) - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_public_subscribe(caplog: pytest.LogCaptureFixture) -> None: - """ - Function that checks if the websocket client - is able to subscribe to public feeds. - """ - - async def test_subscription() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - subscription: dict[str, str] = {"name": "ticker"} - - with pytest.raises(AttributeError): - # Invalid subscription format - await client.subscribe(subscription={}) - - with pytest.raises(TypeError): - # Pair must be type list[str] - await client.subscribe(subscription=subscription, pair="XBT/USD") # type: ignore[arg-type] - - await client.subscribe(subscription=subscription, pair=["XBT/EUR"]) - await async_wait(seconds=2) - - asyncio_run(test_subscription()) - - for expected in ( - "'channelName': 'ticker', 'event': 'subscriptionStatus', 'pair': 'XBT/EUR'", - "'status': 'subscribed', 'subscription': {'name': 'ticker'}}", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_public_subscribe_without_pair_failing() -> None: - """ - Checks that subscribing without specifying a pair fails. - """ - - async def test_subscription() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - - with pytest.raises( - ValueError, - match=r"At least one pair must be specified when subscribing to public feeds.", - ): - await client.subscribe(subscription={"name": "ticker"}) - await async_wait(seconds=2) - - asyncio_run(test_subscription()) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_private_subscribe( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks if the authenticated websocket client can subscribe to private feeds. - """ - - async def test_subscription() -> None: - subscription: dict[str, str] = {"name": "ownTrades"} - - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - with pytest.raises( - KrakenAuthenticationError, - match=r"Credentials are invalid.", - ): - await client.subscribe(subscription=subscription) - - with pytest.raises( - KrakenAuthenticationError, - match=r"Credentials are invalid.", - ): - # same here also using a pair for coverage ... - await client.subscribe(subscription=subscription, pair=["XBT/EUR"]) - - auth_client: SpotWebsocketClientV1TestWrapper = ( - SpotWebsocketClientV1TestWrapper(key=spot_api_key, secret=spot_secret_key) - ) - with pytest.raises( - ValueError, - match=r"Cannot subscribe to private endpoint with specific pair!", - ): - await auth_client.subscribe(subscription=subscription, pair=["XBT/EUR"]) - - await async_wait(seconds=1) - - await auth_client.subscribe(subscription=subscription) - await async_wait(seconds=2) - - asyncio_run(test_subscription()) - for expected in ( - "'status': 'subscribed', 'subscription': {'name': 'ownTrades'}}", - "{'channelName': 'ownTrades', 'event': 'subscriptionStatus'", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_public_unsubscribe(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks if the websocket client can unsubscribe from public feeds. - """ - - async def test_unsubscribe() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - - subscription: dict[str, str] = {"name": "ticker"} - pair: list[str] = ["XBT/USD"] - await client.subscribe(subscription=subscription, pair=pair) - await async_wait(seconds=3) - - await client.unsubscribe(subscription=subscription, pair=pair) - - await async_wait(seconds=2) - - asyncio_run(test_unsubscribe()) - - # todo: regex! - for expected in ( - "'channelName': 'ticker', 'event': 'subscriptionStatus', 'pair': 'XBT/USD'", - "'status': 'subscribed', 'subscription': {'name': 'ticker'}", - "'unsubscribed', 'subscription': {'name': 'ticker'}}", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_public_unsubscribe_failure(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks if the websocket client responses with failures - when the ``unsubscribe`` function receives invalid parameters. - """ - - async def check_unsubscribe_fail() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - - # We did not subscribed to this tickers but it will work, - # and the response will inform us that there are no subscriptions. - await client.unsubscribe( - subscription={"name": "ticker"}, - pair=["DOT/USD", "ETH/USD"], - ) - - with pytest.raises( - AttributeError, - match=r"Subscription requires a \"name\" key.", - ): - await client.unsubscribe(subscription={}) - - with pytest.raises( - TypeError, - match=r"Parameter pair must be type of list\[str\] \(e.g. pair=\[\"XBTUSD\"\]\)", - ): - await client.unsubscribe(subscription={"name": "ticker"}, pair="XBT/USD") # type: ignore[arg-type] - - await async_wait(seconds=2) - - asyncio_run(check_unsubscribe_fail()) - - # todo: regex! - for expected in ( - "{'errorMessage': 'Subscription Not Found', 'event': 'subscriptionStatus', 'pair': 'DOT/USD'", - "{'errorMessage': 'Subscription Not Found', 'event': 'subscriptionStatus', 'pair': 'ETH/USD'", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_public_unsubscribe_without_pair_failing() -> None: - """ - Checks that subscribing without specifying a pair fails. - """ - - async def test_subscription() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - - with pytest.raises( - ValueError, - match=r"At least one pair must be specified when unsubscribing from public feeds.", - ): - await client.unsubscribe(subscription={"name": "ticker"}) - await async_wait(seconds=2) - - asyncio_run(test_subscription()) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_private_unsubscribe( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks if private subscriptions are available. - """ - - async def check_unsubscribe() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - - await client.subscribe(subscription={"name": "ownTrades"}) - await async_wait(seconds=1) - - await client.unsubscribe(subscription={"name": "ownTrades"}) - await async_wait(seconds=2) - # todo: check if subs are removed from known list - - asyncio_run(check_unsubscribe()) - - for expected in ( - "{'channelName': 'ownTrades', 'event': 'subscriptionStatus'", - "'status': 'subscribed', 'subscription': {'name': 'ownTrades'}}", - "'status': 'unsubscribed', 'subscription': {'name': 'ownTrades'}}", - ): - assert expected in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_private_unsubscribe_failing(spot_api_key: str, spot_secret_key: str) -> None: - """ - Checks if the ``unsubscribe`` function fails when invalid - parameters are passed. - """ - - async def check_unsubscribe_failing() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - auth_client: SpotWebsocketClientV1TestWrapper = ( - SpotWebsocketClientV1TestWrapper(key=spot_api_key, secret=spot_secret_key) - ) - - with pytest.raises( - KrakenAuthenticationError, - match=r"Credentials are invalid.", - ): - # private feed on unauthenticated client - await client.unsubscribe(subscription={"name": "ownTrades"}) - - with pytest.raises( - ValueError, - match=r"Cannot unsubscribe from private endpoint with specific pair!", - ): - await auth_client.unsubscribe( - subscription={"name": "ownTrades"}, - pair=["XBTUSD"], - ) - - await async_wait(seconds=2) - - asyncio_run(check_unsubscribe_failing()) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_send_private_message_raw(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks that the send_message function is able to send raw messages. - """ - - async def test_send_message() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - await client.send_message( - message={ - "event": "subscribe", - "pair": ["XBT/USD"], - "subscription": {"name": "ticker"}, - }, - private=False, - raw=True, - ) - - await async_wait(seconds=2) - - asyncio_run(test_send_message()) - - assert ( - "'channelName': 'ticker', 'event': 'subscriptionStatus', 'pair': 'XBT/USD', 'status': 'subscribed', 'subscription': {'name': 'ticker'}" - in caplog.text - ) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_send_private_message_from_public_connection_failing() -> None: - """ - Ensures that the public websocket connection can't send messages that - need authentication. - """ - - async def test_send_message() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - with pytest.raises(KrakenAuthenticationError): - await client.send_message(message={}, private=True) - - await async_wait(seconds=2) - - asyncio_run(test_send_message()) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_reconnect( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, - mocker: MockerFixture, -) -> None: - """ - Checks if the reconnect works properly when forcing a closed connection. - """ - caplog.set_level(logging.INFO) - - async def check_reconnect() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - await async_wait(seconds=2) - - await client.subscribe(subscription={"name": "ticker"}, pair=["XBT/USD"]) - await client.subscribe(subscription={"name": "openOrders"}) - await async_wait(seconds=2) - - for obj in (client._priv_conn, client._pub_conn): - mocker.patch.object( - obj, - "_ConnectSpotWebsocketBase__get_reconnect_wait", - return_value=2, - ) - await client._pub_conn.close_connection() - await client._priv_conn.close_connection() - - await async_wait(seconds=5) - - asyncio_run(check_reconnect()) - - for phrase in ( - "Recover public subscriptions []: waiting", - "Recover authenticated subscriptions []: waiting", - "Recover public subscriptions []: done", - "Recover authenticated subscriptions []: done", - "Websocket connected!", - "'event': 'systemStatus', 'status': 'online', 'version': ", # '1.9.x'} - "'openOrders', 'event': 'subscriptionStatus', 'status': 'subscribed',", - "'channelName': 'ticker', 'event': 'subscriptionStatus', 'pair': 'XBT/USD', 'status': 'subscribed', 'subscription': {'name': 'ticker'}", - "got an exception sent 1000 (OK); then received 1000 (OK)", - "Recover public subscriptions [{'event': 'subscribe', 'pair': ['XBT/USD'], 'subscription': {'name': 'ticker'}}]: waiting", - "Recover authenticated subscriptions [{'event': 'subscribe', 'subscription': {'name': 'openOrders'}}]: waiting", - "{'event': 'subscribe', 'pair': ['XBT/USD'], 'subscription': {'name': 'ticker'}}: OK", - "{'event': 'subscribe', 'subscription': {'name': 'openOrders'}}: OK", - "Recover public subscriptions [{'event': 'subscribe', 'pair': ['XBT/USD'], 'subscription': {'name': 'ticker'}}]: done", - "Recover authenticated subscriptions [{'event': 'subscribe', 'subscription': {'name': 'openOrders'}}]: done", - ): - assert phrase in caplog.text - - -# ------------------------------------------------------------------------------ -# Executables - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_create_order( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks the ``create_order`` function by submitting a - new order - but in validate mode. - - The order submission will fail, because the testing API keys do not have - trade permission - but it is also checked that error messages - starting with "EGeneral:Invalid" are not included in the received - messages. This ensures that the Kraken API received the message and the only - problem is the permission. - - NOTE: This function is not disabled, since the function is executed in - validate mode. - """ - - async def execute_create_order() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - params: dict = { - "ordertype": "limit", - "side": "buy", - "pair": "XBT/USD", - "volume": "2", - "price": "1000", - "price2": "1200", - "leverage": "2", - "oflags": "viqc", - "starttm": "0", - "expiretm": "1000", - "userref": "12345678", - "validate": True, - "close_ordertype": "limit", - "close_price": "1000", - "close_price2": "1200", - "timeinforce": "GTC", - } - await client.create_order(**params) - await async_wait(seconds=2) - - asyncio_run(execute_create_order()) - - assert ( - "{'errorMessage': 'EGeneral:Permission denied', 'event': 'addOrderStatus'" - in caplog.text - ) - assert "'errorMessage': 'EGeneral:Invalid" not in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_create_order_failing_no_connection(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks the ``create_order`` function by submitting a - new order - it is intended to check what happens when there is no open - authenticated connection - it should fail. - - The order submission will fail, because the testing API keys do not have - trade permission - but it is also checked that error messages - starting with "EGeneral:Invalid" are not included in the received - messages. This ensures that the Kraken API received the message and the only - problem is the permission. - - NOTE: This function is not disabled, since the function is executed in - validate mode. - """ - - async def execute_create_order() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - with pytest.raises(KrakenAuthenticationError): - await client.create_order( - ordertype="limit", - side="buy", - pair="XBT/USD", - volume="2", - price="1000", - validate=True, - ) - await async_wait(seconds=2) - - asyncio_run(execute_create_order()) - - assert ( - "Can't place order - Authenticated websocket not connected!" not in caplog.text - ) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_edit_order( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks the edit order function by editing an order in validate mode. - - Same as with the trade endpoint - the response will include - a permission denied error - but it is also checked that no other - error includes the "invalid" string which means that the only problem - is the permission. - - NOTE: This function is not disabled, since the orderId does not - exist and would not cause any problems. - """ - - async def execute_edit_order() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - - await client.edit_order( - orderid="OHSAUDZ-ASJKGD-EPAFUIH", - reqid=1244, - pair="XBT/USD", - price="120", - price2="1300", - oflags="fok", - newuserref="833773", - validate=True, - ) - await async_wait(seconds=2) - - asyncio_run(execute_edit_order()) - - assert ( - "{'errorMessage': 'EGeneral:Permission denied', 'event': 'editOrderStatus'" - in caplog.text - ) - assert "'errorMessage': 'EGeneral:Invalid" not in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_edit_order_failing_no_connection(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks the ``edit_order`` function by editing an order - it is intended to - check what happens when there is no open authenticated connection - it - should fail. - - Same as with the trade endpoint - the response will include - a permission denied error - but it is also checked that no other - error includes the "invalid" string which means that the only problem - is the permission. - """ - - async def execute_edit_order() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - with pytest.raises(KrakenAuthenticationError): - await client.edit_order( - orderid="OHSAUDZ-ASJKGD-EPAFUIH", - reqid=1244, - pair="XBT/USD", - price="120", - price2="1300", - oflags="fok", - newuserref="833773", - validate=True, - ) - await async_wait(seconds=2) - - asyncio_run(execute_edit_order()) - - assert ( - "Can't edit order - Authenticated websocket not connected!" not in caplog.text - ) - - -# @pytest.mark.skip("CI does not have trade/cancel permission") -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_cancel_order( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks the ``cancel_order`` function by canceling some orders. - - Same permission denied reason as for create and edit error. - - NOTE: This function is not disabled, since the txid does not - exist and would not cause any problems. - """ - - async def execute_cancel_order() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - await client.cancel_order(txid=["AOUEHF-ASLBD-A6B4A"]) - await async_wait(seconds=2) - - asyncio_run(execute_cancel_order()) - - assert ( - "{'errorMessage': 'EGeneral:Permission denied', 'event': 'cancelOrderStatus'" - in caplog.text - ) - assert "'errorMessage': 'EGeneral:Invalid" not in caplog.text - - -# @pytest.mark.skip("CI does not have trade/cancel permission") -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_cancel_order_failing_no_connection(caplog: pytest.LogCaptureFixture) -> None: - """ - Checks the ``cancel_order`` function - it is intended to check what happens - when there is no open authenticated connection - it should fail. - - - Same permission denied reason as for create and edit error. - - NOTE: This function is not disabled, since the txid does not - exist and would not cause any problems. - """ - - async def execute_cancel_order() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - with pytest.raises(KrakenAuthenticationError): - await client.cancel_order(txid=["AOUEHF-ASLBD-A6B4A"]) - await async_wait(seconds=2) - - asyncio_run(execute_cancel_order()) - - assert ( - "Can't cancel order - Authenticated websocket not connected!" not in caplog.text - ) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -@pytest.mark.skip("CI does not have trade/cancel permission") -def test_cancel_all_orders( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Check the ``cancel_all_orders`` function by executing the function. - - Same permission denied reason as for create, edit and cancel error. - """ - - async def execute_cancel_all() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - await client.cancel_all_orders() - await async_wait(seconds=2) - - asyncio_run(execute_cancel_all()) - - assert ( - "{'errorMessage': 'EGeneral:Permission denied', 'event': 'cancelAllStatus'" - in caplog.text - ) - assert "'errorMessage': 'EGeneral:Invalid" not in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_cancel_all_orders_failing_no_connection( - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks the ``cancel_all_orders`` function - it is intended to check what - happens when there is no open authenticated connection - it should fail. - - Same permission denied reason as for create, edit and cancel error. - """ - - async def execute_cancel_all_orders() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - with pytest.raises(KrakenAuthenticationError): - await client.cancel_all_orders() - await async_wait(seconds=2) - - asyncio_run(execute_cancel_all_orders()) - - assert ( - "Can't cancel all orders - Authenticated websocket not connected!" - not in caplog.text - ) - - -@pytest.mark.spot() -@pytest.mark.spot_auth() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_cancel_all_orders_after( - spot_api_key: str, - spot_secret_key: str, - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checking the ``cancel_all_orders_after`` function by - executing it. - - NOTE: This function is not disabled, since the value 0 is - submitted which would reset the timer and would not cause - any problems. - """ - - async def execute_cancel_after() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper( - key=spot_api_key, - secret=spot_secret_key, - ) - await client.cancel_all_orders_after(0) - await async_wait(seconds=3) - - asyncio_run(execute_cancel_after()) - - assert ( - "{'errorMessage': 'EGeneral:Permission denied', 'event': 'cancelAllOrdersAfterStatus'" - in caplog.text - ) - assert "'errorMessage': 'EGeneral:Invalid" not in caplog.text in caplog.text - - -@pytest.mark.spot() -@pytest.mark.spot_websocket() -@pytest.mark.spot_websocket_v1() -def test_cancel_all_orders_after_failing_no_connection( - caplog: pytest.LogCaptureFixture, -) -> None: - """ - Checks the ``cancel_all_orders_after`` function - it is intended to check - what happens when there is no open authenticated connection - it should - fail. - - NOTE: This function is not disabled, since the value 0 is - submitted which would reset the timer and would not cause - any problems. - """ - - async def execute_cancel_all_orders() -> None: - client: SpotWebsocketClientV1TestWrapper = SpotWebsocketClientV1TestWrapper() - with pytest.raises(KrakenAuthenticationError): - await client.cancel_all_orders_after() - await async_wait(seconds=2) - - asyncio_run(execute_cancel_all_orders()) - - assert ( - "Can't cancel all orders after - Authenticated websocket not connected!" - not in caplog.text - )