diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 6389a50df..748efc4d9 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,11 +1,12 @@ -FROM freqtradeorg/freqtrade:develop +FROM freqtradeorg/freqtrade:develop_freqairl USER root # Install dependencies COPY requirements-dev.txt /freqtrade/ RUN apt-get update \ - && apt-get -y install git mercurial sudo vim build-essential \ + && apt-get -y install --no-install-recommends apt-utils dialog \ + && apt-get -y install --no-install-recommends git sudo vim build-essential \ && apt-get clean \ && mkdir -p /home/ftuser/.vscode-server /home/ftuser/.vscode-server-insiders /home/ftuser/commandhistory \ && echo "export PROMPT_COMMAND='history -a'" >> /home/ftuser/.bashrc \ diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 41b8475ec..08b8240b9 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -11,29 +11,32 @@ "mounts": [ "source=freqtrade-bashhistory,target=/home/ftuser/commandhistory,type=volume" ], + "workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/freqtrade,type=bind,consistency=cached", // Uncomment to connect as a non-root user if you've added one. See https://aka.ms/vscode-remote/containers/non-root. "remoteUser": "ftuser", + "onCreateCommand": "pip install --user -e .", "postCreateCommand": "freqtrade create-userdir --userdir user_data/", - "workspaceFolder": "/freqtrade/", - - "settings": { - "terminal.integrated.shell.linux": "/bin/bash", - "editor.insertSpaces": true, - "files.trimTrailingWhitespace": true, - "[markdown]": { - "files.trimTrailingWhitespace": false, + "workspaceFolder": "/workspaces/freqtrade", + "customizations": { + "settings": { + "terminal.integrated.shell.linux": "/bin/bash", + "editor.insertSpaces": true, + "files.trimTrailingWhitespace": true, + "[markdown]": { + "files.trimTrailingWhitespace": false, + }, + "python.pythonPath": "/usr/local/bin/python", }, - "python.pythonPath": "/usr/local/bin/python", - }, - // Add the IDs of extensions you want installed when the container is created. - "extensions": [ - "ms-python.python", - "ms-python.vscode-pylance", - "davidanson.vscode-markdownlint", - "ms-azuretools.vscode-docker", - "vscode-icons-team.vscode-icons", - ], + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "ms-python.python", + "ms-python.vscode-pylance", + "davidanson.vscode-markdownlint", + "ms-azuretools.vscode-docker", + "vscode-icons-team.vscode-icons", + ], + } } diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 54c9eab50..8637c0d68 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -20,7 +20,7 @@ Please do not use bug reports to request new features. * Operating system: ____ * Python Version: _____ (`python -V`) * CCXT version: _____ (`pip freeze | grep ccxt`) - * Freqtrade Version: ____ (`freqtrade -V` or `docker-compose run --rm freqtrade -V` for Freqtrade running in docker) + * Freqtrade Version: ____ (`freqtrade -V` or `docker compose run --rm freqtrade -V` for Freqtrade running in docker) Note: All issues other than enhancement requests will be closed without further comment if the above template is deleted or not filled out. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index a18915462..db335bf09 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -18,7 +18,7 @@ Have you search for this feature before requesting it? It's highly likely that a * Operating system: ____ * Python Version: _____ (`python -V`) * CCXT version: _____ (`pip freeze | grep ccxt`) - * Freqtrade Version: ____ (`freqtrade -V` or `docker-compose run --rm freqtrade -V` for Freqtrade running in docker) + * Freqtrade Version: ____ (`freqtrade -V` or `docker compose run --rm freqtrade -V` for Freqtrade running in docker) ## Describe the enhancement diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 4b02e5f19..9283f0e4f 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -18,7 +18,7 @@ Please do not use the question template to report bugs or to request new feature * Operating system: ____ * Python Version: _____ (`python -V`) * CCXT version: _____ (`pip freeze | grep ccxt`) - * Freqtrade Version: ____ (`freqtrade -V` or `docker-compose run --rm freqtrade -V` for Freqtrade running in docker) + * Freqtrade Version: ____ (`freqtrade -V` or `docker compose run --rm freqtrade -V` for Freqtrade running in docker) ## Your question diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4d1f28a0d..dfbc0cee7 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -10,7 +10,7 @@ updates: directory: "/" schedule: interval: weekly - open-pull-requests-limit: 10 + open-pull-requests-limit: 15 target-branch: develop - package-ecosystem: "github-actions" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bb5bc209e..a8a261d0e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,36 +14,36 @@ on: - cron: '0 5 * * 4' concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: "${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }}" cancel-in-progress: true - +permissions: + repository-projects: read jobs: build_linux: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-22.04 ] - python-version: ["3.8", "3.9", "3.10"] + os: [ ubuntu-20.04, ubuntu-22.04 ] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Cache_dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 id: cache with: path: ~/dependencies/ key: ${{ runner.os }}-dependencies - name: pip cache (linux) - uses: actions/cache@v3 - if: runner.os == 'Linux' + uses: actions/cache@v4 with: path: ~/.cache/pip key: test-${{ matrix.os }}-${{ matrix.python-version }}-pip @@ -54,7 +54,6 @@ jobs: cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd .. - name: Installation - *nix - if: runner.os == 'Linux' run: | python -m pip install --upgrade pip wheel export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH @@ -66,15 +65,9 @@ jobs: - name: Tests run: | pytest --random-order --cov=freqtrade --cov-config=.coveragerc - if: matrix.python-version != '3.9' || matrix.os != 'ubuntu-22.04' - - - name: Tests incl. ccxt compatibility tests - run: | - pytest --random-order --cov=freqtrade --cov-config=.coveragerc --longrun - if: matrix.python-version == '3.9' && matrix.os == 'ubuntu-22.04' - name: Coveralls - if: (runner.os == 'Linux' && matrix.python-version == '3.9') + if: (runner.os == 'Linux' && matrix.python-version == '3.10' && matrix.os == 'ubuntu-22.04') env: # Coveralls token. Not used as secret due to github not providing secrets to forked repositories COVERALLS_REPO_TOKEN: 6D1m0xupS3FgutfuGao8keFf9Hc0FpIXu @@ -82,9 +75,20 @@ jobs: # Allow failure for coveralls coveralls || true + - name: Check for repository changes + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "Repository is dirty, changes detected:" + git status + git diff + exit 1 + else + echo "Repository is clean, no changes detected." + fi + - name: Backtesting (multi) run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade new-strategy -s AwesomeStrategy freqtrade new-strategy -s AwesomeStrategyMin --template minimal @@ -92,18 +96,18 @@ jobs: - name: Hyperopt run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data - freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all - - - name: Flake8 - run: | - flake8 + freqtrade hyperopt --datadir tests/testdata -e 6 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all - name: Sort imports (isort) run: | isort --check . + - name: Run Ruff + run: | + ruff check --output-format=github . + - name: Mypy run: | mypy freqtrade scripts tests @@ -116,34 +120,34 @@ jobs: details: Freqtrade CI failed on ${{ matrix.os }} webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} - build_macos: + build-macos: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ macos-latest ] - python-version: ["3.8", "3.9", "3.10"] + os: [ "macos-latest", "macos-13" ] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + check-latest: true - name: Cache_dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 id: cache with: path: ~/dependencies/ - key: ${{ runner.os }}-dependencies + key: ${{ matrix.os }}-dependencies - name: pip cache (macOS) - uses: actions/cache@v3 - if: runner.os == 'macOS' + uses: actions/cache@v4 with: path: ~/Library/Caches/pip - key: test-${{ matrix.os }}-${{ matrix.python-version }}-pip + key: ${{ matrix.os }}-${{ matrix.python-version }}-pip - name: TA binary *nix if: steps.cache.outputs.cache-hit != 'true' @@ -151,10 +155,28 @@ jobs: cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd .. - name: Installation - macOS - if: runner.os == 'macOS' run: | - brew update - brew install hdf5 c-blosc + # brew update + # TODO: Should be the brew upgrade + # homebrew fails to update python due to unlinking failures + # https://github.com/actions/runner-images/issues/6817 + rm /usr/local/bin/2to3 || true + rm /usr/local/bin/2to3-3.11 || true + rm /usr/local/bin/2to3-3.12 || true + rm /usr/local/bin/idle3 || true + rm /usr/local/bin/idle3.11 || true + rm /usr/local/bin/idle3.12 || true + rm /usr/local/bin/pydoc3 || true + rm /usr/local/bin/pydoc3.11 || true + rm /usr/local/bin/pydoc3.12 || true + rm /usr/local/bin/python3 || true + rm /usr/local/bin/python3.11 || true + rm /usr/local/bin/python3.12 || true + rm /usr/local/bin/python3-config || true + rm /usr/local/bin/python3.11-config || true + rm /usr/local/bin/python3.12-config || true + + brew install hdf5 c-blosc libomp python -m pip install --upgrade pip wheel export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH export TA_LIBRARY_PATH=${HOME}/dependencies/lib @@ -166,27 +188,38 @@ jobs: run: | pytest --random-order + - name: Check for repository changes + run: | + if [ -n "$(git status --porcelain)" ]; then + echo "Repository is dirty, changes detected:" + git status + git diff + exit 1 + else + echo "Repository is clean, no changes detected." + fi + - name: Backtesting run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade new-strategy -s AwesomeStrategyAdv --template advanced freqtrade backtesting --datadir tests/testdata --strategy AwesomeStrategyAdv - name: Hyperopt run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all - - name: Flake8 - run: | - flake8 - - name: Sort imports (isort) run: | isort --check . + - name: Run Ruff + run: | + ruff check --output-format=github . + - name: Mypy run: | mypy freqtrade scripts @@ -199,24 +232,24 @@ jobs: details: Test Succeeded! webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} - build_windows: + build-windows: runs-on: ${{ matrix.os }} strategy: matrix: os: [ windows-latest ] - python-version: ["3.8", "3.9", "3.10"] + python-version: ["3.9", "3.10", "3.11", "3.12"] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - name: Pip cache (Windows) - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~\AppData\Local\pip\Cache key: ${{ matrix.os }}-${{ matrix.python-version }}-pip @@ -229,21 +262,33 @@ jobs: run: | pytest --random-order + - name: Check for repository changes + run: | + if (git status --porcelain) { + Write-Host "Repository is dirty, changes detected:" + git status + git diff + exit 1 + } + else { + Write-Host "Repository is clean, no changes detected." + } + - name: Backtesting run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade backtesting --datadir tests/testdata --strategy SampleStrategy - name: Hyperopt run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all - - name: Flake8 + - name: Run Ruff run: | - flake8 + ruff check --output-format=github . - name: Mypy run: | @@ -257,13 +302,13 @@ jobs: details: Test Failed webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} - mypy_version_check: - runs-on: ubuntu-20.04 + mypy-version-check: + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.10" @@ -272,19 +317,29 @@ jobs: pip install pyaml python build_helpers/pre_commit_update.py - docs_check: - runs-on: ubuntu-20.04 + pre-commit: + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.10" + - uses: pre-commit/action@v3.0.0 + + docs-check: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 - name: Documentation syntax run: | ./tests/test_docs.sh - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.11" - name: Documentation build run: | @@ -300,10 +355,64 @@ jobs: details: Freqtrade doc test failed! webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} + + build_linux_online: + # Run pytest with "live" checks + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Cache_dependencies + uses: actions/cache@v4 + id: cache + with: + path: ~/dependencies/ + key: ${{ runner.os }}-dependencies + + - name: pip cache (linux) + uses: actions/cache@v4 + with: + path: ~/.cache/pip + key: test-${{ matrix.os }}-${{ matrix.python-version }}-pip + + - name: TA binary *nix + if: steps.cache.outputs.cache-hit != 'true' + run: | + cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd .. + + - name: Installation - *nix + run: | + python -m pip install --upgrade pip wheel + export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH + export TA_LIBRARY_PATH=${HOME}/dependencies/lib + export TA_INCLUDE_PATH=${HOME}/dependencies/include + pip install -r requirements-dev.txt + pip install -e . + + - name: Tests incl. ccxt compatibility tests + env: + CI_WEB_PROXY: http://152.67.78.211:13128 + run: | + pytest --random-order --longrun --durations 20 -n auto --dist loadscope + + # Notify only once - when CI completes (and after deploy) in case it's successfull notify-complete: - needs: [ build_linux, build_macos, build_windows, docs_check, mypy_version_check ] - runs-on: ubuntu-20.04 + needs: [ + build_linux, + build-macos, + build-windows, + docs-check, + mypy-version-check, + pre-commit, + build_linux_online + ] + runs-on: ubuntu-22.04 # Discord notification can't handle schedule events if: (github.event_name != 'schedule') permissions: @@ -326,44 +435,80 @@ jobs: details: Test Completed! webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} - deploy: - needs: [ build_linux, build_macos, build_windows, docs_check, mypy_version_check ] - runs-on: ubuntu-20.04 + build: + name: "Build" + needs: [ build_linux, build-macos, build-windows, docs-check, mypy-version-check, pre-commit ] + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Build distribution + run: | + pip install -U build + python -m build --sdist --wheel + + - name: Upload artifacts 📦 + uses: actions/upload-artifact@v4 + with: + name: freqtrade-build + path: | + dist + retention-days: 10 + + deploy-pypi: + name: "Deploy to PyPI" + needs: [ build ] + runs-on: ubuntu-22.04 + if: (github.event_name == 'release') + environment: + name: release + url: https://pypi.org/p/freqtrade + permissions: + id-token: write + + steps: + - uses: actions/checkout@v4 + + - name: Download artifact 📦 + uses: actions/download-artifact@v4 + with: + name: freqtrade-build + path: dist + + - name: Publish to PyPI (Test) + uses: pypa/gh-action-pypi-publish@v1.8.11 + with: + repository-url: https://test.pypi.org/legacy/ + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@v1.8.11 + + + deploy-docker: + needs: [ build_linux, build-macos, build-windows, docs-check, mypy-version-check, pre-commit ] + runs-on: ubuntu-22.04 if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: - python-version: "3.9" + python-version: "3.11" - name: Extract branch name - shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF##*/})" - id: extract_branch - - - name: Build distribution + id: extract-branch run: | - pip install -U setuptools wheel - python setup.py sdist bdist_wheel - - - name: Publish to PyPI (Test) - uses: pypa/gh-action-pypi-publish@v1.5.1 - if: (github.event_name == 'release') - with: - user: __token__ - password: ${{ secrets.pypi_test_password }} - repository_url: https://test.pypi.org/legacy/ - - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@v1.5.1 - if: (github.event_name == 'release') - with: - user: __token__ - password: ${{ secrets.pypi_password }} + echo "GITHUB_REF='${GITHUB_REF}'" + echo "branch=${GITHUB_REF##*/}" >> "$GITHUB_OUTPUT" - name: Dockerhub login env: @@ -392,33 +537,27 @@ jobs: - name: Build and test and push docker images env: - IMAGE_NAME: freqtradeorg/freqtrade - BRANCH_NAME: ${{ steps.extract_branch.outputs.branch }} + BRANCH_NAME: ${{ steps.extract-branch.outputs.branch }} run: | build_helpers/publish_docker_multi.sh - - name: Discord notification - uses: rjstone/discord-webhook-notify@v1 - if: always() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) && (github.event_name != 'schedule') - with: - severity: info - details: Deploy Succeeded! - webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} - - - deploy_arm: - needs: [ deploy ] + deploy-arm: + name: "Deploy Docker" + permissions: + packages: write + needs: [ deploy-docker ] # Only run on 64bit machines runs-on: [self-hosted, linux, ARM64] if: (github.event_name == 'push' || github.event_name == 'schedule' || github.event_name == 'release') && github.repository == 'freqtrade/freqtrade' steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Extract branch name - shell: bash - run: echo "##[set-output name=branch;]$(echo ${GITHUB_REF##*/})" - id: extract_branch + id: extract-branch + run: | + echo "GITHUB_REF='${GITHUB_REF}'" + echo "branch=${GITHUB_REF##*/}" >> "$GITHUB_OUTPUT" - name: Dockerhub login env: @@ -429,7 +568,16 @@ jobs: - name: Build and test and push docker images env: - IMAGE_NAME: freqtradeorg/freqtrade - BRANCH_NAME: ${{ steps.extract_branch.outputs.branch }} + BRANCH_NAME: ${{ steps.extract-branch.outputs.branch }} + GHCR_USERNAME: ${{ github.actor }} + GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | build_helpers/publish_docker_arm64.sh + + - name: Discord notification + uses: rjstone/discord-webhook-notify@v1 + if: always() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) && (github.event_name != 'schedule') + with: + severity: info + details: Deploy Succeeded! + webhookUrl: ${{ secrets.DISCORD_WEBHOOK }} diff --git a/.github/workflows/docker_update_readme.yml b/.github/workflows/docker_update_readme.yml index 4587626f6..d91e79099 100644 --- a/.github/workflows/docker_update_readme.yml +++ b/.github/workflows/docker_update_readme.yml @@ -8,9 +8,9 @@ jobs: dockerHubDescription: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Docker Hub Description - uses: peter-evans/dockerhub-description@v3 + uses: peter-evans/dockerhub-description@v4 env: DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} diff --git a/.github/workflows/pre-commit-update.yml b/.github/workflows/pre-commit-update.yml new file mode 100644 index 000000000..13188af14 --- /dev/null +++ b/.github/workflows/pre-commit-update.yml @@ -0,0 +1,45 @@ +name: Pre-commit auto-update + +on: + # every day at midnight + schedule: + - cron: "0 3 * * 2" + # on demand + workflow_dispatch: + +permissions: + contents: read + +jobs: + auto-update: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + + + - name: Install pre-commit + run: pip install pre-commit + + - name: Run auto-update + run: pre-commit autoupdate + + - name: Run pre-commit + run: pre-commit run --all-files + + - uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.REPO_SCOPED_TOKEN }} + add-paths: .pre-commit-config.yaml + labels: | + Tech maintenance + Dependencies + branch: update/pre-commit-hooks + title: Update pre-commit hooks + commit-message: "chore: update pre-commit hooks" + committer: Freqtrade Bot + body: Update versions of pre-commit hooks to latest version. + delete-branch: true diff --git a/.gitignore b/.gitignore index d6cec5225..c818981ee 100644 --- a/.gitignore +++ b/.gitignore @@ -7,10 +7,15 @@ logfile.txt user_data/* !user_data/strategy/sample_strategy.py !user_data/notebooks +!user_data/models +!user_data/freqaimodels +user_data/freqaimodels/* +user_data/models/* user_data/notebooks/* freqtrade-plot.html freqtrade-profit-plot.html freqtrade/rpc/api_server/ui/* +build_helpers/ta-lib/* # Macos related .DS_Store @@ -78,6 +83,9 @@ instance/ # Scrapy stuff: .scrapy +# memray +memray-* + # Sphinx documentation docs/_build/ # Mkdocs documentation @@ -103,7 +111,6 @@ target/ #exceptions !*.gitkeep !config_examples/config_binance.example.json -!config_examples/config_bittrex.example.json -!config_examples/config_ftx.example.json !config_examples/config_full.example.json !config_examples/config_kraken.example.json +!config_examples/config_freqai.example.json diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a205f24ec..5a37634ff 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,39 +2,49 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pycqa/flake8 - rev: "4.0.1" + rev: "7.0.0" hooks: - id: flake8 + additional_dependencies: [Flake8-pyproject] # stages: [push] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v0.942" + rev: "v1.8.0" hooks: - id: mypy exclude: build_helpers additional_dependencies: - - types-cachetools==5.2.1 + - types-cachetools==5.3.0.7 - types-filelock==3.2.7 - - types-requests==2.28.8 - - types-tabulate==0.8.11 - - types-python-dateutil==2.8.19 + - types-requests==2.31.0.20240125 + - types-tabulate==0.9.0.20240106 + - types-python-dateutil==2.8.19.20240106 + - SQLAlchemy==2.0.25 # stages: [push] - repo: https://github.com/pycqa/isort - rev: "5.10.1" + rev: "5.13.2" hooks: - id: isort name: isort (python) # stages: [push] + - repo: https://github.com/charliermarsh/ruff-pre-commit + # Ruff version. + rev: 'v0.2.1' + hooks: + - id: ruff + - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.4.0 + rev: v4.5.0 hooks: - id: end-of-file-fixer exclude: | (?x)^( tests/.*| - .*\.svg + .*\.svg| + .*\.yml| + .*\.json )$ - id: mixed-line-ending - id: debug-statements diff --git a/.readthedocs.yml b/.readthedocs.yml index 446181452..6d0d1fe64 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,8 +1,14 @@ # .readthedocs.yml +version: 2 build: - image: latest + os: "ubuntu-22.04" + tools: + python: "3.11" python: - version: 3.8 - setup_py_install: false + install: + - requirements: docs/requirements-docs.txt + +mkdocs: + configuration: mkdocs.yml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b4e0bc024..b0d8f337b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,16 +45,17 @@ pytest tests/test_.py::test_ ### 2. Test if your code is PEP8 compliant -#### Run Flake8 +#### Run Ruff ```bash -flake8 freqtrade tests scripts +ruff . ``` -We receive a lot of code that fails the `flake8` checks. +We receive a lot of code that fails the `ruff` checks. To help with that, we encourage you to install the git pre-commit -hook that will warn you when you try to commit code that fails these checks. -Guide for installing them is [here](http://flake8.pycqa.org/en/latest/user/using-hooks.html). +hook that will warn you when you try to commit code that fails these checks. + +you can manually run pre-commit with `pre-commit run -a`. ##### Additional styles applied @@ -124,7 +125,7 @@ Exceptions: Contributors may be given commit privileges. Preference will be given to those with: -1. Past contributions to Freqtrade and other related open-source projects. Contributions to Freqtrade include both code (both accepted and pending) and friendly participation in the issue tracker and Pull request reviews. Quantity and quality are considered. +1. Past contributions to Freqtrade and other related open-source projects. Contributions to Freqtrade include both code (both accepted and pending) and friendly participation in the issue tracker and Pull request reviews. Both quantity and quality are considered. 1. A coding style that the other core committers find simple, minimal, and clean. 1. Access to resources for cross-platform development and testing. 1. Time to devote to the project regularly. diff --git a/Dockerfile b/Dockerfile index 14a67edc8..e5a33df87 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.10.6-slim-bullseye as base +FROM python:3.11.7-slim-bookworm as base # Setup env ENV LANG C.UTF-8 @@ -11,7 +11,7 @@ ENV FT_APP_ENV="docker" # Prepare environment RUN mkdir /freqtrade \ && apt-get update \ - && apt-get -y install sudo libatlas3-base curl sqlite3 libhdf5-serial-dev \ + && apt-get -y install sudo libatlas3-base curl sqlite3 libhdf5-serial-dev libgomp1 \ && apt-get clean \ && useradd -u 1000 -G sudo -U -m -s /bin/bash ftuser \ && chown ftuser:ftuser /freqtrade \ @@ -25,7 +25,7 @@ FROM base as python-deps RUN apt-get update \ && apt-get -y install build-essential libssl-dev git libffi-dev libgfortran5 pkg-config cmake gcc \ && apt-get clean \ - && pip install --upgrade pip + && pip install --upgrade pip wheel # Install TA-lib COPY build_helpers/* /tmp/ diff --git a/MANIFEST.in b/MANIFEST.in index a14965c09..0ed6da0ca 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -5,3 +5,5 @@ recursive-include freqtrade/templates/ *.j2 *.ipynb include freqtrade/exchange/binance_leverage_tiers.json include freqtrade/rpc/api_server/ui/fallback_file.html include freqtrade/rpc/api_server/ui/favicon.ico + +prune tests diff --git a/README.md b/README.md index aa446ad54..c6e54b112 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # ![freqtrade](https://raw.githubusercontent.com/freqtrade/freqtrade/develop/docs/assets/freqtrade_poweredby.svg) [![Freqtrade CI](https://github.com/freqtrade/freqtrade/workflows/Freqtrade%20CI/badge.svg)](https://github.com/freqtrade/freqtrade/actions/) +[![DOI](https://joss.theoj.org/papers/10.21105/joss.04864/status.svg)](https://doi.org/10.21105/joss.04864) [![Coverage Status](https://coveralls.io/repos/github/freqtrade/freqtrade/badge.svg?branch=develop&service=github)](https://coveralls.io/github/freqtrade/freqtrade?branch=develop) [![Documentation](https://readthedocs.org/projects/freqtrade/badge/)](https://www.freqtrade.io) [![Maintainability](https://api.codeclimate.com/v1/badges/5737e6d668200b7518ff/maintainability)](https://codeclimate.com/github/freqtrade/freqtrade/maintainability) @@ -27,10 +28,9 @@ hesitate to read the source code and understand the mechanism of this bot. Please read the [exchange specific notes](docs/exchanges.md) to learn about eventual, special configurations needed for each exchange. - [X] [Binance](https://www.binance.com/) -- [X] [Bittrex](https://bittrex.com/) -- [X] [FTX](https://ftx.com/#a=2258149) +- [X] [Bitmart](https://bitmart.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) -- [X] [Huobi](http://huobi.com/) +- [X] [HTX](https://www.htx.com/) (Former Huobi) - [X] [Kraken](https://kraken.com/) - [X] [OKX](https://okx.com/) (Former OKEX) - [ ] [potentially many others](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ @@ -39,7 +39,8 @@ Please read the [exchange specific notes](docs/exchanges.md) to learn about even - [X] [Binance](https://www.binance.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) -- [X] [OKX](https://okx.com/). +- [X] [OKX](https://okx.com/) +- [X] [Bybit](https://bybit.com/) Please make sure to read the [exchange specific notes](docs/exchanges.md), as well as the [trading with leverage](docs/leverage.md) documentation before diving in. @@ -58,11 +59,12 @@ Please find the complete documentation on the [freqtrade website](https://www.fr ## Features -- [x] **Based on Python 3.8+**: For botting on any operating system - Windows, macOS and Linux. +- [x] **Based on Python 3.9+**: For botting on any operating system - Windows, macOS and Linux. - [x] **Persistence**: Persistence is achieved through sqlite. - [x] **Dry-run**: Run the bot without paying money. - [x] **Backtesting**: Run a simulation of your buy/sell strategy. - [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data. +- [X] **Adaptive prediction modeling**: Build a smart strategy with FreqAI that self-trains to the market via adaptive machine learning methods. [Learn more](https://www.freqtrade.io/en/stable/freqai/) - [x] **Edge position sizing** Calculate your win rate, risk reward ratio, the best stoploss and adjust your position size before taking a position for each specific market. [Learn more](https://www.freqtrade.io/en/stable/edge/). - [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade or use dynamic whitelists. - [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid. @@ -129,7 +131,7 @@ Telegram is not mandatory. However, this is a great way to control your bot. Mor - `/start`: Starts the trader. - `/stop`: Stops the trader. -- `/stopbuy`: Stop entering new trades. +- `/stopentry`: Stop entering new trades. - `/status |[table]`: Lists all or specific open trades. - `/profit []`: Lists cumulative profit from all finished trades, over the last n days. - `/forceexit |all`: Instantly exits the given trade (Ignoring `minimum_roi`). @@ -163,6 +165,10 @@ first. If it hasn't been reported, please ensure you follow the template guide so that the team can assist you as quickly as possible. +For every [issue](https://github.com/freqtrade/freqtrade/issues/new/choose) created, kindly follow up and mark satisfaction or reminder to close issue when equilibrium ground is reached. + +--Maintain github's [community policy](https://docs.github.com/en/site-policy/github-terms/github-community-code-of-conduct)-- + ### [Feature Requests](https://github.com/freqtrade/freqtrade/labels/enhancement) Have you a great idea to improve the bot you want to share? Please, @@ -201,9 +207,9 @@ To run this bot we recommend you a cloud instance with a minimum of: ### Software requirements -- [Python >= 3.8](http://docs.python-guide.org/en/latest/starting/installation/) +- [Python >= 3.9](http://docs.python-guide.org/en/latest/starting/installation/) - [pip](https://pip.pypa.io/en/stable/installing/) - [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -- [TA-Lib](https://mrjbq7.github.io/ta-lib/install.html) +- [TA-Lib](https://ta-lib.github.io/ta-lib-python/) - [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended) - [Docker](https://www.docker.com/products/docker) (Recommended) diff --git a/build_helpers/TA_Lib-0.4.24-cp310-cp310-win_amd64.whl b/build_helpers/TA_Lib-0.4.24-cp310-cp310-win_amd64.whl deleted file mode 100644 index 9a96b7894..000000000 Binary files a/build_helpers/TA_Lib-0.4.24-cp310-cp310-win_amd64.whl and /dev/null differ diff --git a/build_helpers/TA_Lib-0.4.24-cp38-cp38-win_amd64.whl b/build_helpers/TA_Lib-0.4.24-cp38-cp38-win_amd64.whl deleted file mode 100644 index f6c66375b..000000000 Binary files a/build_helpers/TA_Lib-0.4.24-cp38-cp38-win_amd64.whl and /dev/null differ diff --git a/build_helpers/TA_Lib-0.4.24-cp39-cp39-win_amd64.whl b/build_helpers/TA_Lib-0.4.24-cp39-cp39-win_amd64.whl deleted file mode 100644 index 84d3e60ab..000000000 Binary files a/build_helpers/TA_Lib-0.4.24-cp39-cp39-win_amd64.whl and /dev/null differ diff --git a/build_helpers/TA_Lib-0.4.28-cp310-cp310-win_amd64.whl b/build_helpers/TA_Lib-0.4.28-cp310-cp310-win_amd64.whl new file mode 100644 index 000000000..cb7fdf907 Binary files /dev/null and b/build_helpers/TA_Lib-0.4.28-cp310-cp310-win_amd64.whl differ diff --git a/build_helpers/TA_Lib-0.4.28-cp311-cp311-linux_armv7l.whl b/build_helpers/TA_Lib-0.4.28-cp311-cp311-linux_armv7l.whl new file mode 100644 index 000000000..f88bc8002 Binary files /dev/null and b/build_helpers/TA_Lib-0.4.28-cp311-cp311-linux_armv7l.whl differ diff --git a/build_helpers/TA_Lib-0.4.28-cp311-cp311-win_amd64.whl b/build_helpers/TA_Lib-0.4.28-cp311-cp311-win_amd64.whl new file mode 100644 index 000000000..4cb902191 Binary files /dev/null and b/build_helpers/TA_Lib-0.4.28-cp311-cp311-win_amd64.whl differ diff --git a/build_helpers/TA_Lib-0.4.28-cp312-cp312-win_amd64.whl b/build_helpers/TA_Lib-0.4.28-cp312-cp312-win_amd64.whl new file mode 100644 index 000000000..81ccc4818 Binary files /dev/null and b/build_helpers/TA_Lib-0.4.28-cp312-cp312-win_amd64.whl differ diff --git a/build_helpers/TA_Lib-0.4.28-cp39-cp39-linux_armv7l.whl b/build_helpers/TA_Lib-0.4.28-cp39-cp39-linux_armv7l.whl new file mode 100644 index 000000000..596b5923d Binary files /dev/null and b/build_helpers/TA_Lib-0.4.28-cp39-cp39-linux_armv7l.whl differ diff --git a/build_helpers/TA_Lib-0.4.28-cp39-cp39-win_amd64.whl b/build_helpers/TA_Lib-0.4.28-cp39-cp39-win_amd64.whl new file mode 100644 index 000000000..64a61ff0d Binary files /dev/null and b/build_helpers/TA_Lib-0.4.28-cp39-cp39-win_amd64.whl differ diff --git a/build_helpers/install_ta-lib.sh b/build_helpers/install_ta-lib.sh index 00c4417ae..0315c7025 100755 --- a/build_helpers/install_ta-lib.sh +++ b/build_helpers/install_ta-lib.sh @@ -4,12 +4,13 @@ else INSTALL_LOC=${1} fi echo "Installing to ${INSTALL_LOC}" -if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then +if [ -n "$2" ] || [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then tar zxvf ta-lib-0.4.0-src.tar.gz cd ta-lib \ && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \ - && curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' -o config.guess \ - && curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' -o config.sub \ + && echo "Downloading gcc config.guess and config.sub" \ + && curl -s 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.guess' -o config.guess \ + && curl -s 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.sub' -o config.sub \ && ./configure --prefix=${INSTALL_LOC}/ \ && make if [ $? -ne 0 ]; then @@ -17,11 +18,17 @@ if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then cd .. && rm -rf ./ta-lib/ exit 1 fi - which sudo && sudo make install || make install - if [ -x "$(command -v apt-get)" ]; then - echo "Updating library path using ldconfig" - sudo ldconfig + if [ -z "$2" ]; then + which sudo && sudo make install || make install + if [ -x "$(command -v apt-get)" ]; then + echo "Updating library path using ldconfig" + sudo ldconfig + fi + else + # Don't install with sudo + make install fi + cd .. && rm -rf ./ta-lib/ else echo "TA-lib already installed, skipping installation" diff --git a/build_helpers/install_windows.ps1 b/build_helpers/install_windows.ps1 index 4caefa340..4aa070992 100644 --- a/build_helpers/install_windows.ps1 +++ b/build_helpers/install_windows.ps1 @@ -1,18 +1,11 @@ -# Downloads don't work automatically, since the URL is regenerated via javascript. -# Downloaded from https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib +# vendored Wheels compiled via https://github.com/xmatthias/ta-lib-python/tree/ta_bundled_040 python -m pip install --upgrade pip wheel $pyv = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" -if ($pyv -eq '3.8') { - pip install build_helpers\TA_Lib-0.4.24-cp38-cp38-win_amd64.whl -} -if ($pyv -eq '3.9') { - pip install build_helpers\TA_Lib-0.4.24-cp39-cp39-win_amd64.whl -} -if ($pyv -eq '3.10') { - pip install build_helpers\TA_Lib-0.4.24-cp310-cp310-win_amd64.whl -} + +pip install --find-links=build_helpers\ --prefer-binary TA-Lib + pip install -r requirements-dev.txt pip install -e . diff --git a/build_helpers/pre_commit_update.py b/build_helpers/pre_commit_update.py index 8724d8ade..e6b47d100 100644 --- a/build_helpers/pre_commit_update.py +++ b/build_helpers/pre_commit_update.py @@ -8,12 +8,17 @@ import yaml pre_commit_file = Path('.pre-commit-config.yaml') require_dev = Path('requirements-dev.txt') +require = Path('requirements.txt') with require_dev.open('r') as rfile: requirements = rfile.readlines() +with require.open('r') as rfile: + requirements.extend(rfile.readlines()) + # Extract types only -type_reqs = [r.strip('\n') for r in requirements if r.startswith('types-')] +type_reqs = [r.strip('\n') for r in requirements if r.startswith( + 'types-') or r.startswith('SQLAlchemy')] with pre_commit_file.open('r') as file: f = yaml.load(file, Loader=yaml.FullLoader) diff --git a/build_helpers/publish_docker_arm64.sh b/build_helpers/publish_docker_arm64.sh index 70f99e54b..71fc01509 100755 --- a/build_helpers/publish_docker_arm64.sh +++ b/build_helpers/publish_docker_arm64.sh @@ -3,14 +3,22 @@ # Use BuildKit, otherwise building on ARM fails export DOCKER_BUILDKIT=1 +IMAGE_NAME=freqtradeorg/freqtrade +CACHE_IMAGE=freqtradeorg/freqtrade_cache +GHCR_IMAGE_NAME=ghcr.io/freqtrade/freqtrade + # Replace / with _ to create a valid tag TAG=$(echo "${BRANCH_NAME}" | sed -e "s/\//_/g") TAG_PLOT=${TAG}_plot +TAG_FREQAI=${TAG}_freqai +TAG_FREQAI_RL=${TAG_FREQAI}rl +TAG_FREQAI_TORCH=${TAG_FREQAI}torch TAG_PI="${TAG}_pi" TAG_ARM=${TAG}_arm TAG_PLOT_ARM=${TAG_PLOT}_arm -CACHE_IMAGE=freqtradeorg/freqtrade_cache +TAG_FREQAI_ARM=${TAG_FREQAI}_arm +TAG_FREQAI_RL_ARM=${TAG_FREQAI_RL}_arm echo "Running for ${TAG}" @@ -34,15 +42,19 @@ if [ $? -ne 0 ]; then echo "failed building multiarch images" return 1 fi + +docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG_ARM} -t freqtrade:${TAG_PLOT_ARM} -f docker/Dockerfile.plot . +docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG_ARM} -t freqtrade:${TAG_FREQAI_ARM} -f docker/Dockerfile.freqai . +docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG_FREQAI_ARM} -t freqtrade:${TAG_FREQAI_RL_ARM} -f docker/Dockerfile.freqai_rl . + # Tag image for upload and next build step docker tag freqtrade:$TAG_ARM ${CACHE_IMAGE}:$TAG_ARM - -docker build --cache-from freqtrade:${TAG_ARM} --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG_ARM} -t freqtrade:${TAG_PLOT_ARM} -f docker/Dockerfile.plot . - docker tag freqtrade:$TAG_PLOT_ARM ${CACHE_IMAGE}:$TAG_PLOT_ARM +docker tag freqtrade:$TAG_FREQAI_ARM ${CACHE_IMAGE}:$TAG_FREQAI_ARM +docker tag freqtrade:$TAG_FREQAI_RL_ARM ${CACHE_IMAGE}:$TAG_FREQAI_RL_ARM # Run backtest -docker run --rm -v $(pwd)/config_examples/config_bittrex.example.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG_ARM} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3 +docker run --rm -v $(pwd)/tests/testdata/config.tests.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG_ARM} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3 if [ $? -ne 0 ]; then echo "failed running backtest" @@ -51,8 +63,9 @@ fi docker images -# docker push ${IMAGE_NAME} docker push ${CACHE_IMAGE}:$TAG_PLOT_ARM +docker push ${CACHE_IMAGE}:$TAG_FREQAI_ARM +docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL_ARM docker push ${CACHE_IMAGE}:$TAG_ARM # Create multi-arch image @@ -60,19 +73,47 @@ docker push ${CACHE_IMAGE}:$TAG_ARM # Otherwise installation might fail. echo "create manifests" -docker manifest create --amend ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG} +docker manifest create ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} docker manifest push -p ${IMAGE_NAME}:${TAG} -docker manifest create ${IMAGE_NAME}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM} ${CACHE_IMAGE}:${TAG_PLOT} +docker manifest create ${IMAGE_NAME}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM} docker manifest push -p ${IMAGE_NAME}:${TAG_PLOT} +docker manifest create ${IMAGE_NAME}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI_ARM} +docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI} + +docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM} +docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI_RL} + +# Create special Torch tag - which is identical to the RL tag. +docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_TORCH} ${CACHE_IMAGE}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM} +docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI_TORCH} + +# copy images to ghcr.io + +alias crane="docker run --rm -i -v $(pwd)/.crane:/home/nonroot/.docker/ gcr.io/go-containerregistry/crane" +mkdir .crane +chmod a+rwx .crane + +echo "${GHCR_TOKEN}" | crane auth login ghcr.io -u "${GHCR_USERNAME}" --password-stdin + +crane copy ${IMAGE_NAME}:${TAG_FREQAI_RL} ${GHCR_IMAGE_NAME}:${TAG_FREQAI_RL} +crane copy ${IMAGE_NAME}:${TAG_FREQAI_RL} ${GHCR_IMAGE_NAME}:${TAG_FREQAI_TORCH} +crane copy ${IMAGE_NAME}:${TAG_FREQAI} ${GHCR_IMAGE_NAME}:${TAG_FREQAI} +crane copy ${IMAGE_NAME}:${TAG_PLOT} ${GHCR_IMAGE_NAME}:${TAG_PLOT} +crane copy ${IMAGE_NAME}:${TAG} ${GHCR_IMAGE_NAME}:${TAG} + # Tag as latest for develop builds if [ "${TAG}" = "develop" ]; then + echo 'Tagging image as latest' docker manifest create ${IMAGE_NAME}:latest ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG} docker manifest push -p ${IMAGE_NAME}:latest + + crane copy ${IMAGE_NAME}:latest ${GHCR_IMAGE_NAME}:latest fi docker images +rm -rf .crane # Cleanup old images from arm64 node. docker image prune -a --force --filter "until=24h" diff --git a/build_helpers/publish_docker_multi.sh b/build_helpers/publish_docker_multi.sh index fd5f0ef93..34dc1faa3 100755 --- a/build_helpers/publish_docker_multi.sh +++ b/build_helpers/publish_docker_multi.sh @@ -2,14 +2,17 @@ # The below assumes a correctly setup docker buildx environment +IMAGE_NAME=freqtradeorg/freqtrade +CACHE_IMAGE=freqtradeorg/freqtrade_cache # Replace / with _ to create a valid tag TAG=$(echo "${BRANCH_NAME}" | sed -e "s/\//_/g") TAG_PLOT=${TAG}_plot +TAG_FREQAI=${TAG}_freqai +TAG_FREQAI_RL=${TAG_FREQAI}rl TAG_PI="${TAG}_pi" PI_PLATFORM="linux/arm/v7" echo "Running for ${TAG}" -CACHE_IMAGE=freqtradeorg/freqtrade_cache CACHE_TAG=${CACHE_IMAGE}:${TAG_PI}_cache # Add commit and commit_message to docker container @@ -24,7 +27,10 @@ if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then --cache-to=type=registry,ref=${CACHE_TAG} \ -f docker/Dockerfile.armhf \ --platform ${PI_PLATFORM} \ - -t ${IMAGE_NAME}:${TAG_PI} --push . + -t ${IMAGE_NAME}:${TAG_PI} \ + --push \ + --provenance=false \ + . else echo "event ${GITHUB_EVENT_NAME}: building with cache" # Build regular image @@ -33,12 +39,16 @@ else # Pull last build to avoid rebuilding the whole image # docker pull --platform ${PI_PLATFORM} ${IMAGE_NAME}:${TAG} + # disable provenance due to https://github.com/docker/buildx/issues/1509 docker buildx build \ --cache-from=type=registry,ref=${CACHE_TAG} \ --cache-to=type=registry,ref=${CACHE_TAG} \ -f docker/Dockerfile.armhf \ --platform ${PI_PLATFORM} \ - -t ${IMAGE_NAME}:${TAG_PI} --push . + -t ${IMAGE_NAME}:${TAG_PI} \ + --push \ + --provenance=false \ + . fi if [ $? -ne 0 ]; then @@ -48,12 +58,16 @@ fi # Tag image for upload and next build step docker tag freqtrade:$TAG ${CACHE_IMAGE}:$TAG -docker build --cache-from freqtrade:${TAG} --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG} -t freqtrade:${TAG_PLOT} -f docker/Dockerfile.plot . +docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG} -t freqtrade:${TAG_PLOT} -f docker/Dockerfile.plot . +docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG} -t freqtrade:${TAG_FREQAI} -f docker/Dockerfile.freqai . +docker build --build-arg sourceimage=freqtrade --build-arg sourcetag=${TAG_FREQAI} -t freqtrade:${TAG_FREQAI_RL} -f docker/Dockerfile.freqai_rl . docker tag freqtrade:$TAG_PLOT ${CACHE_IMAGE}:$TAG_PLOT +docker tag freqtrade:$TAG_FREQAI ${CACHE_IMAGE}:$TAG_FREQAI +docker tag freqtrade:$TAG_FREQAI_RL ${CACHE_IMAGE}:$TAG_FREQAI_RL # Run backtest -docker run --rm -v $(pwd)/config_examples/config_bittrex.example.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3 +docker run --rm -v $(pwd)/tests/testdata/config.tests.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3 if [ $? -ne 0 ]; then echo "failed running backtest" @@ -62,10 +76,10 @@ fi docker images -docker push ${CACHE_IMAGE} -docker push ${CACHE_IMAGE}:$TAG_PLOT docker push ${CACHE_IMAGE}:$TAG - +docker push ${CACHE_IMAGE}:$TAG_PLOT +docker push ${CACHE_IMAGE}:$TAG_FREQAI +docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL docker images diff --git a/build_helpers/pyarrow-15.0.0-cp311-cp311-linux_armv7l.whl b/build_helpers/pyarrow-15.0.0-cp311-cp311-linux_armv7l.whl new file mode 100644 index 000000000..11cfc1895 Binary files /dev/null and b/build_helpers/pyarrow-15.0.0-cp311-cp311-linux_armv7l.whl differ diff --git a/build_helpers/pyarrow-15.0.0-cp39-cp39-linux_armv7l.whl b/build_helpers/pyarrow-15.0.0-cp39-cp39-linux_armv7l.whl new file mode 100644 index 000000000..fe2a1e85a Binary files /dev/null and b/build_helpers/pyarrow-15.0.0-cp39-cp39-linux_armv7l.whl differ diff --git a/config_examples/config_binance.example.json b/config_examples/config_binance.example.json index 35b9fcd20..3a2cea530 100644 --- a/config_examples/config_binance.example.json +++ b/config_examples/config_binance.example.json @@ -1,6 +1,6 @@ { "max_open_trades": 3, - "stake_currency": "BTC", + "stake_currency": "USDT", "stake_amount": 0.05, "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", @@ -36,43 +36,29 @@ "ccxt_async_config": { }, "pair_whitelist": [ - "ALGO/BTC", - "ATOM/BTC", - "BAT/BTC", - "BCH/BTC", - "BRD/BTC", - "EOS/BTC", - "ETH/BTC", - "IOTA/BTC", - "LINK/BTC", - "LTC/BTC", - "NEO/BTC", - "NXS/BTC", - "XMR/BTC", - "XRP/BTC", - "XTZ/BTC" + "ALGO/USDT", + "ATOM/USDT", + "BAT/USDT", + "BCH/USDT", + "BRD/USDT", + "EOS/USDT", + "ETH/USDT", + "IOTA/USDT", + "LINK/USDT", + "LTC/USDT", + "NEO/USDT", + "NXS/USDT", + "XMR/USDT", + "XRP/USDT", + "XTZ/USDT" ], "pair_blacklist": [ - "BNB/BTC" + "BNB/.*" ] }, "pairlists": [ {"method": "StaticPairList"} ], - "edge": { - "enabled": false, - "process_throttle_secs": 3600, - "calculate_since_number_of_days": 7, - "allowed_risk": 0.01, - "stoploss_range_min": -0.01, - "stoploss_range_max": -0.1, - "stoploss_range_step": -0.01, - "minimum_winrate": 0.60, - "minimum_expectancy": 0.20, - "min_trade_number": 10, - "max_trade_duration_minute": 1440, - "remove_pumps": false - }, "telegram": { "enabled": false, "token": "your_telegram_token", diff --git a/config_examples/config_freqai.example.json b/config_examples/config_freqai.example.json new file mode 100644 index 000000000..27bc4532c --- /dev/null +++ b/config_examples/config_freqai.example.json @@ -0,0 +1,90 @@ +{ + "trading_mode": "futures", + "margin_mode": "isolated", + "max_open_trades": 5, + "stake_currency": "USDT", + "stake_amount": 200, + "tradable_balance_ratio": 1, + "fiat_display_currency": "USD", + "dry_run": true, + "timeframe": "3m", + "dry_run_wallet": 1000, + "cancel_open_orders_on_exit": true, + "unfilledtimeout": { + "entry": 10, + "exit": 30 + }, + "exchange": { + "name": "binance", + "key": "", + "secret": "", + "ccxt_config": {}, + "ccxt_async_config": {}, + "pair_whitelist": [ + "1INCH/USDT:USDT", + "ALGO/USDT:USDT" + ], + "pair_blacklist": [] + }, + "entry_pricing": { + "price_side": "same", + "use_order_book": true, + "order_book_top": 1, + "price_last_balance": 0.0, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + } + }, + "exit_pricing": { + "price_side": "other", + "use_order_book": true, + "order_book_top": 1 + }, + "pairlists": [ + { + "method": "StaticPairList" + } + ], + "freqai": { + "enabled": true, + "purge_old_models": 2, + "train_period_days": 15, + "backtest_period_days": 7, + "live_retrain_hours": 0, + "identifier": "unique-id", + "feature_parameters": { + "include_timeframes": [ + "3m", + "15m", + "1h" + ], + "include_corr_pairlist": [ + "BTC/USDT:USDT", + "ETH/USDT:USDT" + ], + "label_period_candles": 20, + "include_shifted_candles": 2, + "DI_threshold": 0.9, + "weight_factor": 0.9, + "principal_component_analysis": false, + "use_SVM_to_remove_outliers": true, + "indicator_periods_candles": [ + 10, + 20 + ], + "plot_feature_importances": 0 + }, + "data_split_parameters": { + "test_size": 0.33, + "random_state": 1 + }, + "model_training_parameters": {} + }, + "bot_name": "", + "force_entry_enable": true, + "initial_state": "running", + "internals": { + "process_throttle_secs": 5 + } +} diff --git a/config_examples/config_full.example.json b/config_examples/config_full.example.json index e2e9a16fd..cb2d4797e 100644 --- a/config_examples/config_full.example.json +++ b/config_examples/config_full.example.json @@ -5,6 +5,7 @@ "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", "amount_reserve_percent": 0.05, + "available_capital": 1000, "amend_last_stake_amount": false, "last_stake_amount_min_ratio": 0.5, "dry_run": true, @@ -59,15 +60,17 @@ "force_entry": "market", "stoploss": "market", "stoploss_on_exchange": false, + "stoploss_price_type": "last", "stoploss_on_exchange_interval": 60, "stoploss_on_exchange_limit_ratio": 0.99 }, "order_time_in_force": { - "entry": "gtc", - "exit": "gtc" + "entry": "GTC", + "exit": "GTC" }, "pairlists": [ {"method": "StaticPairList"}, + {"method": "FullTradesFilter"}, { "method": "VolumePairList", "number_assets": 20, @@ -87,11 +90,11 @@ ], "exchange": { "name": "binance", - "sandbox": false, "key": "your_exchange_key", "secret": "your_exchange_secret", "password": "", "log_responses": false, + // "unknown_fee_rate": 1, "ccxt_config": {}, "ccxt_async_config": {}, "pair_whitelist": [ @@ -170,7 +173,24 @@ "jwt_secret_key": "somethingrandom", "CORS_origins": [], "username": "freqtrader", - "password": "SuperSecurePassword" + "password": "SuperSecurePassword", + "ws_token": "secret_ws_t0ken." + }, + "external_message_consumer": { + "enabled": false, + "producers": [ + { + "name": "default", + "host": "127.0.0.2", + "port": 8080, + "ws_token": "secret_ws_t0ken." + } + ], + "wait_timeout": 300, + "ping_timeout": 10, + "sleep_time": 10, + "remove_entry_exit_signals": false, + "message_size_limit": 8 }, "bot_name": "freqtrade", "db_url": "sqlite:///tradesv3.sqlite", @@ -185,6 +205,7 @@ "strategy_path": "user_data/strategies/", "recursive_strategy_search": false, "add_config_files": [], - "dataformat_ohlcv": "json", - "dataformat_trades": "jsongz" + "reduce_df_footprint": false, + "dataformat_ohlcv": "feather", + "dataformat_trades": "feather" } diff --git a/config_examples/config_kraken.example.json b/config_examples/config_kraken.example.json index c55dea6ba..420047627 100644 --- a/config_examples/config_kraken.example.json +++ b/config_examples/config_kraken.example.json @@ -64,20 +64,6 @@ "pairlists": [ {"method": "StaticPairList"} ], - "edge": { - "enabled": false, - "process_throttle_secs": 3600, - "calculate_since_number_of_days": 7, - "allowed_risk": 0.01, - "stoploss_range_min": -0.01, - "stoploss_range_max": -0.1, - "stoploss_range_step": -0.01, - "minimum_winrate": 0.60, - "minimum_expectancy": 0.20, - "min_trade_number": 10, - "max_trade_duration_minute": 1440, - "remove_pumps": false - }, "telegram": { "enabled": false, "token": "your_telegram_token", diff --git a/docker-compose.yml b/docker-compose.yml index 445fbaea0..3b6f45bfc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,6 +6,15 @@ services: # image: freqtradeorg/freqtrade:develop # Use plotting image # image: freqtradeorg/freqtrade:develop_plot + # # Enable GPU Image and GPU Resources (only relevant for freqAI) + # # Make sure to uncomment the whole deploy section + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: 1 + # capabilities: [gpu] # Build step - only needed when additional dependencies are needed # build: # context: . @@ -16,7 +25,7 @@ services: - "./user_data:/freqtrade/user_data" # Expose api on port 8080 (localhost only) # Please read the https://www.freqtrade.io/en/stable/rest-api/ documentation - # before enabling this. + # for more information. ports: - "127.0.0.1:8080:8080" # Default command used when running `docker compose up` diff --git a/docker/Dockerfile.armhf b/docker/Dockerfile.armhf index 73fc681eb..4cb8f5fea 100644 --- a/docker/Dockerfile.armhf +++ b/docker/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM python:3.9.12-slim-bullseye as base +FROM python:3.11.7-slim-bookworm as base # Setup env ENV LANG C.UTF-8 @@ -11,12 +11,13 @@ ENV FT_APP_ENV="docker" # Prepare environment RUN mkdir /freqtrade \ && apt-get update \ - && apt-get -y install sudo libatlas3-base curl sqlite3 libhdf5-dev \ + && apt-get -y install sudo libatlas3-base libopenblas-dev curl sqlite3 libhdf5-dev libutf8proc-dev libsnappy-dev \ && apt-get clean \ && useradd -u 1000 -G sudo -U -m ftuser \ && chown ftuser:ftuser /freqtrade \ # Allow sudoers - && echo "ftuser ALL=(ALL) NOPASSWD: /bin/chown" >> /etc/sudoers + && echo "ftuser ALL=(ALL) NOPASSWD: /bin/chown" >> /etc/sudoers \ + && pip install --upgrade pip WORKDIR /freqtrade @@ -25,18 +26,16 @@ FROM base as python-deps RUN apt-get update \ && apt-get -y install build-essential libssl-dev libffi-dev libgfortran5 pkg-config cmake gcc \ && apt-get clean \ - && pip install --upgrade pip \ && echo "[global]\nextra-index-url=https://www.piwheels.org/simple" > /etc/pip.conf # Install TA-lib COPY build_helpers/* /tmp/ -RUN cd /tmp && /tmp/install_ta-lib.sh && rm -r /tmp/*ta-lib* -ENV LD_LIBRARY_PATH /usr/local/lib # Install dependencies COPY --chown=ftuser:ftuser requirements.txt /freqtrade/ USER ftuser RUN pip install --user --no-cache-dir numpy \ + && pip install --user --no-index --find-links /tmp/ pyarrow TA-Lib==0.4.28 \ && pip install --user --no-cache-dir -r requirements.txt # Copy dependencies to runtime-image diff --git a/docker/Dockerfile.freqai b/docker/Dockerfile.freqai new file mode 100644 index 000000000..e9f04f3d6 --- /dev/null +++ b/docker/Dockerfile.freqai @@ -0,0 +1,8 @@ +ARG sourceimage=freqtradeorg/freqtrade +ARG sourcetag=develop +FROM ${sourceimage}:${sourcetag} + +# Install dependencies +COPY requirements-freqai.txt /freqtrade/ + +RUN pip install -r requirements-freqai.txt --user --no-cache-dir diff --git a/docker/Dockerfile.freqai_rl b/docker/Dockerfile.freqai_rl new file mode 100644 index 000000000..18fb9afa2 --- /dev/null +++ b/docker/Dockerfile.freqai_rl @@ -0,0 +1,8 @@ +ARG sourceimage=freqtradeorg/freqtrade +ARG sourcetag=develop_freqai +FROM ${sourceimage}:${sourcetag} + +# Install dependencies +COPY requirements-freqai.txt requirements-freqai-rl.txt /freqtrade/ + +RUN pip install -r requirements-freqai-rl.txt --user --no-cache-dir diff --git a/docker/Dockerfile.jupyter b/docker/Dockerfile.jupyter index 7d603c667..79fefb3a7 100644 --- a/docker/Dockerfile.jupyter +++ b/docker/Dockerfile.jupyter @@ -1,7 +1,8 @@ FROM freqtradeorg/freqtrade:develop_plot -RUN pip install jupyterlab --user --no-cache-dir +# Pin prompt-toolkit to avoid questionary version conflict +RUN pip install jupyterlab "prompt-toolkit<=3.0.36" jupyter-client --user --no-cache-dir # Empty the ENTRYPOINT to allow all commands ENTRYPOINT [] diff --git a/docker/docker-compose-freqai.yml b/docker/docker-compose-freqai.yml new file mode 100644 index 000000000..ce493d5b7 --- /dev/null +++ b/docker/docker-compose-freqai.yml @@ -0,0 +1,36 @@ +--- +version: '3' +services: + freqtrade: + image: freqtradeorg/freqtrade:stable_freqaitorch + # # Enable GPU Image and GPU Resources + # # Make sure to uncomment the whole deploy section + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: 1 + # capabilities: [gpu] + + # Build step - only needed when additional dependencies are needed + # build: + # context: . + # dockerfile: "./docker/Dockerfile.custom" + restart: unless-stopped + container_name: freqtrade + volumes: + - "./user_data:/freqtrade/user_data" + # Expose api on port 8080 (localhost only) + # Please read the https://www.freqtrade.io/en/stable/rest-api/ documentation + # for more information. + ports: + - "127.0.0.1:8080:8080" + # Default command used when running `docker compose up` + command: > + trade + --logfile /freqtrade/user_data/logs/freqtrade.log + --db-url sqlite:////freqtrade/user_data/tradesv3.sqlite + --config /freqtrade/user_data/config.json + --freqaimodel XGBoostRegressor + --strategy FreqaiExampleStrategy diff --git a/docker/docker-compose-jupyter.yml b/docker/docker-compose-jupyter.yml index 11a01705c..b72c8df84 100644 --- a/docker/docker-compose-jupyter.yml +++ b/docker/docker-compose-jupyter.yml @@ -6,11 +6,11 @@ services: context: .. dockerfile: docker/Dockerfile.jupyter restart: unless-stopped - container_name: freqtrade + # container_name: freqtrade ports: - "127.0.0.1:8888:8888" volumes: - - "./user_data:/freqtrade/user_data" + - "../user_data:/freqtrade/user_data" # Default command used when running `docker compose up` command: > jupyter lab --port=8888 --ip 0.0.0.0 --allow-root diff --git a/docs/advanced-backtesting.md b/docs/advanced-backtesting.md index 5c2500f18..3926fb5b1 100644 --- a/docs/advanced-backtesting.md +++ b/docs/advanced-backtesting.md @@ -29,20 +29,22 @@ If all goes well, you should now see a `backtest-result-{timestamp}_signals.pkl` `user_data/backtest_results` folder. To analyze the entry/exit tags, we now need to use the `freqtrade backtesting-analysis` command -with `--analysis-groups` option provided with space-separated arguments (default `0 1 2`): +with `--analysis-groups` option provided with space-separated arguments: ``` bash -freqtrade backtesting-analysis -c --analysis-groups 0 1 2 3 4 +freqtrade backtesting-analysis -c --analysis-groups 0 1 2 3 4 5 ``` This command will read from the last backtesting results. The `--analysis-groups` option is used to specify the various tabular outputs showing the profit fo each group or trade, ranging from the simplest (0) to the most detailed per pair, per buy and per sell tag (4): +* 0: overall winrate and profit summary by enter_tag * 1: profit summaries grouped by enter_tag * 2: profit summaries grouped by enter_tag and exit_tag * 3: profit summaries grouped by pair and enter_tag * 4: profit summaries grouped by pair, enter_ and exit_tag (this can get quite large) +* 5: profit summaries grouped by exit_tag More options are available by running with the `-h` option. @@ -100,3 +102,68 @@ freqtrade backtesting-analysis -c --analysis-groups 0 2 --enter-re The indicators have to be present in your strategy's main DataFrame (either for your main timeframe or for informative timeframes) otherwise they will simply be ignored in the script output. + +There are a range of candle and trade-related fields that are included in the analysis so are +automatically accessible by including them on the indicator-list, and these include: + +- **open_date :** trade open datetime +- **close_date :** trade close datetime +- **min_rate :** minimum price seen throughout the position +- **max_rate :** maxiumum price seen throughout the position +- **open :** signal candle open price +- **close :** signal candle close price +- **high :** signal candle high price +- **low :** signal candle low price +- **volume :** signal candle volumne +- **profit_ratio :** trade profit ratio +- **profit_abs :** absolute profit return of the trade + + +### Filtering the trade output by date + +To show only trades between dates within your backtested timerange, supply the usual `timerange` option in `YYYYMMDD-[YYYYMMDD]` format: + +``` +--timerange : Timerange to filter output trades, start date inclusive, end date exclusive. e.g. 20220101-20221231 +``` + +For example, if your backtest timerange was `20220101-20221231` but you only want to output trades in January: + +```bash +freqtrade backtesting-analysis -c --timerange 20220101-20220201 +``` + +### Printing out rejected signals + +Use the `--rejected-signals` option to print out rejected signals. + +```bash +freqtrade backtesting-analysis -c --rejected-signals +``` + +### Writing tables to CSV + +Some of the tabular outputs can become large, so printing them out to the terminal is not preferable. +Use the `--analysis-to-csv` option to disable printing out of tables to standard out and write them to CSV files. + +```bash +freqtrade backtesting-analysis -c --analysis-to-csv +``` + +By default this will write one file per output table you specified in the `backtesting-analysis` command, e.g. + +```bash +freqtrade backtesting-analysis -c --analysis-to-csv --rejected-signals --analysis-groups 0 1 +``` + +This will write to `user_data/backtest_results`: + +* rejected_signals.csv +* group_0.csv +* group_1.csv + +To override where the files will be written, also specify the `--analysis-csv-path` option. + +```bash +freqtrade backtesting-analysis -c --analysis-to-csv --analysis-csv-path another/data/path/ +``` diff --git a/docs/advanced-hyperopt.md b/docs/advanced-hyperopt.md index 8a1ebaff3..eb8bf3f84 100644 --- a/docs/advanced-hyperopt.md +++ b/docs/advanced-hyperopt.md @@ -17,6 +17,7 @@ from typing import Any, Dict from pandas import DataFrame +from freqtrade.constants import Config from freqtrade.optimize.hyperopt import IHyperOptLoss TARGET_TRADES = 600 @@ -31,7 +32,7 @@ class SuperDuperHyperOptLoss(IHyperOptLoss): @staticmethod def hyperopt_loss_function(results: DataFrame, trade_count: int, min_date: datetime, max_date: datetime, - config: Dict, processed: Dict[str, DataFrame], + config: Config, processed: Dict[str, DataFrame], backtest_stats: Dict[str, Any], *args, **kwargs) -> float: """ @@ -74,9 +75,11 @@ This function needs to return a floating point number (`float`). Smaller numbers ## Overriding pre-defined spaces -To override a pre-defined space (`roi_space`, `generate_roi_table`, `stoploss_space`, `trailing_space`), define a nested class called Hyperopt and define the required spaces as follows: +To override a pre-defined space (`roi_space`, `generate_roi_table`, `stoploss_space`, `trailing_space`, `max_open_trades_space`), define a nested class called Hyperopt and define the required spaces as follows: ```python +from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal + class MyAwesomeStrategy(IStrategy): class HyperOpt: # Define a custom stoploss space. @@ -93,6 +96,39 @@ class MyAwesomeStrategy(IStrategy): SKDecimal(0.01, 0.07, decimals=3, name='roi_p2'), SKDecimal(0.01, 0.20, decimals=3, name='roi_p3'), ] + + def generate_roi_table(params: Dict) -> Dict[int, float]: + + roi_table = {} + roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3'] + roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2'] + roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1'] + roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0 + + return roi_table + + def trailing_space() -> List[Dimension]: + # All parameters here are mandatory, you can only modify their type or the range. + return [ + # Fixed to true, if optimizing trailing_stop we assume to use trailing stop at all times. + Categorical([True], name='trailing_stop'), + + SKDecimal(0.01, 0.35, decimals=3, name='trailing_stop_positive'), + # 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive', + # so this intermediate parameter is used as the value of the difference between + # them. The value of the 'trailing_stop_positive_offset' is constructed in the + # generate_trailing_params() method. + # This is similar to the hyperspace dimensions used for constructing the ROI tables. + SKDecimal(0.001, 0.1, decimals=3, name='trailing_stop_positive_offset_p1'), + + Categorical([True, False], name='trailing_only_offset_is_reached'), + ] + + # Define a custom max_open_trades space + def max_open_trades_space(self) -> List[Dimension]: + return [ + Integer(-1, 10, name='max_open_trades'), + ] ``` !!! Note @@ -100,7 +136,7 @@ class MyAwesomeStrategy(IStrategy): ### Dynamic parameters -Parameters can also be defined dynamically, but must be available to the instance once the * [`bot_start()` callback](strategy-callbacks.md#bot-start) has been called. +Parameters can also be defined dynamically, but must be available to the instance once the [`bot_start()` callback](strategy-callbacks.md#bot-start) has been called. ``` python diff --git a/docs/advanced-setup.md b/docs/advanced-setup.md index 93a2025ed..54d489aa1 100644 --- a/docs/advanced-setup.md +++ b/docs/advanced-setup.md @@ -192,7 +192,7 @@ $RepeatedMsgReduction on ### Logging to journald -This needs the `systemd` python package installed as the dependency, which is not available on Windows. Hence, the whole journald logging functionality is not available for a bot running on Windows. +This needs the `cysystemd` python package installed as dependency (`pip install cysystemd`), which is not available on Windows. Hence, the whole journald logging functionality is not available for a bot running on Windows. To send Freqtrade log messages to `journald` system service use the `--logfile` command line option with the value in the following format: diff --git a/docs/assets/binance_futures_settings.png b/docs/assets/binance_futures_settings.png new file mode 100644 index 000000000..a3f7a2c70 Binary files /dev/null and b/docs/assets/binance_futures_settings.png differ diff --git a/docs/assets/freqai_DI.jpg b/docs/assets/freqai_DI.jpg new file mode 100644 index 000000000..5e2aead34 Binary files /dev/null and b/docs/assets/freqai_DI.jpg differ diff --git a/docs/assets/freqai_algo.jpg b/docs/assets/freqai_algo.jpg new file mode 100644 index 000000000..44600e71a Binary files /dev/null and b/docs/assets/freqai_algo.jpg differ diff --git a/docs/assets/freqai_algorithm-diagram.jpg b/docs/assets/freqai_algorithm-diagram.jpg new file mode 100644 index 000000000..4126aee65 Binary files /dev/null and b/docs/assets/freqai_algorithm-diagram.jpg differ diff --git a/docs/assets/freqai_dbscan.jpg b/docs/assets/freqai_dbscan.jpg new file mode 100644 index 000000000..0974550d2 Binary files /dev/null and b/docs/assets/freqai_dbscan.jpg differ diff --git a/docs/assets/freqai_doc_logo.svg b/docs/assets/freqai_doc_logo.svg new file mode 100644 index 000000000..23b116883 --- /dev/null +++ b/docs/assets/freqai_doc_logo.svg @@ -0,0 +1,304 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + FreqAI + + + + + + diff --git a/docs/assets/freqai_inlier-metric.jpg b/docs/assets/freqai_inlier-metric.jpg new file mode 100644 index 000000000..d9cbbe8a1 Binary files /dev/null and b/docs/assets/freqai_inlier-metric.jpg differ diff --git a/docs/assets/freqai_moving-window.jpg b/docs/assets/freqai_moving-window.jpg new file mode 100644 index 000000000..9361479ac Binary files /dev/null and b/docs/assets/freqai_moving-window.jpg differ diff --git a/docs/assets/freqai_pytorch-diagram.png b/docs/assets/freqai_pytorch-diagram.png new file mode 100644 index 000000000..f48ebae25 Binary files /dev/null and b/docs/assets/freqai_pytorch-diagram.png differ diff --git a/docs/assets/freqai_weight-factor.jpg b/docs/assets/freqai_weight-factor.jpg new file mode 100644 index 000000000..c7580787d Binary files /dev/null and b/docs/assets/freqai_weight-factor.jpg differ diff --git a/docs/assets/pycharm_debug.png b/docs/assets/pycharm_debug.png new file mode 100644 index 000000000..b1c19ca93 Binary files /dev/null and b/docs/assets/pycharm_debug.png differ diff --git a/docs/assets/tensorboard.jpg b/docs/assets/tensorboard.jpg new file mode 100644 index 000000000..2aefa869d Binary files /dev/null and b/docs/assets/tensorboard.jpg differ diff --git a/docs/backtesting.md b/docs/backtesting.md index a7baf6932..ece3ce7fa 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -31,9 +31,9 @@ optional arguments: Specify timeframe (`1m`, `5m`, `30m`, `1h`, `1d`). --timerange TIMERANGE Specify what timerange of data to use. - --data-format-ohlcv {json,jsongz,hdf5} + --data-format-ohlcv {json,jsongz,hdf5,feather,parquet} Storage format for downloaded candle (OHLCV) data. - (default: `json`). + (default: `feather`). --max-open-trades INT Override the value of the `max_open_trades` configuration setting. @@ -107,7 +107,7 @@ Strategy arguments: ## Test your strategy with Backtesting -Now you have good Buy and Sell strategies and some historic data, you want to test it against +Now you have good Entry and exit strategies and some historic data, you want to test it against real data. This is what we call [backtesting](https://en.wikipedia.org/wiki/Backtesting). Backtesting will use the crypto-currencies (pairs) from your config file and load historical candle (OHLCV) data from `user_data/data/` by default. @@ -170,11 +170,11 @@ freqtrade backtesting --strategy AwesomeStrategy --dry-run-wallet 1000 Using a different on-disk historical candle (OHLCV) data source -Assume you downloaded the history data from the Bittrex exchange and kept it in the `user_data/data/bittrex-20180101` directory. +Assume you downloaded the history data from the Binance exchange and kept it in the `user_data/data/binance-20180101` directory. You can then use this data for backtesting as follows: ```bash -freqtrade backtesting --strategy AwesomeStrategy --datadir user_data/data/bittrex-20180101 +freqtrade backtesting --strategy AwesomeStrategy --datadir user_data/data/binance-20180101 ``` --- @@ -215,7 +215,7 @@ Sometimes your account has certain fee rebates (fee reductions starting with a c To account for this in backtesting, you can use the `--fee` command line option to supply this value to backtesting. This fee must be a ratio, and will be applied twice (once for trade entry, and once for trade exit). -For example, if the buying and selling commission fee is 0.1% (i.e., 0.001 written as ratio), then you would run backtesting as the following: +For example, if the commission fee per order is 0.1% (i.e., 0.001 written as ratio), then you would run backtesting as the following: ```bash freqtrade backtesting --fee 0.001 @@ -252,41 +252,42 @@ The most important in the backtesting is to understand the result. A backtesting result will look like that: ``` -========================================================= BACKTESTING REPORT ========================================================== -| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins Draws Loss Win% | -|:---------|-------:|---------------:|---------------:|-----------------:|---------------:|:-------------|-------------------------:| -| ADA/BTC | 35 | -0.11 | -3.88 | -0.00019428 | -1.94 | 4:35:00 | 14 0 21 40.0 | -| ARK/BTC | 11 | -0.41 | -4.52 | -0.00022647 | -2.26 | 2:03:00 | 3 0 8 27.3 | -| BTS/BTC | 32 | 0.31 | 9.78 | 0.00048938 | 4.89 | 5:05:00 | 18 0 14 56.2 | -| DASH/BTC | 13 | -0.08 | -1.07 | -0.00005343 | -0.53 | 4:39:00 | 6 0 7 46.2 | -| ENG/BTC | 18 | 1.36 | 24.54 | 0.00122807 | 12.27 | 2:50:00 | 8 0 10 44.4 | -| EOS/BTC | 36 | 0.08 | 3.06 | 0.00015304 | 1.53 | 3:34:00 | 16 0 20 44.4 | -| ETC/BTC | 26 | 0.37 | 9.51 | 0.00047576 | 4.75 | 6:14:00 | 11 0 15 42.3 | -| ETH/BTC | 33 | 0.30 | 9.96 | 0.00049856 | 4.98 | 7:31:00 | 16 0 17 48.5 | -| IOTA/BTC | 32 | 0.03 | 1.09 | 0.00005444 | 0.54 | 3:12:00 | 14 0 18 43.8 | -| LSK/BTC | 15 | 1.75 | 26.26 | 0.00131413 | 13.13 | 2:58:00 | 6 0 9 40.0 | -| LTC/BTC | 32 | -0.04 | -1.38 | -0.00006886 | -0.69 | 4:49:00 | 11 0 21 34.4 | -| NANO/BTC | 17 | 1.26 | 21.39 | 0.00107058 | 10.70 | 1:55:00 | 10 0 7 58.5 | -| NEO/BTC | 23 | 0.82 | 18.97 | 0.00094936 | 9.48 | 2:59:00 | 10 0 13 43.5 | -| REQ/BTC | 9 | 1.17 | 10.54 | 0.00052734 | 5.27 | 3:47:00 | 4 0 5 44.4 | -| XLM/BTC | 16 | 1.22 | 19.54 | 0.00097800 | 9.77 | 3:15:00 | 7 0 9 43.8 | -| XMR/BTC | 23 | -0.18 | -4.13 | -0.00020696 | -2.07 | 5:30:00 | 12 0 11 52.2 | -| XRP/BTC | 35 | 0.66 | 22.96 | 0.00114897 | 11.48 | 3:49:00 | 12 0 23 34.3 | -| ZEC/BTC | 22 | -0.46 | -10.18 | -0.00050971 | -5.09 | 2:22:00 | 7 0 15 31.8 | -| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 0 243 43.4 | -========================================================= EXIT REASON STATS ========================================================== -| Exit Reason | Sells | Wins | Draws | Losses | +========================================================= BACKTESTING REPORT ========================================================= +| Pair | Entries | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins Draws Loss Win% | +|:---------|--------:|---------------:|---------------:|-----------------:|---------------:|:-------------|-------------------------:| +| ADA/BTC | 35 | -0.11 | -3.88 | -0.00019428 | -1.94 | 4:35:00 | 14 0 21 40.0 | +| ARK/BTC | 11 | -0.41 | -4.52 | -0.00022647 | -2.26 | 2:03:00 | 3 0 8 27.3 | +| BTS/BTC | 32 | 0.31 | 9.78 | 0.00048938 | 4.89 | 5:05:00 | 18 0 14 56.2 | +| DASH/BTC | 13 | -0.08 | -1.07 | -0.00005343 | -0.53 | 4:39:00 | 6 0 7 46.2 | +| ENG/BTC | 18 | 1.36 | 24.54 | 0.00122807 | 12.27 | 2:50:00 | 8 0 10 44.4 | +| EOS/BTC | 36 | 0.08 | 3.06 | 0.00015304 | 1.53 | 3:34:00 | 16 0 20 44.4 | +| ETC/BTC | 26 | 0.37 | 9.51 | 0.00047576 | 4.75 | 6:14:00 | 11 0 15 42.3 | +| ETH/BTC | 33 | 0.30 | 9.96 | 0.00049856 | 4.98 | 7:31:00 | 16 0 17 48.5 | +| IOTA/BTC | 32 | 0.03 | 1.09 | 0.00005444 | 0.54 | 3:12:00 | 14 0 18 43.8 | +| LSK/BTC | 15 | 1.75 | 26.26 | 0.00131413 | 13.13 | 2:58:00 | 6 0 9 40.0 | +| LTC/BTC | 32 | -0.04 | -1.38 | -0.00006886 | -0.69 | 4:49:00 | 11 0 21 34.4 | +| NANO/BTC | 17 | 1.26 | 21.39 | 0.00107058 | 10.70 | 1:55:00 | 10 0 7 58.5 | +| NEO/BTC | 23 | 0.82 | 18.97 | 0.00094936 | 9.48 | 2:59:00 | 10 0 13 43.5 | +| REQ/BTC | 9 | 1.17 | 10.54 | 0.00052734 | 5.27 | 3:47:00 | 4 0 5 44.4 | +| XLM/BTC | 16 | 1.22 | 19.54 | 0.00097800 | 9.77 | 3:15:00 | 7 0 9 43.8 | +| XMR/BTC | 23 | -0.18 | -4.13 | -0.00020696 | -2.07 | 5:30:00 | 12 0 11 52.2 | +| XRP/BTC | 35 | 0.66 | 22.96 | 0.00114897 | 11.48 | 3:49:00 | 12 0 23 34.3 | +| ZEC/BTC | 22 | -0.46 | -10.18 | -0.00050971 | -5.09 | 2:22:00 | 7 0 15 31.8 | +| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 0 243 43.4 | +====================================================== LEFT OPEN TRADES REPORT ====================================================== +| Pair | Entries | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Win Draw Loss Win% | +|:---------|---------:|---------------:|---------------:|-----------------:|---------------:|:---------------|--------------------:| +| ADA/BTC | 1 | 0.89 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 0 0 100 | +| LTC/BTC | 1 | 0.68 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 0 0 100 | +| TOTAL | 2 | 0.78 | 1.57 | 0.00007855 | 0.78 | 4:00:00 | 2 0 0 100 | +==================== EXIT REASON STATS ==================== +| Exit Reason | Exits | Wins | Draws | Losses | |:-------------------|--------:|------:|-------:|--------:| | trailing_stop_loss | 205 | 150 | 0 | 55 | | stop_loss | 166 | 0 | 0 | 166 | | exit_signal | 56 | 36 | 0 | 20 | | force_exit | 2 | 0 | 0 | 2 | -====================================================== LEFT OPEN TRADES REPORT ====================================================== -| Pair | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Win Draw Loss Win% | -|:---------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|--------------------:| -| ADA/BTC | 1 | 0.89 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 0 0 100 | -| LTC/BTC | 1 | 0.68 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 0 0 100 | -| TOTAL | 2 | 0.78 | 1.57 | 0.00007855 | 0.78 | 4:00:00 | 2 0 0 100 | + ================== SUMMARY METRICS ================== | Metric | Value | |-----------------------------+---------------------| @@ -300,7 +301,11 @@ A backtesting result will look like that: | Absolute profit | 0.00762792 BTC | | Total profit % | 76.2% | | CAGR % | 460.87% | +| Sortino | 1.88 | +| Sharpe | 2.97 | +| Calmar | 6.29 | | Profit factor | 1.11 | +| Expectancy (Ratio) | -0.15 (-0.05) | | Avg. stake amount | 0.001 BTC | | Total trade volume | 0.429 BTC | | | | @@ -319,6 +324,7 @@ A backtesting result will look like that: | Days win/draw/lose | 12 / 82 / 25 | | Avg. Duration Winners | 4:23:00 | | Avg. Duration Loser | 6:55:00 | +| Max Consecutive Wins / Loss | 3 / 4 | | Rejected Entry signals | 3089 | | Entry/Exit Timeouts | 0 / 0 | | Canceled Trade Entries | 34 | @@ -356,7 +362,7 @@ The column `Avg Profit %` shows the average profit for all trades made while the The column `Tot Profit %` shows instead the total profit % in relation to the starting balance. In the above results, we have a starting balance of 0.01 BTC and an absolute profit of 0.00762792 BTC - so the `Tot Profit %` will be `(0.00762792 / 0.01) * 100 ~= 76.2%`. -Your strategy performance is influenced by your buy strategy, your exit strategy, and also by the `minimal_roi` and `stop_loss` you have set. +Your strategy performance is influenced by your entry strategy, your exit strategy, and also by the `minimal_roi` and `stop_loss` you have set. For example, if your `minimal_roi` is only `"0": 0.01` you cannot expect the bot to make more profit than 1% (because it will exit every time a trade reaches 1%). @@ -400,7 +406,11 @@ It contains some useful key metrics about performance of your strategy on backte | Absolute profit | 0.00762792 BTC | | Total profit % | 76.2% | | CAGR % | 460.87% | +| Sortino | 1.88 | +| Sharpe | 2.97 | +| Calmar | 6.29 | | Profit factor | 1.11 | +| Expectancy (Ratio) | -0.15 (-0.05) | | Avg. stake amount | 0.001 BTC | | Total trade volume | 0.429 BTC | | | | @@ -419,6 +429,7 @@ It contains some useful key metrics about performance of your strategy on backte | Days win/draw/lose | 12 / 82 / 25 | | Avg. Duration Winners | 4:23:00 | | Avg. Duration Loser | 6:55:00 | +| Max Consecutive Wins / Loss | 3 / 4 | | Rejected Entry signals | 3089 | | Entry/Exit Timeouts | 0 / 0 | | Canceled Trade Entries | 34 | @@ -447,6 +458,9 @@ It contains some useful key metrics about performance of your strategy on backte - `Absolute profit`: Profit made in stake currency. - `Total profit %`: Total profit. Aligned to the `TOTAL` row's `Tot Profit %` from the first table. Calculated as `(End capital − Starting capital) / Starting capital`. - `CAGR %`: Compound annual growth rate. +- `Sortino`: Annualized Sortino ratio. +- `Sharpe`: Annualized Sharpe ratio. +- `Calmar`: Annualized Calmar ratio. - `Profit factor`: profit / loss. - `Avg. stake amount`: Average stake amount, either `stake_amount` or the average when using dynamic stake amount. - `Total trade volume`: Volume generated on the exchange to reach the above profit. @@ -455,6 +469,7 @@ It contains some useful key metrics about performance of your strategy on backte - `Best day` / `Worst day`: Best and worst day based on daily profit. - `Days win/draw/lose`: Winning / Losing days (draws are usually days without closed trade). - `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades. +- `Max Consecutive Wins / Loss`: Maximum consecutive wins/losses in a row. - `Rejected Entry signals`: Trade entry signals that could not be acted upon due to `max_open_trades` being reached. - `Entry/Exit Timeouts`: Entry/exit orders which did not fill (only applicable if custom pricing is used). - `Canceled Trade Entries`: Number of trades that have been canceled by user request via `adjust_entry_price`. @@ -515,20 +530,21 @@ You can then load the trades to perform further analysis as shown in the [data a Since backtesting lacks some detailed information about what happens within a candle, it needs to take a few assumptions: - Exchange [trading limits](#trading-limits-in-backtesting) are respected -- Buys happen at open-price +- Entries happen at open-price - All orders are filled at the requested price (no slippage, no unfilled orders) - Exit-signal exits happen at open-price of the consecutive candle - Exit-signal is favored over Stoploss, because exit-signals are assumed to trigger on candle's open - ROI - exits are compared to high - but the ROI value is used (e.g. ROI = 2%, high=5% - so the exit will be at 2%) - exits are never "below the candle", so a ROI of 2% may result in a exit at 2.4% if low was at 2.4% profit - - Forceexits caused by `=-1` ROI entries use low as exit value, unless N falls on the candle open (e.g. `120: -1` for 1h candles) + - ROI entries which came into effect on the triggering candle (e.g. `120: 0.02` for 1h candles, from `60: 0.05`) will use the candle's open as exit rate + - Force-exits caused by `=-1` ROI entries use low as exit value, unless N falls on the candle open (e.g. `120: -1` for 1h candles) - Stoploss exits happen exactly at stoploss price, even if low was lower, but the loss will be `2 * fees` higher than the stoploss price - Stoploss is evaluated before ROI within one candle. So you can often see more trades with the `stoploss` exit reason comparing to the results obtained with the same strategy in the Dry Run/Live Trade modes - Low happens before high for stoploss, protecting capital first - Trailing stoploss - Trailing Stoploss is only adjusted if it's below the candle's low (otherwise it would be triggered) - - On trade entry candles that trigger trailing stoploss, the "minimum offset" (`stop_positive_offset`) is assumed (instead of high) - and the stop is calculated from this point + - On trade entry candles that trigger trailing stoploss, the "minimum offset" (`stop_positive_offset`) is assumed (instead of high) - and the stop is calculated from this point. This rule is NOT applicable to custom-stoploss scenarios, since there's no information about the stoploss logic available. - High happens first - adjusting stoploss - Low uses the adjusted stoploss (so exits with large high-low difference are backtested correctly) - ROI applies before trailing-stop, ensuring profits are "top-capped" at ROI if both ROI and trailing stop applies @@ -546,8 +562,8 @@ In addition to the above assumptions, strategy authors should carefully read the ### Trading limits in backtesting -Exchanges have certain trading limits, like minimum base currency, or minimum stake (quote) currency. -These limits are usually listed in the exchange documentation as "trading rules" or similar. +Exchanges have certain trading limits, like minimum (and maximum) base currency, or minimum/maximum stake (quote) currency. +These limits are usually listed in the exchange documentation as "trading rules" or similar and can be quite different between different pairs. Backtesting (as well as live and dry-run) does honor these limits, and will ensure that a stoploss can be placed below this value - so the value will be slightly higher than what the exchange specifies. Freqtrade has however no information about historic limits. @@ -561,6 +577,14 @@ BTC trades at 22.000\$ today (0.001 BTC is related to this) - but the backtestin Today's minimum would be `0.001 * 22_000` - or 22\$. However the limit could also be 50$ - based on `0.001 * 50_000` in some historic setting. +#### Trading precision limits + +Most exchanges pose precision limits on both price and amounts, so you cannot buy 1.0020401 of a pair, or at a price of 1.24567123123. +Instead, these prices and amounts will be rounded or truncated (based on the exchange definition) to the defined trading precision. +The above values may for example be rounded to an amount of 1.002, and a price of 1.24567. + +These precision values are based on current exchange limits (as described in the [above section](#trading-limits-in-backtesting)), as historic precision limits are not available. + ## Improved backtest accuracy One big limitation of backtesting is it's inability to know how prices moved intra-candle (was high before close, or viceversa?). @@ -575,7 +599,8 @@ To utilize this, you can append `--timeframe-detail 5m` to your regular backtest freqtrade backtesting --strategy AwesomeStrategy --timeframe 1h --timeframe-detail 5m ``` -This will load 1h data as well as 5m data for the timeframe. The strategy will be analyzed with the 1h timeframe - and for every "open trade candle" (candles where a trade is open) the 5m data will be used to simulate intra-candle movements. +This will load 1h data as well as 5m data for the timeframe. The strategy will be analyzed with the 1h timeframe, and Entry orders will only be placed at the main timeframe, however Order fills and exit signals will be evaluated at the 5m candle, simulating intra-candle movements. + All callback functions (`custom_exit()`, `custom_stoploss()`, ... ) will be running for each 5m candle once the trade is opened (so 12 times in the above example of 1h timeframe, and 5m detailed timeframe). `--timeframe-detail` must be smaller than the original timeframe, otherwise backtesting will fail to start. @@ -593,22 +618,22 @@ To compare multiple strategies, a list of Strategies can be provided to backtest This is limited to 1 timeframe value per run. However, data is only loaded once from disk so if you have multiple strategies you'd like to compare, this will give a nice runtime boost. -All listed Strategies need to be in the same directory. +All listed Strategies need to be in the same directory, unless also `--recursive-strategy-search` is specified, where sub-directories within the strategy directory are also considered. ``` bash freqtrade backtesting --timerange 20180401-20180410 --timeframe 5m --strategy-list Strategy001 Strategy002 --export trades ``` -This will save the results to `user_data/backtest_results/backtest-result-.json`, injecting the strategy-name into the target filename. +This will save the results to `user_data/backtest_results/backtest-result-.json`, including results for both `Strategy001` and `Strategy002`. There will be an additional table comparing win/losses of the different strategies (identical to the "Total" row in the first table). Detailed output for all strategies one after the other will be available, so make sure to scroll up to see the details per strategy. ``` -=========================================================== STRATEGY SUMMARY ========================================================================= -| Strategy | Buys | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses | Drawdown % | -|:------------|-------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|-------:|-----------:| -| Strategy1 | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 0 | 243 | 45.2 | -| Strategy2 | 1487 | -0.13 | -197.58 | -0.00988917 | -98.79 | 4:43:00 | 662 | 0 | 825 | 241.68 | +=========================================================== STRATEGY SUMMARY =========================================================================== +| Strategy | Entries | Avg Profit % | Cum Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins | Draws | Losses | Drawdown % | +|:------------|---------:|---------------:|---------------:|-----------------:|---------------:|:---------------|------:|-------:|-------:|-----------:| +| Strategy1 | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 | 0 | 243 | 45.2 | +| Strategy2 | 1487 | -0.13 | -197.58 | -0.00988917 | -98.79 | 4:43:00 | 662 | 0 | 825 | 241.68 | ``` ## Next step diff --git a/docs/bot-basics.md b/docs/bot-basics.md index 14823722e..a19f005db 100644 --- a/docs/bot-basics.md +++ b/docs/bot-basics.md @@ -7,16 +7,33 @@ This page provides you some basic concepts on how Freqtrade works and operates. * **Strategy**: Your trading strategy, telling the bot what to do. * **Trade**: Open position. * **Open Order**: Order which is currently placed on the exchange, and is not yet complete. -* **Pair**: Tradable pair, usually in the format of Base/Quote (e.g. XRP/USDT). +* **Pair**: Tradable pair, usually in the format of Base/Quote (e.g. `XRP/USDT` for spot, `XRP/USDT:USDT` for futures). * **Timeframe**: Candle length to use (e.g. `"5m"`, `"1h"`, ...). * **Indicators**: Technical indicators (SMA, EMA, RSI, ...). * **Limit order**: Limit orders which execute at the defined limit price or better. * **Market order**: Guaranteed to fill, may move price depending on the order size. +* **Current Profit**: Currently pending (unrealized) profit for this trade. This is mainly used throughout the bot and UI. +* **Realized Profit**: Already realized profit. Only relevant in combination with [partial exits](strategy-callbacks.md#adjust-trade-position) - which also explains the calculation logic for this. +* **Total Profit**: Combined realized and unrealized profit. The relative number (%) is calculated against the total investment in this trade. ## Fee handling All profit calculations of Freqtrade include fees. For Backtesting / Hyperopt / Dry-run modes, the exchange default fee is used (lowest tier on the exchange). For live operations, fees are used as applied by the exchange (this includes BNB rebates etc.). +## Pair naming + +Freqtrade follows the [ccxt naming convention](https://docs.ccxt.com/#/README?id=consistency-of-base-and-quote-currencies) for currencies. +Using the wrong naming convention in the wrong market will usually result in the bot not recognizing the pair, usually resulting in errors like "this pair is not available". + +### Spot pair naming + +For spot pairs, naming will be `base/quote` (e.g. `ETH/USDT`). + +### Futures pair naming + +For futures pairs, naming will be `base/quote:settle` (e.g. `ETH/USDT:USDT`). + + ## Bot execution logic Starting freqtrade in dry-run or live mode (using `freqtrade trade`) will start the bot and start the bot iteration loop. @@ -57,10 +74,10 @@ This loop will be repeated again and again until the bot is stopped. * Load historic data for configured pairlist. * Calls `bot_start()` once. -* Calls `bot_loop_start()` once. * Calculate indicators (calls `populate_indicators()` once per pair). * Calculate entry / exit signals (calls `populate_entry_trend()` and `populate_exit_trend()` once per pair). * Loops per candle simulating entry and exit points. + * Calls `bot_loop_start()` strategy callback. * Check for Order timeouts, either via the `unfilledtimeout` configuration, or via `check_entry_timeout()` / `check_exit_timeout()` strategy callbacks. * Calls `adjust_entry_price()` strategy callback for open entry orders. * Check for trade entry signals (`enter_long` / `enter_short` columns). @@ -70,8 +87,12 @@ This loop will be repeated again and again until the bot is stopped. * Determine stake size by calling the `custom_stake_amount()` callback. * Check position adjustments for open trades if enabled and call `adjust_trade_position()` to determine if an additional order is requested. * Call `custom_stoploss()` and `custom_exit()` to find custom exit points. - * For exits based on exit-signal and custom-exit: Call `custom_exit_price()` to determine exit price (Prices are moved to be within the closing candle). + * For exits based on exit-signal, custom-exit and partial exits: Call `custom_exit_price()` to determine exit price (Prices are moved to be within the closing candle). * Generate backtest report output !!! Note Both Backtesting and Hyperopt include exchange default Fees in the calculation. Custom fees can be passed to backtesting / hyperopt by specifying the `--fee` argument. + +!!! Warning "Callback call frequency" + Backtesting will call each callback at max. once per candle (`--timeframe-detail` modifies this behavior to once per detailed candle). + Most callbacks will be called once per iteration in live (usually every ~5s) - which can cause backtesting mismatches. diff --git a/docs/bot-usage.md b/docs/bot-usage.md index c6a7f6103..7aeda0c42 100644 --- a/docs/bot-usage.md +++ b/docs/bot-usage.md @@ -3,7 +3,7 @@ This page explains the different parameters of the bot and how to run it. !!! Note - If you've used `setup.sh`, don't forget to activate your virtual environment (`source .env/bin/activate`) before running freqtrade commands. + If you've used `setup.sh`, don't forget to activate your virtual environment (`source .venv/bin/activate`) before running freqtrade commands. !!! Warning "Up-to-date clock" The clock on the system running the bot must be accurate, synchronized to a NTP server frequently enough to avoid problems with communication to the exchanges. diff --git a/docs/configuration.md b/docs/configuration.md index d5c0b3d8b..202fa49bf 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -11,7 +11,7 @@ Per default, the bot loads the configuration from the `config.json` file, locate You can specify a different configuration file used by the bot with the `-c/--config` command-line option. -If you used the [Quick start](installation.md/#quick-start) method for installing +If you used the [Quick start](docker_quickstart.md#docker-quick-start) method for installing the bot, the installation script should have already created the default configuration file (`config.json`) for you. If the default configuration file is not created we recommend to use `freqtrade new-config --config config.json` to generate a basic configuration file. @@ -58,9 +58,20 @@ This is similar to using multiple `--config` parameters, but simpler in usage as !!! Tip "Use multiple configuration files to keep secrets secret" You can use a 2nd configuration file containing your secrets. That way you can share your "primary" configuration file, while still keeping your API keys for yourself. + The 2nd file should only specify what you intend to override. + If a key is in more than one of the configurations, then the "last specified configuration" wins (in the above example, `config-private.json`). + + For one-off commands, you can also use the below syntax by specifying multiple "--config" parameters. + + ``` bash + freqtrade trade --config user_data/config1.json --config user_data/config-private.json <...> + ``` + + The below is equivalent to the example above - but having 2 configuration files in the configuration, for easier reuse. ``` json title="user_data/config.json" "add_config_files": [ + "config1.json", "config-private.json" ] ``` @@ -69,17 +80,6 @@ This is similar to using multiple `--config` parameters, but simpler in usage as freqtrade trade --config user_data/config.json <...> ``` - The 2nd file should only specify what you intend to override. - If a key is in more than one of the configurations, then the "last specified configuration" wins (in the above example, `config-private.json`). - - For one-off commands, you can also use the below syntax by specifying multiple "--config" parameters. - - ``` bash - freqtrade trade --config user_data/config.json --config user_data/config-private.json <...> - ``` - - This is equivalent to the example above - but `config-private.json` is specified as cli argument. - ??? Note "config collision handling" If the same configuration setting takes place in both `config.json` and `config-import.json`, then the parent configuration wins. In the below case, `max_open_trades` would be 3 after the merging - as the reusable "import" configuration has this key overwritten. @@ -111,6 +111,8 @@ This is similar to using multiple `--config` parameters, but simpler in usage as } ``` + If multiple files are in the `add_config_files` section, then they will be assumed to be at identical levels, having the last occurrence override the earlier config (unless a parent already defined such a key). + ## Configuration parameters The table below will list all configuration parameters available. @@ -132,11 +134,11 @@ Mandatory parameters are marked as **Required**, which means that they are requi | Parameter | Description | |------------|-------------| -| `max_open_trades` | **Required.** Number of open trades your bot is allowed to have. Only one open trade per pair is possible, so the length of your pairlist is another limitation that can apply. If -1 then it is ignored (i.e. potentially unlimited open trades, limited by the pairlist). [More information below](#configuring-amount-per-trade).
**Datatype:** Positive integer or -1. +| `max_open_trades` | **Required.** Number of open trades your bot is allowed to have. Only one open trade per pair is possible, so the length of your pairlist is another limitation that can apply. If -1 then it is ignored (i.e. potentially unlimited open trades, limited by the pairlist). [More information below](#configuring-amount-per-trade). [Strategy Override](#parameters-in-the-strategy).
**Datatype:** Positive integer or -1. | `stake_currency` | **Required.** Crypto-currency used for trading.
**Datatype:** String | `stake_amount` | **Required.** Amount of crypto-currency your bot will use for each trade. Set it to `"unlimited"` to allow the bot to use all available balance. [More information below](#configuring-amount-per-trade).
**Datatype:** Positive float or `"unlimited"`. | `tradable_balance_ratio` | Ratio of the total account balance the bot is allowed to trade. [More information below](#configuring-amount-per-trade).
*Defaults to `0.99` 99%).*
**Datatype:** Positive float between `0.1` and `1.0`. -| `available_capital` | Available starting capital for the bot. Useful when running multiple bots on the same exchange account.[More information below](#configuring-amount-per-trade).
**Datatype:** Positive float. +| `available_capital` | Available starting capital for the bot. Useful when running multiple bots on the same exchange account. [More information below](#configuring-amount-per-trade).
**Datatype:** Positive float. | `amend_last_stake_amount` | Use reduced last stake amount if necessary. [More information below](#configuring-amount-per-trade).
*Defaults to `false`.*
**Datatype:** Boolean | `last_stake_amount_min_ratio` | Defines minimum stake amount that has to be left and executed. Applies only to the last stake amount when it's amended to a reduced value (i.e. if `amend_last_stake_amount` is set to `true`). [More information below](#configuring-amount-per-trade).
*Defaults to `0.5`.*
**Datatype:** Float (as ratio) | `amount_reserve_percent` | Reserve some amount in min pair stake amount. The bot will reserve `amount_reserve_percent` + stoploss value when calculating min pair stake amount in order to avoid possible trade refusals.
*Defaults to `0.05` (5%).*
**Datatype:** Positive Float as ratio. @@ -153,29 +155,29 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `trailing_stop_positive_offset` | Offset on when to apply `trailing_stop_positive`. Percentage value which should be positive. More details in the [stoploss documentation](stoploss.md#trailing-stop-loss-only-once-the-trade-has-reached-a-certain-offset). [Strategy Override](#parameters-in-the-strategy).
*Defaults to `0.0` (no offset).*
**Datatype:** Float | `trailing_only_offset_is_reached` | Only apply trailing stoploss when the offset is reached. [stoploss documentation](stoploss.md). [Strategy Override](#parameters-in-the-strategy).
*Defaults to `false`.*
**Datatype:** Boolean | `fee` | Fee used during backtesting / dry-runs. Should normally not be configured, which has freqtrade fall back to the exchange default fee. Set as ratio (e.g. 0.001 = 0.1%). Fee is applied twice for each trade, once when buying, once when selling.
**Datatype:** Float (as ratio) -| `futures_funding_rate` | User-specified funding rate to be used when historical funding rates are not available from the exchange. This does not overwrite real historical rates. It is recommended that this be set to 0 unless you are testing a specific coin and you understand how the funding rate will affect freqtrade's profit calculations. [More information here](leverage.md#unavailable-funding-rates)
*Defaults to None.*
**Datatype:** Float +| `futures_funding_rate` | User-specified funding rate to be used when historical funding rates are not available from the exchange. This does not overwrite real historical rates. It is recommended that this be set to 0 unless you are testing a specific coin and you understand how the funding rate will affect freqtrade's profit calculations. [More information here](leverage.md#unavailable-funding-rates)
*Defaults to `None`.*
**Datatype:** Float | `trading_mode` | Specifies if you want to trade regularly, trade with leverage, or trade contracts whose prices are derived from matching cryptocurrency prices. [leverage documentation](leverage.md).
*Defaults to `"spot"`.*
**Datatype:** String | `margin_mode` | When trading with leverage, this determines if the collateral owned by the trader will be shared or isolated to each trading pair [leverage documentation](leverage.md).
**Datatype:** String | `liquidation_buffer` | A ratio specifying how large of a safety net to place between the liquidation price and the stoploss to prevent a position from reaching the liquidation price [leverage documentation](leverage.md).
*Defaults to `0.05`.*
**Datatype:** Float | | **Unfilled timeout** | `unfilledtimeout.entry` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled entry order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).
**Datatype:** Integer | `unfilledtimeout.exit` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled exit order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).
**Datatype:** Integer -| `unfilledtimeout.unit` | Unit to use in unfilledtimeout setting. Note: If you set unfilledtimeout.unit to "seconds", "internals.process_throttle_secs" must be inferior or equal to timeout [Strategy Override](#parameters-in-the-strategy).
*Defaults to `minutes`.*
**Datatype:** String +| `unfilledtimeout.unit` | Unit to use in unfilledtimeout setting. Note: If you set unfilledtimeout.unit to "seconds", "internals.process_throttle_secs" must be inferior or equal to timeout [Strategy Override](#parameters-in-the-strategy).
*Defaults to `"minutes"`.*
**Datatype:** String | `unfilledtimeout.exit_timeout_count` | How many times can exit orders time out. Once this number of timeouts is reached, an emergency exit is triggered. 0 to disable and allow unlimited order cancels. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `0`.*
**Datatype:** Integer | | **Pricing** -| `entry_pricing.price_side` | Select the side of the spread the bot should look at to get the entry rate. [More information below](#buy-price-side).
*Defaults to `same`.*
**Datatype:** String (either `ask`, `bid`, `same` or `other`). +| `entry_pricing.price_side` | Select the side of the spread the bot should look at to get the entry rate. [More information below](#entry-price).
*Defaults to `"same"`.*
**Datatype:** String (either `ask`, `bid`, `same` or `other`). | `entry_pricing.price_last_balance` | **Required.** Interpolate the bidding price. More information [below](#entry-price-without-orderbook-enabled). -| `entry_pricing.use_order_book` | Enable entering using the rates in [Order Book Entry](#entry-price-with-orderbook-enabled).
*Defaults to `True`.*
**Datatype:** Boolean +| `entry_pricing.use_order_book` | Enable entering using the rates in [Order Book Entry](#entry-price-with-orderbook-enabled).
*Defaults to `true`.*
**Datatype:** Boolean | `entry_pricing.order_book_top` | Bot will use the top N rate in Order Book "price_side" to enter a trade. I.e. a value of 2 will allow the bot to pick the 2nd entry in [Order Book Entry](#entry-price-with-orderbook-enabled).
*Defaults to `1`.*
**Datatype:** Positive Integer | `entry_pricing. check_depth_of_market.enabled` | Do not enter if the difference of buy orders and sell orders is met in Order Book. [Check market depth](#check-depth-of-market).
*Defaults to `false`.*
**Datatype:** Boolean | `entry_pricing. check_depth_of_market.bids_to_ask_delta` | The difference ratio of buy orders and sell orders found in Order Book. A value below 1 means sell order size is greater, while value greater than 1 means buy order size is higher. [Check market depth](#check-depth-of-market)
*Defaults to `0`.*
**Datatype:** Float (as ratio) -| `exit_pricing.price_side` | Select the side of the spread the bot should look at to get the exit rate. [More information below](#exit-price-side).
*Defaults to `same`.*
**Datatype:** String (either `ask`, `bid`, `same` or `other`). +| `exit_pricing.price_side` | Select the side of the spread the bot should look at to get the exit rate. [More information below](#exit-price-side).
*Defaults to `"same"`.*
**Datatype:** String (either `ask`, `bid`, `same` or `other`). | `exit_pricing.price_last_balance` | Interpolate the exiting price. More information [below](#exit-price-without-orderbook-enabled). -| `exit_pricing.use_order_book` | Enable exiting of open trades using [Order Book Exit](#exit-price-with-orderbook-enabled).
*Defaults to `True`.*
**Datatype:** Boolean +| `exit_pricing.use_order_book` | Enable exiting of open trades using [Order Book Exit](#exit-price-with-orderbook-enabled).
*Defaults to `true`.*
**Datatype:** Boolean | `exit_pricing.order_book_top` | Bot will use the top N rate in Order Book "price_side" to exit. I.e. a value of 2 will allow the bot to pick the 2nd ask rate in [Order Book Exit](#exit-price-with-orderbook-enabled)
*Defaults to `1`.*
**Datatype:** Positive Integer | `custom_price_max_distance_ratio` | Configure maximum distance ratio between current and custom entry or exit price.
*Defaults to `0.02` 2%).*
**Datatype:** Positive float | | **TODO** -| `use_exit_signal` | Use exit signals produced by the strategy in addition to the `minimal_roi`. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `true`.*
**Datatype:** Boolean +| `use_exit_signal` | Use exit signals produced by the strategy in addition to the `minimal_roi`.
Setting this to false disables the usage of `"exit_long"` and `"exit_short"` columns. Has no influence on other exit methods (Stoploss, ROI, callbacks). [Strategy Override](#parameters-in-the-strategy).
*Defaults to `true`.*
**Datatype:** Boolean | `exit_profit_only` | Wait until the bot reaches `exit_profit_offset` before taking an exit decision. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `false`.*
**Datatype:** Boolean | `exit_profit_offset` | Exit-signal is only active above this value. Only active in combination with `exit_profit_only=True`. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `0.0`.*
**Datatype:** Float (as ratio) | `ignore_roi_if_entry_signal` | Do not exit if the entry signal is still active. This setting takes preference over `minimal_roi` and `use_exit_signal`. [Strategy Override](#parameters-in-the-strategy).
*Defaults to `false`.*
**Datatype:** Boolean @@ -186,7 +188,6 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `max_entry_position_adjustment` | Maximum additional order(s) for each open trade on top of the first entry Order. Set it to `-1` for unlimited additional orders. [More information here](strategy-callbacks.md#adjust-trade-position).
[Strategy Override](#parameters-in-the-strategy).
*Defaults to `-1`.*
**Datatype:** Positive Integer or -1 | | **Exchange** | `exchange.name` | **Required.** Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename).
**Datatype:** String -| `exchange.sandbox` | Use the 'sandbox' version of the exchange, where the exchange provides a sandbox for risk-free integration. See [here](sandbox-testing.md) in more details.
**Datatype:** Boolean | `exchange.key` | API key to use for the exchange. Only required when you are in production mode.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `exchange.secret` | API secret to use for the exchange. Only required when you are in production mode.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `exchange.password` | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String @@ -197,10 +198,10 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `exchange.ccxt_sync_config` | Additional CCXT parameters passed to the regular (sync) ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.ccxt_async_config` | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.markets_refresh_interval` | The interval in minutes in which markets are reloaded.
*Defaults to `60` minutes.*
**Datatype:** Positive Integer -| `exchange.skip_pair_validation` | Skip pairlist validation on startup.
*Defaults to `false`
**Datatype:** Boolean -| `exchange.skip_open_order_update` | Skips open order updates on startup should the exchange cause problems. Only relevant in live conditions.
*Defaults to `false`
**Datatype:** Boolean +| `exchange.skip_pair_validation` | Skip pairlist validation on startup.
*Defaults to `false`*
**Datatype:** Boolean +| `exchange.skip_open_order_update` | Skips open order updates on startup should the exchange cause problems. Only relevant in live conditions.
*Defaults to `false`*
**Datatype:** Boolean | `exchange.unknown_fee_rate` | Fallback value to use when calculating trading fees. This can be useful for exchanges which have fees in non-tradable currencies. The value provided here will be multiplied with the "fee cost".
*Defaults to `None`
**Datatype:** float -| `exchange.log_responses` | Log relevant exchange responses. For debug mode only - use with care.
*Defaults to `false`
**Datatype:** Boolean +| `exchange.log_responses` | Log relevant exchange responses. For debug mode only - use with care.
*Defaults to `false`*
**Datatype:** Boolean | `experimental.block_bad_exchanges` | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now.
*Defaults to `true`.*
**Datatype:** Boolean | | **Plugins** | `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation of all possible configuration options. @@ -211,26 +212,30 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `telegram.token` | Your Telegram bot token. Only required if `telegram.enabled` is `true`.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `telegram.chat_id` | Your personal Telegram account id. Only required if `telegram.enabled` is `true`.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `telegram.balance_dust_level` | Dust-level (in stake currency) - currencies with a balance below this will not be shown by `/balance`.
**Datatype:** float -| `telegram.reload` | Allow "reload" buttons on telegram messages.
*Defaults to `True`.
**Datatype:** boolean +| `telegram.reload` | Allow "reload" buttons on telegram messages.
*Defaults to `true`.
**Datatype:** boolean | `telegram.notification_settings.*` | Detailed notification settings. Refer to the [telegram documentation](telegram-usage.md) for details.
**Datatype:** dictionary +| `telegram.allow_custom_messages` | Enable the sending of Telegram messages from strategies via the dataprovider.send_msg() function.
**Datatype:** Boolean | | **Webhook** | `webhook.enabled` | Enable usage of Webhook notifications
**Datatype:** Boolean | `webhook.url` | URL for the webhook. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookentry` | Payload to send on entry. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookentrycancel` | Payload to send on entry order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookentryfill` | Payload to send on entry order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookexit` | Payload to send on exit. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookexitcancel` | Payload to send on exit order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookexitfill` | Payload to send on exit order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| `webhook.webhookstatus` | Payload to send on status calls. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String -| | **Rest API / FreqUI** +| `webhook.entry` | Payload to send on entry. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.entry_cancel` | Payload to send on entry order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.entry_fill` | Payload to send on entry order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.exit` | Payload to send on exit. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.exit_cancel` | Payload to send on exit order cancel. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.exit_fill` | Payload to send on exit order filled. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.status` | Payload to send on status calls. Only required if `webhook.enabled` is `true`. See the [webhook documentation](webhook-config.md) for more details.
**Datatype:** String +| `webhook.allow_custom_messages` | Enable the sending of Webhook messages from strategies via the dataprovider.send_msg() function.
**Datatype:** Boolean +| | **Rest API / FreqUI / Producer-Consumer** | `api_server.enabled` | Enable usage of API Server. See the [API Server documentation](rest-api.md) for more details.
**Datatype:** Boolean | `api_server.listen_ip_address` | Bind IP address. See the [API Server documentation](rest-api.md) for more details.
**Datatype:** IPv4 | `api_server.listen_port` | Bind Port. See the [API Server documentation](rest-api.md) for more details.
**Datatype:** Integer between 1024 and 65535 | `api_server.verbosity` | Logging verbosity. `info` will print all RPC Calls, while "error" will only display errors.
**Datatype:** Enum, either `info` or `error`. Defaults to `info`. | `api_server.username` | Username for API server. See the [API Server documentation](rest-api.md) for more details.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `api_server.password` | Password for API server. See the [API Server documentation](rest-api.md) for more details.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String +| `api_server.ws_token` | API token for the Message WebSocket. See the [API Server documentation](rest-api.md) for more details.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `bot_name` | Name of the bot. Passed via API to a client - can be shown to distinguish / name bots.
*Defaults to `freqtrade`*
**Datatype:** String +| `external_message_consumer` | Enable [Producer/Consumer mode](producer-consumer.md) for more details.
**Datatype:** Dict | | **Other** | `initial_state` | Defines the initial application state. If set to stopped, then the bot has to be explicitly started via `/start` RPC command.
*Defaults to `stopped`.*
**Datatype:** Enum, either `stopped` or `running` | `force_entry_enable` | Enables the RPC Commands to force a Trade entry. More information below.
**Datatype:** Boolean @@ -245,8 +250,9 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `db_url` | Declares database URL to use. NOTE: This defaults to `sqlite:///tradesv3.dryrun.sqlite` if `dry_run` is `true`, and to `sqlite:///tradesv3.sqlite` for production instances.
**Datatype:** String, SQLAlchemy connect string | `logfile` | Specifies logfile name. Uses a rolling strategy for log file rotation for 10 files with the 1MB limit per file.
**Datatype:** String | `add_config_files` | Additional config files. These files will be loaded and merged with the current config file. The files are resolved relative to the initial file.
*Defaults to `[]`*.
**Datatype:** List of strings -| `dataformat_ohlcv` | Data format to use to store historical candle (OHLCV) data.
*Defaults to `json`*.
**Datatype:** String -| `dataformat_trades` | Data format to use to store historical trades data.
*Defaults to `jsongz`*.
**Datatype:** String +| `dataformat_ohlcv` | Data format to use to store historical candle (OHLCV) data.
*Defaults to `feather`*.
**Datatype:** String +| `dataformat_trades` | Data format to use to store historical trades data.
*Defaults to `feather`*.
**Datatype:** String +| `reduce_df_footprint` | Recast all numeric columns to float32/int32, with the objective of reducing ram/disk usage (and decreasing train/inference timing in FreqAI). (Currently only affects FreqAI use-cases)
**Datatype:** Boolean.
Default: `False`. ### Parameters in the strategy @@ -256,6 +262,7 @@ Values set in the configuration file always overwrite values set in the strategy * `minimal_roi` * `timeframe` * `stoploss` +* `max_open_trades` * `trailing_stop` * `trailing_stop_positive` * `trailing_stop_positive_offset` @@ -314,7 +321,7 @@ For example, if you have 10 ETH available in your wallet on the exchange and `tr To fully utilize compounding profits when using multiple bots on the same exchange account, you'll want to limit each bot to a certain starting balance. This can be accomplished by setting `available_capital` to the desired starting balance. -Assuming your account has 10.000 USDT and you want to run 2 different strategies on this exchange. +Assuming your account has 10000 USDT and you want to run 2 different strategies on this exchange. You'd set `available_capital=5000` - granting each bot an initial capital of 5000 USDT. The bot will then split this starting balance equally into `max_open_trades` buckets. Profitable trades will result in increased stake-sizes for this bot - without affecting the stake-sizes of the other bot. @@ -525,21 +532,28 @@ It means if the order is not executed immediately AND fully then it is cancelled It is the same as FOK (above) except it can be partially fulfilled. The remaining part is automatically cancelled by the exchange. -The `order_time_in_force` parameter contains a dict with buy and sell time in force policy values. +**PO (Post only):** + +Post only order. The order is either placed as a maker order, or it is canceled. +This means the order must be placed on orderbook for at at least time in an unfilled state. + +#### time_in_force config + +The `order_time_in_force` parameter contains a dict with entry and exit time in force policy values. This can be set in the configuration file or in the strategy. Values set in the configuration file overwrites values set in the strategy. -The possible values are: `gtc` (default), `fok` or `ioc`. +The possible values are: `GTC` (default), `FOK` or `IOC`. ``` python "order_time_in_force": { - "entry": "gtc", - "exit": "gtc" + "entry": "GTC", + "exit": "GTC" }, ``` !!! Warning - This is ongoing work. For now, it is supported only for binance and kucoin. + This is ongoing work. For now, it is supported only for binance, gate and kucoin. Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange. ### What values can be used for fiat_display_currency? @@ -558,9 +572,11 @@ In addition to fiat currencies, a range of crypto currencies is supported. The valid values are: ```json -"BTC", "ETH", "XRP", "LTC", "BCH", "USDT" +"BTC", "ETH", "XRP", "LTC", "BCH", "BNB" ``` +Removing `fiat_display_currency` completely from the configuration will skip initializing coingecko, and will not show any FIAT currency conversion. This has no importance for the correct functioning of the bot. + ## Using Dry-run mode We recommend starting the bot in the Dry-run mode to see how your bot will @@ -580,7 +596,7 @@ creating trades on the exchange. ```json "exchange": { - "name": "bittrex", + "name": "binance", "key": "key", "secret": "secret", ... @@ -599,6 +615,7 @@ Once you will be happy with your bot performance running in the Dry-run mode, yo * Orders are simulated, and will not be posted to the exchange. * Market orders fill based on orderbook volume the moment the order is placed. * Limit orders fill once the price reaches the defined level - or time out based on `unfilledtimeout` settings. +* Limit orders will be converted to market orders if they cross the price by more than 1%. * In combination with `stoploss_on_exchange`, the stop_loss price is assumed to be filled. * Open orders (not trades, which are stored in the database) are kept open after bot restarts, with the assumption that they were not filled while being offline. @@ -629,7 +646,7 @@ API Keys are usually only required for live trading (trading for real money, bot ```json { "exchange": { - "name": "bittrex", + "name": "binance", "key": "af8ddd35195e9dc500b9a6f799f6f5c93d89193b", "secret": "08a9dc6db3d7b53e1acebd9275677f4b0a04f1a5", //"password": "", // Optional, not needed by all exchanges) @@ -650,17 +667,8 @@ You should also make sure to read the [Exchanges](exchanges.md) section of the d ### Using proxy with Freqtrade -To use a proxy with freqtrade, add the kwarg `"aiohttp_trust_env"=true` to the `"ccxt_async_kwargs"` dict in the exchange section of the configuration. - -An example for this can be found in `config_examples/config_full.example.json` - -``` json -"ccxt_async_config": { - "aiohttp_trust_env": true -} -``` - -Then, export your proxy settings using the variables `"HTTP_PROXY"` and `"HTTPS_PROXY"` set to the appropriate values +To use a proxy with freqtrade, export your proxy settings using the variables `"HTTP_PROXY"` and `"HTTPS_PROXY"` set to the appropriate values. +This will have the proxy settings applied to everything (telegram, coingecko, ...) **except** for exchange requests. ``` bash export HTTP_PROXY="http://addr:port" @@ -668,6 +676,22 @@ export HTTPS_PROXY="http://addr:port" freqtrade ``` +#### Proxy exchange requests + +To use a proxy for exchange connections - you will have to define the proxies as part of the ccxt configuration. + +``` json +{ + "exchange": { + "ccxt_config": { + "httpsProxy": "http://addr:port", + } + } +} +``` + +For more information on available proxy types, please consult the [ccxt proxy documentation](https://docs.ccxt.com/#/README?id=proxy). + ## Next step Now you have configured your config.json, the next step is to [start your bot](bot-usage.md). diff --git a/docs/data-analysis.md b/docs/data-analysis.md index 926ed3eae..200aa289d 100644 --- a/docs/data-analysis.md +++ b/docs/data-analysis.md @@ -5,12 +5,12 @@ You can analyze the results of backtests and trading history easily using Jupyte ## Quick start with docker Freqtrade provides a docker-compose file which starts up a jupyter lab server. -You can run this server using the following command: `docker-compose -f docker/docker-compose-jupyter.yml up` +You can run this server using the following command: `docker compose -f docker/docker-compose-jupyter.yml up` This will create a dockercontainer running jupyter lab, which will be accessible using `https://127.0.0.1:8888/lab`. Please use the link that's printed in the console after startup for simplified login. -For more information, Please visit the [Data analysis with Docker](docker_quickstart.md#data-analayis-using-docker-compose) section. +For more information, Please visit the [Data analysis with Docker](docker_quickstart.md#data-analysis-using-docker-compose) section. ### Pro tips @@ -27,7 +27,7 @@ For this to work, first activate your virtual environment and run the following ``` bash # Activate virtual environment -source .env/bin/activate +source .venv/bin/activate pip install ipykernel ipython kernel install --user --name=freqtrade @@ -83,7 +83,7 @@ from pathlib import Path project_root = "somedir/freqtrade" i=0 try: - os.chdirdir(project_root) + os.chdir(project_root) assert Path('LICENSE').is_file() except: while i<4 and (not Path('LICENSE').is_file()): diff --git a/docs/data-download.md b/docs/data-download.md index 681fb717d..890a89b60 100644 --- a/docs/data-download.md +++ b/docs/data-download.md @@ -6,7 +6,7 @@ To download data (candles / OHLCV) needed for backtesting and hyperoptimization If no additional parameter is specified, freqtrade will download data for `"1m"` and `"5m"` timeframes for the last 30 days. Exchange and pairs will come from `config.json` (if specified using `-c/--config`). -Otherwise `--exchange` becomes mandatory. +Without provided configuration, `--exchange` becomes mandatory. You can use a relative timerange (`--days 20`) or an absolute starting point (`--timerange 20200101-`). For incremental downloads, the relative approach should be used. @@ -25,19 +25,19 @@ usage: freqtrade download-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [--include-inactive-pairs] [--timerange TIMERANGE] [--dl-trades] [--exchange EXCHANGE] - [-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]] - [--erase] - [--data-format-ohlcv {json,jsongz,hdf5}] - [--data-format-trades {json,jsongz,hdf5}] + [-t TIMEFRAMES [TIMEFRAMES ...]] [--erase] + [--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}] + [--data-format-trades {json,jsongz,hdf5,feather}] [--trading-mode {spot,margin,futures}] [--prepend] -optional arguments: +options: -h, --help show this help message and exit -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] Limit command to these pairs. Pairs are space- separated. - --pairs-file FILE File containing a list of pairs to download. + --pairs-file FILE File containing a list of pairs. Takes precedence over + --pairs or pairs configured in the configuration. --days INT Download data for given number of days. --new-pairs-days INT Download data of new pairs for given number of days. Default: `None`. @@ -48,26 +48,26 @@ optional arguments: --dl-trades Download trades instead of OHLCV data. The bot will resample trades to the desired timeframe as specified as --timeframes/-t. - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no - config is provided. - -t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...], --timeframes {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...] + --exchange EXCHANGE Exchange name. Only valid if no config is provided. + -t TIMEFRAMES [TIMEFRAMES ...], --timeframes TIMEFRAMES [TIMEFRAMES ...] Specify which tickers to download. Space-separated list. Default: `1m 5m`. --erase Clean all existing data for the selected exchange/pairs/timeframes. - --data-format-ohlcv {json,jsongz,hdf5} + --data-format-ohlcv {json,jsongz,hdf5,feather,parquet} Storage format for downloaded candle (OHLCV) data. - (default: `json`). - --data-format-trades {json,jsongz,hdf5} + (default: `feather`). + --data-format-trades {json,jsongz,hdf5,feather} Storage format for downloaded trades data. (default: - `jsongz`). - --trading-mode {spot,margin,futures} + `feather`). + --trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures} Select Trading mode - --prepend Allow data prepending. + --prepend Allow data prepending. (Data-appending is disabled) Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: + --logfile FILE, --log-file FILE + Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. -V, --version show program's version number and exit @@ -76,25 +76,150 @@ Common arguments: `userdir/config.json` or `config.json` whichever exists). Multiple --config options may be used. Can be set to `-` to read config from stdin. - -d PATH, --datadir PATH + -d PATH, --datadir PATH, --data-dir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. ``` +!!! Tip "Downloading all data for one quote currency" + Often, you'll want to download data for all pairs of a specific quote-currency. In such cases, you can use the following shorthand: + `freqtrade download-data --exchange binance --pairs .*/USDT <...>`. The provided "pairs" string will be expanded to contain all active pairs on the exchange. + To also download data for inactive (delisted) pairs, add `--include-inactive-pairs` to the command. + !!! Note "Startup period" `download-data` is a strategy-independent command. The idea is to download a big chunk of data once, and then iteratively increase the amount of data stored. For that reason, `download-data` does not care about the "startup-period" defined in a strategy. It's up to the user to download additional days if the backtest should start at a specific point in time (while respecting startup period). +### Start download + +A very simple command (assuming an available `config.json` file) can look as follows. + +```bash +freqtrade download-data --exchange binance +``` + +This will download historical candle (OHLCV) data for all the currency pairs defined in the configuration. + +Alternatively, specify the pairs directly + +```bash +freqtrade download-data --exchange binance --pairs ETH/USDT XRP/USDT BTC/USDT +``` + +or as regex (in this case, to download all active USDT pairs) + +```bash +freqtrade download-data --exchange binance --pairs .*/USDT +``` + +### Other Notes + +* To use a different directory than the exchange specific default, use `--datadir user_data/data/some_directory`. +* To change the exchange used to download the historical data from, please use a different configuration file (you'll probably need to adjust rate limits etc.) +* To use `pairs.json` from some other directory, use `--pairs-file some_other_dir/pairs.json`. +* To download historical candle (OHLCV) data for only 10 days, use `--days 10` (defaults to 30 days). +* To download historical candle (OHLCV) data from a fixed starting point, use `--timerange 20200101-` - which will download all data from January 1st, 2020. +* Use `--timeframes` to specify what timeframe download the historical candle (OHLCV) data for. Default is `--timeframes 1m 5m` which will download 1-minute and 5-minute data. +* To use exchange, timeframe and list of pairs as defined in your configuration file, use the `-c/--config` option. With this, the script uses the whitelist defined in the config as the list of currency pairs to download data for and does not require the pairs.json file. You can combine `-c/--config` with most other options. + +??? Note "Permission denied errors" + If your configuration directory `user_data` was made by docker, you may get the following error: + + ``` + cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission denied + ``` + + You can fix the permissions of your user-data directory as follows: + + ``` + sudo chown -R $UID:$GID user_data + ``` + +### Download additional data before the current timerange + +Assuming you downloaded all data from 2022 (`--timerange 20220101-`) - but you'd now like to also backtest with earlier data. +You can do so by using the `--prepend` flag, combined with `--timerange` - specifying an end-date. + +``` bash +freqtrade download-data --exchange binance --pairs ETH/USDT XRP/USDT BTC/USDT --prepend --timerange 20210101-20220101 +``` + +!!! Note + Freqtrade will ignore the end-date in this mode if data is available, updating the end-date to the existing data start point. + +### Data format + +Freqtrade currently supports the following data-formats: + +* `feather` - a dataformat based on Apache Arrow +* `json` - plain "text" json files +* `jsongz` - a gzip-zipped version of json files +* `hdf5` - a high performance datastore +* `parquet` - columnar datastore (OHLCV only) + +By default, both OHLCV data and trades data are stored in the `feather` format. + +This can be changed via the `--data-format-ohlcv` and `--data-format-trades` command line arguments respectively. +To persist this change, you should also add the following snippet to your configuration, so you don't have to insert the above arguments each time: + +``` jsonc + // ... + "dataformat_ohlcv": "hdf5", + "dataformat_trades": "hdf5", + // ... +``` + +If the default data-format has been changed during download, then the keys `dataformat_ohlcv` and `dataformat_trades` in the configuration file need to be adjusted to the selected dataformat as well. + +!!! Note + You can convert between data-formats using the [convert-data](#sub-command-convert-data) and [convert-trade-data](#sub-command-convert-trade-data) methods. + +#### Dataformat comparison + +The following comparisons have been made with the following data, and by using the linux `time` command. + +``` +Found 6 pair / timeframe combinations. ++----------+-------------+--------+---------------------+---------------------+ +| Pair | Timeframe | Type | From | To | +|----------+-------------+--------+---------------------+---------------------| +| BTC/USDT | 5m | spot | 2017-08-17 04:00:00 | 2022-09-13 19:25:00 | +| ETH/USDT | 1m | spot | 2017-08-17 04:00:00 | 2022-09-13 19:26:00 | +| BTC/USDT | 1m | spot | 2017-08-17 04:00:00 | 2022-09-13 19:30:00 | +| XRP/USDT | 5m | spot | 2018-05-04 08:10:00 | 2022-09-13 19:15:00 | +| XRP/USDT | 1m | spot | 2018-05-04 08:11:00 | 2022-09-13 19:22:00 | +| ETH/USDT | 5m | spot | 2017-08-17 04:00:00 | 2022-09-13 19:20:00 | ++----------+-------------+--------+---------------------+---------------------+ +``` + +Timings have been taken in a not very scientific way with the following command, which forces reading the data into memory. + +``` bash +time freqtrade list-data --show-timerange --data-format-ohlcv +``` + +| Format | Size | timing | +|------------|-------------|-------------| +| `feather` | 72Mb | 3.5s | +| `json` | 149Mb | 25.6s | +| `jsongz` | 39Mb | 27s | +| `hdf5` | 145Mb | 3.9s | +| `parquet` | 83Mb | 3.8s | + +Size has been taken from the BTC/USDT 1m spot combination for the timerange specified above. + +To have a best performance/size mix, we recommend using the default feather format, or parquet. + ### Pairs file In alternative to the whitelist from `config.json`, a `pairs.json` file can be used. If you are using Binance for example: -- create a directory `user_data/data/binance` and copy or create the `pairs.json` file in that directory. -- update the `pairs.json` file to contain the currency pairs you are interested in. +* create a directory `user_data/data/binance` and copy or create the `pairs.json` file in that directory. +* update the `pairs.json` file to contain the currency pairs you are interested in. ```bash mkdir -p user_data/data/binance @@ -113,130 +238,48 @@ Mixing different stake-currencies is allowed for this file, since it's only used ] ``` -!!! Tip "Downloading all data for one quote currency" - Often, you'll want to download data for all pairs of a specific quote-currency. In such cases, you can use the following shorthand: - `freqtrade download-data --exchange binance --pairs .*/USDT <...>`. The provided "pairs" string will be expanded to contain all active pairs on the exchange. - To also download data for inactive (delisted) pairs, add `--include-inactive-pairs` to the command. - -??? Note "Permission denied errors" - If your configuration directory `user_data` was made by docker, you may get the following error: - - ``` - cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission denied - ``` - - You can fix the permissions of your user-data directory as follows: - - ``` - sudo chown -R $UID:$GID user_data - ``` - -### Start download - -Then run: - -```bash -freqtrade download-data --exchange binance -``` - -This will download historical candle (OHLCV) data for all the currency pairs you defined in `pairs.json`. - -Alternatively, specify the pairs directly - -```bash -freqtrade download-data --exchange binance --pairs ETH/USDT XRP/USDT BTC/USDT -``` - -or as regex (to download all active USDT pairs) - -```bash -freqtrade download-data --exchange binance --pairs .*/USDT -``` - -### Other Notes - -- To use a different directory than the exchange specific default, use `--datadir user_data/data/some_directory`. -- To change the exchange used to download the historical data from, please use a different configuration file (you'll probably need to adjust rate limits etc.) -- To use `pairs.json` from some other directory, use `--pairs-file some_other_dir/pairs.json`. -- To download historical candle (OHLCV) data for only 10 days, use `--days 10` (defaults to 30 days). -- To download historical candle (OHLCV) data from a fixed starting point, use `--timerange 20200101-` - which will download all data from January 1st, 2020. -- Use `--timeframes` to specify what timeframe download the historical candle (OHLCV) data for. Default is `--timeframes 1m 5m` which will download 1-minute and 5-minute data. -- To use exchange, timeframe and list of pairs as defined in your configuration file, use the `-c/--config` option. With this, the script uses the whitelist defined in the config as the list of currency pairs to download data for and does not require the pairs.json file. You can combine `-c/--config` with most other options. - -#### Download additional data before the current timerange - -Assuming you downloaded all data from 2022 (`--timerange 20220101-`) - but you'd now like to also backtest with earlier data. -You can do so by using the `--prepend` flag, combined with `--timerange` - specifying an end-date. - -``` bash -freqtrade download-data --exchange binance --pairs ETH/USDT XRP/USDT BTC/USDT --prepend --timerange 20210101-20220101 -``` - !!! Note - Freqtrade will ignore the end-date in this mode if data is available, updating the end-date to the existing data start point. + The `pairs.json` file is only used when no configuration is loaded (implicitly by naming, or via `--config` flag). + You can force the usage of this file via `--pairs-file pairs.json` - however we recommend to use the pairlist from within the configuration, either via `exchange.pair_whitelist` or `pairs` setting in the configuration. -### Data format - -Freqtrade currently supports 3 data-formats for both OHLCV and trades data: - -* `json` (plain "text" json files) -* `jsongz` (a gzip-zipped version of json files) -* `hdf5` (a high performance datastore) - -By default, OHLCV data is stored as `json` data, while trades data is stored as `jsongz` data. - -This can be changed via the `--data-format-ohlcv` and `--data-format-trades` command line arguments respectively. -To persist this change, you can should also add the following snippet to your configuration, so you don't have to insert the above arguments each time: - -``` jsonc - // ... - "dataformat_ohlcv": "hdf5", - "dataformat_trades": "hdf5", - // ... -``` - -If the default data-format has been changed during download, then the keys `dataformat_ohlcv` and `dataformat_trades` in the configuration file need to be adjusted to the selected dataformat as well. - -!!! Note - You can convert between data-formats using the [convert-data](#sub-command-convert-data) and [convert-trade-data](#sub-command-convert-trade-data) methods. - -#### Sub-command convert data +## Sub-command convert data ``` usage: freqtrade convert-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] --format-from - {json,jsongz,hdf5} --format-to - {json,jsongz,hdf5} [--erase] - [-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]] + {json,jsongz,hdf5,feather,parquet} --format-to + {json,jsongz,hdf5,feather,parquet} [--erase] [--exchange EXCHANGE] + [-t TIMEFRAMES [TIMEFRAMES ...]] [--trading-mode {spot,margin,futures}] - [--candle-types {spot,,futures,mark,index,premiumIndex,funding_rate} [{spot,,futures,mark,index,premiumIndex,funding_rate} ...]] + [--candle-types {spot,futures,mark,index,premiumIndex,funding_rate} [{spot,futures,mark,index,premiumIndex,funding_rate} ...]] -optional arguments: +options: -h, --help show this help message and exit -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] Limit command to these pairs. Pairs are space- separated. - --format-from {json,jsongz,hdf5} + --format-from {json,jsongz,hdf5,feather,parquet} Source format for data conversion. - --format-to {json,jsongz,hdf5} + --format-to {json,jsongz,hdf5,feather,parquet} Destination format for data conversion. --erase Clean all existing data for the selected exchange/pairs/timeframes. - -t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...], --timeframes {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...] + --exchange EXCHANGE Exchange name. Only valid if no config is provided. + -t TIMEFRAMES [TIMEFRAMES ...], --timeframes TIMEFRAMES [TIMEFRAMES ...] Specify which tickers to download. Space-separated list. Default: `1m 5m`. - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no - config is provided. - --trading-mode {spot,margin,futures} + --trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures} Select Trading mode - --candle-types {spot,,futures,mark,index,premiumIndex,funding_rate} [{spot,,futures,mark,index,premiumIndex,funding_rate} ...] - Select candle type to use + --candle-types {spot,futures,mark,index,premiumIndex,funding_rate} [{spot,futures,mark,index,premiumIndex,funding_rate} ...] + Select candle type to convert. Defaults to all + available types. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: + --logfile FILE, --log-file FILE + Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. -V, --version show program's version number and exit @@ -245,14 +288,13 @@ Common arguments: `userdir/config.json` or `config.json` whichever exists). Multiple --config options may be used. Can be set to `-` to read config from stdin. - -d PATH, --datadir PATH + -d PATH, --datadir PATH, --data-dir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. - ``` -##### Example converting data +### Example converting data The following command will convert all candle (OHLCV) data available in `~/.freqtrade/data/binance` from json to jsongz, saving diskspace in the process. It'll also remove original json data files (`--erase` parameter). @@ -261,30 +303,34 @@ It'll also remove original json data files (`--erase` parameter). freqtrade convert-data --format-from json --format-to jsongz --datadir ~/.freqtrade/data/binance -t 5m 15m --erase ``` -#### Sub-command convert trade data +## Sub-command convert trade data ``` usage: freqtrade convert-trade-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] --format-from - {json,jsongz,hdf5} --format-to - {json,jsongz,hdf5} [--erase] + {json,jsongz,hdf5,feather,parquet} + --format-to + {json,jsongz,hdf5,feather,parquet} + [--erase] [--exchange EXCHANGE] -optional arguments: +options: -h, --help show this help message and exit -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] - Show profits for only these pairs. Pairs are space- + Limit command to these pairs. Pairs are space- separated. - --format-from {json,jsongz,hdf5} + --format-from {json,jsongz,hdf5,feather,parquet} Source format for data conversion. - --format-to {json,jsongz,hdf5} + --format-to {json,jsongz,hdf5,feather,parquet} Destination format for data conversion. --erase Clean all existing data for the selected exchange/pairs/timeframes. + --exchange EXCHANGE Exchange name. Only valid if no config is provided. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: + --logfile FILE, --log-file FILE + Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. -V, --version show program's version number and exit @@ -293,14 +339,14 @@ Common arguments: `userdir/config.json` or `config.json` whichever exists). Multiple --config options may be used. Can be set to `-` to read config from stdin. - -d PATH, --datadir PATH + -d PATH, --datadir PATH, --data-dir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. ``` -##### Example converting trades +### Example converting trades The following command will convert all available trade-data in `~/.freqtrade/data/kraken` from jsongz to json. It'll also remove original jsongz data files (`--erase` parameter). @@ -309,7 +355,7 @@ It'll also remove original jsongz data files (`--erase` parameter). freqtrade convert-trade-data --format-from jsongz --format-to json --datadir ~/.freqtrade/data/kraken --erase ``` -### Sub-command trades to ohlcv +## Sub-command trades to ohlcv When you need to use `--dl-trades` (kraken only) to download data, conversion of trades data to ohlcv data is the last step. This command will allow you to repeat this last step for additional timeframes without re-downloading the data. @@ -318,31 +364,31 @@ This command will allow you to repeat this last step for additional timeframes w usage: freqtrade trades-to-ohlcv [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] - [-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]] + [-t TIMEFRAMES [TIMEFRAMES ...]] [--exchange EXCHANGE] - [--data-format-ohlcv {json,jsongz,hdf5}] - [--data-format-trades {json,jsongz,hdf5}] + [--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}] + [--data-format-trades {json,jsongz,hdf5,feather}] -optional arguments: +options: -h, --help show this help message and exit -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] Limit command to these pairs. Pairs are space- separated. - -t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...], --timeframes {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...] + -t TIMEFRAMES [TIMEFRAMES ...], --timeframes TIMEFRAMES [TIMEFRAMES ...] Specify which tickers to download. Space-separated list. Default: `1m 5m`. - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no - config is provided. - --data-format-ohlcv {json,jsongz,hdf5} + --exchange EXCHANGE Exchange name. Only valid if no config is provided. + --data-format-ohlcv {json,jsongz,hdf5,feather,parquet} Storage format for downloaded candle (OHLCV) data. - (default: `json`). - --data-format-trades {json,jsongz,hdf5} + (default: `feather`). + --data-format-trades {json,jsongz,hdf5,feather} Storage format for downloaded trades data. (default: - `jsongz`). + `feather`). Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: + --logfile FILE, --log-file FILE + Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. -V, --version show program's version number and exit @@ -351,46 +397,49 @@ Common arguments: `userdir/config.json` or `config.json` whichever exists). Multiple --config options may be used. Can be set to `-` to read config from stdin. - -d PATH, --datadir PATH + -d PATH, --datadir PATH, --data-dir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. ``` -#### Example trade-to-ohlcv conversion +### Example trade-to-ohlcv conversion ``` bash freqtrade trades-to-ohlcv --exchange kraken -t 5m 1h 1d --pairs BTC/EUR ETH/EUR ``` -### Sub-command list-data +## Sub-command list-data You can get a list of downloaded data using the `list-data` sub-command. ``` usage: freqtrade list-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [--exchange EXCHANGE] - [--data-format-ohlcv {json,jsongz,hdf5}] + [--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}] [-p PAIRS [PAIRS ...]] [--trading-mode {spot,margin,futures}] + [--show-timerange] -optional arguments: +options: -h, --help show this help message and exit - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no - config is provided. - --data-format-ohlcv {json,jsongz,hdf5} + --exchange EXCHANGE Exchange name. Only valid if no config is provided. + --data-format-ohlcv {json,jsongz,hdf5,feather,parquet} Storage format for downloaded candle (OHLCV) data. - (default: `json`). + (default: `feather`). -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] Limit command to these pairs. Pairs are space- separated. - --trading-mode {spot,margin,futures} + --trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures} Select Trading mode + --show-timerange Show timerange available for available data. (May take + a while to calculate). Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: + --logfile FILE, --log-file FILE + Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. -V, --version show program's version number and exit @@ -399,14 +448,14 @@ Common arguments: `userdir/config.json` or `config.json` whichever exists). Multiple --config options may be used. Can be set to `-` to read config from stdin. - -d PATH, --datadir PATH + -d PATH, --datadir PATH, --data-dir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. ``` -#### Example list-data +### Example list-data ```bash > freqtrade list-data --userdir ~/.freqtrade/user_data/ @@ -420,12 +469,12 @@ ETH/BTC 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d ETH/USDT 5m, 15m, 30m, 1h, 2h, 4h ``` -### Trades (tick) data +## Trades (tick) data By default, `download-data` sub-command downloads Candles (OHLCV) data. Some exchanges also provide historic trade-data via their API. This data can be useful if you need many different timeframes, since it is only downloaded once, and then resampled locally to the desired timeframes. -Since this data is large by default, the files use gzip by default. They are stored in your data-directory with the naming convention of `-trades.json.gz` (`ETH_BTC-trades.json.gz`). Incremental mode is also supported, as for historic OHLCV data, so downloading the data once per week with `--days 8` will create an incremental data-repository. +Since this data is large by default, the files use the feather fileformat by default. They are stored in your data-directory with the naming convention of `-trades.feather` (`ETH_BTC-trades.feather`). Incremental mode is also supported, as for historic OHLCV data, so downloading the data once per week with `--days 8` will create an incremental data-repository. To use this mode, simply add `--dl-trades` to your call. This will swap the download method to download trades, and resamples the data locally. diff --git a/docs/deprecated.md b/docs/deprecated.md index beceb12ab..6719ce56d 100644 --- a/docs/deprecated.md +++ b/docs/deprecated.md @@ -66,11 +66,16 @@ We will keep a compatibility layer for 1-2 versions (so both `buy_tag` and `ente #### Naming changes -Webhook terminology changed from "sell" to "exit", and from "buy" to "entry". +Webhook terminology changed from "sell" to "exit", and from "buy" to "entry", removing "webhook" in the process. -* `webhookbuy` -> `webhookentry` -* `webhookbuyfill` -> `webhookentryfill` -* `webhookbuycancel` -> `webhookentrycancel` -* `webhooksell` -> `webhookexit` -* `webhooksellfill` -> `webhookexitfill` -* `webhooksellcancel` -> `webhookexitcancel` +* `webhookbuy`, `webhookentry` -> `entry` +* `webhookbuyfill`, `webhookentryfill` -> `entry_fill` +* `webhookbuycancel`, `webhookentrycancel` -> `entry_cancel` +* `webhooksell`, `webhookexit` -> `exit` +* `webhooksellfill`, `webhookexitfill` -> `exit_fill` +* `webhooksellcancel`, `webhookexitcancel` -> `exit_cancel` + + +## Removal of `populate_any_indicators` + +version 2023.3 saw the removal of `populate_any_indicators` in favor of split methods for feature engineering and targets. Please read the [migration document](strategy_migration.md#freqai-strategy) for full details. diff --git a/docs/developer.md b/docs/developer.md index aca4ce4ed..9c549012d 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -24,7 +24,7 @@ This will spin up a local server (usually on port 8000) so you can see if everyt To configure a development environment, you can either use the provided [DevContainer](#devcontainer-setup), or use the `setup.sh` script and answer "y" when asked "Do you want to install dependencies for dev [y/N]? ". Alternatively (e.g. if your system is not supported by the setup.sh script), follow the manual installation process and run `pip3 install -e .[all]`. -This will install all required tools for development, including `pytest`, `flake8`, `mypy`, and `coveralls`. +This will install all required tools for development, including `pytest`, `ruff`, `mypy`, and `coveralls`. Then install the git hook scripts by running `pre-commit install`, so your changes will be verified locally before committing. This avoids a lot of waiting for CI already, as some basic formatting checks are done locally on your machine. @@ -49,6 +49,13 @@ For more information about the [Remote container extension](https://code.visuals New code should be covered by basic unittests. Depending on the complexity of the feature, Reviewers may request more in-depth unittests. If necessary, the Freqtrade team can assist and give guidance with writing good tests (however please don't expect anyone to write the tests for you). +#### How to run tests + +Use `pytest` in root folder to run all available testcases and confirm your local environment is setup correctly + +!!! Note "feature branches" + Tests are expected to pass on the `develop` and `stable` branches. Other branches may be work in progress with tests not working yet. + #### Checking log content in tests Freqtrade uses 2 main methods to check log content in tests, `log_has()` and `log_has_re()` (to check using regex, in case of dynamic log-messages). @@ -70,7 +77,7 @@ def test_method_to_test(caplog): ### Debug configuration -To debug freqtrade, we recommend VSCode with the following launch configuration (located in `.vscode/launch.json`). +To debug freqtrade, we recommend VSCode (with the Python extension) with the following launch configuration (located in `.vscode/launch.json`). Details will obviously vary between setups - but this should work to get you started. ``` json @@ -95,6 +102,19 @@ This method can also be used to debug a strategy, by setting the breakpoints wit A similar setup can also be taken for Pycharm - using `freqtrade` as module name, and setting the command line arguments as "parameters". +??? Tip "Correct venv usage" + When using a virtual environment (which you should), make sure that your Editor is using the correct virtual environment to avoid problems or "unknown import" errors. + + #### Vscode + + You can select the correct environment in VSCode with the command "Python: Select Interpreter" - which will show you environments the extension detected. + If your environment has not been detected, you can also pick a path manually. + + #### Pycharm + + In pycharm, you can select the appropriate Environment in the "Run/Debug Configurations" window. + ![Pycharm debug configuration](assets/pycharm_debug.png) + !!! Note "Startup directory" This assumes that you have the repository checked out, and the editor is started at the repository root level (so setup.py is at the top level of your repository). @@ -298,6 +318,7 @@ Additional tests / steps to complete: * Check if balance shows correctly (*) * Create market order (*) * Create limit order (*) +* Cancel order (*) * Complete trade (enter + exit) (*) * Compare result calculation between exchange and bot * Ensure fees are applied correctly (check the database against the exchange) @@ -320,18 +341,18 @@ To check how the new exchange behaves, you can use the following snippet: ``` python import ccxt -from datetime import datetime +from datetime import datetime, timezone from freqtrade.data.converter import ohlcv_to_dataframe -ct = ccxt.binance() +ct = ccxt.binance() # Use the exchange you're testing timeframe = "1d" -pair = "XLM/BTC" # Make sure to use a pair that exists on that exchange! +pair = "BTC/USDT" # Make sure to use a pair that exists on that exchange! raw = ct.fetch_ohlcv(pair, timeframe=timeframe) # convert to dataframe df1 = ohlcv_to_dataframe(raw, timeframe, pair=pair, drop_incomplete=False) print(df1.tail(1)) -print(datetime.utcnow()) +print(datetime.now(timezone.utc)) ``` ``` output @@ -356,7 +377,7 @@ from pathlib import Path exchange = ccxt.binance({ 'apiKey': '', 'secret': '' - 'options': {'defaultType': 'future'} + 'options': {'defaultType': 'swap'} }) _ = exchange.load_markets() @@ -398,6 +419,9 @@ This part of the documentation is aimed at maintainers, and shows how to create ### Create release branch +!!! Note + Make sure that the `stable` branch is up-to-date! + First, pick a commit that's about one week old (to not include latest additions to releases). ``` bash @@ -409,14 +433,12 @@ Determine if crucial bugfixes have been made between this commit and the current * Merge the release branch (stable) into this branch. * Edit `freqtrade/__init__.py` and add the version matching the current date (for example `2019.7` for July 2019). Minor versions can be `2019.7.1` should we need to do a second release that month. Version numbers must follow allowed versions from PEP0440 to avoid failures pushing to pypi. -* Commit this part -* push that branch to the remote and create a PR against the stable branch +* Commit this part. +* Push that branch to the remote and create a PR against the **stable branch**. +* Update develop version to next version following the pattern `2019.8-dev`. ### Create changelog from git commits -!!! Note - Make sure that the `stable` branch is up-to-date! - ``` bash # Needs to be done before merging / pulling that branch. git log --oneline --no-decorate --no-merges stable..new_release @@ -433,6 +455,11 @@ To keep the release-log short, best wrap the full git changelog into a collapsib ``` +### FreqUI release + +If FreqUI has been updated substantially, make sure to create a release before merging the release branch. +Make sure that freqUI CI on the release is finished and passed before merging the release. + ### Create github release / tag Once the PR against stable is merged (best right after merging): @@ -440,7 +467,13 @@ Once the PR against stable is merged (best right after merging): * Use the button "Draft a new release" in the Github UI (subsection releases). * Use the version-number specified as tag. * Use "stable" as reference (this step comes after the above PR is merged). -* Use the above changelog as release comment (as codeblock) +* Use the above changelog as release comment (as codeblock). +* Use the below snippet for the new release + +??? Tip "Release template" + ```` + --8<-- "includes/release_template.md" + ```` ## Releases diff --git a/docs/docker_quickstart.md b/docs/docker_quickstart.md index 84c1d596a..0c9e8001a 100644 --- a/docs/docker_quickstart.md +++ b/docs/docker_quickstart.md @@ -4,20 +4,25 @@ This page explains how to run the bot with Docker. It is not meant to work out o ## Install Docker -Start by downloading and installing Docker CE for your platform: +Start by downloading and installing Docker / Docker Desktop for your platform: * [Mac](https://docs.docker.com/docker-for-mac/install/) * [Windows](https://docs.docker.com/docker-for-windows/install/) * [Linux](https://docs.docker.com/install/) -To simplify running freqtrade, [`docker-compose`](https://docs.docker.com/compose/install/) should be installed and available to follow the below [docker quick start guide](#docker-quick-start). +!!! Info "Docker compose install" + Freqtrade documentation assumes the use of Docker desktop (or the docker compose plugin). + While the docker-compose standalone installation still works, it will require changing all `docker compose` commands from `docker compose` to `docker-compose` to work (e.g. `docker compose up -d` will become `docker-compose up -d`). -## Freqtrade with docker-compose +??? Warning "Docker on windows" + If you just installed docker on a windows system, make sure to reboot your system, otherwise you might encounter unexplainable Problems related to network connectivity to docker containers. -Freqtrade provides an official Docker image on [Dockerhub](https://hub.docker.com/r/freqtradeorg/freqtrade/), as well as a [docker-compose file](https://github.com/freqtrade/freqtrade/blob/stable/docker-compose.yml) ready for usage. +## Freqtrade with docker + +Freqtrade provides an official Docker image on [Dockerhub](https://hub.docker.com/r/freqtradeorg/freqtrade/), as well as a [docker compose file](https://github.com/freqtrade/freqtrade/blob/stable/docker-compose.yml) ready for usage. !!! Note - - The following section assumes that `docker` and `docker-compose` are installed and available to the logged in user. + - The following section assumes that `docker` is installed and available to the logged in user. - All below commands use relative directories and will have to be executed from the directory containing the `docker-compose.yml` file. ### Docker quick start @@ -31,13 +36,13 @@ cd ft_userdata/ curl https://raw.githubusercontent.com/freqtrade/freqtrade/stable/docker-compose.yml -o docker-compose.yml # Pull the freqtrade image -docker-compose pull +docker compose pull # Create user directory structure -docker-compose run --rm freqtrade create-userdir --userdir user_data +docker compose run --rm freqtrade create-userdir --userdir user_data # Create configuration - Requires answering interactive questions -docker-compose run --rm freqtrade new-config --config user_data/config.json +docker compose run --rm freqtrade new-config --config user_data/config.json ``` The above snippet creates a new directory called `ft_userdata`, downloads the latest compose file and pulls the freqtrade image. @@ -64,7 +69,7 @@ The `SampleStrategy` is run by default. Once this is done, you're ready to launch the bot in trading mode (Dry-run or Live-trading, depending on your answer to the corresponding question you made above). ``` bash -docker-compose up -d +docker compose up -d ``` !!! Warning "Default configuration" @@ -76,7 +81,7 @@ If you've selected to enable FreqUI in the `new-config` step, you will have freq You can now access the UI by typing localhost:8080 in your browser. -??? Note "UI Access on a remote servers" +??? Note "UI Access on a remote server" If you're running on a VPS, you should consider using either a ssh tunnel, or setup a VPN (openVPN, wireguard) to connect to your bot. This will ensure that freqUI is not directly exposed to the internet, which is not recommended for security reasons (freqUI does not support https out of the box). Setup of these tools is not part of this tutorial, however many good tutorials can be found on the internet. @@ -84,27 +89,27 @@ You can now access the UI by typing localhost:8080 in your browser. #### Monitoring the bot -You can check for running instances with `docker-compose ps`. +You can check for running instances with `docker compose ps`. This should list the service `freqtrade` as `running`. If that's not the case, best check the logs (see next point). -#### Docker-compose logs +#### Docker compose logs Logs will be written to: `user_data/logs/freqtrade.log`. -You can also check the latest log with the command `docker-compose logs -f`. +You can also check the latest log with the command `docker compose logs -f`. #### Database The database will be located at: `user_data/tradesv3.sqlite` -#### Updating freqtrade with docker-compose +#### Updating freqtrade with docker -Updating freqtrade when using `docker-compose` is as simple as running the following 2 commands: +Updating freqtrade when using `docker` is as simple as running the following 2 commands: ``` bash # Download the latest image -docker-compose pull +docker compose pull # Restart the image -docker-compose up -d +docker compose up -d ``` This will first pull the latest image, and will then restart the container with the just pulled version. @@ -116,43 +121,43 @@ This will first pull the latest image, and will then restart the container with Advanced users may edit the docker-compose file further to include all possible options or arguments. -All freqtrade arguments will be available by running `docker-compose run --rm freqtrade `. +All freqtrade arguments will be available by running `docker compose run --rm freqtrade `. -!!! Warning "`docker-compose` for trade commands" - Trade commands (`freqtrade trade <...>`) should not be ran via `docker-compose run` - but should use `docker-compose up -d` instead. +!!! Warning "`docker compose` for trade commands" + Trade commands (`freqtrade trade <...>`) should not be ran via `docker compose run` - but should use `docker compose up -d` instead. This makes sure that the container is properly started (including port forwardings) and will make sure that the container will restart after a system reboot. If you intend to use freqUI, please also ensure to adjust the [configuration accordingly](rest-api.md#configuration-with-docker), otherwise the UI will not be available. -!!! Note "`docker-compose run --rm`" +!!! Note "`docker compose run --rm`" Including `--rm` will remove the container after completion, and is highly recommended for all modes except trading mode (running with `freqtrade trade` command). -??? Note "Using docker without docker-compose" - "`docker-compose run --rm`" will require a compose file to be provided. +??? Note "Using docker without docker compose" + "`docker compose run --rm`" will require a compose file to be provided. Some freqtrade commands that don't require authentication such as `list-pairs` can be run with "`docker run --rm`" instead. For example `docker run --rm freqtradeorg/freqtrade:stable list-pairs --exchange binance --quote BTC --print-json`. This can be useful for fetching exchange information to add to your `config.json` without affecting your running containers. -#### Example: Download data with docker-compose +#### Example: Download data with docker Download backtesting data for 5 days for the pair ETH/BTC and 1h timeframe from Binance. The data will be stored in the directory `user_data/data/` on the host. ``` bash -docker-compose run --rm freqtrade download-data --pairs ETH/BTC --exchange binance --days 5 -t 1h +docker compose run --rm freqtrade download-data --pairs ETH/BTC --exchange binance --days 5 -t 1h ``` Head over to the [Data Downloading Documentation](data-download.md) for more details on downloading data. -#### Example: Backtest with docker-compose +#### Example: Backtest with docker Run backtesting in docker-containers for SampleStrategy and specified timerange of historical data, on 5m timeframe: ``` bash -docker-compose run --rm freqtrade backtesting --config user_data/config.json --strategy SampleStrategy --timerange 20190801-20191001 -i 5m +docker compose run --rm freqtrade backtesting --config user_data/config.json --strategy SampleStrategy --timerange 20190801-20191001 -i 5m ``` Head over to the [Backtesting Documentation](backtesting.md) to learn more. -### Additional dependencies with docker-compose +### Additional dependencies with docker If your strategy requires dependencies not included in the default image - it will be necessary to build the image on your host. For this, please create a Dockerfile containing installation steps for the additional dependencies (have a look at [docker/Dockerfile.custom](https://github.com/freqtrade/freqtrade/blob/develop/docker/Dockerfile.custom) for an example). @@ -166,15 +171,15 @@ You'll then also need to modify the `docker-compose.yml` file and uncomment the dockerfile: "./Dockerfile." ``` -You can then run `docker-compose build --pull` to build the docker image, and run it using the commands described above. +You can then run `docker compose build --pull` to build the docker image, and run it using the commands described above. -### Plotting with docker-compose +### Plotting with docker -Commands `freqtrade plot-profit` and `freqtrade plot-dataframe` ([Documentation](plotting.md)) are available by changing the image to `*_plot` in your docker-compose.yml file. +Commands `freqtrade plot-profit` and `freqtrade plot-dataframe` ([Documentation](plotting.md)) are available by changing the image to `*_plot` in your `docker-compose.yml` file. You can then use these commands as follows: ``` bash -docker-compose run --rm freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH --timerange=20180801-20180805 +docker compose run --rm freqtrade plot-dataframe --strategy AwesomeStrategy -p BTC/ETH --timerange=20180801-20180805 ``` The output will be stored in the `user_data/plot` directory, and can be opened with any modern browser. @@ -185,7 +190,7 @@ Freqtrade provides a docker-compose file which starts up a jupyter lab server. You can run this server using the following command: ``` bash -docker-compose -f docker/docker-compose-jupyter.yml up +docker compose -f docker/docker-compose-jupyter.yml up ``` This will create a docker-container running jupyter lab, which will be accessible using `https://127.0.0.1:8888/lab`. @@ -194,23 +199,27 @@ Please use the link that's printed in the console after startup for simplified l Since part of this image is built on your machine, it is recommended to rebuild the image from time to time to keep freqtrade (and dependencies) up-to-date. ``` bash -docker-compose -f docker/docker-compose-jupyter.yml build --no-cache +docker compose -f docker/docker-compose-jupyter.yml build --no-cache ``` ## Troubleshooting ### Docker on Windows -* Error: `"Timestamp for this request is outside of the recvWindow."` - * The market api requests require a synchronized clock but the time in the docker container shifts a bit over time into the past. - To fix this issue temporarily you need to run `wsl --shutdown` and restart docker again (a popup on windows 10 will ask you to do so). - A permanent solution is either to host the docker container on a linux host or restart the wsl from time to time with the scheduler. +* Error: `"Timestamp for this request is outside of the recvWindow."` + The market api requests require a synchronized clock but the time in the docker container shifts a bit over time into the past. + To fix this issue temporarily you need to run `wsl --shutdown` and restart docker again (a popup on windows 10 will ask you to do so). + A permanent solution is either to host the docker container on a linux host or restart the wsl from time to time with the scheduler. - ``` bash - taskkill /IM "Docker Desktop.exe" /F - wsl --shutdown - start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe" - ``` + ``` bash + taskkill /IM "Docker Desktop.exe" /F + wsl --shutdown + start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe" + ``` + +* Cannot connect to the API (Windows) + If you're on windows and just installed Docker (desktop), make sure to reboot your System. Docker can have problems with network connectivity without a restart. + You should obviously also make sure to have your [settings](#accessing-the-ui) accordingly. !!! Warning Due to the above, we do not recommend the usage of docker on windows for production setups, but only for experimentation, datadownload and backtesting. diff --git a/docs/edge.md b/docs/edge.md index e92abf40f..bb702f202 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -2,6 +2,10 @@ The `Edge Positioning` module uses probability to calculate your win rate and risk reward ratio. It will use these statistics to control your strategy trade entry points, position size and, stoploss. +!!! Danger "Deprecated functionality" + `Edge positioning` (or short Edge) is currently in maintenance mode only (we keep existing functionality alive) and should be considered as deprecated. + It will currently not receive new features until either someone stepped forward to take up ownership of that module - or we'll decide to remove edge from freqtrade. + !!! Warning When using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data. diff --git a/docs/exchanges.md b/docs/exchanges.md index 50ebf9e0a..c106ea4cf 100644 --- a/docs/exchanges.md +++ b/docs/exchanges.md @@ -54,15 +54,45 @@ This configuration enables kraken, as well as rate-limiting to avoid bans from t ## Binance +!!! Warning "Server location and geo-ip restrictions" + Please be aware that Binance restricts API access regarding the server country. The current and non-exhaustive countries blocked are Canada, Malaysia, Netherlands and United States. Please go to [binance terms > b. Eligibility](https://www.binance.com/en/terms) to find up to date list. + Binance supports [time_in_force](configuration.md#understand-order_time_in_force). !!! Tip "Stoploss on Exchange" - Binance supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange.. + Binance supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange. + On futures, Binance supports both `stop-limit` as well as `stop-market` orders. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use. -### Binance Blacklist +### Binance Blacklist recommendation -For Binance, please add `"BNB/"` to your blacklist to avoid issues. -Accounts having BNB accounts use this to pay for fees - if your first trade happens to be on `BNB`, further trades will consume this position and make the initial BNB trade unsellable as the expected amount is not there anymore. +For Binance, it is suggested to add `"BNB/"` to your blacklist to avoid issues, unless you are willing to maintain enough extra `BNB` on the account or unless you're willing to disable using `BNB` for fees. +Binance accounts may use `BNB` for fees, and if a trade happens to be on `BNB`, further trades may consume this position and make the initial BNB trade unsellable as the expected amount is not there anymore. + +### Binance sites + +Binance has been split into 2, and users must use the correct ccxt exchange ID for their exchange, otherwise API keys are not recognized. + +* [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance`. +* [binance.us](https://www.binance.us/) - US based users. Use exchange id: `binanceus`. + +### Binance RSA keys + +Freqtrade supports binance RSA API keys. + +We recommend to use them as environment variable. + +``` bash +export FREQTRADE__EXCHANGE__SECRET="$(cat ./rsa_binance.private)" +``` + +They can however also be configured via configuration file. Since json doesn't support multi-line strings, you'll have to replace all newlines with `\n` to have a valid json file. + +``` json +// ... + "key": "", + "secret": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBABACAFQA<...>s8KX8=\n-----END PRIVATE KEY-----" +// ... +``` ### Binance Futures @@ -86,15 +116,19 @@ When trading on Binance Futures market, orderbook must be used because there is }, ``` -### Binance sites +#### Binance futures settings -Binance has been split into 2, and users must use the correct ccxt exchange ID for their exchange, otherwise API keys are not recognized. +Users will also have to have the futures-setting "Position Mode" set to "One-way Mode", and "Asset Mode" set to "Single-Asset Mode". +These settings will be checked on startup, and freqtrade will show an error if this setting is wrong. -* [binance.com](https://www.binance.com/) - International users. Use exchange id: `binance`. -* [binance.us](https://www.binance.us/) - US based users. Use exchange id: `binanceus`. +![Binance futures settings](assets/binance_futures_settings.png) + +Freqtrade will not attempt to change these settings. ## Kraken +Kraken supports [time_in_force](configuration.md#understand-order_time_in_force) with settings "GTC" (good till cancelled), "IOC" (immediate-or-cancel) and "PO" (Post only) settings. + !!! Tip "Stoploss on Exchange" Kraken supports `stoploss_on_exchange` and can use both stop-loss-market and stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use. @@ -104,13 +138,41 @@ Binance has been split into 2, and users must use the correct ccxt exchange ID f The Kraken API does only provide 720 historic candles, which is sufficient for Freqtrade dry-run and live trade modes, but is a problem for backtesting. To download data for the Kraken exchange, using `--dl-trades` is mandatory, otherwise the bot will download the same 720 candles over and over, and you'll not have enough backtest data. -Due to the heavy rate-limiting applied by Kraken, the following configuration section should be used to download data: +To speed up downloading, you can download the [trades zip files](https://support.kraken.com/hc/en-us/articles/360047543791-Downloadable-historical-market-data-time-and-sales-) kraken provides. +These are usually updated once per quarter. Freqtrade expects these files to be placed in `user_data/data/kraken/trades_csv`. -``` json - "ccxt_async_config": { - "enableRateLimit": true, - "rateLimit": 3100 - }, +A structure as follows can make sense if using incremental files, with the "full" history in one directory, and incremental files in different directories. +The assumption for this mode is that the data is downloaded and unzipped keeping filenames as they are. +Duplicate content will be ignored (based on timestamp) - though the assumption is that there is no gap in the data. + +This means, if your "full" history ends in Q4 2022 - then both incremental updates Q1 2023 and Q2 2023 are available. +Not having this will lead to incomplete data, and therefore invalid results while using the data. + +``` +└── trades_csv +    ├── Kraken_full_history +    │   ├── BCHEUR.csv +    │   └── XBTEUR.csv +    ├── Kraken_Trading_History_Q1_2023 +    │   ├── BCHEUR.csv +    │   └── XBTEUR.csv +    └── Kraken_Trading_History_Q2_2023 +       ├── BCHEUR.csv +       └── XBTEUR.csv +``` + +You can convert these files into freqtrade files: + +``` bash +freqtrade convert-trade-data --exchange kraken --format-from kraken_csv --format-to feather +# Convert trade data to different ohlcv timeframes +freqtrade trades-to-ohlcv -p BTC/EUR BCH/EUR --exchange kraken -t 1m 5m 15m 1h +``` + +The converted data also makes downloading data possible, and will start the download after the latest loaded trade. + +``` bash +freqtrade download-data --exchange kraken --dl-trades -p BTC/EUR BCH/EUR ``` !!! Warning "Downloading data from kraken" @@ -121,68 +183,6 @@ Due to the heavy rate-limiting applied by Kraken, the following configuration se Please pay attention that rateLimit configuration entry holds delay in milliseconds between requests, NOT requests\sec rate. So, in order to mitigate Kraken API "Rate limit exceeded" exception, this configuration should be increased, NOT decreased. -## Bittrex - -### Order types - -Bittrex does not support market orders. If you have a message at the bot startup about this, you should change order type values set in your configuration and/or in the strategy from `"market"` to `"limit"`. See some more details on this [here in the FAQ](faq.md#im-getting-the-exchange-bittrex-does-not-support-market-orders-message-and-cannot-run-my-strategy). - -Bittrex also does not support `VolumePairlist` due to limited / split API constellation at the moment. -Please use `StaticPairlist`. Other pairlists (other than `VolumePairlist`) should not be affected. - -### Volume pairlist - -Bittrex does not support the direct usage of VolumePairList. This can however be worked around by using the advanced mode with `lookback_days: 1` (or more), which will emulate 24h volume. - -Read more in the [pairlist documentation](plugins.md#volumepairlist-advanced-mode). - -### Restricted markets - -Bittrex split its exchange into US and International versions. -The International version has more pairs available, however the API always returns all pairs, so there is currently no automated way to detect if you're affected by the restriction. - -If you have restricted pairs in your whitelist, you'll get a warning message in the log on Freqtrade startup for each restricted pair. - -The warning message will look similar to the following: - -``` output -[...] Message: bittrex {"success":false,"message":"RESTRICTED_MARKET","result":null,"explanation":null}" -``` - -If you're an "International" customer on the Bittrex exchange, then this warning will probably not impact you. -If you're a US customer, the bot will fail to create orders for these pairs, and you should remove them from your whitelist. - -You can get a list of restricted markets by using the following snippet: - -``` python -import ccxt -ct = ccxt.bittrex() -lm = ct.load_markets() - -res = [p for p, x in lm.items() if 'US' in x['info']['prohibitedIn']] -print(res) -``` - -## FTX - -!!! Tip "Stoploss on Exchange" - FTX supports `stoploss_on_exchange` and can use both stop-loss-market and stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it. - You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type of stoploss shall be used. - -### Using subaccounts - -To use subaccounts with FTX, you need to edit the configuration and add the following: - -``` json -"exchange": { - "ccxt_config": { - "headers": { - "FTX-SUBACCOUNT": "name" - } - }, -} -``` - ## Kucoin Kucoin requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows: @@ -205,13 +205,13 @@ Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force) ### Kucoin Blacklists -For Kucoin, please add `"KCS/"` to your blacklist to avoid issues. -Accounts having KCS accounts use this to pay for fees - if your first trade happens to be on `KCS`, further trades will consume this position and make the initial KCS trade unsellable as the expected amount is not there anymore. +For Kucoin, it is suggested to add `"KCS/"` to your blacklist to avoid issues, unless you are willing to maintain enough extra `KCS` on the account or unless you're willing to disable using `KCS` for fees. +Kucoin accounts may use `KCS` for fees, and if a trade happens to be on `KCS`, further trades may consume this position and make the initial `KCS` trade unsellable as the expected amount is not there anymore. -## Huobi +## HTX (formerly Huobi) !!! Tip "Stoploss on Exchange" - Huobi supports `stoploss_on_exchange` and uses `stop-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange. + HTX supports `stoploss_on_exchange` and uses `stop-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange. ## OKX (former OKEX) @@ -231,8 +231,8 @@ OKX requires a passphrase for each api key, you will therefore need to add this OKX only provides 100 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode. !!! Warning "Futures" - OKX Futures has the concept of "position mode" - which can be Net or long/short (hedge mode). - Freqtrade supports both modes - but changing the mode mid-trading is not supported and will lead to exceptions and failures to place trades. + OKX Futures has the concept of "position mode" - which can be "Buy/Sell" or long/short (hedge mode). + Freqtrade supports both modes (we recommend to use Buy/Sell mode) - but changing the mode mid-trading is not supported and will lead to exceptions and failures to place trades. OKX also only provides MARK candles for the past ~3 months. Backtesting futures prior to that date will therefore lead to slight deviations, as funding-fees cannot be calculated correctly without this data. ## Gate.io @@ -243,6 +243,43 @@ OKX requires a passphrase for each api key, you will therefore need to add this Gate.io allows the use of `POINT` to pay for fees. As this is not a tradable currency (no regular market available), automatic fee calculations will fail (and default to a fee of 0). The configuration parameter `exchange.unknown_fee_rate` can be used to specify the exchange rate between Point and the stake currency. Obviously, changing the stake-currency will also require changes to this value. +## Bybit + +Futures trading on bybit is currently supported for USDT markets, and will use isolated futures mode. +Users with unified accounts (there's no way back) can create a Sub-account which will start as "non-unified", and can therefore use isolated futures. +On startup, freqtrade will set the position mode to "One-way Mode" for the whole (sub)account. This avoids making this call over and over again (slowing down bot operations), but means that changes to this setting may result in exceptions and errors + +As bybit doesn't provide funding rate history, the dry-run calculation is used for live trades as well. + +API Keys for live futures trading (Subaccount on non-unified) must have the following permissions: +* Read-write +* Contract - Orders +* Contract - Positions + +We do strongly recommend to limit all API keys to the IP you're going to use it from. + +!!! Tip "Stoploss on Exchange" + Bybit (futures only) supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange. + On futures, Bybit supports both `stop-limit` as well as `stop-market` orders. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use. + +## Bitmart + +Bitmart requires the API key Memo (the name you give the API key) to go along with the exchange key and secret. +It's therefore required to pass the UID as well. + +```json +"exchange": { + "name": "bitmart", + "uid": "your_bitmart_api_key_memo", + "secret": "your_exchange_secret", + "password": "your_exchange_api_key_password", + // ... +} +``` + +!!! Warning "Necessary Verification" + Bitmart requires Verification Lvl2 to successfully trade on the spot market through the API - even though trading via UI works just fine with just Lvl1 verification. + ## All exchanges Should you experience constant errors with Nonce (like `InvalidNonce`), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys. @@ -278,7 +315,7 @@ For example, to test the order type `FOK` with Kraken, and modify candle limit t "exchange": { "name": "kraken", "_ft_has_params": { - "order_time_in_force": ["gtc", "fok"], + "order_time_in_force": ["GTC", "FOK"], "ohlcv_candle_limit": 200 } //... diff --git a/docs/faq.md b/docs/faq.md index f1542d08e..95a9924f9 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -2,9 +2,9 @@ ## Supported Markets -Freqtrade supports spot trading only. +Freqtrade supports spot trading, as well as (isolated) futures trading for some selected exchanges. Please refer to the [documentation start page](index.md#supported-futures-exchanges-experimental) for an uptodate list of supported exchanges. -### Can I open short positions? +### Can my bot open short positions? Freqtrade can open short positions in futures markets. This requires the strategy to be made for this - and `"trading_mode": "futures"` in the configuration. @@ -12,15 +12,22 @@ Please make sure to read the [relevant documentation page](leverage.md) first. In spot markets, you can in some cases use leveraged spot tokens, which reflect an inverted pair (eg. BTCUP/USD, BTCDOWN/USD, ETHBULL/USD, ETHBEAR/USD,...) which can be traded with Freqtrade. -### Can I trade options or futures? +### Can my bot trade options or futures? -Futures trading is supported for selected exchanges. +Futures trading is supported for selected exchanges. Please refer to the [documentation start page](index.md#supported-futures-exchanges-experimental) for an uptodate list of supported exchanges. ## Beginner Tips & Tricks * When you work with your strategy & hyperopt file you should use a proper code editor like VSCode or PyCharm. A good code editor will provide syntax highlighting as well as line numbers, making it easy to find syntax errors (most likely pointed out by Freqtrade during startup). -## Freqtrade common issues +## Freqtrade common questions + +### Can freqtrade open multiple positions on the same pair in parallel? + +No. Freqtrade will only open one position per pair at a time. +You can however use the [`adjust_trade_position()` callback](strategy-callbacks.md#adjust-trade-position) to adjust an open position. + +Backtesting provides an option for this in `--eps` - however this is only there to highlight "hidden" signals, and will not work in live. ### The bot does not start @@ -29,8 +36,8 @@ Running the bot with `freqtrade trade --config config.json` shows the output `fr This could be caused by the following reasons: * The virtual environment is not active. - * Run `source .env/bin/activate` to activate the virtual environment. -* The installation did not work correctly. + * Run `source .venv/bin/activate` to activate the virtual environment. +* The installation did not complete successfully. * Please check the [Installation documentation](installation.md). ### I have waited 5 minutes, why hasn't the bot made any trades yet? @@ -67,19 +74,27 @@ This is not a bot-problem, but will also happen while manual trading. While freqtrade can handle this (it'll sell 99 COIN), fees are often below the minimum tradable lot-size (you can only trade full COIN, not 0.9 COIN). Leaving the dust (0.9 COIN) on the exchange makes usually sense, as the next time freqtrade buys COIN, it'll eat into the remaining small balance, this time selling everything it bought, and therefore slowly declining the dust balance (although it most likely will never reach exactly 0). -Where possible (e.g. on binance), the use of the exchange's dedicated fee currency will fix this. +Where possible (e.g. on binance), the use of the exchange's dedicated fee currency will fix this. On binance, it's sufficient to have BNB in your account, and have "Pay fees in BNB" enabled in your profile. Your BNB balance will slowly decline (as it's used to pay fees) - but you'll no longer encounter dust (Freqtrade will include the fees in the profit calculations). Other exchanges don't offer such possibilities, where it's simply something you'll have to accept or move to a different exchange. +### I deposited more funds to the exchange, but my bot doesn't recognize this + +Freqtrade will update the exchange balance when necessary (Before placing an order). +RPC calls (Telegram's `/balance`, API calls to `/balance`) can trigger an update at max. once per hour. + +If `adjust_trade_position` is enabled (and the bot has open trades eligible for position adjustments) - then the wallets will be refreshed once per hour. +To force an immediate update, you can use `/reload_config` - which will restart the bot. + ### I want to use incomplete candles Freqtrade will not provide incomplete candles to strategies. Using incomplete candles will lead to repainting and consequently to strategies with "ghost" buys, which are impossible to both backtest, and verify after they happened. You can use "current" market data by using the [dataprovider](strategy-customization.md#orderbookpair-maximum)'s orderbook or ticker methods - which however cannot be used during backtesting. -### Is there a setting to only SELL the coins being held and not perform anymore BUYS? +### Is there a setting to only Exit the trades being held and not perform any new Entries? -You can use the `/stopbuy` command in Telegram to prevent future buys, followed by `/forceexit all` (sell all open trades). +You can use the `/stopentry` command in Telegram to prevent future trade entry, followed by `/forceexit all` (sell all open trades). ### I want to run multiple bots on the same machine @@ -95,6 +110,12 @@ If this happens for all pairs in the pairlist, this might indicate a recent exch Irrespectively of the reason, Freqtrade will fill up these candles with "empty" candles, where open, high, low and close are set to the previous candle close - and volume is empty. In a chart, this will look like a `_` - and is aligned with how exchanges usually represent 0 volume candles. +### I'm getting "Price jump between 2 candles detected" + +This message is a warning that the candles had a price jump of > 30%. +This might be a sign that the pair stopped trading, and some token exchange took place (e.g. COCOS in 2021 - where price jumped from 0.0000154 to 0.01621). +This message is often accompanied by ["Missing data fillup"](#im-getting-missing-data-fillup-messages-in-the-log) - as trading on such pairs is often stopped for some time. + ### I'm getting "Outdated history for pair xxx" in the log The bot is trying to tell you that it got an outdated last candle (not the last complete candle). @@ -107,15 +128,9 @@ This warning can point to one of the below problems: * Barely traded pair -> Check the pair on the exchange webpage, look at the timeframe your strategy uses. If the pair does not have any volume in some candles (usually visualized with a "volume 0" bar, and a "_" as candle), this pair did not have any trades in this timeframe. These pairs should ideally be avoided, as they can cause problems with order-filling. * API problem -> API returns wrong data (this only here for completeness, and should not happen with supported exchanges). -### I'm getting the "RESTRICTED_MARKET" message in the log - -Currently known to happen for US Bittrex users. - -Read [the Bittrex section about restricted markets](exchanges.md#restricted-markets) for more information. - ### I'm getting the "Exchange XXX does not support market orders." message and cannot run my strategy -As the message says, your exchange does not support market orders and you have one of the [order types](configuration.md/#understand-order_types) set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Bittrex and Gate.io). +As the message says, your exchange does not support market orders and you have one of the [order types](configuration.md/#understand-order_types) set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Gate.io). To fix this, redefine order types in the strategy to use "limit" instead of "market": @@ -129,6 +144,13 @@ To fix this, redefine order types in the strategy to use "limit" instead of "mar The same fix should be applied in the configuration file, if order types are defined in your custom config rather than in the strategy. +### I'm trying to start the bot live, but get an API permission error + +Errors like `Invalid API-key, IP, or permissions for action` mean exactly what they actually say. +Your API key is either invalid (copy/paste error? check for leading/trailing spaces in the config), expired, or the IP you're running the bot from is not enabled in the Exchange's API console. +Usually, the permission "Spot Trading" (or the equivalent in the exchange you use) will be necessary. +Futures will usually have to be enabled specifically. + ### How do I search the bot logs for something? By default, the bot writes its log into stderr stream. This is implemented this way so that you can easily separate the bot's diagnostics messages from Backtesting, Edge and Hyperopt results, output from other various Freqtrade utility sub-commands, as well as from the output of your custom `print()`'s you may have inserted into your strategy. So if you need to search the log messages with the grep utility, you need to redirect stderr to stdout and disregard stdout. @@ -177,8 +199,8 @@ The GPU improvements would only apply to pandas-native calculations - or ones wr For hyperopt, freqtrade is using scikit-optimize, which is built on top of scikit-learn. Their statement about GPU support is [pretty clear](https://scikit-learn.org/stable/faq.html#will-you-add-gpu-support). -GPU's also are only good at crunching numbers (floating point operations). -For hyperopt, we need both number-crunching (find next parameters) and running python code (running backtesting). +GPU's also are only good at crunching numbers (floating point operations). +For hyperopt, we need both number-crunching (find next parameters) and running python code (running backtesting). As such, GPU's are not too well suited for most parts of hyperopt. The benefit of using GPU would therefore be pretty slim - and will not justify the complexity introduced by trying to add GPU support. @@ -219,9 +241,9 @@ already 8\*10^9\*10 evaluations. A roughly total of 80 billion evaluations. Did you run 100 000 evaluations? Congrats, you've done roughly 1 / 100 000 th of the search space, assuming that the bot never tests the same parameters more than once. -* The time it takes to run 1000 hyperopt epochs depends on things like: The available cpu, hard-disk, ram, timeframe, timerange, indicator settings, indicator count, amount of coins that hyperopt test strategies on and the resulting trade count - which can be 650 trades in a year or 100000 trades depending if the strategy aims for big profits by trading rarely or for many low profit trades. +* The time it takes to run 1000 hyperopt epochs depends on things like: The available cpu, hard-disk, ram, timeframe, timerange, indicator settings, indicator count, amount of coins that hyperopt test strategies on and the resulting trade count - which can be 650 trades in a year or 100000 trades depending if the strategy aims for big profits by trading rarely or for many low profit trades. -Example: 4% profit 650 times vs 0,3% profit a trade 10000 times in a year. If we assume you set the --timerange to 365 days. +Example: 4% profit 650 times vs 0,3% profit a trade 10000 times in a year. If we assume you set the --timerange to 365 days. Example: `freqtrade --config config.json --strategy SampleStrategy --hyperopt SampleHyperopt -e 1000 --timerange 20190601-20200601` @@ -235,8 +257,26 @@ The Edge module is mostly a result of brainstorming of [@mishaker](https://githu You can find further info on expectancy, win rate, risk management and position size in the following sources: - https://www.tradeciety.com/ultimate-math-guide-for-traders/ -- http://www.vantharp.com/tharp-concepts/expectancy.asp - https://samuraitradingacademy.com/trading-expectancy/ - https://www.learningmarkets.com/determining-expectancy-in-your-trading/ -- http://www.lonestocktrader.com/make-money-trading-positive-expectancy/ +- https://www.lonestocktrader.com/make-money-trading-positive-expectancy/ - https://www.babypips.com/trading/trade-expectancy-matter + +## Official channels + +Freqtrade is using exclusively the following official channels: + +* [Freqtrade discord server](https://discord.gg/p7nuUNVfP7) +* [Freqtrade documentation (https://freqtrade.io)](https://freqtrade.io) +* [Freqtrade github organization](https://github.com/freqtrade) + +Nobody affiliated with the freqtrade project will ask you about your exchange keys or anything else exposing your funds to exploitation. +Should you be asked to expose your exchange keys or send funds to some random wallet, then please don't follow these instructions. + +Failing to follow these guidelines will not be responsibility of freqtrade. + +## "Freqtrade token" + +Freqtrade does not have a Crypto token offering. + +Token offerings you find on the internet referring Freqtrade, FreqAI or freqUI must be considered to be a scam, trying to exploit freqtrade's popularity for their own, nefarious gains. diff --git a/docs/freqai-configuration.md b/docs/freqai-configuration.md new file mode 100644 index 000000000..dd0dde5d4 --- /dev/null +++ b/docs/freqai-configuration.md @@ -0,0 +1,418 @@ +# Configuration + +FreqAI is configured through the typical [Freqtrade config file](configuration.md) and the standard [Freqtrade strategy](strategy-customization.md). Examples of FreqAI config and strategy files can be found in `config_examples/config_freqai.example.json` and `freqtrade/templates/FreqaiExampleStrategy.py`, respectively. + +## Setting up the configuration file + + Although there are plenty of additional parameters to choose from, as highlighted in the [parameter table](freqai-parameter-table.md#parameter-table), a FreqAI config must at minimum include the following parameters (the parameter values are only examples): + +```json + "freqai": { + "enabled": true, + "purge_old_models": 2, + "train_period_days": 30, + "backtest_period_days": 7, + "identifier" : "unique-id", + "feature_parameters" : { + "include_timeframes": ["5m","15m","4h"], + "include_corr_pairlist": [ + "ETH/USD", + "LINK/USD", + "BNB/USD" + ], + "label_period_candles": 24, + "include_shifted_candles": 2, + "indicator_periods_candles": [10, 20] + }, + "data_split_parameters" : { + "test_size": 0.25 + } + } +``` + +A full example config is available in `config_examples/config_freqai.example.json`. + +## Building a FreqAI strategy + +The FreqAI strategy requires including the following lines of code in the standard [Freqtrade strategy](strategy-customization.md): + +```python + # user should define the maximum startup candle count (the largest number of candles + # passed to any single indicator) + startup_candle_count: int = 20 + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + + # the model will return all labels created by user in `set_freqai_targets()` + # (& appended targets), an indication of whether or not the prediction should be accepted, + # the target mean/std values for each of the labels created by user in + # `set_freqai_targets()` for each training period. + + dataframe = self.freqai.start(dataframe, metadata, self) + + return dataframe + + def feature_engineering_expand_all(self, dataframe: DataFrame, period, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and + `include_corr_pairs`. In other words, a single feature defined in this function + will automatically expand to a total of + `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` * + `include_corr_pairs` numbers of features added to the model. + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + :param period: period of the indicator - usage example: + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) + """ + + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) + dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period) + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) + + return dataframe + + def feature_engineering_expand_basic(self, dataframe: DataFrame, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. + In other words, a single feature defined in this function + will automatically expand to a total of + `include_timeframes` * `include_shifted_candles` * `include_corr_pairs` + numbers of features added to the model. + + Features defined here will *not* be automatically duplicated on user defined + `indicator_periods_candles` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200) + """ + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] + return dataframe + + def feature_engineering_standard(self, dataframe: DataFrame, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + This optional function will be called once with the dataframe of the base timeframe. + This is the final function to be called, which means that the dataframe entering this + function will contain all the features and columns created by all other + freqai_feature_engineering_* functions. + + This function is a good place to do custom exotic feature extractions (e.g. tsfresh). + This function is a good place for any feature that should not be auto-expanded upon + (e.g. day of the week). + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + """ + dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + dataframe["%-hour_of_day"] = (dataframe["date"].dt.hour + 1) / 25 + return dataframe + + def set_freqai_targets(self, dataframe: DataFrame, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + :param df: strategy dataframe which will receive the targets + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 + ) + return dataframe +``` + +Notice how the `feature_engineering_*()` is where [features](freqai-feature-engineering.md#feature-engineering) are added. Meanwhile `set_freqai_targets()` adds the labels/targets. A full example strategy is available in `templates/FreqaiExampleStrategy.py`. + +!!! Note + The `self.freqai.start()` function cannot be called outside the `populate_indicators()`. + +!!! Note + Features **must** be defined in `feature_engineering_*()`. Defining FreqAI features in `populate_indicators()` + will cause the algorithm to fail in live/dry mode. In order to add generalized features that are not associated with a specific pair or timeframe, you should use `feature_engineering_standard()` + (as exemplified in `freqtrade/templates/FreqaiExampleStrategy.py`). + +## Important dataframe key patterns + +Below are the values you can expect to include/use inside a typical strategy dataframe (`df[]`): + +| DataFrame Key | Description | +|------------|-------------| +| `df['&*']` | Any dataframe column prepended with `&` in `set_freqai_targets()` is treated as a training target (label) inside FreqAI (typically following the naming convention `&-s*`). For example, to predict the close price 40 candles into the future, you would set `df['&-s_close'] = df['close'].shift(-self.freqai_info["feature_parameters"]["label_period_candles"])` with `"label_period_candles": 40` in the config. FreqAI makes the predictions and gives them back under the same key (`df['&-s_close']`) to be used in `populate_entry/exit_trend()`.
**Datatype:** Depends on the output of the model. +| `df['&*_std/mean']` | Standard deviation and mean values of the defined labels during training (or live tracking with `fit_live_predictions_candles`). Commonly used to understand the rarity of a prediction (use the z-score as shown in `templates/FreqaiExampleStrategy.py` and explained [here](#creating-a-dynamic-target-threshold) to evaluate how often a particular prediction was observed during training or historically with `fit_live_predictions_candles`).
**Datatype:** Float. +| `df['do_predict']` | Indication of an outlier data point. The return value is integer between -2 and 2, which lets you know if the prediction is trustworthy or not. `do_predict==1` means that the prediction is trustworthy. If the Dissimilarity Index (DI, see details [here](freqai-feature-engineering.md#identifying-outliers-with-the-dissimilarity-index-di)) of the input data point is above the threshold defined in the config, FreqAI will subtract 1 from `do_predict`, resulting in `do_predict==0`. If `use_SVM_to_remove_outliers` is active, the Support Vector Machine (SVM, see details [here](freqai-feature-engineering.md#identifying-outliers-using-a-support-vector-machine-svm)) may also detect outliers in training and prediction data. In this case, the SVM will also subtract 1 from `do_predict`. If the input data point was considered an outlier by the SVM but not by the DI, or vice versa, the result will be `do_predict==0`. If both the DI and the SVM considers the input data point to be an outlier, the result will be `do_predict==-1`. As with the SVM, if `use_DBSCAN_to_remove_outliers` is active, DBSCAN (see details [here](freqai-feature-engineering.md#identifying-outliers-with-dbscan)) may also detect outliers and subtract 1 from `do_predict`. Hence, if both the SVM and DBSCAN are active and identify a datapoint that was above the DI threshold as an outlier, the result will be `do_predict==-2`. A particular case is when `do_predict == 2`, which means that the model has expired due to exceeding `expired_hours`.
**Datatype:** Integer between -2 and 2. +| `df['DI_values']` | Dissimilarity Index (DI) values are proxies for the level of confidence FreqAI has in the prediction. A lower DI means the prediction is close to the training data, i.e., higher prediction confidence. See details about the DI [here](freqai-feature-engineering.md#identifying-outliers-with-the-dissimilarity-index-di).
**Datatype:** Float. +| `df['%*']` | Any dataframe column prepended with `%` in `feature_engineering_*()` is treated as a training feature. For example, you can include the RSI in the training feature set (similar to in `templates/FreqaiExampleStrategy.py`) by setting `df['%-rsi']`. See more details on how this is done [here](freqai-feature-engineering.md).
**Note:** Since the number of features prepended with `%` can multiply very quickly (10s of thousands of features are easily engineered using the multiplictative functionality of, e.g., `include_shifted_candles` and `include_timeframes` as described in the [parameter table](freqai-parameter-table.md)), these features are removed from the dataframe that is returned from FreqAI to the strategy. To keep a particular type of feature for plotting purposes, you would prepend it with `%%` (see details below).
**Datatype:** Depends on the feature created by the user. +| `df['%%*']` | Any dataframe column prepended with `%%` in `feature_engineering_*()` is treated as a training feature, just the same as the above `%` prepend. However, in this case, the features are returned back to the strategy for FreqUI/plot-dataframe plotting and monitoring in Dry/Live/Backtesting
**Datatype:** Depends on the feature created by the user. Please note that features created in `feature_engineering_expand()` will have automatic FreqAI naming schemas depending on the expansions that you configured (i.e. `include_timeframes`, `include_corr_pairlist`, `indicators_periods_candles`, `include_shifted_candles`). So if you want to plot `%%-rsi` from `feature_engineering_expand_all()`, the final naming scheme for your plotting config would be: `%%-rsi-period_10_ETH/USDT:USDT_1h` for the `rsi` feature with `period=10`, `timeframe=1h`, and `pair=ETH/USDT:USDT` (the `:USDT` is added if you are using futures pairs). It is useful to simply add `print(dataframe.columns)` in your `populate_indicators()` after `self.freqai.start()` to see the full list of available features that are returned to the strategy for plotting purposes. + +## Setting the `startup_candle_count` + +The `startup_candle_count` in the FreqAI strategy needs to be set up in the same way as in the standard Freqtrade strategy (see details [here](strategy-customization.md#strategy-startup-period)). This value is used by Freqtrade to ensure that a sufficient amount of data is provided when calling the `dataprovider`, to avoid any NaNs at the beginning of the first training. You can easily set this value by identifying the longest period (in candle units) which is passed to the indicator creation functions (e.g., TA-Lib functions). In the presented example, `startup_candle_count` is 20 since this is the maximum value in `indicators_periods_candles`. + +!!! Note + There are instances where the TA-Lib functions actually require more data than just the passed `period` or else the feature dataset gets populated with NaNs. Anecdotally, multiplying the `startup_candle_count` by 2 always leads to a fully NaN free training dataset. Hence, it is typically safest to multiply the expected `startup_candle_count` by 2. Look out for this log message to confirm that the data is clean: + + ``` + 2022-08-31 15:14:04 - freqtrade.freqai.data_kitchen - INFO - dropped 0 training points due to NaNs in populated dataset 4319. + ``` + +## Creating a dynamic target threshold + +Deciding when to enter or exit a trade can be done in a dynamic way to reflect current market conditions. FreqAI allows you to return additional information from the training of a model (more info [here](freqai-feature-engineering.md#returning-additional-info-from-training)). For example, the `&*_std/mean` return values describe the statistical distribution of the target/label *during the most recent training*. Comparing a given prediction to these values allows you to know the rarity of the prediction. In `templates/FreqaiExampleStrategy.py`, the `target_roi` and `sell_roi` are defined to be 1.25 z-scores away from the mean which causes predictions that are closer to the mean to be filtered out. + +```python +dataframe["target_roi"] = dataframe["&-s_close_mean"] + dataframe["&-s_close_std"] * 1.25 +dataframe["sell_roi"] = dataframe["&-s_close_mean"] - dataframe["&-s_close_std"] * 1.25 +``` + +To consider the population of *historical predictions* for creating the dynamic target instead of information from the training as discussed above, you would set `fit_live_predictions_candles` in the config to the number of historical prediction candles you wish to use to generate target statistics. + +```json + "freqai": { + "fit_live_predictions_candles": 300, + } +``` + +If this value is set, FreqAI will initially use the predictions from the training data and subsequently begin introducing real prediction data as it is generated. FreqAI will save this historical data to be reloaded if you stop and restart a model with the same `identifier`. + +## Using different prediction models + +FreqAI has multiple example prediction model libraries that are ready to be used as is via the flag `--freqaimodel`. These libraries include `CatBoost`, `LightGBM`, and `XGBoost` regression, classification, and multi-target models, and can be found in `freqai/prediction_models/`. + +Regression and classification models differ in what targets they predict - a regression model will predict a target of continuous values, for example what price BTC will be at tomorrow, whilst a classifier will predict a target of discrete values, for example if the price of BTC will go up tomorrow or not. This means that you have to specify your targets differently depending on which model type you are using (see details [below](#setting-model-targets)). + +All of the aforementioned model libraries implement gradient boosted decision tree algorithms. They all work on the principle of ensemble learning, where predictions from multiple simple learners are combined to get a final prediction that is more stable and generalized. The simple learners in this case are decision trees. Gradient boosting refers to the method of learning, where each simple learner is built in sequence - the subsequent learner is used to improve on the error from the previous learner. If you want to learn more about the different model libraries you can find the information in their respective docs: + +* CatBoost: https://catboost.ai/en/docs/ +* LightGBM: https://lightgbm.readthedocs.io/en/v3.3.2/# +* XGBoost: https://xgboost.readthedocs.io/en/stable/# + +There are also numerous online articles describing and comparing the algorithms. Some relatively lightweight examples would be [CatBoost vs. LightGBM vs. XGBoost — Which is the best algorithm?](https://towardsdatascience.com/catboost-vs-lightgbm-vs-xgboost-c80f40662924#:~:text=In%20CatBoost%2C%20symmetric%20trees%2C%20or,the%20same%20depth%20can%20differ.) and [XGBoost, LightGBM or CatBoost — which boosting algorithm should I use?](https://medium.com/riskified-technology/xgboost-lightgbm-or-catboost-which-boosting-algorithm-should-i-use-e7fda7bb36bc). Keep in mind that the performance of each model is highly dependent on the application and so any reported metrics might not be true for your particular use of the model. + +Apart from the models already available in FreqAI, it is also possible to customize and create your own prediction models using the `IFreqaiModel` class. You are encouraged to inherit `fit()`, `train()`, and `predict()` to customize various aspects of the training procedures. You can place custom FreqAI models in `user_data/freqaimodels` - and freqtrade will pick them up from there based on the provided `--freqaimodel` name - which has to correspond to the class name of your custom model. +Make sure to use unique names to avoid overriding built-in models. + +### Setting model targets + +#### Regressors + +If you are using a regressor, you need to specify a target that has continuous values. FreqAI includes a variety of regressors, such as the `CatboostRegressor`via the flag `--freqaimodel CatboostRegressor`. An example of how you could set a regression target for predicting the price 100 candles into the future would be + +```python +df['&s-close_price'] = df['close'].shift(-100) +``` + +If you want to predict multiple targets, you need to define multiple labels using the same syntax as shown above. + +#### Classifiers + +If you are using a classifier, you need to specify a target that has discrete values. FreqAI includes a variety of classifiers, such as the `CatboostClassifier` via the flag `--freqaimodel CatboostClassifier`. If you elects to use a classifier, the classes need to be set using strings. For example, if you want to predict if the price 100 candles into the future goes up or down you would set + +```python +df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down') +``` + +If you want to predict multiple targets you must specify all labels in the same label column. You could, for example, add the label `same` to define where the price was unchanged by setting + +```python +df['&s-up_or_down'] = np.where( df["close"].shift(-100) > df["close"], 'up', 'down') +df['&s-up_or_down'] = np.where( df["close"].shift(-100) == df["close"], 'same', df['&s-up_or_down']) +``` + +## PyTorch Module + +### Quick start + +The easiest way to quickly run a pytorch model is with the following command (for regression task): + +```bash +freqtrade trade --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel PyTorchMLPRegressor --strategy-path freqtrade/templates +``` + +!!! Note "Installation/docker" + The PyTorch module requires large packages such as `torch`, which should be explicitly requested during `./setup.sh -i` by answering "y" to the question "Do you also want dependencies for freqai-rl or PyTorch (~700mb additional space required) [y/N]?". + Users who prefer docker should ensure they use the docker image appended with `_freqaitorch`. + We do provide an explicit docker-compose file for this in `docker/docker-compose-freqai.yml` - which can be used via `docker compose -f docker/docker-compose-freqai.yml run ...` - or can be copied to replace the original docker file. + This docker-compose file also contains a (disabled) section to enable GPU resources within docker containers. This obviously assumes the system has GPU resources available. + +### Structure + +#### Model + +You can construct your own Neural Network architecture in PyTorch by simply defining your `nn.Module` class inside your custom [`IFreqaiModel` file](#using-different-prediction-models) and then using that class in your `def train()` function. Here is an example of logistic regression model implementation using PyTorch (should be used with nn.BCELoss criterion) for classification tasks. + +```python + +class LogisticRegression(nn.Module): + def __init__(self, input_size: int): + super().__init__() + # Define your layers + self.linear = nn.Linear(input_size, 1) + self.activation = nn.Sigmoid() + + def forward(self, x: torch.Tensor) -> torch.Tensor: + # Define the forward pass + out = self.linear(x) + out = self.activation(out) + return out + +class MyCoolPyTorchClassifier(BasePyTorchClassifier): + """ + This is a custom IFreqaiModel showing how a user might setup their own + custom Neural Network architecture for their training. + """ + + @property + def data_convertor(self) -> PyTorchDataConvertor: + return DefaultPyTorchDataConvertor(target_tensor_type=torch.float) + + def __init__(self, **kwargs) -> None: + super().__init__(**kwargs) + config = self.freqai_info.get("model_training_parameters", {}) + self.learning_rate: float = config.get("learning_rate", 3e-4) + self.model_kwargs: Dict[str, Any] = config.get("model_kwargs", {}) + self.trainer_kwargs: Dict[str, Any] = config.get("trainer_kwargs", {}) + + def fit(self, data_dictionary: Dict, dk: FreqaiDataKitchen, **kwargs) -> Any: + """ + User sets up the training and test data to fit their desired model here + :param data_dictionary: the dictionary holding all data for train, test, + labels, weights + :param dk: The datakitchen object for the current coin/model + """ + + class_names = self.get_class_names() + self.convert_label_column_to_int(data_dictionary, dk, class_names) + n_features = data_dictionary["train_features"].shape[-1] + model = LogisticRegression( + input_dim=n_features + ) + model.to(self.device) + optimizer = torch.optim.AdamW(model.parameters(), lr=self.learning_rate) + criterion = torch.nn.CrossEntropyLoss() + init_model = self.get_init_model(dk.pair) + trainer = PyTorchModelTrainer( + model=model, + optimizer=optimizer, + criterion=criterion, + model_meta_data={"class_names": class_names}, + device=self.device, + init_model=init_model, + data_convertor=self.data_convertor, + **self.trainer_kwargs, + ) + trainer.fit(data_dictionary, self.splits) + return trainer + +``` + +#### Trainer + +The `PyTorchModelTrainer` performs the idiomatic PyTorch train loop: +Define our model, loss function, and optimizer, and then move them to the appropriate device (GPU or CPU). Inside the loop, we iterate through the batches in the dataloader, move the data to the device, compute the prediction and loss, backpropagate, and update the model parameters using the optimizer. + +In addition, the trainer is responsible for the following: + - saving and loading the model + - converting the data from `pandas.DataFrame` to `torch.Tensor`. + +#### Integration with Freqai module + +Like all freqai models, PyTorch models inherit `IFreqaiModel`. `IFreqaiModel` declares three abstract methods: `train`, `fit`, and `predict`. we implement these methods in three levels of hierarchy. +From top to bottom: + +1. `BasePyTorchModel` - Implements the `train` method. all `BasePyTorch*` inherit it. responsible for general data preparation (e.g., data normalization) and calling the `fit` method. Sets `device` attribute used by children classes. Sets `model_type` attribute used by the parent class. +2. `BasePyTorch*` - Implements the `predict` method. Here, the `*` represents a group of algorithms, such as classifiers or regressors. responsible for data preprocessing, predicting, and postprocessing if needed. +3. `PyTorch*Classifier` / `PyTorch*Regressor` - implements the `fit` method. responsible for the main train flaw, where we initialize the trainer and model objects. + +![image](assets/freqai_pytorch-diagram.png) + +#### Full example + +Building a PyTorch regressor using MLP (multilayer perceptron) model, MSELoss criterion, and AdamW optimizer. + +```python +class PyTorchMLPRegressor(BasePyTorchRegressor): + def __init__(self, **kwargs) -> None: + super().__init__(**kwargs) + config = self.freqai_info.get("model_training_parameters", {}) + self.learning_rate: float = config.get("learning_rate", 3e-4) + self.model_kwargs: Dict[str, Any] = config.get("model_kwargs", {}) + self.trainer_kwargs: Dict[str, Any] = config.get("trainer_kwargs", {}) + + def fit(self, data_dictionary: Dict, dk: FreqaiDataKitchen, **kwargs) -> Any: + n_features = data_dictionary["train_features"].shape[-1] + model = PyTorchMLPModel( + input_dim=n_features, + output_dim=1, + **self.model_kwargs + ) + model.to(self.device) + optimizer = torch.optim.AdamW(model.parameters(), lr=self.learning_rate) + criterion = torch.nn.MSELoss() + init_model = self.get_init_model(dk.pair) + trainer = PyTorchModelTrainer( + model=model, + optimizer=optimizer, + criterion=criterion, + device=self.device, + init_model=init_model, + target_tensor_type=torch.float, + **self.trainer_kwargs, + ) + trainer.fit(data_dictionary) + return trainer +``` + +Here we create a `PyTorchMLPRegressor` class that implements the `fit` method. The `fit` method specifies the training building blocks: model, optimizer, criterion, and trainer. We inherit both `BasePyTorchRegressor` and `BasePyTorchModel`, where the former implements the `predict` method that is suitable for our regression task, and the latter implements the train method. + +??? Note "Setting Class Names for Classifiers" + When using classifiers, the user must declare the class names (or targets) by overriding the `IFreqaiModel.class_names` attribute. This is achieved by setting `self.freqai.class_names` in the FreqAI strategy inside the `set_freqai_targets` method. + + For example, if you are using a binary classifier to predict price movements as up or down, you can set the class names as follows: + ```python + def set_freqai_targets(self, dataframe: DataFrame, metadata: Dict, **kwargs) -> DataFrame: + self.freqai.class_names = ["down", "up"] + dataframe['&s-up_or_down'] = np.where(dataframe["close"].shift(-100) > + dataframe["close"], 'up', 'down') + + return dataframe + ``` + To see a full example, you can refer to the [classifier test strategy class](https://github.com/freqtrade/freqtrade/blob/develop/tests/strategy/strats/freqai_test_classifier.py). + + +#### Improving performance with `torch.compile()` + +Torch provides a `torch.compile()` method that can be used to improve performance for specific GPU hardware. More details can be found [here](https://pytorch.org/tutorials/intermediate/torch_compile_tutorial.html). In brief, you simply wrap your `model` in `torch.compile()`: + + +```python + model = PyTorchMLPModel( + input_dim=n_features, + output_dim=1, + **self.model_kwargs + ) + model.to(self.device) + model = torch.compile(model) +``` + +Then proceed to use the model as normal. Keep in mind that doing this will remove eager execution, which means errors and tracebacks will not be informative. diff --git a/docs/freqai-developers.md b/docs/freqai-developers.md new file mode 100644 index 000000000..37f4543b7 --- /dev/null +++ b/docs/freqai-developers.md @@ -0,0 +1,78 @@ +# Development + +## Project architecture + +The architecture and functions of FreqAI are generalized to encourages development of unique features, functions, models, etc. + +The class structure and a detailed algorithmic overview is depicted in the following diagram: + +![image](assets/freqai_algorithm-diagram.jpg) + +As shown, there are three distinct objects comprising FreqAI: + +* **IFreqaiModel** - A singular persistent object containing all the necessary logic to collect, store, and process data, engineer features, run training, and inference models. +* **FreqaiDataKitchen** - A non-persistent object which is created uniquely for each unique asset/model. Beyond metadata, it also contains a variety of data processing tools. +* **FreqaiDataDrawer** - A singular persistent object containing all the historical predictions, models, and save/load methods. + +There are a variety of built-in [prediction models](freqai-configuration.md#using-different-prediction-models) which inherit directly from `IFreqaiModel`. Each of these models have full access to all methods in `IFreqaiModel` and can therefore override any of those functions at will. However, advanced users will likely stick to overriding `fit()`, `train()`, `predict()`, and `data_cleaning_train/predict()`. + +## Data handling + +FreqAI aims to organize model files, prediction data, and meta data in a way that simplifies post-processing and enhances crash resilience by automatic data reloading. The data is saved in a file structure,`user_data_dir/models/`, which contains all the data associated with the trainings and backtests. The `FreqaiDataKitchen()` relies heavily on the file structure for proper training and inferencing and should therefore not be manually modified. + +### File structure + +The file structure is automatically generated based on the model `identifier` set in the [config](freqai-configuration.md#setting-up-the-configuration-file). The following structure shows where the data is stored for post processing: + +| Structure | Description | +|-----------|-------------| +| `config_*.json` | A copy of the model specific configuration file. | +| `historic_predictions.pkl` | A file containing all historic predictions generated during the lifetime of the `identifier` model during live deployment. `historic_predictions.pkl` is used to reload the model after a crash or a config change. A backup file is always held in case of corruption on the main file. FreqAI **automatically** detects corruption and replaces the corrupted file with the backup. | +| `pair_dictionary.json` | A file containing the training queue as well as the on disk location of the most recently trained model. | +| `sub-train-*_TIMESTAMP` | A folder containing all the files associated with a single model, such as:
+|| `*_metadata.json` - Metadata for the model, such as normalization max/min, expected training feature list, etc.
+|| `*_model.*` - The model file saved to disk for reloading from a crash. Can be `joblib` (typical boosting libs), `zip` (stable_baselines), `hd5` (keras type), etc.
+|| `*_pca_object.pkl` - The [Principal component analysis (PCA)](freqai-feature-engineering.md#data-dimensionality-reduction-with-principal-component-analysis) transform (if `principal_component_analysis: True` is set in the config) which will be used to transform unseen prediction features.
+|| `*_svm_model.pkl` - The [Support Vector Machine (SVM)](freqai-feature-engineering.md#identifying-outliers-using-a-support-vector-machine-svm) model (if `use_SVM_to_remove_outliers: True` is set in the config) which is used to detect outliers in unseen prediction features.
+|| `*_trained_df.pkl` - The dataframe containing all the training features used to train the `identifier` model. This is used for computing the [Dissimilarity Index (DI)](freqai-feature-engineering.md#identifying-outliers-with-the-dissimilarity-index-di) and can also be used for post-processing.
+|| `*_trained_dates.df.pkl` - The dates associated with the `trained_df.pkl`, which is useful for post-processing. | + +The example file structure would look like this: + +``` +├── models +│   └── unique-id +│   ├── config_freqai.example.json +│   ├── historic_predictions.backup.pkl +│   ├── historic_predictions.pkl +│   ├── pair_dictionary.json +│   ├── sub-train-1INCH_1662821319 +│   │   ├── cb_1inch_1662821319_metadata.json +│   │   ├── cb_1inch_1662821319_model.joblib +│   │   ├── cb_1inch_1662821319_pca_object.pkl +│   │   ├── cb_1inch_1662821319_svm_model.joblib +│   │   ├── cb_1inch_1662821319_trained_dates_df.pkl +│   │   └── cb_1inch_1662821319_trained_df.pkl +│   ├── sub-train-1INCH_1662821371 +│   │   ├── cb_1inch_1662821371_metadata.json +│   │   ├── cb_1inch_1662821371_model.joblib +│   │   ├── cb_1inch_1662821371_pca_object.pkl +│   │   ├── cb_1inch_1662821371_svm_model.joblib +│   │   ├── cb_1inch_1662821371_trained_dates_df.pkl +│   │   └── cb_1inch_1662821371_trained_df.pkl +│   ├── sub-train-ADA_1662821344 +│   │   ├── cb_ada_1662821344_metadata.json +│   │   ├── cb_ada_1662821344_model.joblib +│   │   ├── cb_ada_1662821344_pca_object.pkl +│   │   ├── cb_ada_1662821344_svm_model.joblib +│   │   ├── cb_ada_1662821344_trained_dates_df.pkl +│   │   └── cb_ada_1662821344_trained_df.pkl +│   └── sub-train-ADA_1662821399 +│   ├── cb_ada_1662821399_metadata.json +│   ├── cb_ada_1662821399_model.joblib +│   ├── cb_ada_1662821399_pca_object.pkl +│   ├── cb_ada_1662821399_svm_model.joblib +│   ├── cb_ada_1662821399_trained_dates_df.pkl +│   └── cb_ada_1662821399_trained_df.pkl + +``` diff --git a/docs/freqai-feature-engineering.md b/docs/freqai-feature-engineering.md new file mode 100644 index 000000000..6a1537d91 --- /dev/null +++ b/docs/freqai-feature-engineering.md @@ -0,0 +1,393 @@ +# Feature engineering + +## Defining the features + +Low level feature engineering is performed in the user strategy within a set of functions called `feature_engineering_*`. These function set the `base features` such as, `RSI`, `MFI`, `EMA`, `SMA`, time of day, volume, etc. The `base features` can be custom indicators or they can be imported from any technical-analysis library that you can find. FreqAI is equipped with a set of functions to simplify rapid large-scale feature engineering: + +| Function | Description | +|---------------|-------------| +| `feature_engineering_expand_all()` | This optional function will automatically expand the defined features on the config defined `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. +| `feature_engineering_expand_basic()` | This optional function will automatically expand the defined features on the config defined `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. Note: this function does *not* expand across `indicator_periods_candles`. +| `feature_engineering_standard()` | This optional function will be called once with the dataframe of the base timeframe. This is the final function to be called, which means that the dataframe entering this function will contain all the features and columns from the base asset created by the other `feature_engineering_expand` functions. This function is a good place to do custom exotic feature extractions (e.g. tsfresh). This function is also a good place for any feature that should not be auto-expanded upon (e.g., day of the week). +| `set_freqai_targets()` | Required function to set the targets for the model. All targets must be prepended with `&` to be recognized by the FreqAI internals. + +Meanwhile, high level feature engineering is handled within `"feature_parameters":{}` in the FreqAI config. Within this file, it is possible to decide large scale feature expansions on top of the `base_features` such as "including correlated pairs" or "including informative timeframes" or even "including recent candles." + +It is advisable to start from the template `feature_engineering_*` functions in the source provided example strategy (found in `templates/FreqaiExampleStrategy.py`) to ensure that the feature definitions are following the correct conventions. Here is an example of how to set the indicators and labels in the strategy: + +```python + def feature_engineering_expand_all(self, dataframe: DataFrame, period, metadata, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and + `include_corr_pairs`. In other words, a single feature defined in this function + will automatically expand to a total of + `indicator_periods_candles` * `include_timeframes` * `include_shifted_candles` * + `include_corr_pairs` numbers of features added to the model. + + All features must be prepended with `%` to be recognized by FreqAI internals. + + Access metadata such as the current pair/timeframe/period with: + + `metadata["pair"]` `metadata["tf"]` `metadata["period"]` + + :param df: strategy dataframe which will receive the features + :param period: period of the indicator - usage example: + :param metadata: metadata of current pair + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) + """ + + dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) + dataframe["%-mfi-period"] = ta.MFI(dataframe, timeperiod=period) + dataframe["%-adx-period"] = ta.ADX(dataframe, timeperiod=period) + dataframe["%-sma-period"] = ta.SMA(dataframe, timeperiod=period) + dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period) + + bollinger = qtpylib.bollinger_bands( + qtpylib.typical_price(dataframe), window=period, stds=2.2 + ) + dataframe["bb_lowerband-period"] = bollinger["lower"] + dataframe["bb_middleband-period"] = bollinger["mid"] + dataframe["bb_upperband-period"] = bollinger["upper"] + + dataframe["%-bb_width-period"] = ( + dataframe["bb_upperband-period"] + - dataframe["bb_lowerband-period"] + ) / dataframe["bb_middleband-period"] + dataframe["%-close-bb_lower-period"] = ( + dataframe["close"] / dataframe["bb_lowerband-period"] + ) + + dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) + + dataframe["%-relative_volume-period"] = ( + dataframe["volume"] / dataframe["volume"].rolling(period).mean() + ) + + return dataframe + + def feature_engineering_expand_basic(self, dataframe: DataFrame, metadata, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + This function will automatically expand the defined features on the config defined + `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. + In other words, a single feature defined in this function + will automatically expand to a total of + `include_timeframes` * `include_shifted_candles` * `include_corr_pairs` + numbers of features added to the model. + + Features defined here will *not* be automatically duplicated on user defined + `indicator_periods_candles` + + Access metadata such as the current pair/timeframe with: + + `metadata["pair"]` `metadata["tf"]` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + :param metadata: metadata of current pair + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200) + """ + dataframe["%-pct-change"] = dataframe["close"].pct_change() + dataframe["%-raw_volume"] = dataframe["volume"] + dataframe["%-raw_price"] = dataframe["close"] + return dataframe + + def feature_engineering_standard(self, dataframe: DataFrame, metadata, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + This optional function will be called once with the dataframe of the base timeframe. + This is the final function to be called, which means that the dataframe entering this + function will contain all the features and columns created by all other + freqai_feature_engineering_* functions. + + This function is a good place to do custom exotic feature extractions (e.g. tsfresh). + This function is a good place for any feature that should not be auto-expanded upon + (e.g. day of the week). + + Access metadata such as the current pair with: + + `metadata["pair"]` + + All features must be prepended with `%` to be recognized by FreqAI internals. + + :param df: strategy dataframe which will receive the features + :param metadata: metadata of current pair + usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + """ + dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7 + dataframe["%-hour_of_day"] = (dataframe["date"].dt.hour + 1) / 25 + return dataframe + + def set_freqai_targets(self, dataframe: DataFrame, metadata, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + Access metadata such as the current pair with: + + `metadata["pair"]` + + :param df: strategy dataframe which will receive the targets + :param metadata: metadata of current pair + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + dataframe["&-s_close"] = ( + dataframe["close"] + .shift(-self.freqai_info["feature_parameters"]["label_period_candles"]) + .rolling(self.freqai_info["feature_parameters"]["label_period_candles"]) + .mean() + / dataframe["close"] + - 1 + ) + + return dataframe +``` + +In the presented example, the user does not wish to pass the `bb_lowerband` as a feature to the model, +and has therefore not prepended it with `%`. The user does, however, wish to pass `bb_width` to the +model for training/prediction and has therefore prepended it with `%`. + +After having defined the `base features`, the next step is to expand upon them using the powerful `feature_parameters` in the configuration file: + +```json + "freqai": { + //... + "feature_parameters" : { + "include_timeframes": ["5m","15m","4h"], + "include_corr_pairlist": [ + "ETH/USD", + "LINK/USD", + "BNB/USD" + ], + "label_period_candles": 24, + "include_shifted_candles": 2, + "indicator_periods_candles": [10, 20] + }, + //... + } +``` + +The `include_timeframes` in the config above are the timeframes (`tf`) of each call to `feature_engineering_expand_*()` in the strategy. In the presented case, the user is asking for the `5m`, `15m`, and `4h` timeframes of the `rsi`, `mfi`, `roc`, and `bb_width` to be included in the feature set. + +You can ask for each of the defined features to be included also for informative pairs using the `include_corr_pairlist`. This means that the feature set will include all the features from `feature_engineering_expand_*()` on all the `include_timeframes` for each of the correlated pairs defined in the config (`ETH/USD`, `LINK/USD`, and `BNB/USD` in the presented example). + +`include_shifted_candles` indicates the number of previous candles to include in the feature set. For example, `include_shifted_candles: 2` tells FreqAI to include the past 2 candles for each of the features in the feature set. + +In total, the number of features the user of the presented example strategy has created is: length of `include_timeframes` * no. features in `feature_engineering_expand_*()` * length of `include_corr_pairlist` * no. `include_shifted_candles` * length of `indicator_periods_candles` + $= 3 * 3 * 3 * 2 * 2 = 108$. + + !!! note "Learn more about creative feature engineering" + Check out our [medium article](https://emergentmethods.medium.com/freqai-from-price-to-prediction-6fadac18b665) geared toward helping users learn how to creatively engineer features. + +### Gain finer control over `feature_engineering_*` functions with `metadata` + +All `feature_engineering_*` and `set_freqai_targets()` functions are passed a `metadata` dictionary which contains information about the `pair`, `tf` (timeframe), and `period` that FreqAI is automating for feature building. As such, a user can use `metadata` inside `feature_engineering_*` functions as criteria for blocking/reserving features for certain timeframes, periods, pairs etc. + +```python +def feature_engineering_expand_all(self, dataframe: DataFrame, period, metadata, **kwargs) -> DataFrame: + if metadata["tf"] == "1h": + dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) +``` + +This will block `ta.ROC()` from being added to any timeframes other than `"1h"`. + +### Returning additional info from training + +Important metrics can be returned to the strategy at the end of each model training by assigning them to `dk.data['extra_returns_per_train']['my_new_value'] = XYZ` inside the custom prediction model class. + +FreqAI takes the `my_new_value` assigned in this dictionary and expands it to fit the dataframe that is returned to the strategy. You can then use the returned metrics in your strategy through `dataframe['my_new_value']`. An example of how return values can be used in FreqAI are the `&*_mean` and `&*_std` values that are used to [created a dynamic target threshold](freqai-configuration.md#creating-a-dynamic-target-threshold). + +Another example, where the user wants to use live metrics from the trade database, is shown below: + +```json + "freqai": { + "extra_returns_per_train": {"total_profit": 4} + } +``` + +You need to set the standard dictionary in the config so that FreqAI can return proper dataframe shapes. These values will likely be overridden by the prediction model, but in the case where the model has yet to set them, or needs a default initial value, the pre-set values are what will be returned. + +### Weighting features for temporal importance + +FreqAI allows you to set a `weight_factor` to weight recent data more strongly than past data via an exponential function: + +$$ W_i = \exp(\frac{-i}{\alpha*n}) $$ + +where $W_i$ is the weight of data point $i$ in a total set of $n$ data points. Below is a figure showing the effect of different weight factors on the data points in a feature set. + +![weight-factor](assets/freqai_weight-factor.jpg) + +## Building the data pipeline + +By default, FreqAI builds a dynamic pipeline based on user congfiguration settings. The default settings are robust and designed to work with a variety of methods. These two steps are a `MinMaxScaler(-1,1)` and a `VarianceThreshold` which removes any column that has 0 variance. Users can activate other steps with more configuration parameters. For example if users add `use_SVM_to_remove_outliers: true` to the `freqai` config, then FreqAI will automatically add the [`SVMOutlierExtractor`](#identifying-outliers-using-a-support-vector-machine-svm) to the pipeline. Likewise, users can add `principal_component_analysis: true` to the `freqai` config to activate PCA. The [DissimilarityIndex](#identifying-outliers-with-the-dissimilarity-index-di) is activated with `DI_threshold: 1`. Finally, noise can also be added to the data with `noise_standard_deviation: 0.1`. Finally, users can add [DBSCAN](#identifying-outliers-with-dbscan) outlier removal with `use_DBSCAN_to_remove_outliers: true`. + +!!! note "More information available" + Please review the [parameter table](freqai-parameter-table.md) for more information on these parameters. + + +### Customizing the pipeline + +Users are encouraged to customize the data pipeline to their needs by building their own data pipeline. This can be done by simply setting `dk.feature_pipeline` to their desired `Pipeline` object inside their `IFreqaiModel` `train()` function, or if they prefer not to touch the `train()` function, they can override `define_data_pipeline`/`define_label_pipeline` functions in their `IFreqaiModel`: + +!!! note "More information available" + FreqAI uses the the [`DataSieve`](https://github.com/emergentmethods/datasieve) pipeline, which follows the SKlearn pipeline API, but adds, among other features, coherence between the X, y, and sample_weight vector point removals, feature removal, feature name following. + +```python +from datasieve.transforms import SKLearnWrapper, DissimilarityIndex +from datasieve.pipeline import Pipeline +from sklearn.preprocessing import QuantileTransformer, StandardScaler +from freqai.base_models import BaseRegressionModel + + +class MyFreqaiModel(BaseRegressionModel): + """ + Some cool custom model + """ + def fit(self, data_dictionary: Dict, dk: FreqaiDataKitchen, **kwargs) -> Any: + """ + My custom fit function + """ + model = cool_model.fit() + return model + + def define_data_pipeline(self) -> Pipeline: + """ + User defines their custom feature pipeline here (if they wish) + """ + feature_pipeline = Pipeline([ + ('qt', SKLearnWrapper(QuantileTransformer(output_distribution='normal'))), + ('di', ds.DissimilarityIndex(di_threshold=1)) + ]) + + return feature_pipeline + + def define_label_pipeline(self) -> Pipeline: + """ + User defines their custom label pipeline here (if they wish) + """ + label_pipeline = Pipeline([ + ('qt', SKLearnWrapper(StandardScaler())), + ]) + + return label_pipeline +``` + +Here, you are defining the exact pipeline that will be used for your feature set during training and prediction. You can use *most* SKLearn transformation steps by wrapping them in the `SKLearnWrapper` class as shown above. In addition, you can use any of the transformations available in the [`DataSieve` library](https://github.com/emergentmethods/datasieve). + +You can easily add your own transformation by creating a class that inherits from the datasieve `BaseTransform` and implementing your `fit()`, `transform()` and `inverse_transform()` methods: + +```python +from datasieve.transforms.base_transform import BaseTransform +# import whatever else you need + +class MyCoolTransform(BaseTransform): + def __init__(self, **kwargs): + self.param1 = kwargs.get('param1', 1) + + def fit(self, X, y=None, sample_weight=None, feature_list=None, **kwargs): + # do something with X, y, sample_weight, or/and feature_list + return X, y, sample_weight, feature_list + + def transform(self, X, y=None, sample_weight=None, + feature_list=None, outlier_check=False, **kwargs): + # do something with X, y, sample_weight, or/and feature_list + return X, y, sample_weight, feature_list + + def inverse_transform(self, X, y=None, sample_weight=None, feature_list=None, **kwargs): + # do/dont do something with X, y, sample_weight, or/and feature_list + return X, y, sample_weight, feature_list +``` + +!!! note "Hint" + You can define this custom class in the same file as your `IFreqaiModel`. + +### Migrating a custom `IFreqaiModel` to the new Pipeline + +If you have created your own custom `IFreqaiModel` with a custom `train()`/`predict()` function, *and* you still rely on `data_cleaning_train/predict()`, then you will need to migrate to the new pipeline. If your model does *not* rely on `data_cleaning_train/predict()`, then you do not need to worry about this migration. + +More details about the migration can be found [here](strategy_migration.md#freqai---new-data-pipeline). + +## Outlier detection + +Equity and crypto markets suffer from a high level of non-patterned noise in the form of outlier data points. FreqAI implements a variety of methods to identify such outliers and hence mitigate risk. + +### Identifying outliers with the Dissimilarity Index (DI) + +The Dissimilarity Index (DI) aims to quantify the uncertainty associated with each prediction made by the model. + +You can tell FreqAI to remove outlier data points from the training/test data sets using the DI by including the following statement in the config: + +```json + "freqai": { + "feature_parameters" : { + "DI_threshold": 1 + } + } +``` + +Which will add `DissimilarityIndex` step to your `feature_pipeline` and set the threshold to 1. The DI allows predictions which are outliers (not existent in the model feature space) to be thrown out due to low levels of certainty. To do so, FreqAI measures the distance between each training data point (feature vector), $X_{a}$, and all other training data points: + +$$ d_{ab} = \sqrt{\sum_{j=1}^p(X_{a,j}-X_{b,j})^2} $$ + +where $d_{ab}$ is the distance between the normalized points $a$ and $b$, and $p$ is the number of features, i.e., the length of the vector $X$. The characteristic distance, $\overline{d}$, for a set of training data points is simply the mean of the average distances: + +$$ \overline{d} = \sum_{a=1}^n(\sum_{b=1}^n(d_{ab}/n)/n) $$ + +$\overline{d}$ quantifies the spread of the training data, which is compared to the distance between a new prediction feature vectors, $X_k$ and all the training data: + +$$ d_k = \arg \min d_{k,i} $$ + +This enables the estimation of the Dissimilarity Index as: + +$$ DI_k = d_k/\overline{d} $$ + +You can tweak the DI through the `DI_threshold` to increase or decrease the extrapolation of the trained model. A higher `DI_threshold` means that the DI is more lenient and allows predictions further away from the training data to be used whilst a lower `DI_threshold` has the opposite effect and hence discards more predictions. + +Below is a figure that describes the DI for a 3D data set. + +![DI](assets/freqai_DI.jpg) + +### Identifying outliers using a Support Vector Machine (SVM) + +You can tell FreqAI to remove outlier data points from the training/test data sets using a Support Vector Machine (SVM) by including the following statement in the config: + +```json + "freqai": { + "feature_parameters" : { + "use_SVM_to_remove_outliers": true + } + } +``` + +Which will add `SVMOutlierExtractor` step to your `feature_pipeline`. The SVM will be trained on the training data and any data point that the SVM deems to be beyond the feature space will be removed. + +You can elect to provide additional parameters for the SVM, such as `shuffle`, and `nu` via the `feature_parameters.svm_params` dictionary in the config. + +The parameter `shuffle` is by default set to `False` to ensure consistent results. If it is set to `True`, running the SVM multiple times on the same data set might result in different outcomes due to `max_iter` being to low for the algorithm to reach the demanded `tol`. Increasing `max_iter` solves this issue but causes the procedure to take longer time. + +The parameter `nu`, *very* broadly, is the amount of data points that should be considered outliers and should be between 0 and 1. + +### Identifying outliers with DBSCAN + +You can configure FreqAI to use DBSCAN to cluster and remove outliers from the training/test data set or incoming outliers from predictions, by activating `use_DBSCAN_to_remove_outliers` in the config: + +```json + "freqai": { + "feature_parameters" : { + "use_DBSCAN_to_remove_outliers": true + } + } +``` + +Which will add the `DataSieveDBSCAN` step to your `feature_pipeline`. This is an unsupervised machine learning algorithm that clusters data without needing to know how many clusters there should be. + +Given a number of data points $N$, and a distance $\varepsilon$, DBSCAN clusters the data set by setting all data points that have $N-1$ other data points within a distance of $\varepsilon$ as *core points*. A data point that is within a distance of $\varepsilon$ from a *core point* but that does not have $N-1$ other data points within a distance of $\varepsilon$ from itself is considered an *edge point*. A cluster is then the collection of *core points* and *edge points*. Data points that have no other data points at a distance $<\varepsilon$ are considered outliers. The figure below shows a cluster with $N = 3$. + +![dbscan](assets/freqai_dbscan.jpg) + +FreqAI uses `sklearn.cluster.DBSCAN` (details are available on scikit-learn's webpage [here](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.DBSCAN.html) (external website)) with `min_samples` ($N$) taken as 1/4 of the no. of time points (candles) in the feature set. `eps` ($\varepsilon$) is computed automatically as the elbow point in the *k-distance graph* computed from the nearest neighbors in the pairwise distances of all data points in the feature set. diff --git a/docs/freqai-parameter-table.md b/docs/freqai-parameter-table.md new file mode 100644 index 000000000..905ea479a --- /dev/null +++ b/docs/freqai-parameter-table.md @@ -0,0 +1,117 @@ +# Parameter table + +The table below will list all configuration parameters available for FreqAI. Some of the parameters are exemplified in `config_examples/config_freqai.example.json`. + +Mandatory parameters are marked as **Required** and have to be set in one of the suggested ways. + +### General configuration parameters + +| Parameter | Description | +|------------|-------------| +| | **General configuration parameters within the `config.freqai` tree** +| `freqai` | **Required.**
The parent dictionary containing all the parameters for controlling FreqAI.
**Datatype:** Dictionary. +| `train_period_days` | **Required.**
Number of days to use for the training data (width of the sliding window).
**Datatype:** Positive integer. +| `backtest_period_days` | **Required.**
Number of days to inference from the trained model before sliding the `train_period_days` window defined above, and retraining the model during backtesting (more info [here](freqai-running.md#backtesting)). This can be fractional days, but beware that the provided `timerange` will be divided by this number to yield the number of trainings necessary to complete the backtest.
**Datatype:** Float. +| `identifier` | **Required.**
A unique ID for the current model. If models are saved to disk, the `identifier` allows for reloading specific pre-trained models/data.
**Datatype:** String. +| `live_retrain_hours` | Frequency of retraining during dry/live runs.
**Datatype:** Float > 0.
Default: `0` (models retrain as often as possible). +| `expiration_hours` | Avoid making predictions if a model is more than `expiration_hours` old.
**Datatype:** Positive integer.
Default: `0` (models never expire). +| `purge_old_models` | Number of models to keep on disk (not relevant to backtesting). Default is 2, which means that dry/live runs will keep the latest 2 models on disk. Setting to 0 keeps all models. This parameter also accepts a boolean to maintain backwards compatibility.
**Datatype:** Integer.
Default: `2`. +| `save_backtest_models` | Save models to disk when running backtesting. Backtesting operates most efficiently by saving the prediction data and reusing them directly for subsequent runs (when you wish to tune entry/exit parameters). Saving backtesting models to disk also allows to use the same model files for starting a dry/live instance with the same model `identifier`.
**Datatype:** Boolean.
Default: `False` (no models are saved). +| `fit_live_predictions_candles` | Number of historical candles to use for computing target (label) statistics from prediction data, instead of from the training dataset (more information can be found [here](freqai-configuration.md#creating-a-dynamic-target-threshold)).
**Datatype:** Positive integer. +| `continual_learning` | Use the final state of the most recently trained model as starting point for the new model, allowing for incremental learning (more information can be found [here](freqai-running.md#continual-learning)). Beware that this is currently a naive approach to incremental learning, and it has a high probability of overfitting/getting stuck in local minima while the market moves away from your model. We have the connections here primarily for experimental purposes and so that it is ready for more mature approaches to continual learning in chaotic systems like the crypto market.
**Datatype:** Boolean.
Default: `False`. +| `write_metrics_to_disk` | Collect train timings, inference timings and cpu usage in json file.
**Datatype:** Boolean.
Default: `False` +| `data_kitchen_thread_count` |
Designate the number of threads you want to use for data processing (outlier methods, normalization, etc.). This has no impact on the number of threads used for training. If user does not set it (default), FreqAI will use max number of threads - 2 (leaving 1 physical core available for Freqtrade bot and FreqUI)
**Datatype:** Positive integer. +| `activate_tensorboard` |
Indicate whether or not to activate tensorboard for the tensorboard enabled modules (currently Reinforcment Learning, XGBoost, Catboost, and PyTorch). Tensorboard needs Torch installed, which means you will need the torch/RL docker image or you need to answer "yes" to the install question about whether or not you wish to install Torch.
**Datatype:** Boolean.
Default: `True`. + +### Feature parameters + +| Parameter | Description | +|------------|-------------| +| | **Feature parameters within the `freqai.feature_parameters` sub dictionary** +| `feature_parameters` | A dictionary containing the parameters used to engineer the feature set. Details and examples are shown [here](freqai-feature-engineering.md).
**Datatype:** Dictionary. +| `include_timeframes` | A list of timeframes that all indicators in `feature_engineering_expand_*()` will be created for. The list is added as features to the base indicators dataset.
**Datatype:** List of timeframes (strings). +| `include_corr_pairlist` | A list of correlated coins that FreqAI will add as additional features to all `pair_whitelist` coins. All indicators set in `feature_engineering_expand_*()` during feature engineering (see details [here](freqai-feature-engineering.md)) will be created for each correlated coin. The correlated coins features are added to the base indicators dataset.
**Datatype:** List of assets (strings). +| `label_period_candles` | Number of candles into the future that the labels are created for. This is used in `feature_engineering_expand_all()` (see `templates/FreqaiExampleStrategy.py` for detailed usage). You can create custom labels and choose whether to make use of this parameter or not.
**Datatype:** Positive integer. +| `include_shifted_candles` | Add features from previous candles to subsequent candles with the intent of adding historical information. If used, FreqAI will duplicate and shift all features from the `include_shifted_candles` previous candles so that the information is available for the subsequent candle.
**Datatype:** Positive integer. +| `weight_factor` | Weight training data points according to their recency (see details [here](freqai-feature-engineering.md#weighting-features-for-temporal-importance)).
**Datatype:** Positive float (typically < 1). +| `indicator_max_period_candles` | **No longer used (#7325)**. Replaced by `startup_candle_count` which is set in the [strategy](freqai-configuration.md#building-a-freqai-strategy). `startup_candle_count` is timeframe independent and defines the maximum *period* used in `feature_engineering_*()` for indicator creation. FreqAI uses this parameter together with the maximum timeframe in `include_time_frames` to calculate how many data points to download such that the first data point does not include a NaN.
**Datatype:** Positive integer. +| `indicator_periods_candles` | Time periods to calculate indicators for. The indicators are added to the base indicator dataset.
**Datatype:** List of positive integers. +| `principal_component_analysis` | Automatically reduce the dimensionality of the data set using Principal Component Analysis. See details about how it works [here](#reducing-data-dimensionality-with-principal-component-analysis)
**Datatype:** Boolean.
Default: `False`. +| `plot_feature_importances` | Create a feature importance plot for each model for the top/bottom `plot_feature_importances` number of features. Plot is stored in `user_data/models//sub-train-_.html`.
**Datatype:** Integer.
Default: `0`. +| `DI_threshold` | Activates the use of the Dissimilarity Index for outlier detection when set to > 0. See details about how it works [here](freqai-feature-engineering.md#identifying-outliers-with-the-dissimilarity-index-di).
**Datatype:** Positive float (typically < 1). +| `use_SVM_to_remove_outliers` | Train a support vector machine to detect and remove outliers from the training dataset, as well as from incoming data points. See details about how it works [here](freqai-feature-engineering.md#identifying-outliers-using-a-support-vector-machine-svm).
**Datatype:** Boolean. +| `svm_params` | All parameters available in Sklearn's `SGDOneClassSVM()`. See details about some select parameters [here](freqai-feature-engineering.md#identifying-outliers-using-a-support-vector-machine-svm).
**Datatype:** Dictionary. +| `use_DBSCAN_to_remove_outliers` | Cluster data using the DBSCAN algorithm to identify and remove outliers from training and prediction data. See details about how it works [here](freqai-feature-engineering.md#identifying-outliers-with-dbscan).
**Datatype:** Boolean. +| `noise_standard_deviation` | If set, FreqAI adds noise to the training features with the aim of preventing overfitting. FreqAI generates random deviates from a gaussian distribution with a standard deviation of `noise_standard_deviation` and adds them to all data points. `noise_standard_deviation` should be kept relative to the normalized space, i.e., between -1 and 1. In other words, since data in FreqAI is always normalized to be between -1 and 1, `noise_standard_deviation: 0.05` would result in 32% of the data being randomly increased/decreased by more than 2.5% (i.e., the percent of data falling within the first standard deviation).
**Datatype:** Integer.
Default: `0`. +| `outlier_protection_percentage` | Enable to prevent outlier detection methods from discarding too much data. If more than `outlier_protection_percentage` % of points are detected as outliers by the SVM or DBSCAN, FreqAI will log a warning message and ignore outlier detection, i.e., the original dataset will be kept intact. If the outlier protection is triggered, no predictions will be made based on the training dataset.
**Datatype:** Float.
Default: `30`. +| `reverse_train_test_order` | Split the feature dataset (see below) and use the latest data split for training and test on historical split of the data. This allows the model to be trained up to the most recent data point, while avoiding overfitting. However, you should be careful to understand the unorthodox nature of this parameter before employing it.
**Datatype:** Boolean.
Default: `False` (no reversal). +| `shuffle_after_split` | Split the data into train and test sets, and then shuffle both sets individually.
**Datatype:** Boolean.
Default: `False`. +| `buffer_train_data_candles` | Cut `buffer_train_data_candles` off the beginning and end of the training data *after* the indicators were populated. The main example use is when predicting maxima and minima, the argrelextrema function cannot know the maxima/minima at the edges of the timerange. To improve model accuracy, it is best to compute argrelextrema on the full timerange and then use this function to cut off the edges (buffer) by the kernel. In another case, if the targets are set to a shifted price movement, this buffer is unnecessary because the shifted candles at the end of the timerange will be NaN and FreqAI will automatically cut those off of the training dataset.
**Datatype:** Integer.
Default: `0`. + +### Data split parameters + +| Parameter | Description | +|------------|-------------| +| | **Data split parameters within the `freqai.data_split_parameters` sub dictionary** +| `data_split_parameters` | Include any additional parameters available from scikit-learn `test_train_split()`, which are shown [here](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html) (external website).
**Datatype:** Dictionary. +| `test_size` | The fraction of data that should be used for testing instead of training.
**Datatype:** Positive float < 1. +| `shuffle` | Shuffle the training data points during training. Typically, to not remove the chronological order of data in time-series forecasting, this is set to `False`.
**Datatype:** Boolean.
Defaut: `False`. + +### Model training parameters + +| Parameter | Description | +|------------|-------------| +| | **Model training parameters within the `freqai.model_training_parameters` sub dictionary** +| `model_training_parameters` | A flexible dictionary that includes all parameters available by the selected model library. For example, if you use `LightGBMRegressor`, this dictionary can contain any parameter available by the `LightGBMRegressor` [here](https://lightgbm.readthedocs.io/en/latest/pythonapi/lightgbm.LGBMRegressor.html) (external website). If you select a different model, this dictionary can contain any parameter from that model. A list of the currently available models can be found [here](freqai-configuration.md#using-different-prediction-models).
**Datatype:** Dictionary. +| `n_estimators` | The number of boosted trees to fit in the training of the model.
**Datatype:** Integer. +| `learning_rate` | Boosting learning rate during training of the model.
**Datatype:** Float. +| `n_jobs`, `thread_count`, `task_type` | Set the number of threads for parallel processing and the `task_type` (`gpu` or `cpu`). Different model libraries use different parameter names.
**Datatype:** Float. + +### Reinforcement Learning parameters + +| Parameter | Description | +|------------|-------------| +| | **Reinforcement Learning Parameters within the `freqai.rl_config` sub dictionary** +| `rl_config` | A dictionary containing the control parameters for a Reinforcement Learning model.
**Datatype:** Dictionary. +| `train_cycles` | Training time steps will be set based on the `train_cycles * number of training data points.
**Datatype:** Integer. +| `max_trade_duration_candles`| Guides the agent training to keep trades below desired length. Example usage shown in `prediction_models/ReinforcementLearner.py` within the customizable `calculate_reward()` function.
**Datatype:** int. +| `model_type` | Model string from stable_baselines3 or SBcontrib. Available strings include: `'TRPO', 'ARS', 'RecurrentPPO', 'MaskablePPO', 'PPO', 'A2C', 'DQN'`. User should ensure that `model_training_parameters` match those available to the corresponding stable_baselines3 model by visiting their documentaiton. [PPO doc](https://stable-baselines3.readthedocs.io/en/master/modules/ppo.html) (external website)
**Datatype:** string. +| `policy_type` | One of the available policy types from stable_baselines3
**Datatype:** string. +| `max_training_drawdown_pct` | The maximum drawdown that the agent is allowed to experience during training.
**Datatype:** float.
Default: 0.8 +| `cpu_count` | Number of threads/cpus to dedicate to the Reinforcement Learning training process (depending on if `ReinforcementLearning_multiproc` is selected or not). Recommended to leave this untouched, by default, this value is set to the total number of physical cores minus 1.
**Datatype:** int. +| `model_reward_parameters` | Parameters used inside the customizable `calculate_reward()` function in `ReinforcementLearner.py`
**Datatype:** int. +| `add_state_info` | Tell FreqAI to include state information in the feature set for training and inferencing. The current state variables include trade duration, current profit, trade position. This is only available in dry/live runs, and is automatically switched to false for backtesting.
**Datatype:** bool.
Default: `False`. +| `net_arch` | Network architecture which is well described in [`stable_baselines3` doc](https://stable-baselines3.readthedocs.io/en/master/guide/custom_policy.html#examples). In summary: `[, dict(vf=[], pi=[])]`. By default this is set to `[128, 128]`, which defines 2 shared hidden layers with 128 units each. +| `randomize_starting_position` | Randomize the starting point of each episode to avoid overfitting.
**Datatype:** bool.
Default: `False`. +| `drop_ohlc_from_features` | Do not include the normalized ohlc data in the feature set passed to the agent during training (ohlc will still be used for driving the environment in all cases)
**Datatype:** Boolean.
**Default:** `False` +| `progress_bar` | Display a progress bar with the current progress, elapsed time and estimated remaining time.
**Datatype:** Boolean.
Default: `False`. + +### PyTorch parameters + +#### general + +| Parameter | Description | +|------------|-------------| +| | **Model training parameters within the `freqai.model_training_parameters` sub dictionary** +| `learning_rate` | Learning rate to be passed to the optimizer.
**Datatype:** float.
Default: `3e-4`. +| `model_kwargs` | Parameters to be passed to the model class.
**Datatype:** dict.
Default: `{}`. +| `trainer_kwargs` | Parameters to be passed to the trainer class.
**Datatype:** dict.
Default: `{}`. + +#### trainer_kwargs + +| Parameter | Description | +|--------------|-------------| +| | **Model training parameters within the `freqai.model_training_parameters.model_kwargs` sub dictionary** +| `n_epochs` | The `n_epochs` parameter is a crucial setting in the PyTorch training loop that determines the number of times the entire training dataset will be used to update the model's parameters. An epoch represents one full pass through the entire training dataset. Overrides `n_steps`. Either `n_epochs` or `n_steps` must be set.

**Datatype:** int. optional.
Default: `10`. +| `n_steps` | An alternative way of setting `n_epochs` - the number of training iterations to run. Iteration here refer to the number of times we call `optimizer.step()`. Ignored if `n_epochs` is set. A simplified version of the function:

n_epochs = n_steps / (n_obs / batch_size)

The motivation here is that `n_steps` is easier to optimize and keep stable across different n_obs - the number of data points.

**Datatype:** int. optional.
Default: `None`. +| `batch_size` | The size of the batches to use during training.

**Datatype:** int.
Default: `64`. + + +### Additional parameters + +| Parameter | Description | +|------------|-------------| +| | **Extraneous parameters** +| `freqai.keras` | If the selected model makes use of Keras (typical for TensorFlow-based prediction models), this flag needs to be activated so that the model save/loading follows Keras standards.
**Datatype:** Boolean.
Default: `False`. +| `freqai.conv_width` | The width of a neural network input tensor. This replaces the need for shifting candles (`include_shifted_candles`) by feeding in historical data points as the second dimension of the tensor. Technically, this parameter can also be used for regressors, but it only adds computational overhead and does not change the model training/prediction.
**Datatype:** Integer.
Default: `2`. +| `freqai.reduce_df_footprint` | Recast all numeric columns to float32/int32, with the objective of reducing ram/disk usage and decreasing train/inference timing. This parameter is set in the main level of the Freqtrade configuration file (not inside FreqAI).
**Datatype:** Boolean.
Default: `False`. diff --git a/docs/freqai-reinforcement-learning.md b/docs/freqai-reinforcement-learning.md new file mode 100644 index 000000000..c5cda3bc3 --- /dev/null +++ b/docs/freqai-reinforcement-learning.md @@ -0,0 +1,280 @@ +# Reinforcement Learning + +!!! Note "Installation size" + Reinforcement learning dependencies include large packages such as `torch`, which should be explicitly requested during `./setup.sh -i` by answering "y" to the question "Do you also want dependencies for freqai-rl (~700mb additional space required) [y/N]?". + Users who prefer docker should ensure they use the docker image appended with `_freqairl`. + +## Background and terminology + +### What is RL and why does FreqAI need it? + +Reinforcement learning involves two important components, the *agent* and the training *environment*. During agent training, the agent moves through historical data candle by candle, always making 1 of a set of actions: Long entry, long exit, short entry, short exit, neutral). During this training process, the environment tracks the performance of these actions and rewards the agent according to a custom user made `calculate_reward()` (here we offer a default reward for users to build on if they wish [details here](#creating-a-custom-reward-function)). The reward is used to train weights in a neural network. + +A second important component of the FreqAI RL implementation is the use of *state* information. State information is fed into the network at each step, including current profit, current position, and current trade duration. These are used to train the agent in the training environment, and to reinforce the agent in dry/live (this functionality is not available in backtesting). *FreqAI + Freqtrade is a perfect match for this reinforcing mechanism since this information is readily available in live deployments.* + +Reinforcement learning is a natural progression for FreqAI, since it adds a new layer of adaptivity and market reactivity that Classifiers and Regressors cannot match. However, Classifiers and Regressors have strengths that RL does not have such as robust predictions. Improperly trained RL agents may find "cheats" and "tricks" to maximize reward without actually winning any trades. For this reason, RL is more complex and demands a higher level of understanding than typical Classifiers and Regressors. + +### The RL interface + +With the current framework, we aim to expose the training environment via the common "prediction model" file, which is a user inherited `BaseReinforcementLearner` object (e.g. `freqai/prediction_models/ReinforcementLearner`). Inside this user class, the RL environment is available and customized via `MyRLEnv` as [shown below](#creating-a-custom-reward-function). + +We envision the majority of users focusing their effort on creative design of the `calculate_reward()` function [details here](#creating-a-custom-reward-function), while leaving the rest of the environment untouched. Other users may not touch the environment at all, and they will only play with the configuration settings and the powerful feature engineering that already exists in FreqAI. Meanwhile, we enable advanced users to create their own model classes entirely. + +The framework is built on stable_baselines3 (torch) and OpenAI gym for the base environment class. But generally speaking, the model class is well isolated. Thus, the addition of competing libraries can be easily integrated into the existing framework. For the environment, it is inheriting from `gym.Env` which means that it is necessary to write an entirely new environment in order to switch to a different library. + +### Important considerations + +As explained above, the agent is "trained" in an artificial trading "environment". In our case, that environment may seem quite similar to a real Freqtrade backtesting environment, but it is *NOT*. In fact, the RL training environment is much more simplified. It does not incorporate any of the complicated strategy logic, such as callbacks like `custom_exit`, `custom_stoploss`, leverage controls, etc. The RL environment is instead a very "raw" representation of the true market, where the agent has free will to learn the policy (read: stoploss, take profit, etc.) which is enforced by the `calculate_reward()`. Thus, it is important to consider that the agent training environment is not identical to the real world. + +## Running Reinforcement Learning + +Setting up and running a Reinforcement Learning model is the same as running a Regressor or Classifier. The same two flags, `--freqaimodel` and `--strategy`, must be defined on the command line: + +```bash +freqtrade trade --freqaimodel ReinforcementLearner --strategy MyRLStrategy --config config.json +``` + +where `ReinforcementLearner` will use the templated `ReinforcementLearner` from `freqai/prediction_models/ReinforcementLearner` (or a custom user defined one located in `user_data/freqaimodels`). The strategy, on the other hand, follows the same base [feature engineering](freqai-feature-engineering.md) with `feature_engineering_*` as a typical Regressor. The difference lies in the creation of the targets, Reinforcement Learning doesn't require them. However, FreqAI requires a default (neutral) value to be set in the action column: + +```python + def set_freqai_targets(self, dataframe, **kwargs) -> DataFrame: + """ + *Only functional with FreqAI enabled strategies* + Required function to set the targets for the model. + All targets must be prepended with `&` to be recognized by the FreqAI internals. + + More details about feature engineering available: + + https://www.freqtrade.io/en/latest/freqai-feature-engineering + + :param df: strategy dataframe which will receive the targets + usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"] + """ + # For RL, there are no direct targets to set. This is filler (neutral) + # until the agent sends an action. + dataframe["&-action"] = 0 + return dataframe +``` + +Most of the function remains the same as for typical Regressors, however, the function below shows how the strategy must pass the raw price data to the agent so that it has access to raw OHLCV in the training environment: + +```python + def feature_engineering_standard(self, dataframe: DataFrame, **kwargs) -> DataFrame: + # The following features are necessary for RL models + dataframe[f"%-raw_close"] = dataframe["close"] + dataframe[f"%-raw_open"] = dataframe["open"] + dataframe[f"%-raw_high"] = dataframe["high"] + dataframe[f"%-raw_low"] = dataframe["low"] + return dataframe +``` + +Finally, there is no explicit "label" to make - instead it is necessary to assign the `&-action` column which will contain the agent's actions when accessed in `populate_entry/exit_trends()`. In the present example, the neutral action to 0. This value should align with the environment used. FreqAI provides two environments, both use 0 as the neutral action. + +After users realize there are no labels to set, they will soon understand that the agent is making its "own" entry and exit decisions. This makes strategy construction rather simple. The entry and exit signals come from the agent in the form of an integer - which are used directly to decide entries and exits in the strategy: + +```python + def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame: + + enter_long_conditions = [df["do_predict"] == 1, df["&-action"] == 1] + + if enter_long_conditions: + df.loc[ + reduce(lambda x, y: x & y, enter_long_conditions), ["enter_long", "enter_tag"] + ] = (1, "long") + + enter_short_conditions = [df["do_predict"] == 1, df["&-action"] == 3] + + if enter_short_conditions: + df.loc[ + reduce(lambda x, y: x & y, enter_short_conditions), ["enter_short", "enter_tag"] + ] = (1, "short") + + return df + + def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame: + exit_long_conditions = [df["do_predict"] == 1, df["&-action"] == 2] + if exit_long_conditions: + df.loc[reduce(lambda x, y: x & y, exit_long_conditions), "exit_long"] = 1 + + exit_short_conditions = [df["do_predict"] == 1, df["&-action"] == 4] + if exit_short_conditions: + df.loc[reduce(lambda x, y: x & y, exit_short_conditions), "exit_short"] = 1 + + return df +``` + +It is important to consider that `&-action` depends on which environment they choose to use. The example above shows 5 actions, where 0 is neutral, 1 is enter long, 2 is exit long, 3 is enter short and 4 is exit short. + +## Configuring the Reinforcement Learner + +In order to configure the `Reinforcement Learner` the following dictionary must exist in the `freqai` config: + +```json + "rl_config": { + "train_cycles": 25, + "add_state_info": true, + "max_trade_duration_candles": 300, + "max_training_drawdown_pct": 0.02, + "cpu_count": 8, + "model_type": "PPO", + "policy_type": "MlpPolicy", + "model_reward_parameters": { + "rr": 1, + "profit_aim": 0.025 + } + } +``` + +Parameter details can be found [here](freqai-parameter-table.md), but in general the `train_cycles` decides how many times the agent should cycle through the candle data in its artificial environment to train weights in the model. `model_type` is a string which selects one of the available models in [stable_baselines](https://stable-baselines3.readthedocs.io/en/master/)(external link). + +!!! Note + If you would like to experiment with `continual_learning`, then you should set that value to `true` in the main `freqai` configuration dictionary. This will tell the Reinforcement Learning library to continue training new models from the final state of previous models, instead of retraining new models from scratch each time a retrain is initiated. + +!!! Note + Remember that the general `model_training_parameters` dictionary should contain all the model hyperparameter customizations for the particular `model_type`. For example, `PPO` parameters can be found [here](https://stable-baselines3.readthedocs.io/en/master/modules/ppo.html). + +## Creating a custom reward function + +!!! danger "Not for production" + Warning! + The reward function provided with the Freqtrade source code is a showcase of functionality designed to show/test as many possible environment control features as possible. It is also designed to run quickly on small computers. This is a benchmark, it is *not* for live production. Please beware that you will need to create your own custom_reward() function or use a template built by other users outside of the Freqtrade source code. + +As you begin to modify the strategy and the prediction model, you will quickly realize some important differences between the Reinforcement Learner and the Regressors/Classifiers. Firstly, the strategy does not set a target value (no labels!). Instead, you set the `calculate_reward()` function inside the `MyRLEnv` class (see below). A default `calculate_reward()` is provided inside `prediction_models/ReinforcementLearner.py` to demonstrate the necessary building blocks for creating rewards, but this is *not* designed for production. Users *must* create their own custom reinforcement learning model class or use a pre-built one from outside the Freqtrade source code and save it to `user_data/freqaimodels`. It is inside the `calculate_reward()` where creative theories about the market can be expressed. For example, you can reward your agent when it makes a winning trade, and penalize the agent when it makes a losing trade. Or perhaps, you wish to reward the agent for entering trades, and penalize the agent for sitting in trades too long. Below we show examples of how these rewards are all calculated: + +!!! note "Hint" + The best reward functions are ones that are continuously differentiable, and well scaled. In other words, adding a single large negative penalty to a rare event is not a good idea, and the neural net will not be able to learn that function. Instead, it is better to add a small negative penalty to a common event. This will help the agent learn faster. Not only this, but you can help improve the continuity of your rewards/penalties by having them scale with severity according to some linear/exponential functions. In other words, you'd slowly scale the penalty as the duration of the trade increases. This is better than a single large penalty occuring at a single point in time. + +```python +from freqtrade.freqai.prediction_models.ReinforcementLearner import ReinforcementLearner +from freqtrade.freqai.RL.Base5ActionRLEnv import Actions, Base5ActionRLEnv, Positions + + +class MyCoolRLModel(ReinforcementLearner): + """ + User created RL prediction model. + + Save this file to `freqtrade/user_data/freqaimodels` + + then use it with: + + freqtrade trade --freqaimodel MyCoolRLModel --config config.json --strategy SomeCoolStrat + + Here the users can override any of the functions + available in the `IFreqaiModel` inheritance tree. Most importantly for RL, this + is where the user overrides `MyRLEnv` (see below), to define custom + `calculate_reward()` function, or to override any other parts of the environment. + + This class also allows users to override any other part of the IFreqaiModel tree. + For example, the user can override `def fit()` or `def train()` or `def predict()` + to take fine-tuned control over these processes. + + Another common override may be `def data_cleaning_predict()` where the user can + take fine-tuned control over the data handling pipeline. + """ + class MyRLEnv(Base5ActionRLEnv): + """ + User made custom environment. This class inherits from BaseEnvironment and gym.Env. + Users can override any functions from those parent classes. Here is an example + of a user customized `calculate_reward()` function. + + Warning! + This is function is a showcase of functionality designed to show as many possible + environment control features as possible. It is also designed to run quickly + on small computers. This is a benchmark, it is *not* for live production. + """ + def calculate_reward(self, action: int) -> float: + # first, penalize if the action is not valid + if not self._is_valid(action): + return -2 + pnl = self.get_unrealized_profit() + + factor = 100 + + pair = self.pair.replace(':', '') + + # you can use feature values from dataframe + # Assumes the shifted RSI indicator has been generated in the strategy. + rsi_now = self.raw_features[f"%-rsi-period_10_shift-1_{pair}_" + f"{self.config['timeframe']}"].iloc[self._current_tick] + + # reward agent for entering trades + if (action in (Actions.Long_enter.value, Actions.Short_enter.value) + and self._position == Positions.Neutral): + if rsi_now < 40: + factor = 40 / rsi_now + else: + factor = 1 + return 25 * factor + + # discourage agent from not entering trades + if action == Actions.Neutral.value and self._position == Positions.Neutral: + return -1 + max_trade_duration = self.rl_config.get('max_trade_duration_candles', 300) + trade_duration = self._current_tick - self._last_trade_tick + if trade_duration <= max_trade_duration: + factor *= 1.5 + elif trade_duration > max_trade_duration: + factor *= 0.5 + # discourage sitting in position + if self._position in (Positions.Short, Positions.Long) and \ + action == Actions.Neutral.value: + return -1 * trade_duration / max_trade_duration + # close long + if action == Actions.Long_exit.value and self._position == Positions.Long: + if pnl > self.profit_aim * self.rr: + factor *= self.rl_config['model_reward_parameters'].get('win_reward_factor', 2) + return float(pnl * factor) + # close short + if action == Actions.Short_exit.value and self._position == Positions.Short: + if pnl > self.profit_aim * self.rr: + factor *= self.rl_config['model_reward_parameters'].get('win_reward_factor', 2) + return float(pnl * factor) + return 0. +``` + +## Using Tensorboard + +Reinforcement Learning models benefit from tracking training metrics. FreqAI has integrated Tensorboard to allow users to track training and evaluation performance across all coins and across all retrainings. Tensorboard is activated via the following command: + +```bash +tensorboard --logdir user_data/models/unique-id +``` + +where `unique-id` is the `identifier` set in the `freqai` configuration file. This command must be run in a separate shell to view the output in the browser at 127.0.0.1:6006 (6006 is the default port used by Tensorboard). + +![tensorboard](assets/tensorboard.jpg) + +## Custom logging + +FreqAI also provides a built in episodic summary logger called `self.tensorboard_log` for adding custom information to the Tensorboard log. By default, this function is already called once per step inside the environment to record the agent actions. All values accumulated for all steps in a single episode are reported at the conclusion of each episode, followed by a full reset of all metrics to 0 in preparation for the subsequent episode. + +`self.tensorboard_log` can also be used anywhere inside the environment, for example, it can be added to the `calculate_reward` function to collect more detailed information about how often various parts of the reward were called: + +```python + class MyRLEnv(Base5ActionRLEnv): + """ + User made custom environment. This class inherits from BaseEnvironment and gym.Env. + Users can override any functions from those parent classes. Here is an example + of a user customized `calculate_reward()` function. + """ + def calculate_reward(self, action: int) -> float: + if not self._is_valid(action): + self.tensorboard_log("invalid") + return -2 + +``` + +!!! Note + The `self.tensorboard_log()` function is designed for tracking incremented objects only i.e. events, actions inside the training environment. If the event of interest is a float, the float can be passed as the second argument e.g. `self.tensorboard_log("float_metric1", 0.23)`. In this case the metric values are not incremented. + +## Choosing a base environment + +FreqAI provides three base environments, `Base3ActionRLEnvironment`, `Base4ActionEnvironment` and `Base5ActionEnvironment`. As the names imply, the environments are customized for agents that can select from 3, 4 or 5 actions. The `Base3ActionEnvironment` is the simplest, the agent can select from hold, long, or short. This environment can also be used for long-only bots (it automatically follows the `can_short` flag from the strategy), where long is the enter condition and short is the exit condition. Meanwhile, in the `Base4ActionEnvironment`, the agent can enter long, enter short, hold neutral, or exit position. Finally, in the `Base5ActionEnvironment`, the agent has the same actions as Base4, but instead of a single exit action, it separates exit long and exit short. The main changes stemming from the environment selection include: + +* the actions available in the `calculate_reward` +* the actions consumed by the user strategy + +All of the FreqAI provided environments inherit from an action/position agnostic environment object called the `BaseEnvironment`, which contains all shared logic. The architecture is designed to be easily customized. The simplest customization is the `calculate_reward()` (see details [here](#creating-a-custom-reward-function)). However, the customizations can be further extended into any of the functions inside the environment. You can do this by simply overriding those functions inside your `MyRLEnv` in the prediction model file. Or for more advanced customizations, it is encouraged to create an entirely new environment inherited from `BaseEnvironment`. + +!!! Note + Only the `Base3ActionRLEnv` can do long-only training/trading (set the user strategy attribute `can_short = False`). diff --git a/docs/freqai-running.md b/docs/freqai-running.md new file mode 100644 index 000000000..553a8b698 --- /dev/null +++ b/docs/freqai-running.md @@ -0,0 +1,184 @@ +# Running FreqAI + +There are two ways to train and deploy an adaptive machine learning model - live deployment and historical backtesting. In both cases, FreqAI runs/simulates periodic retraining of models as shown in the following figure: + +![freqai-window](assets/freqai_moving-window.jpg) + +## Live deployments + +FreqAI can be run dry/live using the following command: + +```bash +freqtrade trade --strategy FreqaiExampleStrategy --config config_freqai.example.json --freqaimodel LightGBMRegressor +``` + +When launched, FreqAI will start training a new model, with a new `identifier`, based on the config settings. Following training, the model will be used to make predictions on incoming candles until a new model is available. New models are typically generated as often as possible, with FreqAI managing an internal queue of the coin pairs to try to keep all models equally up to date. FreqAI will always use the most recently trained model to make predictions on incoming live data. If you do not want FreqAI to retrain new models as often as possible, you can set `live_retrain_hours` to tell FreqAI to wait at least that number of hours before training a new model. Additionally, you can set `expired_hours` to tell FreqAI to avoid making predictions on models that are older than that number of hours. + +Trained models are by default saved to disk to allow for reuse during backtesting or after a crash. You can opt to [purge old models](#purging-old-model-data) to save disk space by setting `"purge_old_models": true` in the config. + +To start a dry/live run from a saved backtest model (or from a previously crashed dry/live session), you only need to specify the `identifier` of the specific model: + +```json + "freqai": { + "identifier": "example", + "live_retrain_hours": 0.5 + } +``` + +In this case, although FreqAI will initiate with a pre-trained model, it will still check to see how much time has elapsed since the model was trained. If a full `live_retrain_hours` has elapsed since the end of the loaded model, FreqAI will start training a new model. + +### Automatic data download + +FreqAI automatically downloads the proper amount of data needed to ensure training of a model through the defined `train_period_days` and `startup_candle_count` (see the [parameter table](freqai-parameter-table.md) for detailed descriptions of these parameters). + +### Saving prediction data + +All predictions made during the lifetime of a specific `identifier` model are stored in `historic_predictions.pkl` to allow for reloading after a crash or changes made to the config. + +### Purging old model data + +FreqAI stores new model files after each successful training. These files become obsolete as new models are generated to adapt to new market conditions. If you are planning to leave FreqAI running for extended periods of time with high frequency retraining, you should enable `purge_old_models` in the config: + +```json + "freqai": { + "purge_old_models": 4, + } +``` + +This will automatically purge all models older than the four most recently trained ones to save disk space. Inputing "0" will never purge any models. + +## Backtesting + +The FreqAI backtesting module can be executed with the following command: + +```bash +freqtrade backtesting --strategy FreqaiExampleStrategy --strategy-path freqtrade/templates --config config_examples/config_freqai.example.json --freqaimodel LightGBMRegressor --timerange 20210501-20210701 +``` + +If this command has never been executed with the existing config file, FreqAI will train a new model +for each pair, for each backtesting window within the expanded `--timerange`. + +Backtesting mode requires [downloading the necessary data](#downloading-data-to-cover-the-full-backtest-period) before deployment (unlike in dry/live mode where FreqAI handles the data downloading automatically). You should be careful to consider that the time range of the downloaded data is more than the backtesting time range. This is because FreqAI needs data prior to the desired backtesting time range in order to train a model to be ready to make predictions on the first candle of the set backtesting time range. More details on how to calculate the data to download can be found [here](#deciding-the-size-of-the-sliding-training-window-and-backtesting-duration). + +!!! Note "Model reuse" + Once the training is completed, you can execute the backtesting again with the same config file and + FreqAI will find the trained models and load them instead of spending time training. This is useful + if you want to tweak (or even hyperopt) buy and sell criteria inside the strategy. If you + *want* to retrain a new model with the same config file, you should simply change the `identifier`. + This way, you can return to using any model you wish by simply specifying the `identifier`. + +!!! Note + Backtesting calls `set_freqai_targets()` one time for each backtest window (where the number of windows is the full backtest timerange divided by the `backtest_period_days` parameter). Doing this means that the targets simulate dry/live behavior without look ahead bias. However, the definition of the features in `feature_engineering_*()` is performed once on the entire training timerange. This means that you should be sure that features do not look-ahead into the future. + More details about look-ahead bias can be found in [Common Mistakes](strategy-customization.md#common-mistakes-when-developing-strategies). + +--- + +### Saving prediction data + +To allow for tweaking your strategy (**not** the features!), FreqAI will automatically save the predictions during backtesting so that they can be reused for future backtests and live runs using the same `identifier` model. This provides a performance enhancement geared towards enabling **high-level hyperopting** of entry/exit criteria. + +An additional directory called `backtesting_predictions`, which contains all the predictions stored in `hdf` format, will be created in the `unique-id` folder. + +To change your **features**, you **must** set a new `identifier` in the config to signal to FreqAI to train new models. + +To save the models generated during a particular backtest so that you can start a live deployment from one of them instead of training a new model, you must set `save_backtest_models` to `True` in the config. + +### Backtest live collected predictions + +FreqAI allow you to reuse live historic predictions through the backtest parameter `--freqai-backtest-live-models`. This can be useful when you want to reuse predictions generated in dry/run for comparison or other study. + +The `--timerange` parameter must not be informed, as it will be automatically calculated through the data in the historic predictions file. + + +### Downloading data to cover the full backtest period + +For live/dry deployments, FreqAI will download the necessary data automatically. However, to use backtesting functionality, you need to download the necessary data using `download-data` (details [here](data-download.md#data-downloading)). You need to pay careful attention to understanding how much *additional* data needs to be downloaded to ensure that there is a sufficient amount of training data *before* the start of the backtesting time range. The amount of additional data can be roughly estimated by moving the start date of the time range backwards by `train_period_days` and the `startup_candle_count` (see the [parameter table](freqai-parameter-table.md) for detailed descriptions of these parameters) from the beginning of the desired backtesting time range. + +As an example, to backtest the `--timerange 20210501-20210701` using the [example config](freqai-configuration.md#setting-up-the-configuration-file) which sets `train_period_days` to 30, together with `startup_candle_count: 40` on a maximum `include_timeframes` of 1h, the start date for the downloaded data needs to be `20210501` - 30 days - 40 * 1h / 24 hours = 20210330 (31.7 days earlier than the start of the desired training time range). + +### Deciding the size of the sliding training window and backtesting duration + +The backtesting time range is defined with the typical `--timerange` parameter in the configuration file. The duration of the sliding training window is set by `train_period_days`, whilst `backtest_period_days` is the sliding backtesting window, both in number of days (`backtest_period_days` can be +a float to indicate sub-daily retraining in live/dry mode). In the presented [example config](freqai-configuration.md#setting-up-the-configuration-file) (found in `config_examples/config_freqai.example.json`), the user is asking FreqAI to use a training period of 30 days and backtest on the subsequent 7 days. After the training of the model, FreqAI will backtest the subsequent 7 days. The "sliding window" then moves one week forward (emulating FreqAI retraining once per week in live mode) and the new model uses the previous 30 days (including the 7 days used for backtesting by the previous model) to train. This is repeated until the end of `--timerange`. This means that if you set `--timerange 20210501-20210701`, FreqAI will have trained 8 separate models at the end of `--timerange` (because the full range comprises 8 weeks). + +!!! Note + Although fractional `backtest_period_days` is allowed, you should be aware that the `--timerange` is divided by this value to determine the number of models that FreqAI will need to train in order to backtest the full range. For example, by setting a `--timerange` of 10 days, and a `backtest_period_days` of 0.1, FreqAI will need to train 100 models per pair to complete the full backtest. Because of this, a true backtest of FreqAI adaptive training would take a *very* long time. The best way to fully test a model is to run it dry and let it train constantly. In this case, backtesting would take the exact same amount of time as a dry run. + +## Defining model expirations + +During dry/live mode, FreqAI trains each coin pair sequentially (on separate threads/GPU from the main Freqtrade bot). This means that there is always an age discrepancy between models. If you are training on 50 pairs, and each pair requires 5 minutes to train, the oldest model will be over 4 hours old. This may be undesirable if the characteristic time scale (the trade duration target) for a strategy is less than 4 hours. You can decide to only make trade entries if the model is less than a certain number of hours old by setting the `expiration_hours` in the config file: + +```json + "freqai": { + "expiration_hours": 0.5, + } +``` + +In the presented example config, the user will only allow predictions on models that are less than 1/2 hours old. + +## Controlling the model learning process + +Model training parameters are unique to the selected machine learning library. FreqAI allows you to set any parameter for any library using the `model_training_parameters` dictionary in the config. The example config (found in `config_examples/config_freqai.example.json`) shows some of the example parameters associated with `Catboost` and `LightGBM`, but you can add any parameters available in those libraries or any other machine learning library you choose to implement. + +Data split parameters are defined in `data_split_parameters` which can be any parameters associated with scikit-learn's `train_test_split()` function. `train_test_split()` has a parameters called `shuffle` which allows to shuffle the data or keep it unshuffled. This is particularly useful to avoid biasing training with temporally auto-correlated data. More details about these parameters can be found the [scikit-learn website](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html) (external website). + +The FreqAI specific parameter `label_period_candles` defines the offset (number of candles into the future) used for the `labels`. In the presented [example config](freqai-configuration.md#setting-up-the-configuration-file), the user is asking for `labels` that are 24 candles in the future. + +## Continual learning + +You can choose to adopt a continual learning scheme by setting `"continual_learning": true` in the config. By enabling `continual_learning`, after training an initial model from scratch, subsequent trainings will start from the final model state of the preceding training. This gives the new model a "memory" of the previous state. By default, this is set to `False` which means that all new models are trained from scratch, without input from previous models. + +???+ danger "Continual learning enforces a constant parameter space" + Since `continual_learning` means that the model parameter space *cannot* change between trainings, `principal_component_analysis` is automatically disabled when `continual_learning` is enabled. Hint: PCA changes the parameter space and the number of features, learn more about PCA [here](freqai-feature-engineering.md#data-dimensionality-reduction-with-principal-component-analysis). + +???+ danger "Experimental functionality" + Beware that this is currently a naive approach to incremental learning, and it has a high probability of overfitting/getting stuck in local minima while the market moves away from your model. We have the mechanics available in FreqAI primarily for experimental purposes and so that it is ready for more mature approaches to continual learning in chaotic systems like the crypto market. + +## Hyperopt + +You can hyperopt using the same command as for [typical Freqtrade hyperopt](hyperopt.md): + +```bash +freqtrade hyperopt --hyperopt-loss SharpeHyperOptLoss --strategy FreqaiExampleStrategy --freqaimodel LightGBMRegressor --strategy-path freqtrade/templates --config config_examples/config_freqai.example.json --timerange 20220428-20220507 +``` + +`hyperopt` requires you to have the data pre-downloaded in the same fashion as if you were doing [backtesting](#backtesting). In addition, you must consider some restrictions when trying to hyperopt FreqAI strategies: + +- The `--analyze-per-epoch` hyperopt parameter is not compatible with FreqAI. +- It's not possible to hyperopt indicators in the `feature_engineering_*()` and `set_freqai_targets()` functions. This means that you cannot optimize model parameters using hyperopt. Apart from this exception, it is possible to optimize all other [spaces](hyperopt.md#running-hyperopt-with-smaller-search-space). +- The backtesting instructions also apply to hyperopt. + +The best method for combining hyperopt and FreqAI is to focus on hyperopting entry/exit thresholds/criteria. You need to focus on hyperopting parameters that are not used in your features. For example, you should not try to hyperopt rolling window lengths in the feature creation, or any part of the FreqAI config which changes predictions. In order to efficiently hyperopt the FreqAI strategy, FreqAI stores predictions as dataframes and reuses them. Hence the requirement to hyperopt entry/exit thresholds/criteria only. + +A good example of a hyperoptable parameter in FreqAI is a threshold for the [Dissimilarity Index (DI)](freqai-feature-engineering.md#identifying-outliers-with-the-dissimilarity-index-di) `DI_values` beyond which we consider data points as outliers: + +```python +di_max = IntParameter(low=1, high=20, default=10, space='buy', optimize=True, load=True) +dataframe['outlier'] = np.where(dataframe['DI_values'] > self.di_max.value/10, 1, 0) +``` + +This specific hyperopt would help you understand the appropriate `DI_values` for your particular parameter space. + +## Using Tensorboard + +!!! note "Availability" + FreqAI includes tensorboard for a variety of models, including XGBoost, all PyTorch models, Reinforcement Learning, and Catboost. If you would like to see Tensorboard integrated into another model type, please open an issue on the [Freqtrade GitHub](https://github.com/freqtrade/freqtrade/issues) + +!!! danger "Requirements" + Tensorboard logging requires the FreqAI torch installation/docker image. + + +The easiest way to use tensorboard is to ensure `freqai.activate_tensorboard` is set to `True` (default setting) in your configuration file, run FreqAI, then open a separate shell and run: + +```bash +cd freqtrade +tensorboard --logdir user_data/models/unique-id +``` + +where `unique-id` is the `identifier` set in the `freqai` configuration file. This command must be run in a separate shell if you wish to view the output in your browser at 127.0.0.1:6060 (6060 is the default port used by Tensorboard). + +![tensorboard](assets/tensorboard.jpg) + + +!!! note "Deactivate for improved performance" + Tensorboard logging can slow down training and should be deactivated for production use. diff --git a/docs/freqai.md b/docs/freqai.md new file mode 100644 index 000000000..a81c9a81b --- /dev/null +++ b/docs/freqai.md @@ -0,0 +1,141 @@ +![freqai-logo](assets/freqai_doc_logo.svg) + +# FreqAI + +## Introduction + +FreqAI is a software designed to automate a variety of tasks associated with training a predictive machine learning model to generate market forecasts given a set of input signals. In general, FreqAI aims to be a sandbox for easily deploying robust machine learning libraries on real-time data ([details](#freqai-position-in-open-source-machine-learning-landscape)). + +!!! Note + FreqAI is, and always will be, a not-for-profit, open-source project. FreqAI does *not* have a crypto token, FreqAI does *not* sell signals, and FreqAI does not have a domain besides the present [freqtrade documentation](https://www.freqtrade.io/en/latest/freqai/). + +Features include: + +* **Self-adaptive retraining** - Retrain models during [live deployments](freqai-running.md#live-deployments) to self-adapt to the market in a supervised manner +* **Rapid feature engineering** - Create large rich [feature sets](freqai-feature-engineering.md#feature-engineering) (10k+ features) based on simple user-created strategies +* **High performance** - Threading allows for adaptive model retraining on a separate thread (or on GPU if available) from model inferencing (prediction) and bot trade operations. Newest models and data are kept in RAM for rapid inferencing +* **Realistic backtesting** - Emulate self-adaptive training on historic data with a [backtesting module](freqai-running.md#backtesting) that automates retraining +* **Extensibility** - The generalized and robust architecture allows for incorporating any [machine learning library/method](freqai-configuration.md#using-different-prediction-models) available in Python. Eight examples are currently available, including classifiers, regressors, and a convolutional neural network +* **Smart outlier removal** - Remove outliers from training and prediction data sets using a variety of [outlier detection techniques](freqai-feature-engineering.md#outlier-detection) +* **Crash resilience** - Store trained models to disk to make reloading from a crash fast and easy, and [purge obsolete files](freqai-running.md#purging-old-model-data) for sustained dry/live runs +* **Automatic data normalization** - [Normalize the data](freqai-feature-engineering.md#feature-normalization) in a smart and statistically safe way +* **Automatic data download** - Compute timeranges for data downloads and update historic data (in live deployments) +* **Cleaning of incoming data** - Handle NaNs safely before training and model inferencing +* **Dimensionality reduction** - Reduce the size of the training data via [Principal Component Analysis](freqai-feature-engineering.md#data-dimensionality-reduction-with-principal-component-analysis) +* **Deploying bot fleets** - Set one bot to train models while a fleet of [consumers](producer-consumer.md) use signals. + +## Quick start + +The easiest way to quickly test FreqAI is to run it in dry mode with the following command: + +```bash +freqtrade trade --config config_examples/config_freqai.example.json --strategy FreqaiExampleStrategy --freqaimodel LightGBMRegressor --strategy-path freqtrade/templates +``` + +You will see the boot-up process of automatic data downloading, followed by simultaneous training and trading. + +!!! danger "Not for production" + The example strategy provided with the Freqtrade source code is designed for showcasing/testing a wide variety of FreqAI features. It is also designed to run on small computers so that it can be used as a benchmark between developers and users. It is *not* designed to be run in production. + +An example strategy, prediction model, and config to use as a starting points can be found in +`freqtrade/templates/FreqaiExampleStrategy.py`, `freqtrade/freqai/prediction_models/LightGBMRegressor.py`, and +`config_examples/config_freqai.example.json`, respectively. + +## General approach + +You provide FreqAI with a set of custom *base indicators* (the same way as in a [typical Freqtrade strategy](strategy-customization.md)) as well as target values (*labels*). For each pair in the whitelist, FreqAI trains a model to predict the target values based on the input of custom indicators. The models are then consistently retrained, with a predetermined frequency, to adapt to market conditions. FreqAI offers the ability to both backtest strategies (emulating reality with periodic retraining on historic data) and deploy dry/live runs. In dry/live conditions, FreqAI can be set to constant retraining in a background thread to keep models as up to date as possible. + +An overview of the algorithm, explaining the data processing pipeline and model usage, is shown below. + +![freqai-algo](assets/freqai_algo.jpg) + +### Important machine learning vocabulary + +**Features** - the parameters, based on historic data, on which a model is trained. All features for a single candle are stored as a vector. In FreqAI, you build a feature data set from anything you can construct in the strategy. + +**Labels** - the target values that the model is trained toward. Each feature vector is associated with a single label that is defined by you within the strategy. These labels intentionally look into the future and are what you are training the model to be able to predict. + +**Training** - the process of "teaching" the model to match the feature sets to the associated labels. Different types of models "learn" in different ways which means that one might be better than another for a specific application. More information about the different models that are already implemented in FreqAI can be found [here](freqai-configuration.md#using-different-prediction-models). + +**Train data** - a subset of the feature data set that is fed to the model during training to "teach" the model how to predict the targets. This data directly influences weight connections in the model. + +**Test data** - a subset of the feature data set that is used to evaluate the performance of the model after training. This data does not influence nodal weights within the model. + +**Inferencing** - the process of feeding a trained model new unseen data on which it will make a prediction. + +## Install prerequisites + +The normal Freqtrade install process will ask if you wish to install FreqAI dependencies. You should reply "yes" to this question if you wish to use FreqAI. If you did not reply yes, you can manually install these dependencies after the install with: + +``` bash +pip install -r requirements-freqai.txt +``` + +!!! Note + Catboost will not be installed on low-powered arm devices (raspberry), since it does not provide wheels for this platform. + +### Usage with docker + +If you are using docker, a dedicated tag with FreqAI dependencies is available as `:freqai`. As such - you can replace the image line in your docker compose file with `image: freqtradeorg/freqtrade:develop_freqai`. This image contains the regular FreqAI dependencies. Similar to native installs, Catboost will not be available on ARM based devices. If you would like to use PyTorch or Reinforcement learning, you should use the torch or RL tags, `image: freqtradeorg/freqtrade:develop_freqaitorch`, `image: freqtradeorg/freqtrade:develop_freqairl`. + +!!! note "docker-compose-freqai.yml" + We do provide an explicit docker-compose file for this in `docker/docker-compose-freqai.yml` - which can be used via `docker compose -f docker/docker-compose-freqai.yml run ...` - or can be copied to replace the original docker file. This docker-compose file also contains a (disabled) section to enable GPU resources within docker containers. This obviously assumes the system has GPU resources available. + +### FreqAI position in open-source machine learning landscape + +Forecasting chaotic time-series based systems, such as equity/cryptocurrency markets, requires a broad set of tools geared toward testing a wide range of hypotheses. Fortunately, a recent maturation of robust machine learning libraries (e.g. `scikit-learn`) has opened up a wide range of research possibilities. Scientists from a diverse range of fields can now easily prototype their studies on an abundance of established machine learning algorithms. Similarly, these user-friendly libraries enable "citzen scientists" to use their basic Python skills for data exploration. However, leveraging these machine learning libraries on historical and live chaotic data sources can be logistically difficult and expensive. Additionally, robust data collection, storage, and handling presents a disparate challenge. [`FreqAI`](#freqai) aims to provide a generalized and extensible open-sourced framework geared toward live deployments of adaptive modeling for market forecasting. The `FreqAI` framework is effectively a sandbox for the rich world of open-source machine learning libraries. Inside the `FreqAI` sandbox, users find they can combine a wide variety of third-party libraries to test creative hypotheses on a free live 24/7 chaotic data source - cryptocurrency exchange data. + +### Citing FreqAI + +FreqAI is [published in the Journal of Open Source Software](https://joss.theoj.org/papers/10.21105/joss.04864). If you find FreqAI useful in your research, please use the following citation: + +```bibtex +@article{Caulk2022, + doi = {10.21105/joss.04864}, + url = {https://doi.org/10.21105/joss.04864}, + year = {2022}, publisher = {The Open Journal}, + volume = {7}, number = {80}, pages = {4864}, + author = {Robert A. Caulk and Elin Törnquist and Matthias Voppichler and Andrew R. Lawless and Ryan McMullan and Wagner Costa Santos and Timothy C. Pogue and Johan van der Vlugt and Stefan P. Gehring and Pascal Schmidt}, + title = {FreqAI: generalizing adaptive modeling for chaotic time-series market forecasts}, + journal = {Journal of Open Source Software} } +``` + +## Common pitfalls + +FreqAI cannot be combined with dynamic `VolumePairlists` (or any pairlist filter that adds and removes pairs dynamically). +This is for performance reasons - FreqAI relies on making quick predictions/retrains. To do this effectively, +it needs to download all the training data at the beginning of a dry/live instance. FreqAI stores and appends +new candles automatically for future retrains. This means that if new pairs arrive later in the dry run due to a volume pairlist, it will not have the data ready. However, FreqAI does work with the `ShufflePairlist` or a `VolumePairlist` which keeps the total pairlist constant (but reorders the pairs according to volume). + +## Additional learning materials + +Here we compile some external materials that provide deeper looks into various components of FreqAI: + +- [Real-time head-to-head: Adaptive modeling of financial market data using XGBoost and CatBoost](https://emergentmethods.medium.com/real-time-head-to-head-adaptive-modeling-of-financial-market-data-using-xgboost-and-catboost-995a115a7495) +- [FreqAI - from price to prediction](https://emergentmethods.medium.com/freqai-from-price-to-prediction-6fadac18b665) + + +## Support + +You can find support for FreqAI in a variety of places, including the [Freqtrade discord](https://discord.gg/Jd8JYeWHc4), the dedicated [FreqAI discord](https://discord.gg/7AMWACmbjT), and in [github issues](https://github.com/freqtrade/freqtrade/issues). + +## Credits + +FreqAI is developed by a group of individuals who all contribute specific skillsets to the project. + +Conception and software development: +Robert Caulk @robcaulk + +Theoretical brainstorming and data analysis: +Elin Törnquist @th0rntwig + +Code review and software architecture brainstorming: +@xmatthias + +Software development: +Wagner Costa @wagnercosta +Emre Suzen @aemr3 +Timothy Pogue @wizrds + +Beta testing and bug reporting: +Stefan Gehring @bloodhunter4rc, @longyu, Andrew Lawless @paranoidandy, Pascal Schmidt @smidelis, Ryan McMullan @smarmau, Juha Nykänen @suikula, Johan van der Vlugt @jooopiert, Richárd Józsa @richardjosza diff --git a/docs/hyperopt.md b/docs/hyperopt.md index c9ec30056..d3371d771 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -31,7 +31,7 @@ The docker-image includes hyperopt dependencies, no further action needed. ### Easy installation script (setup.sh) / Manual installation ```bash -source .env/bin/activate +source .venv/bin/activate pip install -r requirements-hyperopt.txt ``` @@ -40,7 +40,8 @@ pip install -r requirements-hyperopt.txt ``` usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-s NAME] [--strategy-path PATH] - [--recursive-strategy-search] [-i TIMEFRAME] + [--recursive-strategy-search] [--freqaimodel NAME] + [--freqaimodel-path PATH] [-i TIMEFRAME] [--timerange TIMERANGE] [--data-format-ohlcv {json,jsongz,hdf5}] [--max-open-trades INT] @@ -49,11 +50,11 @@ usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--eps] [--dmmp] [--enable-protections] [--dry-run-wallet DRY_RUN_WALLET] [--timeframe-detail TIMEFRAME_DETAIL] [-e INT] - [--spaces {all,buy,sell,roi,stoploss,trailing,protection,default} [{all,buy,sell,roi,stoploss,trailing,protection,default} ...]] + [--spaces {all,buy,sell,roi,stoploss,trailing,protection,trades,default} [{all,buy,sell,roi,stoploss,trailing,protection,trades,default} ...]] [--print-all] [--no-color] [--print-json] [-j JOBS] [--random-state INT] [--min-trades INT] [--hyperopt-loss NAME] [--disable-param-export] - [--ignore-missing-spaces] + [--ignore-missing-spaces] [--analyze-per-epoch] optional arguments: -h, --help show this help message and exit @@ -95,7 +96,7 @@ optional arguments: Specify detail timeframe for backtesting (`1m`, `5m`, `30m`, `1h`, `1d`). -e INT, --epochs INT Specify number of epochs (default: 100). - --spaces {all,buy,sell,roi,stoploss,trailing,protection,default} [{all,buy,sell,roi,stoploss,trailing,protection,default} ...] + --spaces {all,buy,sell,roi,stoploss,trailing,protection,trades,default} [{all,buy,sell,roi,stoploss,trailing,protection,trades,default} ...] Specify which parameters to hyperopt. Space-separated list. --print-all Print all results, not only the best ones. @@ -129,6 +130,7 @@ optional arguments: --ignore-missing-spaces, --ignore-unparameterized-spaces Suppress errors for any requested Hyperopt spaces that do not contain any parameters. + --analyze-per-epoch Run populate_indicators once per epoch. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). @@ -154,6 +156,10 @@ Strategy arguments: --recursive-strategy-search Recursively search for a strategy in the strategies folder. + --freqaimodel NAME Specify a custom freqaimodels. + --freqaimodel-path PATH + Specify additional lookup path for freqaimodels. + ``` ### Hyperopt checklist @@ -174,6 +180,7 @@ Rarely you may also need to create a [nested class](advanced-hyperopt.md#overrid * `generate_roi_table` - for custom ROI optimization (if you need the ranges for the values in the ROI table that differ from default or the number of entries (steps) in the ROI table which differs from the default 4 steps) * `stoploss_space` - for custom stoploss optimization (if you need the range for the stoploss parameter in the optimization hyperspace that differs from default) * `trailing_space` - for custom trailing stop optimization (if you need the ranges for the trailing stop parameters in the optimization hyperspace that differ from default) +* `max_open_trades_space` - for custom max_open_trades optimization (if you need the ranges for the max_open_trades parameter in the optimization hyperspace that differ from default) !!! Tip "Quickly optimize ROI, stoploss and trailing stoploss" You can quickly optimize the spaces `roi`, `stoploss` and `trailing` without changing anything in your strategy. @@ -185,7 +192,7 @@ Rarely you may also need to create a [nested class](advanced-hyperopt.md#overrid ### Hyperopt execution logic -Hyperopt will first load your data into memory and will then run `populate_indicators()` once per Pair to generate all indicators. +Hyperopt will first load your data into memory and will then run `populate_indicators()` once per Pair to generate all indicators, unless `--analyze-per-epoch` is specified. Hyperopt will then spawn into different processes (number of processors, or `-j `), and run backtesting over and over again, changing the parameters that are part of the `--spaces` defined. @@ -330,11 +337,15 @@ There are four parameter types each suited for different purposes. * `CategoricalParameter` - defines a parameter with a predetermined number of choices. * `BooleanParameter` - Shorthand for `CategoricalParameter([True, False])` - great for "enable" parameters. -!!! Tip "Disabling parameter optimization" - Each parameter takes two boolean parameters: - * `load` - when set to `False` it will not load values configured in `buy_params` and `sell_params`. - * `optimize` - when set to `False` parameter will not be included in optimization process. - Use these parameters to quickly prototype various ideas. +### Parameter options + +There are two parameter options that can help you to quickly test various ideas: + +* `optimize` - when set to `False`, the parameter will not be included in optimization process. (Default: True) +* `load` - when set to `False`, results of a previous hyperopt run (in `buy_params` and `sell_params` either in your strategy or the JSON output file) will not be used as the starting value for subsequent hyperopts. The default value specified in the parameter will be used instead. (Default: True) + +!!! Tip "Effects of `load=False` on backtesting" + Be aware that setting the `load` option to `False` will mean backtesting will also use the default value specified in the parameter and *not* the value found through hyperoptimisation. !!! Warning Hyperoptable parameters cannot be used in `populate_indicators` - as hyperopt does not recalculate indicators for each epoch, so the starting value would be used in this case. @@ -359,7 +370,7 @@ class MyAwesomeStrategy(IStrategy): timeframe = '15m' minimal_roi = { "0": 0.10 - }, + } # Define the parameter spaces buy_ema_short = IntParameter(3, 50, default=5) buy_ema_long = IntParameter(15, 200, default=50) @@ -394,7 +405,7 @@ class MyAwesomeStrategy(IStrategy): return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - conditions = [] + conditions = [] conditions.append(qtpylib.crossed_above( dataframe[f'ema_long_{self.buy_ema_long.value}'], dataframe[f'ema_short_{self.buy_ema_short.value}'] )) @@ -426,9 +437,15 @@ While this strategy is most likely too simple to provide consistent profit, it s `range` property may also be used with `DecimalParameter` and `CategoricalParameter`. `RealParameter` does not provide this property due to infinite search space. ??? Hint "Performance tip" - By doing the calculation of all possible indicators in `populate_indicators()`, the calculation of the indicator happens only once for every parameter. - While this may slow down the hyperopt startup speed, the overall performance will increase as the Hyperopt execution itself may pick the same value for multiple epochs (changing other values). - You should however try to use space ranges as small as possible. Every new column will require more memory, and every possibility hyperopt can try will increase the search space. + During normal hyperopting, indicators are calculated once and supplied to each epoch, linearly increasing RAM usage as a factor of increasing cores. As this also has performance implications, there are two alternatives to reduce RAM usage + + * Move `ema_short` and `ema_long` calculations from `populate_indicators()` to `populate_entry_trend()`. Since `populate_entry_trend()` will be calculated every epoch, you don't need to use `.range` functionality. + * hyperopt provides `--analyze-per-epoch` which will move the execution of `populate_indicators()` to the epoch process, calculating a single value per parameter per epoch instead of using the `.range` functionality. In this case, `.range` functionality will only return the actually used value. + + These alternatives will reduce RAM usage, but increase CPU usage. However, your hyperopting run will be less likely to fail due to Out Of Memory (OOM) issues. + + Whether you are using `.range` functionality or the alternatives above, you should try to use space ranges as small as possible since this will improve CPU/RAM usage. + ## Optimizing protections @@ -636,6 +653,7 @@ Legal values are: * `roi`: just optimize the minimal profit table for your strategy * `stoploss`: search for the best stoploss value * `trailing`: search for the best trailing stop values +* `trades`: search for the best max open trades values * `protection`: search for the best protection parameters (read the [protections section](#optimizing-protections) on how to properly define these) * `default`: `all` except `trailing` and `protection` * space-separated list of any of the above values for example `--spaces roi stoploss` @@ -879,6 +897,7 @@ To combat these, you have multiple options: * Avoid using `--timeframe-detail` (this loads a lot of additional data into memory). * Reduce the number of parallel processes (`-j `). * Increase the memory of your machine. +* Use `--analyze-per-epoch` if you're using a lot of parameters with `.range` functionality. ## The objective has been evaluated at this point before. @@ -907,6 +926,12 @@ Once the optimized strategy has been implemented into your strategy, you should To achieve same the results (number of trades, their durations, profit, etc.) as during Hyperopt, please use the same configuration and parameters (timerange, timeframe, ...) used for hyperopt `--dmmp`/`--disable-max-market-positions` and `--eps`/`--enable-position-stacking` for Backtesting. -Should results not match, please double-check to make sure you transferred all conditions correctly. -Pay special care to the stoploss (and trailing stoploss) parameters, as these are often set in configuration files, which override changes to the strategy. -You should also carefully review the log of your backtest to ensure that there were no parameters inadvertently set by the configuration (like `stoploss` or `trailing_stop`). +### Why do my backtest results not match my hyperopt results? +Should results not match, check the following factors: + +* You may have added parameters to hyperopt in `populate_indicators()` where they will be calculated only once **for all epochs**. If you are, for example, trying to optimise multiple SMA timeperiod values, the hyperoptable timeperiod parameter should be placed in `populate_entry_trend()` which is calculated every epoch. See [Optimizing an indicator parameter](https://www.freqtrade.io/en/stable/hyperopt/#optimizing-an-indicator-parameter). +* If you have disabled the auto-export of hyperopt parameters into the JSON parameters file, double-check to make sure you transferred all hyperopted values into your strategy correctly. +* Check the logs to verify what parameters are being set and what values are being used. +* Pay special care to the stoploss, max_open_trades and trailing stoploss parameters, as these are often set in configuration files, which override changes to the strategy. Check the logs of your backtest to ensure that there were no parameters inadvertently set by the configuration (like `stoploss`, `max_open_trades` or `trailing_stop`). +* Verify that you do not have an unexpected parameters JSON file overriding the parameters or the default hyperopt settings in your strategy. +* Verify that any protections that are enabled in backtesting are also enabled when hyperopting, and vice versa. When using `--space protection`, protections are auto-enabled for hyperopting. diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index 0f55c1b79..9781edf10 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -6,7 +6,7 @@ In your configuration, you can use Static Pairlist (defined by the [`StaticPairL Additionally, [`AgeFilter`](#agefilter), [`PrecisionFilter`](#precisionfilter), [`PriceFilter`](#pricefilter), [`ShuffleFilter`](#shufflefilter), [`SpreadFilter`](#spreadfilter) and [`VolatilityFilter`](#volatilityfilter) act as Pairlist Filters, removing certain pairs and/or moving their positions in the pairlist. -If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading and backtesting. Pairlist Handlers are executed in the sequence they are configured. You should always configure either `StaticPairList` or `VolumePairList` as the starting Pairlist Handler. +If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading and backtesting. Pairlist Handlers are executed in the sequence they are configured. You can define either `StaticPairList`, `VolumePairList`, `ProducerPairList`, `RemotePairList` or `MarketCapPairList` as the starting Pairlist Handler. Inactive markets are always removed from the resulting pairlist. Explicitly blacklisted pairs (those in the `pair_blacklist` configuration setting) are also always removed from the resulting pairlist. @@ -22,7 +22,11 @@ You may also use something like `.*DOWN/BTC` or `.*UP/BTC` to exclude leveraged * [`StaticPairList`](#static-pair-list) (default, if not configured differently) * [`VolumePairList`](#volume-pair-list) +* [`ProducerPairList`](#producerpairlist) +* [`RemotePairList`](#remotepairlist) +* [`MarketCapPairList`](#marketcappairlist) * [`AgeFilter`](#agefilter) +* [`FullTradesFilter`](#fulltradesfilter) * [`OffsetFilter`](#offsetfilter) * [`PerformanceFilter`](#performancefilter) * [`PrecisionFilter`](#precisionfilter) @@ -84,7 +88,7 @@ Filtering instances (not the first position in the list) will not apply any cach You can define a minimum volume with `min_value` - which will filter out pairs with a volume lower than the specified value in the specified timerange. -### VolumePairList Advanced mode +##### VolumePairList Advanced mode `VolumePairList` can also operate in an advanced mode to build volume over a given timerange of specified candle size. It utilizes exchange historical candle data, builds a typical price (calculated by (open+high+low)/3) and multiplies the typical price with every candle's volume. The sum is the `quoteVolume` over the given range. This allows different scenarios, for a more smoothened volume, when using longer ranges with larger candle sizes, or the opposite when using a short range with small candles. @@ -109,8 +113,8 @@ For convenience `lookback_days` can be specified, which will imply that 1d candl !!! Warning "Performance implications when using lookback range" If used in first position in combination with lookback, the computation of the range based volume can be time and resource consuming, as it downloads candles for all tradable pairs. Hence it's highly advised to use the standard approach with `VolumeFilter` to narrow the pairlist down for further range volume calculation. -??? Tip "Unsupported exchanges (Bittrex, Gemini)" - On some exchanges (like Bittrex and Gemini), regular VolumePairList does not work as the api does not natively provide 24h volume. This can be worked around by using candle data to build the volume. +??? Tip "Unsupported exchanges" + On some exchanges (like Gemini), regular VolumePairList does not work as the api does not natively provide 24h volume. This can be worked around by using candle data to build the volume. To roughly simulate 24h volume, you can use the following configuration. Please note that These pairlists will only refresh once per day. @@ -146,6 +150,140 @@ More sophisticated approach can be used, by using `lookback_timeframe` for candl !!! Note `VolumePairList` does not support backtesting mode. +#### ProducerPairList + +With `ProducerPairList`, you can reuse the pairlist from a [Producer](producer-consumer.md) without explicitly defining the pairlist on each consumer. + +[Consumer mode](producer-consumer.md) is required for this pairlist to work. + +The pairlist will perform a check on active pairs against the current exchange configuration to avoid attempting to trade on invalid markets. + +You can limit the length of the pairlist with the optional parameter `number_assets`. Using `"number_assets"=0` or omitting this key will result in the reuse of all producer pairs valid for the current setup. + +```json +"pairlists": [ + { + "method": "ProducerPairList", + "number_assets": 5, + "producer_name": "default", + } +], +``` + + +!!! Tip "Combining pairlists" + This pairlist can be combined with all other pairlists and filters for further pairlist reduction, and can also act as an "additional" pairlist, on top of already defined pairs. + `ProducerPairList` can also be used multiple times in sequence, combining the pairs from multiple producers. + Obviously in complex such configurations, the Producer may not provide data for all pairs, so the strategy must be fit for this. + +#### RemotePairList + +It allows the user to fetch a pairlist from a remote server or a locally stored json file within the freqtrade directory, enabling dynamic updates and customization of the trading pairlist. + +The RemotePairList is defined in the pairlists section of the configuration settings. It uses the following configuration options: + +```json +"pairlists": [ + { + "method": "RemotePairList", + "mode": "whitelist", + "processing_mode": "filter", + "pairlist_url": "https://example.com/pairlist", + "number_assets": 10, + "refresh_period": 1800, + "keep_pairlist_on_failure": true, + "read_timeout": 60, + "bearer_token": "my-bearer-token", + "save_to_file": "user_data/filename.json" + } +] +``` + +The optional `mode` option specifies if the pairlist should be used as a `blacklist` or as a `whitelist`. The default value is "whitelist". + +The optional `processing_mode` option in the RemotePairList configuration determines how the retrieved pairlist is processed. It can have two values: "filter" or "append". + +In "filter" mode, the retrieved pairlist is used as a filter. Only the pairs present in both the original pairlist and the retrieved pairlist are included in the final pairlist. Other pairs are filtered out. + +In "append" mode, the retrieved pairlist is added to the original pairlist. All pairs from both lists are included in the final pairlist without any filtering. + +The `pairlist_url` option specifies the URL of the remote server where the pairlist is located, or the path to a local file (if file:/// is prepended). This allows the user to use either a remote server or a local file as the source for the pairlist. + +The `save_to_file` option, when provided with a valid filename, saves the processed pairlist to that file in JSON format. This option is optional, and by default, the pairlist is not saved to a file. + +??? Example "Multi bot with shared pairlist example" + + `save_to_file` can be used to save the pairlist to a file with Bot1: + + ```json + "pairlists": [ + { + "method": "RemotePairList", + "mode": "whitelist", + "pairlist_url": "https://example.com/pairlist", + "number_assets": 10, + "refresh_period": 1800, + "keep_pairlist_on_failure": true, + "read_timeout": 60, + "save_to_file": "user_data/filename.json" + } + ] + ``` + + This saved pairlist file can be loaded by Bot2, or any additional bot with this configuration: + + ```json + "pairlists": [ + { + "method": "RemotePairList", + "mode": "whitelist", + "pairlist_url": "file:///user_data/filename.json", + "number_assets": 10, + "refresh_period": 10, + "keep_pairlist_on_failure": true, + } + ] + ``` + +The user is responsible for providing a server or local file that returns a JSON object with the following structure: + +```json +{ + "pairs": ["XRP/USDT", "ETH/USDT", "LTC/USDT"], + "refresh_period": 1800 +} +``` + +The `pairs` property should contain a list of strings with the trading pairs to be used by the bot. The `refresh_period` property is optional and specifies the number of seconds that the pairlist should be cached before being refreshed. + +The optional `keep_pairlist_on_failure` specifies whether the previous received pairlist should be used if the remote server is not reachable or returns an error. The default value is true. + +The optional `read_timeout` specifies the maximum amount of time (in seconds) to wait for a response from the remote source, The default value is 60. + +The optional `bearer_token` will be included in the requests Authorization Header. + +!!! Note + In case of a server error the last received pairlist will be kept if `keep_pairlist_on_failure` is set to true, when set to false a empty pairlist is returned. + +#### MarketCapPairList + +`MarketCapPairList` employs sorting/filtering of pairs by their marketcap rank based of CoinGecko. It will only recognize coins up to the coin placed at rank 250. The returned pairlist will be sorted based of their marketcap ranks. + +```json +"pairlists": [ + { + "method": "MarketCapPairList", + "number_assets": 20, + "max_rank": 50, + "refresh_period": 86400 + } +] +``` + +`number_assets` defines the maximum number of pairs returned by the pairlist. `max_rank` will determine the maximum rank used in creating/filtering the pairlist. It's expected that some coins within the top `max_rank` marketcap will not be included in the resulting pairlist since not all pairs will have active trading pairs in your preferred market/stake/exchange combination. + +`refresh_period` setting defines the period (in seconds) at which the marketcap rank data will be refreshed. Defaults to 86,400s (1 day). The pairlist cache (`refresh_period`) is applicable on both generating pairlists (first position in the list) and filtering instances (not the first position in the list). + #### AgeFilter Removes pairs that have been listed on the exchange for less than `min_days_listed` days (defaults to `10`) or more than `max_days_listed` days (defaults `None` mean infinity). @@ -156,6 +294,17 @@ be caught out buying before the pair has finished dropping in price. This filter allows freqtrade to ignore pairs until they have been listed for at least `min_days_listed` days and listed before `max_days_listed`. +#### FullTradesFilter + +Shrink whitelist to consist only in-trade pairs when the trade slots are full (when `max_open_trades` isn't being set to `-1` in the config). + +When the trade slots are full, there is no need to calculate indicators of the rest of the pairs (except informative pairs) since no new trade can be opened. By shrinking the whitelist to just the in-trade pairs, you can improve calculation speeds and reduce CPU usage. When a trade slot is free (either a trade is closed or `max_open_trades` value in config is increased), then the whitelist will return to normal state. + +When multiple pairlist filters are being used, it's recommended to put this filter at second position directly below the primary pairlist, so when the trade slots are full, the bot doesn't have to download data for the rest of the filters. + +!!! Warning "Backtesting" + `FullTradesFilter` does not support backtesting mode. + #### OffsetFilter Offsets an incoming pairlist by a given `offset` value. @@ -241,7 +390,7 @@ This option is disabled by default, and will only apply if set to > 0. The `max_value` setting removes pairs where the minimum value change is above a specified value. This is useful when an exchange has unbalanced limits. For example, if step-size = 1 (so you can only buy 1, or 2, or 3, but not 1.1 Coins) - and the price is pretty high (like 20\$) as the coin has risen sharply since the last limit adaption. As a result of the above, you can only buy for 20\$, or 40\$ - but not for 25\$. -On exchanges that deduct fees from the receiving currency (e.g. FTX) - this can result in high value coins / amounts that are unsellable as the amount is slightly below the limit. +On exchanges that deduct fees from the receiving currency (e.g. binance) - this can result in high value coins / amounts that are unsellable as the amount is slightly below the limit. The `low_price_ratio` setting removes pairs where a raise of 1 price unit (pip) is above the `low_price_ratio` ratio. This option is disabled by default, and will only apply if set to > 0. @@ -259,6 +408,18 @@ Min price precision for SHITCOIN/BTC is 8 decimals. If its price is 0.00000011 - Shuffles (randomizes) pairs in the pairlist. It can be used for preventing the bot from trading some of the pairs more frequently then others when you want all pairs be treated with the same priority. +By default, ShuffleFilter will shuffle pairs once per candle. +To shuffle on every iteration, set `"shuffle_frequency"` to `"iteration"` instead of the default of `"candle"`. + +``` json + { + "method": "ShuffleFilter", + "shuffle_frequency": "candle", + "seed": 42 + } + +``` + !!! Tip You may set the `seed` value for this Pairlist to obtain reproducible results, which can be useful for repeated backtesting sessions. If `seed` is not set, the pairs are shuffled in the non-repeatable random order. ShuffleFilter will automatically detect runmodes and apply the `seed` only for backtesting modes - if a `seed` value is set. @@ -284,7 +445,7 @@ If the trading range over the last 10 days is <1% or >99%, remove the pair from "lookback_days": 10, "min_rate_of_change": 0.01, "max_rate_of_change": 0.99, - "refresh_period": 1440 + "refresh_period": 86400 } ] ``` @@ -339,7 +500,7 @@ The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets, "method": "RangeStabilityFilter", "lookback_days": 10, "min_rate_of_change": 0.01, - "refresh_period": 1440 + "refresh_period": 86400 }, { "method": "VolatilityFilter", diff --git a/docs/includes/protections.md b/docs/includes/protections.md index e0ad8189f..12af081c0 100644 --- a/docs/includes/protections.md +++ b/docs/includes/protections.md @@ -149,7 +149,7 @@ The below example assumes a timeframe of 1 hour: * Locks each pair after selling for an additional 5 candles (`CooldownPeriod`), giving other pairs a chance to get filled. * Stops trading for 4 hours (`4 * 1h candles`) if the last 2 days (`48 * 1h candles`) had 20 trades, which caused a max-drawdown of more than 20%. (`MaxDrawdown`). * Stops trading if more than 4 stoploss occur for all pairs within a 1 day (`24 * 1h candles`) limit (`StoplossGuard`). -* Locks all pairs that had 4 Trades within the last 6 hours (`6 * 1h candles`) with a combined profit ratio of below 0.02 (<2%) (`LowProfitPairs`). +* Locks all pairs that had 2 Trades within the last 6 hours (`6 * 1h candles`) with a combined profit ratio of below 0.02 (<2%) (`LowProfitPairs`). * Locks all pairs for 2 candles that had a profit of below 0.01 (<1%) within the last 24h (`24 * 1h candles`), a minimum of 4 trades. ``` python diff --git a/docs/includes/release_template.md b/docs/includes/release_template.md new file mode 100644 index 000000000..87a3564da --- /dev/null +++ b/docs/includes/release_template.md @@ -0,0 +1,37 @@ +## Highlighted changes + +- ... + +### How to update + +As always, you can update your bot using one of the following commands: + +#### docker-compose + +```bash +docker-compose pull +docker-compose up -d +``` + +#### Installation via setup script + +``` +# Deactivate venv and run +./setup.sh --update +``` + +#### Plain native installation + +``` +git pull +pip install -U -r requirements.txt +``` + +
+Expand full changelog + +``` + +``` + +
diff --git a/docs/includes/showcase.md b/docs/includes/showcase.md new file mode 100644 index 000000000..766703b9f --- /dev/null +++ b/docs/includes/showcase.md @@ -0,0 +1,11 @@ +This section will highlight a few projects from members of the community. +!!! Note + The projects below are for the most part not maintained by the freqtrade , therefore use your own caution before using them. + +- [Example freqtrade strategies](https://github.com/freqtrade/freqtrade-strategies/) +- [FrequentHippo - Grafana dashboard with dry/live runs and backtests](http://frequenthippo.ddns.net:3000/) (by hippocritical). +- [Online pairlist generator](https://remotepairlist.com/) (by Blood4rc). +- [Freqtrade Backtesting Project](https://strat.ninja/) (by Blood4rc). +- [Freqtrade analysis notebook](https://github.com/froggleston/freqtrade_analysis_notebook) (by Froggleston). +- [TUI for freqtrade](https://github.com/froggleston/freqtrade-frogtrade9000) (by Froggleston). +- [Bot Academy](https://botacademy.ddns.net/) (by stash86) - Blog about crypto bot projects. diff --git a/docs/index.md b/docs/index.md index 7c35e92b6..26debe993 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,6 +1,7 @@ ![freqtrade](assets/freqtrade_poweredby.svg) [![Freqtrade CI](https://github.com/freqtrade/freqtrade/workflows/Freqtrade%20CI/badge.svg)](https://github.com/freqtrade/freqtrade/actions/) +[![DOI](https://joss.theoj.org/papers/10.21105/joss.04864/status.svg)](https://doi.org/10.21105/joss.04864) [![Coverage Status](https://coveralls.io/repos/github/freqtrade/freqtrade/badge.svg?branch=develop&service=github)](https://coveralls.io/github/freqtrade/freqtrade?branch=develop) [![Maintainability](https://api.codeclimate.com/v1/badges/5737e6d668200b7518ff/maintainability)](https://codeclimate.com/github/freqtrade/freqtrade/maintainability) @@ -32,17 +33,16 @@ Freqtrade is a free and open source crypto trading bot written in Python. It is - Run: Test your strategy with simulated money (Dry-Run mode) or deploy it with real money (Live-Trade mode). - Run using Edge (optional module): The concept is to find the best historical [trade expectancy](edge.md#expectancy) by markets based on variation of the stop-loss and then allow/reject markets to trade. The sizing of the trade is based on a risk of a percentage of your capital. - Control/Monitor: Use Telegram or a WebUI (start/stop the bot, show profit/loss, daily summary, current open trades results, etc.). -- Analyse: Further analysis can be performed on either Backtesting data or Freqtrade trading history (SQL database), including automated standard plots, and methods to load the data into [interactive environments](data-analysis.md). +- Analyze: Further analysis can be performed on either Backtesting data or Freqtrade trading history (SQL database), including automated standard plots, and methods to load the data into [interactive environments](data-analysis.md). ## Supported exchange marketplaces Please read the [exchange specific notes](exchanges.md) to learn about eventual, special configurations needed for each exchange. - [X] [Binance](https://www.binance.com/) -- [X] [Bittrex](https://bittrex.com/) -- [X] [FTX](https://ftx.com/#a=2258149) +- [X] [Bitmart](https://bitmart.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) -- [X] [Huobi](http://huobi.com/) +- [X] [HTX](https://www.htx.com/) (Former Huobi) - [X] [Kraken](https://kraken.com/) - [X] [OKX](https://okx.com/) (Former OKEX) - [ ] [potentially many others through ccxt](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ @@ -51,7 +51,8 @@ Please read the [exchange specific notes](exchanges.md) to learn about eventual, - [X] [Binance](https://www.binance.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) -- [X] [OKX](https://okx.com/). +- [X] [OKX](https://okx.com/) +- [X] [Bybit](https://bybit.com/) Please make sure to read the [exchange specific notes](exchanges.md), as well as the [trading with leverage](leverage.md) documentation before diving in. @@ -62,6 +63,10 @@ Exchanges confirmed working by the community: - [X] [Bitvavo](https://bitvavo.com/) - [X] [Kucoin](https://www.kucoin.com/) +## Community showcase + +--8<-- "includes/showcase.md" + ## Requirements ### Hardware requirements @@ -78,7 +83,7 @@ To run this bot we recommend you a linux cloud instance with a minimum of: Alternatively -- Python 3.8+ +- Python 3.9+ - pip (pip3) - git - TA-Lib diff --git a/docs/installation.md b/docs/installation.md index 92aa59498..a87a3ff4e 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -24,7 +24,7 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito The `stable` branch contains the code of the last release (done usually once per month on an approximately one week old snapshot of the `develop` branch to prevent packaging bugs, so potentially it's more stable). !!! Note - Python3.8 or higher and the corresponding `pip` are assumed to be available. The install-script will warn you and stop if that's not the case. `git` is also needed to clone the Freqtrade repository. + Python3.9 or higher and the corresponding `pip` are assumed to be available. The install-script will warn you and stop if that's not the case. `git` is also needed to clone the Freqtrade repository. Also, python headers (`python-dev` / `python-devel`) must be available for the installation to complete successfully. !!! Warning "Up-to-date clock" @@ -42,11 +42,11 @@ These requirements apply to both [Script Installation](#script-installation) and ### Install guide -* [Python >= 3.8.x](http://docs.python-guide.org/en/latest/starting/installation/) +* [Python >= 3.9](http://docs.python-guide.org/en/latest/starting/installation/) * [pip](https://pip.pypa.io/en/stable/installing/) * [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) * [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended) -* [TA-Lib](https://mrjbq7.github.io/ta-lib/install.html) (install instructions [below](#install-ta-lib)) +* [TA-Lib](https://ta-lib.github.io/ta-lib-python/) (install instructions [below](#install-ta-lib)) ### Install code @@ -54,7 +54,7 @@ We've included/collected install instructions for Ubuntu, MacOS, and Windows. Th OS Specific steps are listed first, the [Common](#common) section below is necessary for all systems. !!! Note - Python3.8 or higher and the corresponding pip are assumed to be available. + Python3.9 or higher and the corresponding pip are assumed to be available. === "Debian/Ubuntu" #### Install necessary dependencies @@ -143,11 +143,11 @@ If you are on Debian, Ubuntu or MacOS, freqtrade provides the script to install ### Activate your virtual environment -Each time you open a new terminal, you must run `source .env/bin/activate` to activate your virtual environment. +Each time you open a new terminal, you must run `source .venv/bin/activate` to activate your virtual environment. ```bash -# then activate your .env -source ./.env/bin/activate +# activate virtual environment +source ./.venv/bin/activate ``` ### Congratulations @@ -169,10 +169,10 @@ You can as well update, configure and reset the codebase of your bot with `./scr ** --install ** With this option, the script will install the bot and most dependencies: -You will need to have git and python3.8+ installed beforehand for this to work. +You will need to have git and python3.9+ installed beforehand for this to work. * Mandatory software as: `ta-lib` -* Setup your virtualenv under `.env/` +* Setup your virtualenv under `.venv/` This option is a combination of installation tasks and `--reset` @@ -204,7 +204,7 @@ sudo ./build_helpers/install_ta-lib.sh ##### TA-Lib manual installation -Official webpage: https://mrjbq7.github.io/ta-lib/install.html +[Official installation guide](https://ta-lib.github.io/ta-lib-python/install.html) ```bash wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz @@ -225,17 +225,18 @@ rm -rf ./ta-lib* You will run freqtrade in separated `virtual environment` ```bash -# create virtualenv in directory /freqtrade/.env -python3 -m venv .env +# create virtualenv in directory /freqtrade/.venv +python3 -m venv .venv # run virtualenv -source .env/bin/activate +source .venv/bin/activate ``` #### Install python dependencies ```bash python3 -m pip install --upgrade pip +python3 -m pip install -r requirements.txt python3 -m pip install -e . ``` @@ -284,10 +285,8 @@ cd freqtrade #### Freqtrade install: Conda Environment -Prepare conda-freqtrade environment, using file `environment.yml`, which exist in main freqtrade directory - ```bash -conda env create -n freqtrade-conda -f environment.yml +conda create --name freqtrade python=3.11 ``` !!! Note "Creating Conda Environment" @@ -296,12 +295,9 @@ conda env create -n freqtrade-conda -f environment.yml ```bash # choose your own packages conda env create -n [name of the environment] [python version] [packages] - - # point to file with packages - conda env create -n [name of the environment] -f [file] ``` -#### Enter/exit freqtrade-conda environment +#### Enter/exit freqtrade environment To check available environments, type @@ -313,7 +309,7 @@ Enter installed environment ```bash # enter conda environment -conda activate freqtrade-conda +conda activate freqtrade # exit conda environment - don't do it now conda deactivate @@ -323,9 +319,20 @@ Install last python dependencies with pip ```bash python3 -m pip install --upgrade pip +python3 -m pip install -r requirements.txt python3 -m pip install -e . ``` +Patch conda libta-lib (Linux only) + +```bash +# Ensure that the environment is active! +conda activate freqtrade + +cd build_helpers +bash install_ta-lib.sh ${CONDA_PREFIX} nosudo +``` + ### Congratulations [You are ready](#you-are-ready), and run the bot @@ -339,8 +346,8 @@ conda env list # activate base environment conda activate -# activate freqtrade-conda environment -conda activate freqtrade-conda +# activate freqtrade environment +conda activate freqtrade #deactivate any conda environments conda deactivate @@ -376,7 +383,7 @@ You've made it this far, so you have successfully installed freqtrade. freqtrade create-userdir --userdir user_data # Step 2 - Create a new configuration file -freqtrade new-config --config config.json +freqtrade new-config --config user_data/config.json ``` You are ready to run, read [Bot Configuration](configuration.md), remember to start with `dry_run: True` and verify that everything is working. @@ -386,7 +393,7 @@ To learn how to setup your configuration, please refer to the [Bot Configuration ### Start the Bot ```bash -freqtrade trade --config config.json --strategy SampleStrategy +freqtrade trade --config user_data/config.json --strategy SampleStrategy ``` !!! Warning @@ -404,8 +411,8 @@ If you used (1)`Script` or (2)`Manual` installation, you need to run the bot in # if: bash: freqtrade: command not found -# then activate your .env -source ./.env/bin/activate +# then activate your virtual environment +source ./.venv/bin/activate ``` ### MacOS installation error diff --git a/docs/leverage.md b/docs/leverage.md index 491e6eda0..09ebf1075 100644 --- a/docs/leverage.md +++ b/docs/leverage.md @@ -13,7 +13,7 @@ Please only use advanced trading modes when you know how freqtrade (and your strategy) works. Also, never risk more than what you can afford to lose. -Please read the [strategy migration guide](strategy_migration.md#strategy-migration-between-v2-and-v3) to migrate your strategy from a freqtrade v2 strategy, to v3 strategy that can short and trade futures. +If you already have an existing strategy, please read the [strategy migration guide](strategy_migration.md#strategy-migration-between-v2-and-v3) to migrate your strategy from a freqtrade v2 strategy, to strategy of version 3 which can short and trade futures. ## Shorting @@ -62,6 +62,11 @@ You will also have to pick a "margin mode" (explanation below) - with freqtrade "margin_mode": "isolated" ``` +##### Pair namings + +Freqtrade follows the [ccxt naming conventions for futures](https://docs.ccxt.com/#/README?id=perpetual-swap-perpetual-future). +A futures pair will therefore have the naming of `base/quote:settle` (e.g. `ETH/USDT:USDT`). + ### Margin mode On top of `trading_mode` - you will also have to configure your `margin_mode`. @@ -85,6 +90,8 @@ One account is used to share collateral between markets (trading pairs). Margin "margin_mode": "cross" ``` +Please read the [exchange specific notes](exchanges.md) for exchanges that support this mode and how they differ. + ## Set leverage to use Different strategies and risk profiles will require different levels of leverage. diff --git a/docs/lookahead-analysis.md b/docs/lookahead-analysis.md new file mode 100644 index 000000000..e998b1b77 --- /dev/null +++ b/docs/lookahead-analysis.md @@ -0,0 +1,103 @@ +# Lookahead analysis + +This page explains how to validate your strategy in terms of look ahead bias. + +Checking look ahead bias is the bane of any strategy since it is sometimes very easy to introduce backtest bias - +but very hard to detect. + +Backtesting initializes all timestamps at once and calculates all indicators in the beginning. +This means that if your indicators or entry/exit signals could look into future candles and falsify your backtest. + +Lookahead-analysis requires historic data to be available. +To learn how to get data for the pairs and exchange you're interested in, +head over to the [Data Downloading](data-download.md) section of the documentation. + +This command is built upon backtesting since it internally chains backtests and pokes at the strategy to provoke it to show look ahead bias. +This is done by not looking at the strategy itself - but at the results it returned. +The results are things like changed indicator-values and moved entries/exits compared to the full backtest. + +You can use commands of [Backtesting](backtesting.md). +It also supports the lookahead-analysis of freqai strategies. + +- `--cache` is forced to "none". +- `--max-open-trades` is forced to be at least equal to the number of pairs. +- `--dry-run-wallet` is forced to be basically infinite (1 billion). +- `--stake-amount` is forced to be a static 10000 (10k). + +Those are set to avoid users accidentally generating false positives. + +## Lookahead-analysis command reference + +``` +usage: freqtrade lookahead-analysis [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] [-s NAME] + [--strategy-path PATH] + [--recursive-strategy-search] + [--freqaimodel NAME] + [--freqaimodel-path PATH] [-i TIMEFRAME] + [--timerange TIMERANGE] + [--data-format-ohlcv {json,jsongz,hdf5,feather,parquet}] + [--max-open-trades INT] + [--stake-amount STAKE_AMOUNT] + [--fee FLOAT] [-p PAIRS [PAIRS ...]] + [--enable-protections] + [--dry-run-wallet DRY_RUN_WALLET] + [--timeframe-detail TIMEFRAME_DETAIL] + [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]] + [--export {none,trades,signals}] + [--export-filename PATH] + [--breakdown {day,week,month} [{day,week,month} ...]] + [--cache {none,day,week,month}] + [--freqai-backtest-live-models] + [--minimum-trade-amount INT] + [--targeted-trade-amount INT] + [--lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME] + +options: + --minimum-trade-amount INT + Minimum trade amount for lookahead-analysis + --targeted-trade-amount INT + Targeted trade amount for lookahead analysis + --lookahead-analysis-exportfilename LOOKAHEAD_ANALYSIS_EXPORTFILENAME + Use this csv-filename to store lookahead-analysis- + results +``` + +!!! Note "" + The above Output was reduced to options `lookahead-analysis` adds on top of regular backtesting commands. + +### Summary + +Checks a given strategy for look ahead bias via lookahead-analysis +Look ahead bias means that the backtest uses data from future candles thereby not making it viable beyond backtesting +and producing false hopes for the one backtesting. + +### Introduction + +Many strategies - without the programmer knowing - have fallen prey to look ahead bias. + +Any backtest will populate the full dataframe including all time stamps at the beginning. +If the programmer is not careful or oblivious how things work internally +(which sometimes can be really hard to find out) then it will just look into the future making the strategy amazing +but not realistic. + +This command is made to try to verify the validity in the form of the aforementioned look ahead bias. + +### How does the command work? + +It will start with a backtest of all pairs to generate a baseline for indicators and entries/exits. +After the backtest ran, it will look if the `minimum-trade-amount` is met +and if not cancel the lookahead-analysis for this strategy. + +After setting the baseline it will then do additional runs for every entry and exit separately. +When a verification-backtest is done, it will compare the indicators as the signal (either entry or exit) and report the bias. +After all signals have been verified or falsified a result-table will be generated for the user to see. + +### Caveats + +- `lookahead-analysis` can only verify / falsify the trades it calculated and verified. +If the strategy has many different signals / signal types, it's up to you to select appropriate parameters to ensure that all signals have triggered at least once. Not triggered signals will not have been verified. +This could lead to a false-negative (the strategy will then be reported as non-biased). +- `lookahead-analysis` has access to everything that backtesting has too. +Please don't provoke any configs like enabling position stacking. +If you decide to do so, then make doubly sure that you won't ever run out of `max_open_trades` amount and neither leftover money in your wallet. diff --git a/docs/overrides/main.html b/docs/overrides/main.html index dfc5264be..cba627ead 100644 --- a/docs/overrides/main.html +++ b/docs/overrides/main.html @@ -11,9 +11,6 @@ {% endif %}