Compare commits

...

283 Commits

Author SHA1 Message Date
Matthias 4f1e249574 Merge pull request #12452 from freqtrade/new_release
New release 2025.10
2025-10-31 16:53:02 +01:00
Matthias e23a211503 chore: bump version to 2025.10 2025-10-31 07:05:04 +01:00
Matthias 2e78440ef1 Merge branch 'stable' into new_release 2025-10-31 07:04:49 +01:00
Matthias cbaba293b5 fix: more complete fix for #12451 2025-10-31 07:02:53 +01:00
Matthias cdd9968831 test: use realistic arguments for tests 2025-10-31 07:02:53 +01:00
Matthias 6b4318a801 fix: trade.id must be checked as int
fixes problem with psycopg3

closes #12451
2025-10-31 07:02:53 +01:00
Matthias 95f2cc0f88 Merge pull request #12449 from stash86/develop-copy
throw error on recursive analysis on 0 startup candle
2025-10-31 06:28:56 +01:00
Stefano 1d652d1284 throw error on recursive analysis on 0 startup candle 2025-10-31 08:51:56 +09:00
Matthias 758f1eea93 test: consistent use of "spaces" in tests 2025-10-30 06:38:43 +01:00
Matthias f952502af5 Merge pull request #12447 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-10-30 06:37:31 +01:00
Freqtrade Bot b17a274ee8 chore: update pre-commit hooks 2025-10-30 03:21:28 +00:00
Matthias 4adab37b2a test: update test for removal of --hyperopt argument 2025-10-29 17:58:00 +01:00
Matthias ff7b1e0edc chore: remove long-deprecated "--hyperopt" argument 2025-10-29 17:57:51 +01:00
Matthias b2aa392a98 fix: log level setup 2025-10-28 20:00:39 +01:00
Matthias 0c1b892713 chore: add parameter descriptions to load_object 2025-10-28 19:41:35 +01:00
Matthias ee0952a848 chore: simplify iResolver 2025-10-28 19:35:18 +01:00
Matthias a166f452cb chore: move comment to right place 2025-10-28 19:32:57 +01:00
Matthias a458264bc5 fix: improve resilience in strategy wrapper 2025-10-28 19:09:09 +01:00
Matthias 13919054ac Merge pull request #12439 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-10-28 06:20:17 +01:00
Freqtrade Bot 8e4aeb62d3 chore: update pre-commit hooks 2025-10-28 03:19:47 +00:00
Matthias 609ac560fb Merge pull request #12434 from freqtrade/dependabot/pip/develop/ccxt-4.5.12
chore(deps): bump ccxt from 4.5.11 to 4.5.12
2025-10-27 20:06:12 +01:00
Matthias 5ae0328722 chore: fix redundant import 2025-10-27 19:49:49 +01:00
Matthias 89802da1c7 test: update tests for new okx limits 2025-10-27 19:45:21 +01:00
Matthias 43be6eef67 chore: re-align okx limits with ccxt 2025-10-27 19:45:15 +01:00
Matthias dc736da971 Merge pull request #12423 from freqtrade/dependabot/pip/develop/scipy-8c88e3b5d9
chore(deps-dev): bump scipy-stubs from 1.16.2.3 to 1.16.2.4 in the scipy group
2025-10-27 13:35:54 +01:00
Matthias aae1731e3b chore: bump scipy-stubs in pre-commit config 2025-10-27 13:20:37 +01:00
dependabot[bot] f39acd5585 chore(deps-dev): bump scipy-stubs in the scipy group
Bumps the scipy group with 1 update: [scipy-stubs](https://github.com/scipy/scipy-stubs).


Updates `scipy-stubs` from 1.16.2.3 to 1.16.2.4
- [Release notes](https://github.com/scipy/scipy-stubs/releases)
- [Commits](https://github.com/scipy/scipy-stubs/compare/v1.16.2.3...v1.16.2.4)

---
updated-dependencies:
- dependency-name: scipy-stubs
  dependency-version: 1.16.2.4
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: scipy
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 08:05:24 +00:00
Matthias 50f32ee56a Merge pull request #12435 from samgermain/cross-docs
cross leverage docs fix
2025-10-27 09:04:07 +01:00
Matthias 7d62e97024 Merge pull request #12425 from freqtrade/dependabot/pip/develop/types-c656cdcffe
chore(deps-dev): bump types-cachetools from 6.2.0.20250827 to 6.2.0.20251022 in the types group
2025-10-27 09:02:44 +01:00
Matthias 15eb454103 Merge pull request #12433 from freqtrade/dependabot/pip/develop/pydantic-2.12.3
chore(deps): bump pydantic from 2.12.2 to 2.12.3
2025-10-27 08:37:21 +01:00
Sam 179cefa89f cross leverage docs fix 2025-10-27 00:33:33 -06:00
dependabot[bot] c251877aba chore(deps): bump ccxt from 4.5.11 to 4.5.12
Bumps [ccxt](https://github.com/ccxt/ccxt) from 4.5.11 to 4.5.12.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg)
- [Commits](https://github.com/ccxt/ccxt/compare/v4.5.11...v4.5.12)

---
updated-dependencies:
- dependency-name: ccxt
  dependency-version: 4.5.12
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 06:25:41 +00:00
Matthias 8352b0fe07 Merge pull request #12426 from freqtrade/dependabot/pip/develop/aiohttp-3.13.1
chore(deps): bump aiohttp from 3.13.0 to 3.13.1
2025-10-27 07:23:46 +01:00
Matthias 2a7859b3df Merge pull request #12431 from freqtrade/dependabot/pip/develop/ta-lib-0.6.8
chore(deps): bump ta-lib from 0.6.7 to 0.6.8
2025-10-27 07:18:43 +01:00
dependabot[bot] 4064586d18 chore(deps): bump pydantic from 2.12.2 to 2.12.3
Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.12.2 to 2.12.3.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.12.2...v2.12.3)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-version: 2.12.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 05:46:12 +00:00
Matthias 7ddb6d3554 Merge pull request #12429 from freqtrade/dependabot/pip/develop/xgboost-3.1.1
chore(deps): bump xgboost from 3.0.5 to 3.1.1
2025-10-27 06:45:15 +01:00
Matthias 9206c0086f chore: add ta-lib armhf wheels 2025-10-27 06:43:22 +01:00
Matthias 0c6e5ace59 chore: bump types-cachetools in pre-commit config 2025-10-27 06:42:10 +01:00
Matthias 47f5b25265 Merge pull request #12430 from freqtrade/dependabot/pip/develop/uvicorn-0.38.0
chore(deps): bump uvicorn from 0.37.0 to 0.38.0
2025-10-27 06:41:13 +01:00
Matthias e3c8ef19c3 Merge pull request #12424 from freqtrade/dependabot/pip/develop/ruff-0.14.1
chore(deps-dev): bump ruff from 0.14.0 to 0.14.1
2025-10-27 06:40:42 +01:00
Matthias 803ef41a75 Merge pull request #12427 from freqtrade/dependabot/pip/develop/psutil-7.1.1
chore(deps): bump psutil from 7.1.0 to 7.1.1
2025-10-27 06:40:30 +01:00
Matthias 984f505fa6 Merge pull request #12428 from freqtrade/dependabot/pip/develop/fastapi-0.119.1
chore(deps): bump fastapi from 0.119.0 to 0.119.1
2025-10-27 06:40:15 +01:00
Matthias b89266225d Merge pull request #12432 from freqtrade/dependabot/pip/develop/python-rapidjson-1.22
chore(deps): bump python-rapidjson from 1.21 to 1.22
2025-10-27 06:39:58 +01:00
dependabot[bot] a45930a5cf chore(deps): bump python-rapidjson from 1.21 to 1.22
Bumps [python-rapidjson](https://github.com/python-rapidjson/python-rapidjson) from 1.21 to 1.22.
- [Changelog](https://github.com/python-rapidjson/python-rapidjson/blob/master/CHANGES.rst)
- [Commits](https://github.com/python-rapidjson/python-rapidjson/compare/v1.21...v1.22)

---
updated-dependencies:
- dependency-name: python-rapidjson
  dependency-version: '1.22'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:04:33 +00:00
dependabot[bot] fe06a87aa2 chore(deps): bump ta-lib from 0.6.7 to 0.6.8
Bumps [ta-lib](https://github.com/ta-lib/ta-lib-python) from 0.6.7 to 0.6.8.
- [Release notes](https://github.com/ta-lib/ta-lib-python/releases)
- [Changelog](https://github.com/TA-Lib/ta-lib-python/blob/master/CHANGELOG)
- [Commits](https://github.com/ta-lib/ta-lib-python/compare/v0.6.7...v0.6.8)

---
updated-dependencies:
- dependency-name: ta-lib
  dependency-version: 0.6.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:04:32 +00:00
dependabot[bot] f9940c4f1f chore(deps): bump uvicorn from 0.37.0 to 0.38.0
Bumps [uvicorn](https://github.com/Kludex/uvicorn) from 0.37.0 to 0.38.0.
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](https://github.com/Kludex/uvicorn/compare/0.37.0...0.38.0)

---
updated-dependencies:
- dependency-name: uvicorn
  dependency-version: 0.38.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:04:11 +00:00
dependabot[bot] 5c3ebd3761 chore(deps): bump xgboost from 3.0.5 to 3.1.1
Bumps [xgboost](https://github.com/dmlc/xgboost) from 3.0.5 to 3.1.1.
- [Release notes](https://github.com/dmlc/xgboost/releases)
- [Changelog](https://github.com/dmlc/xgboost/blob/master/NEWS.md)
- [Commits](https://github.com/dmlc/xgboost/compare/v3.0.5...v3.1.1)

---
updated-dependencies:
- dependency-name: xgboost
  dependency-version: 3.1.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:03:53 +00:00
dependabot[bot] 9050325fda chore(deps): bump fastapi from 0.119.0 to 0.119.1
Bumps [fastapi](https://github.com/fastapi/fastapi) from 0.119.0 to 0.119.1.
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](https://github.com/fastapi/fastapi/compare/0.119.0...0.119.1)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-version: 0.119.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:03:03 +00:00
dependabot[bot] 9ca2342a0b chore(deps): bump psutil from 7.1.0 to 7.1.1
Bumps [psutil](https://github.com/giampaolo/psutil) from 7.1.0 to 7.1.1.
- [Changelog](https://github.com/giampaolo/psutil/blob/master/HISTORY.rst)
- [Commits](https://github.com/giampaolo/psutil/compare/release-7.1.0...release-7.1.1)

---
updated-dependencies:
- dependency-name: psutil
  dependency-version: 7.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:02:56 +00:00
dependabot[bot] ad9bb75fd5 chore(deps): bump aiohttp from 3.13.0 to 3.13.1
---
updated-dependencies:
- dependency-name: aiohttp
  dependency-version: 3.13.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:02:51 +00:00
dependabot[bot] f96dfd04f7 chore(deps-dev): bump types-cachetools in the types group
Bumps the types group with 1 update: [types-cachetools](https://github.com/typeshed-internal/stub_uploader).


Updates `types-cachetools` from 6.2.0.20250827 to 6.2.0.20251022
- [Commits](https://github.com/typeshed-internal/stub_uploader/commits)

---
updated-dependencies:
- dependency-name: types-cachetools
  dependency-version: 6.2.0.20251022
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: types
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:02:40 +00:00
dependabot[bot] d63982c32c chore(deps-dev): bump ruff from 0.14.0 to 0.14.1
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.14.0 to 0.14.1.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.14.0...0.14.1)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.14.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 03:02:36 +00:00
Matthias 14b5392d5f Merge pull request #12420 from qinhanlei/uv-pip
Add support for uv in setup.sh
2025-10-26 09:47:48 +01:00
Matthias 16dd4073ff docs: update setup script docs for uv support 2025-10-26 09:32:36 +01:00
Matthias 9595936d73 chore: fix uv only install 2025-10-26 09:04:30 +01:00
Matthias c18a52fd2d test: update tests for new error formatting 2025-10-25 13:15:41 +02:00
Matthias 75c39d3617 feat: improve strategy error warning
closes #12418
2025-10-25 13:15:24 +02:00
Matthias 911a803a56 fix: improve error-handling for odd configurations 2025-10-25 09:49:55 +02:00
Matthias f04315fa8f fix: gracefully handle custom stake returning string
closes #12421
2025-10-25 09:42:45 +02:00
Matthias 89e68d7d4d test: add test case for string custom stake amount 2025-10-25 09:42:45 +02:00
Hanlei Qin 4fc5f33fa1 fix an omission 2025-10-25 15:16:20 +08:00
Matthias c2056085c9 Merge pull request #12419 from stash86/main-stash
Fix typo
2025-10-25 08:49:17 +02:00
Hanlei Qin 9f7b7ef889 Use uv instead of pip if available 2025-10-25 12:33:14 +08:00
Stefano cdb194a363 fix typo 2025-10-25 13:13:40 +09:00
Stefano 0986350f05 fix typo 2025-10-25 13:11:11 +09:00
Hanlei Qin 119cadcb2b Replace pip with uv for package installations in setup.sh 2025-10-24 19:55:57 +08:00
Matthias 803db3b55b Merge pull request #12413 from hippocritical/develop
add np.NAN to strategy updater conversion (which worked in 1.x but not in 2.x anymore)
2025-10-24 08:41:51 +02:00
hippocritical c2fd6e3237 NAN is sometimes used by some programmers when numpy was 1.x but now on 2.x the caps version is disallowed.
Added the caps conversion to lower case nan to fix that automatically.

Source:
https://numpy.org/doc/2.0/reference/constants.html?utm_source=chatgpt.com
NaN and NAN are aliases of nan.
2025-10-24 08:11:44 +02:00
Matthias bf7fc79519 Merge pull request #12412 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-10-23 19:46:01 +02:00
Freqtrade Bot cded5bcb4c chore: update pre-commit hooks 2025-10-23 17:29:57 +00:00
Matthias f8d3373e13 docs: update documentation to refer to psycopg3
It's the newer version with broader support for new packages (e.g. numpy2).

closes #12409
2025-10-23 19:11:43 +02:00
Matthias f1d48c8189 test: explicitly test for psycopg3 2025-10-23 07:11:15 +02:00
Matthias 866bda8606 test: update test string for psycopg3 2025-10-23 07:06:36 +02:00
Matthias 78a00ef249 Merge pull request #12398 from freqtrade/fix/remove_deprecation_warning
Work around os.fork deprecation
2025-10-21 06:34:28 +02:00
Matthias b6bc3042b4 Merge pull request #12408 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-10-21 06:25:23 +02:00
Freqtrade Bot 4ee699d27b chore: update pre-commit hooks 2025-10-21 03:19:09 +00:00
Matthias 2effa7a31b Merge branch 'develop' into fix/remove_deprecation_warning 2025-10-20 20:23:08 +02:00
Matthias c50b77303d Merge pull request #12400 from qinhanlei/patch-1
Update sb3_contrib dependency condition
2025-10-20 20:20:55 +02:00
Matthias 40bfaa6245 chore: align pyproject.toml platform limitations 2025-10-20 19:41:50 +02:00
Matthias f4656a0c6e test: ensure mp_start runs on startup 2025-10-20 19:30:32 +02:00
Matthias 161e5e3dfa refactor: switch mp-method to forkserver globally 2025-10-20 19:28:17 +02:00
Robert Caulk 023da4fc29 Merge pull request #12299 from freqtrade/dependabot/pip/develop/gymnasium-1.2.1
chore(deps): bump gymnasium from 0.29.1 to 1.2.1
2025-10-20 17:07:49 +02:00
dependabot[bot] 5c8261f8d1 chore(deps): bump gymnasium from 0.29.1 to 1.2.1
Bumps [gymnasium](https://github.com/Farama-Foundation/Gymnasium) from 0.29.1 to 1.2.1.
- [Release notes](https://github.com/Farama-Foundation/Gymnasium/releases)
- [Commits](https://github.com/Farama-Foundation/Gymnasium/compare/v0.29.1...v1.2.1)

---
updated-dependencies:
- dependency-name: gymnasium
  dependency-version: 1.2.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 04:30:27 +00:00
Matthias 080aafa1da Merge pull request #12406 from freqtrade/dependabot/pip/develop/torch-2.9.0
chore(deps): bump torch from 2.8.0 to 2.9.0
2025-10-20 06:26:48 +02:00
Matthias 43d6a6782a Merge pull request #12402 from freqtrade/dependabot/pip/develop/cryptography-46.0.3
chore(deps): bump cryptography from 46.0.2 to 46.0.3
2025-10-20 06:25:52 +02:00
Matthias f0028a6b6e Merge pull request #12407 from freqtrade/dependabot/pip/develop/humanize-4.14.0
chore(deps): bump humanize from 4.13.0 to 4.14.0
2025-10-20 06:25:09 +02:00
Matthias 98439f4e48 Merge pull request #12405 from freqtrade/dependabot/pip/develop/numpy-2.3.4
chore(deps): bump numpy from 2.3.3 to 2.3.4
2025-10-20 06:24:54 +02:00
Matthias 78802ae9aa Merge pull request #12404 from freqtrade/dependabot/pip/develop/numexpr-2.14.1
chore(deps): bump numexpr from 2.13.1 to 2.14.1
2025-10-20 06:24:24 +02:00
Matthias 99b4e5382e Merge pull request #12401 from freqtrade/dependabot/pip/develop/pydantic-2.12.2
chore(deps): bump pydantic from 2.12.0 to 2.12.2
2025-10-20 06:24:08 +02:00
Matthias 2b24f939da Merge pull request #12403 from freqtrade/dependabot/pip/develop/mkdocs-3c1a69b1c7
chore(deps): bump mkdocs-material from 9.6.21 to 9.6.22 in the mkdocs group
2025-10-20 06:23:24 +02:00
dependabot[bot] 3271e5cd43 chore(deps): bump humanize from 4.13.0 to 4.14.0
Bumps [humanize](https://github.com/python-humanize/humanize) from 4.13.0 to 4.14.0.
- [Release notes](https://github.com/python-humanize/humanize/releases)
- [Commits](https://github.com/python-humanize/humanize/compare/4.13.0...4.14.0)

---
updated-dependencies:
- dependency-name: humanize
  dependency-version: 4.14.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 03:02:42 +00:00
dependabot[bot] 94bd6b7142 chore(deps): bump torch from 2.8.0 to 2.9.0
Bumps [torch](https://github.com/pytorch/pytorch) from 2.8.0 to 2.9.0.
- [Release notes](https://github.com/pytorch/pytorch/releases)
- [Changelog](https://github.com/pytorch/pytorch/blob/main/RELEASE.md)
- [Commits](https://github.com/pytorch/pytorch/compare/v2.8.0...v2.9.0)

---
updated-dependencies:
- dependency-name: torch
  dependency-version: 2.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 03:02:37 +00:00
dependabot[bot] b59c4caf81 chore(deps): bump numpy from 2.3.3 to 2.3.4
Bumps [numpy](https://github.com/numpy/numpy) from 2.3.3 to 2.3.4.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst)
- [Commits](https://github.com/numpy/numpy/compare/v2.3.3...v2.3.4)

---
updated-dependencies:
- dependency-name: numpy
  dependency-version: 2.3.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 03:02:21 +00:00
dependabot[bot] 8bfa3a5d11 chore(deps): bump numexpr from 2.13.1 to 2.14.1
Bumps [numexpr](https://github.com/pydata/numexpr) from 2.13.1 to 2.14.1.
- [Release notes](https://github.com/pydata/numexpr/releases)
- [Changelog](https://github.com/pydata/numexpr/blob/master/RELEASE_NOTES.rst)
- [Commits](https://github.com/pydata/numexpr/compare/v2.13.1...v2.14.1)

---
updated-dependencies:
- dependency-name: numexpr
  dependency-version: 2.14.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 03:02:14 +00:00
dependabot[bot] b161924941 chore(deps): bump mkdocs-material in the mkdocs group
Bumps the mkdocs group with 1 update: [mkdocs-material](https://github.com/squidfunk/mkdocs-material).


Updates `mkdocs-material` from 9.6.21 to 9.6.22
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.21...9.6.22)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-version: 9.6.22
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: mkdocs
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 03:02:09 +00:00
dependabot[bot] aad125211e chore(deps): bump cryptography from 46.0.2 to 46.0.3
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.2 to 46.0.3.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/46.0.2...46.0.3)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 46.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 03:02:03 +00:00
dependabot[bot] 39f8149e27 chore(deps): bump pydantic from 2.12.0 to 2.12.2
Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.12.0 to 2.12.2.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.12.0...v2.12.2)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-version: 2.12.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-20 03:02:00 +00:00
WingStone d6541d81c3 Update sb3_contrib dependency condition
Install dependencies for development on macOS with Intel x86_64 Chip.
2025-10-20 10:49:35 +08:00
Matthias 763f08a08e test: test catboost on aarch64 runners 2025-10-19 16:46:33 +02:00
Matthias 886d5d1db6 chore: update catboost install 2025-10-19 16:45:13 +02:00
Matthias 9b1fc7a6d4 Merge pull request #12394 from freqtrade/feat/bitget_futures
Add support for bitget futures
2025-10-19 16:32:39 +02:00
Matthias 8d95ca3506 chore: disable deprecationWarning
Very targeted at  'CatBoostClassifier' object has no attribute '__sklearn_tags__'
2025-10-19 16:32:25 +02:00
Matthias 44ec500744 test: add Test-case to ensure hyperopt logging 2025-10-19 12:59:08 +02:00
Matthias 8526733b36 chore: update hyperopt test strategy to new interface 2025-10-19 12:55:00 +02:00
Matthias 9041000bc4 fix: attempt to work around deprecation message 2025-10-19 12:05:52 +02:00
Matthias be16ffea23 fix: move logging setup to hyperopter
restores hyperopt logging functionality
2025-10-19 09:09:59 +02:00
Matthias a0c4b520fc fix: okxus doesn't support futures trading 2025-10-19 08:24:06 +02:00
Matthias dcd9e2ef14 feat: bitget stop orders don't block assets 2025-10-18 13:02:33 +02:00
Matthias 46dc378472 test: add bitget leverage prep test 2025-10-18 09:53:42 +02:00
Matthias d1e73c1916 test: add test for cross liquidation price not supported 2025-10-18 09:48:48 +02:00
Matthias 0f60ee8763 feat: add bitget as supported exchange 2025-10-18 08:53:18 +02:00
Matthias 5b45f1bbc8 docs: add bitget as supported exchange 2025-10-18 08:52:52 +02:00
Matthias d283252ac7 fix: bitget only provides 100 funding rate candles per call 2025-10-18 08:47:55 +02:00
Matthias 02a0ce8c49 test: enable online bitget tests 2025-10-18 08:47:55 +02:00
Matthias f82d8f3b52 test: refactor _get_params test for simpler reading 2025-10-18 08:47:55 +02:00
Matthias 1f620257f9 test: test for get_params 2025-10-18 08:47:55 +02:00
Matthias 16e9109e96 test: add test for bitget exchange init 2025-10-18 08:47:55 +02:00
Matthias 0c65c915a4 feat: more settings for bitget futures 2025-10-18 08:47:55 +02:00
Matthias 7aca82b590 docs: clarify exchange warning 2025-10-18 08:47:55 +02:00
Matthias 99566b4d9b docs: slight refactor to exchanges structure 2025-10-18 08:47:55 +02:00
Matthias eb31581c7b docs(bitget): Add futures notes for bitget 2025-10-18 08:47:55 +02:00
Matthias d46af09c10 docs: add bitget to support matrix 2025-10-18 08:47:55 +02:00
Matthias badc7ed18c feat(bitget): fix liquidation formula 2025-10-18 08:47:55 +02:00
Matthias 3da36eae31 feat: bitget futures order parameters 2025-10-18 08:47:55 +02:00
Matthias fcbe58e971 feat: Add bitget exchange init 2025-10-18 08:47:55 +02:00
Matthias 572ce0b739 feat: bitget liquidation price calc 2025-10-18 08:47:55 +02:00
Matthias 0f31607617 feat: Enable bitget futures trading 2025-10-18 08:47:55 +02:00
Matthias 6a15f0c271 chore: update exchange docstrings 2025-10-18 08:45:56 +02:00
Matthias d77bcf0e18 chore: update web proxy url 2025-10-16 20:51:57 +02:00
Matthias 5df0530223 Merge pull request #12389 from mrpabloyeah/add-day-of-week-to-backtest-breakdowns
Add day of week to backtest breakdowns
2025-10-16 20:16:02 +02:00
Matthias 522fa092ba test: add explicit weekday test 2025-10-16 19:23:53 +02:00
Matthias 8f6f2ab872 test: add explicit test for weekday change 2025-10-16 19:21:31 +02:00
Matthias 7185026378 chore: revert unnecessary period name customization 2025-10-16 19:17:10 +02:00
Matthias db11844661 Merge pull request #12392 from freqtrade/dependabot/pip/develop/ccxt-4.5.11
chore(deps): bump ccxt from 4.5.10 to 4.5.11
2025-10-16 07:03:08 +02:00
Matthias 163d8a0e10 Merge pull request #12391 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-10-16 06:45:34 +02:00
dependabot[bot] 7a38423c1e chore(deps): bump ccxt from 4.5.10 to 4.5.11
Bumps [ccxt](https://github.com/ccxt/ccxt) from 4.5.10 to 4.5.11.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg)
- [Commits](https://github.com/ccxt/ccxt/compare/v4.5.10...v4.5.11)

---
updated-dependencies:
- dependency-name: ccxt
  dependency-version: 4.5.11
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-16 04:43:09 +00:00
Matthias 46e0219040 chore: add devcontainer update to dependabot 2025-10-16 06:38:08 +02:00
Freqtrade Bot 1ff49aa614 chore: update pre-commit hooks 2025-10-16 03:17:22 +00:00
Matthias c878c673ab fix: improve datetime for trade_list_to_dataframe
closes #12388
2025-10-15 19:36:06 +02:00
Matthias 642f24eba5 chore: fix odd debug message wording 2025-10-15 19:31:10 +02:00
Matthias bdd60ecbbd fix: Set use_db for historic analysis
closes #12390
2025-10-15 18:27:20 +02:00
Matthias 4cf736911d fix: cleanup backtest after it ran 2025-10-15 18:19:02 +02:00
Matthias 0bf83f8744 chore: improved reset_backtest function 2025-10-15 18:17:55 +02:00
Matthias 6bd7fdb8ac chore: improved naming for method 2025-10-15 18:17:30 +02:00
Matthias a745136190 chore: fix action version missmatch 2025-10-15 06:59:37 +02:00
Matthias a672c32d6a chore: add dependabot cooldown configs 2025-10-15 06:58:31 +02:00
mrpabloyeah 1294724ee8 Add day of week to backtest breakdowns 2025-10-14 21:13:48 +02:00
Matthias b13af0e88b Merge pull request #12385 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-10-14 06:50:12 +02:00
Matthias 0041bf5e4e test: use ft_additional_exchange_init in tests 2025-10-14 06:30:05 +02:00
Matthias d7c027fc7a test: add ft_additional_exchange_init to simplify test setups 2025-10-14 06:29:59 +02:00
Matthias b3ceaa87d7 chore: remove redundant comment 2025-10-14 06:29:44 +02:00
Freqtrade Bot d237974ebe chore: update pre-commit hooks 2025-10-14 03:16:08 +00:00
Matthias a82c852675 Merge pull request #12370 from freqtrade/dependabot/pip/develop/scipy-78fb2d86bd
chore(deps-dev): bump scipy-stubs from 1.16.2.0 to 1.16.2.3 in the scipy group
2025-10-13 08:45:48 +02:00
Matthias bb76099b5a Merge pull request #12381 from freqtrade/dependabot/pip/develop/aiohttp-3.13.0
chore(deps): bump aiohttp from 3.12.15 to 3.13.0
2025-10-13 08:18:11 +02:00
Matthias 01ca34ebee chore: bump scipy-stubs in pre-commit config 2025-10-13 08:17:53 +02:00
dependabot[bot] 4af18a3471 chore(deps): bump aiohttp from 3.12.15 to 3.13.0
---
updated-dependencies:
- dependency-name: aiohttp
  dependency-version: 3.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 05:32:12 +00:00
dependabot[bot] 5d8500ff7f chore(deps-dev): bump scipy-stubs in the scipy group
Bumps the scipy group with 1 update: [scipy-stubs](https://github.com/scipy/scipy-stubs).


Updates `scipy-stubs` from 1.16.2.0 to 1.16.2.3
- [Release notes](https://github.com/scipy/scipy-stubs/releases)
- [Commits](https://github.com/scipy/scipy-stubs/compare/v1.16.2.0...v1.16.2.3)

---
updated-dependencies:
- dependency-name: scipy-stubs
  dependency-version: 1.16.2.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: scipy
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 05:25:30 +00:00
Matthias 8a59dfd495 Merge pull request #12380 from freqtrade/dependabot/pip/develop/pydantic-2.12.0
chore(deps): bump pydantic from 2.11.10 to 2.12.0
2025-10-13 07:24:30 +02:00
Matthias f4da8edb90 Merge pull request #12376 from freqtrade/dependabot/pip/develop/sqlalchemy-2.0.44
chore(deps): bump sqlalchemy from 2.0.43 to 2.0.44
2025-10-13 07:20:41 +02:00
Matthias f1824f6f2e Merge pull request #12368 from freqtrade/dependabot/pip/develop/types-42ec8c0646
chore(deps-dev): bump types-python-dateutil from 2.9.0.20250822 to 2.9.0.20251008 in the types group
2025-10-13 07:09:57 +02:00
dependabot[bot] 54b01bd44d chore(deps): bump pydantic from 2.11.10 to 2.12.0
Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.11.10 to 2.12.0.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/main/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.11.10...v2.12.0)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-version: 2.12.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 04:48:24 +00:00
Matthias 634be642f2 Merge pull request #12377 from freqtrade/dependabot/pip/develop/aiofiles-25.1.0
chore(deps): bump aiofiles from 24.1.0 to 25.1.0
2025-10-13 06:47:28 +02:00
Matthias 2e5000a016 chore: bump sqlalchemy in pre-commit config 2025-10-13 06:47:14 +02:00
dependabot[bot] b51ed49dbf chore(deps): bump sqlalchemy from 2.0.43 to 2.0.44
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.43 to 2.0.44.
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES.rst)
- [Commits](https://github.com/sqlalchemy/sqlalchemy/commits)

---
updated-dependencies:
- dependency-name: sqlalchemy
  dependency-version: 2.0.44
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 04:43:22 +00:00
Matthias 92d2bde559 chore: bump pre-commit python-dateutil stubs 2025-10-13 06:39:38 +02:00
Matthias 92ae444026 Merge pull request #12375 from freqtrade/dependabot/pip/develop/ccxt-4.5.10
chore(deps): bump ccxt from 4.5.7 to 4.5.10
2025-10-13 06:36:23 +02:00
Matthias 51795474d7 Merge pull request #12373 from freqtrade/dependabot/pip/develop/isort-7.0.0
chore(deps-dev): bump isort from 6.1.0 to 7.0.0
2025-10-13 06:35:04 +02:00
Matthias 63a37fc2d3 Merge pull request #12374 from freqtrade/dependabot/pip/develop/rich-14.2.0
chore(deps): bump rich from 14.1.0 to 14.2.0
2025-10-13 06:34:42 +02:00
Matthias 7d79ac1e56 Merge pull request #12378 from freqtrade/dependabot/pip/develop/ruff-0.14.0
chore(deps-dev): bump ruff from 0.13.3 to 0.14.0
2025-10-13 06:34:25 +02:00
Matthias acf6d94ee1 Merge pull request #12371 from freqtrade/dependabot/pip/develop/cachetools-6.2.1
chore(deps): bump cachetools from 6.2.0 to 6.2.1
2025-10-13 06:34:05 +02:00
Matthias a03e726aad Merge pull request #12372 from freqtrade/dependabot/pip/develop/filelock-3.20.0
chore(deps): bump filelock from 3.19.1 to 3.20.0
2025-10-13 06:33:45 +02:00
Matthias 6ce27e50f0 Merge pull request #12379 from freqtrade/dependabot/pip/develop/fastapi-0.119.0
chore(deps): bump fastapi from 0.118.0 to 0.119.0
2025-10-13 06:33:33 +02:00
Matthias d3bdf1ab96 Merge pull request #12369 from freqtrade/dependabot/github_actions/develop/astral-sh/setup-uv-7.1.0
chore(deps): bump astral-sh/setup-uv from 6.8.0 to 7.1.0
2025-10-13 06:33:18 +02:00
dependabot[bot] a0ec5f6fe2 chore(deps): bump fastapi from 0.118.0 to 0.119.0
Bumps [fastapi](https://github.com/fastapi/fastapi) from 0.118.0 to 0.119.0.
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](https://github.com/fastapi/fastapi/compare/0.118.0...0.119.0)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-version: 0.119.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:03:46 +00:00
dependabot[bot] d512ae6c86 chore(deps-dev): bump ruff from 0.13.3 to 0.14.0
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.13.3 to 0.14.0.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.13.3...0.14.0)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.14.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:03:33 +00:00
dependabot[bot] 612790c730 chore(deps): bump aiofiles from 24.1.0 to 25.1.0
Bumps [aiofiles](https://github.com/Tinche/aiofiles) from 24.1.0 to 25.1.0.
- [Release notes](https://github.com/Tinche/aiofiles/releases)
- [Changelog](https://github.com/Tinche/aiofiles/blob/main/CHANGELOG.md)
- [Commits](https://github.com/Tinche/aiofiles/compare/v24.1.0...v25.1.0)

---
updated-dependencies:
- dependency-name: aiofiles
  dependency-version: 25.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:03:25 +00:00
dependabot[bot] 0e84c203e6 chore(deps): bump ccxt from 4.5.7 to 4.5.10
Bumps [ccxt](https://github.com/ccxt/ccxt) from 4.5.7 to 4.5.10.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg)
- [Commits](https://github.com/ccxt/ccxt/compare/v4.5.7...v4.5.10)

---
updated-dependencies:
- dependency-name: ccxt
  dependency-version: 4.5.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:02:24 +00:00
dependabot[bot] 61119d60b9 chore(deps): bump rich from 14.1.0 to 14.2.0
Bumps [rich](https://github.com/Textualize/rich) from 14.1.0 to 14.2.0.
- [Release notes](https://github.com/Textualize/rich/releases)
- [Changelog](https://github.com/Textualize/rich/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Textualize/rich/compare/v14.1.0...v14.2.0)

---
updated-dependencies:
- dependency-name: rich
  dependency-version: 14.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:02:10 +00:00
dependabot[bot] 3870758ab8 chore(deps-dev): bump isort from 6.1.0 to 7.0.0
Bumps [isort](https://github.com/PyCQA/isort) from 6.1.0 to 7.0.0.
- [Release notes](https://github.com/PyCQA/isort/releases)
- [Changelog](https://github.com/PyCQA/isort/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PyCQA/isort/compare/6.1.0...7.0.0)

---
updated-dependencies:
- dependency-name: isort
  dependency-version: 7.0.0
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:02:06 +00:00
dependabot[bot] 1b76900b9e chore(deps): bump filelock from 3.19.1 to 3.20.0
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.19.1 to 3.20.0.
- [Release notes](https://github.com/tox-dev/py-filelock/releases)
- [Changelog](https://github.com/tox-dev/filelock/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/py-filelock/compare/3.19.1...3.20.0)

---
updated-dependencies:
- dependency-name: filelock
  dependency-version: 3.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:02:00 +00:00
dependabot[bot] b63d61f2b2 chore(deps): bump cachetools from 6.2.0 to 6.2.1
Bumps [cachetools](https://github.com/tkem/cachetools) from 6.2.0 to 6.2.1.
- [Changelog](https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/tkem/cachetools/compare/v6.2.0...v6.2.1)

---
updated-dependencies:
- dependency-name: cachetools
  dependency-version: 6.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:01:54 +00:00
dependabot[bot] 90e36700c3 chore(deps): bump astral-sh/setup-uv from 6.8.0 to 7.1.0
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.8.0 to 7.1.0.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/d0cc045d04ccac9d8b7881df0226f9e82c39688e...3259c6206f993105e3a61b142c2d97bf4b9ef83d)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 7.1.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:01:30 +00:00
dependabot[bot] d79b82d24e chore(deps-dev): bump types-python-dateutil in the types group
Bumps the types group with 1 update: [types-python-dateutil](https://github.com/typeshed-internal/stub_uploader).


Updates `types-python-dateutil` from 2.9.0.20250822 to 2.9.0.20251008
- [Commits](https://github.com/typeshed-internal/stub_uploader/commits)

---
updated-dependencies:
- dependency-name: types-python-dateutil
  dependency-version: 2.9.0.20251008
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: types
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-13 03:01:15 +00:00
Matthias b8e288e613 Merge pull request #12282 from mrpabloyeah/update-documentation-for-trade-and-order-objects
Update documentation for Trade and Order objects
2025-10-12 15:36:58 +02:00
Matthias ca76ccb6af docs: improve some documentation wording 2025-10-12 15:22:36 +02:00
Matthias bb6e33c8c4 docs: remove methods that are not considered as public interface 2025-10-12 10:29:07 +02:00
Matthias f529b7b526 docs: Update trade-object documentation
partially reverts c1cd14 - includes a few enhancements to it
2025-10-12 10:25:56 +02:00
Matthias ea0c51c498 Merge pull request #12201 from mihalt/fix_merge_informative_pair
Fix the truncation of values by merge_ordered in merge_informative_pair
2025-10-12 10:15:47 +02:00
Matthias a9447e7edf Merge branch 'develop' into fix_merge_informative_pair 2025-10-12 09:51:43 +02:00
Matthias 93b87696c6 fix: handle case where informative does not overlap with the main data 2025-10-12 09:51:31 +02:00
Matthias 876875cff2 test: add test-case for no overlap merges 2025-10-12 09:51:15 +02:00
Matthias 2649ba0916 docs (freqAI): align docs with actual model name 2025-10-11 16:04:04 +02:00
Matthias 923f687a33 Merge pull request #12354 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-10-09 06:31:22 +02:00
Freqtrade Bot 613fdad671 chore: update pre-commit hooks 2025-10-09 03:15:03 +00:00
Matthias d8a89a3a42 chore: re-add type requirement 2025-10-08 07:08:48 +02:00
Matthias 34cba1480e test: improved line-annotation test-case 2025-10-08 07:07:39 +02:00
Matthias 9ea249180a test: add annotation line test 2025-10-08 06:42:53 +02:00
Matthias 4ba13a4254 fic: Improve type safety for annotationType 2025-10-08 06:42:38 +02:00
Matthias e6371f38fd chore: bump docker image to 3.13.8 2025-10-08 06:36:15 +02:00
Matthias e55a196e8f docs: update docs for line annotations
closes #12307
2025-10-07 19:29:52 +02:00
Matthias f9696d557c feat: Add line chart type 2025-10-07 19:29:52 +02:00
Matthias 0715f46a4a docs: fix broken doc example 2025-10-07 19:29:52 +02:00
Matthias a5450672b1 feat: add line annotations 2025-10-07 19:29:52 +02:00
Matthias 39bf71680c test: Update test case description wording 2025-10-07 07:12:58 +02:00
Matthias 372cfeee33 fix: timeout exit count should consider remaining amount
closes #12343
2025-10-07 06:50:54 +02:00
Matthias ca4e4efeb8 test: Add test scenario for partially filled exit
* followed by exit_timeout_count
* shouldn't place order for the full amount

part of #12343
2025-10-07 06:48:35 +02:00
Matthias 96c65dacdd Merge pull request #12345 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-10-07 06:27:24 +02:00
Freqtrade Bot c46080f0b2 chore: update pre-commit hooks 2025-10-07 03:13:29 +00:00
Matthias cfd7d0a38b test: add ccxt parse test for kraken
part of #12326
2025-10-06 19:13:20 +02:00
Matthias 0df1650f2d Merge pull request #12338 from freqtrade/dependabot/pip/develop/pydantic-2.11.10
chore(deps): bump pydantic from 2.11.9 to 2.11.10
2025-10-06 08:17:06 +02:00
Matthias 8bba3081ab Merge pull request #12330 from freqtrade/dependabot/pip/develop/mkdocs-d51531eb39
chore(deps): bump mkdocs-material from 9.6.20 to 9.6.21 in the mkdocs group
2025-10-06 07:06:38 +02:00
Matthias d5f23bb5a8 Merge pull request #12336 from freqtrade/dependabot/pip/develop/certifi-2025.10.5
chore(deps): bump certifi from 2025.8.3 to 2025.10.5
2025-10-06 06:57:46 +02:00
Matthias b81df43132 Merge pull request #12332 from freqtrade/dependabot/github_actions/develop/peter-evans/dockerhub-description-5.0.0
chore(deps): bump peter-evans/dockerhub-description from 4.0.2 to 5.0.0
2025-10-06 06:52:28 +02:00
Matthias c5f303f0c4 Merge pull request #12339 from freqtrade/dependabot/pip/develop/pandas-2.3.3
chore(deps): bump pandas from 2.3.2 to 2.3.3
2025-10-06 06:51:51 +02:00
Matthias 3a51db79c9 docs: update open-source spelling to open source
based on https://opensource.org/blog/is-open-source-ever-hyphenated
2025-10-06 06:38:18 +02:00
dependabot[bot] bda9606ae3 chore(deps): bump pydantic from 2.11.9 to 2.11.10
Bumps [pydantic](https://github.com/pydantic/pydantic) from 2.11.9 to 2.11.10.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/v2.11.10/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v2.11.9...v2.11.10)

---
updated-dependencies:
- dependency-name: pydantic
  dependency-version: 2.11.10
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 04:34:03 +00:00
Matthias b59e208468 Merge pull request #12341 from freqtrade/dependabot/pip/develop/isort-6.1.0
chore(deps-dev): bump isort from 6.0.1 to 6.1.0
2025-10-06 06:30:41 +02:00
dependabot[bot] 6b6f0a1d87 chore(deps): bump pandas from 2.3.2 to 2.3.3
Bumps [pandas](https://github.com/pandas-dev/pandas) from 2.3.2 to 2.3.3.
- [Release notes](https://github.com/pandas-dev/pandas/releases)
- [Commits](https://github.com/pandas-dev/pandas/compare/v2.3.2...v2.3.3)

---
updated-dependencies:
- dependency-name: pandas
  dependency-version: 2.3.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 04:30:26 +00:00
Matthias 5676dd89af Merge pull request #12337 from freqtrade/dependabot/pip/develop/cryptography-46.0.2
chore(deps): bump cryptography from 46.0.1 to 46.0.2
2025-10-06 06:30:25 +02:00
Matthias 3ec26e169e Merge pull request #12340 from freqtrade/dependabot/pip/develop/ruff-0.13.3
chore(deps-dev): bump ruff from 0.13.2 to 0.13.3
2025-10-06 06:29:25 +02:00
Matthias 2115af3857 Merge pull request #12342 from freqtrade/dependabot/pip/develop/plotly-6.3.1
chore(deps): bump plotly from 6.3.0 to 6.3.1
2025-10-06 06:29:07 +02:00
Matthias ed3f619db6 Merge pull request #12335 from freqtrade/dependabot/pip/develop/numexpr-2.13.1
chore(deps): bump numexpr from 2.13.0 to 2.13.1
2025-10-06 06:28:52 +02:00
Matthias e58f42de21 Merge pull request #12334 from freqtrade/dependabot/pip/develop/fastapi-0.118.0
chore(deps): bump fastapi from 0.117.1 to 0.118.0
2025-10-06 06:28:35 +02:00
Matthias 0f26fe4bc9 Merge pull request #12333 from freqtrade/dependabot/github_actions/develop/docker/login-action-3.6.0
chore(deps): bump docker/login-action from 3.5.0 to 3.6.0
2025-10-06 06:27:53 +02:00
Matthias 69a715dff1 Merge pull request #12331 from freqtrade/dependabot/github_actions/develop/astral-sh/setup-uv-6.8.0
chore(deps): bump astral-sh/setup-uv from 6.7.0 to 6.8.0
2025-10-06 06:27:36 +02:00
dependabot[bot] dba758b5e4 chore(deps): bump plotly from 6.3.0 to 6.3.1
Bumps [plotly](https://github.com/plotly/plotly.py) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/plotly/plotly.py/releases)
- [Changelog](https://github.com/plotly/plotly.py/blob/main/CHANGELOG.md)
- [Commits](https://github.com/plotly/plotly.py/compare/v6.3.0...v6.3.1)

---
updated-dependencies:
- dependency-name: plotly
  dependency-version: 6.3.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:03:03 +00:00
dependabot[bot] d6218892bf chore(deps-dev): bump isort from 6.0.1 to 6.1.0
Bumps [isort](https://github.com/PyCQA/isort) from 6.0.1 to 6.1.0.
- [Release notes](https://github.com/PyCQA/isort/releases)
- [Changelog](https://github.com/PyCQA/isort/blob/main/CHANGELOG.md)
- [Commits](https://github.com/PyCQA/isort/compare/6.0.1...6.1.0)

---
updated-dependencies:
- dependency-name: isort
  dependency-version: 6.1.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:02:55 +00:00
dependabot[bot] 4608279305 chore(deps-dev): bump ruff from 0.13.2 to 0.13.3
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.13.2 to 0.13.3.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.13.2...0.13.3)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.13.3
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:02:49 +00:00
dependabot[bot] bbd7a19ef9 chore(deps): bump cryptography from 46.0.1 to 46.0.2
Bumps [cryptography](https://github.com/pyca/cryptography) from 46.0.1 to 46.0.2.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/46.0.1...46.0.2)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-version: 46.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:02:24 +00:00
dependabot[bot] 9a95ad1435 chore(deps): bump certifi from 2025.8.3 to 2025.10.5
Bumps [certifi](https://github.com/certifi/python-certifi) from 2025.8.3 to 2025.10.5.
- [Commits](https://github.com/certifi/python-certifi/compare/2025.08.03...2025.10.05)

---
updated-dependencies:
- dependency-name: certifi
  dependency-version: 2025.10.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:02:19 +00:00
dependabot[bot] 5bd42d5625 chore(deps): bump numexpr from 2.13.0 to 2.13.1
Bumps [numexpr](https://github.com/pydata/numexpr) from 2.13.0 to 2.13.1.
- [Release notes](https://github.com/pydata/numexpr/releases)
- [Changelog](https://github.com/pydata/numexpr/blob/master/RELEASE_NOTES.rst)
- [Commits](https://github.com/pydata/numexpr/compare/v2.13.0...v2.13.1)

---
updated-dependencies:
- dependency-name: numexpr
  dependency-version: 2.13.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:02:07 +00:00
dependabot[bot] 0c446d45df chore(deps): bump fastapi from 0.117.1 to 0.118.0
Bumps [fastapi](https://github.com/fastapi/fastapi) from 0.117.1 to 0.118.0.
- [Release notes](https://github.com/fastapi/fastapi/releases)
- [Commits](https://github.com/fastapi/fastapi/compare/0.117.1...0.118.0)

---
updated-dependencies:
- dependency-name: fastapi
  dependency-version: 0.118.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:02:01 +00:00
dependabot[bot] 2bfc8d86a9 chore(deps): bump docker/login-action from 3.5.0 to 3.6.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.5.0 to 3.6.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/184bdaa0721073962dff0199f1fb9940f07167d1...5e57cd118135c172c3672efd75eb46360885c0ef)

---
updated-dependencies:
- dependency-name: docker/login-action
  dependency-version: 3.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:01:53 +00:00
dependabot[bot] 98ab14f67e chore(deps): bump peter-evans/dockerhub-description from 4.0.2 to 5.0.0
Bumps [peter-evans/dockerhub-description](https://github.com/peter-evans/dockerhub-description) from 4.0.2 to 5.0.0.
- [Release notes](https://github.com/peter-evans/dockerhub-description/releases)
- [Commits](https://github.com/peter-evans/dockerhub-description/compare/432a30c9e07499fd01da9f8a49f0faf9e0ca5b77...1b9a80c056b620d92cedb9d9b5a223409c68ddfa)

---
updated-dependencies:
- dependency-name: peter-evans/dockerhub-description
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:01:48 +00:00
dependabot[bot] 845e96f12e chore(deps): bump astral-sh/setup-uv from 6.7.0 to 6.8.0
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.7.0 to 6.8.0.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/b75a909f75acd358c2196fb9a5f1299a9a8868a4...d0cc045d04ccac9d8b7881df0226f9e82c39688e)

---
updated-dependencies:
- dependency-name: astral-sh/setup-uv
  dependency-version: 6.8.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:01:45 +00:00
dependabot[bot] 1ad75f5ec5 chore(deps): bump mkdocs-material in the mkdocs group
Bumps the mkdocs group with 1 update: [mkdocs-material](https://github.com/squidfunk/mkdocs-material).


Updates `mkdocs-material` from 9.6.20 to 9.6.21
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.20...9.6.21)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-version: 9.6.21
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: mkdocs
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-06 03:01:44 +00:00
Matthias 89b6e69340 Merge pull request #12311 from freqtrade/fix/allow-override
fix: Allow users to override the exchange check for FreqAI incase the…
2025-10-05 08:09:28 +02:00
Matthias 2d40807b66 chore: fix description typo 2025-10-05 07:56:42 +02:00
Matthias 8e44bc48b8 docs: update IOC documentation
related: #12322
2025-10-04 11:45:09 +02:00
Matthias 082fd0fd8b fix: "taker" may not always be filled for futures pairs
Gate fee removal:  https://github.com/ccxt/ccxt/pull/14271
2025-10-03 18:25:13 +02:00
Matthias 9e4af4f8ad Merge pull request #12321 from stash86/main-stash
fix typo
2025-10-03 18:02:05 +02:00
Stefano 0740f87a32 fix typo 2025-10-03 15:38:19 +09:00
Matthias 5542febef6 Merge pull request #12309 from freqtrade/feat/hyperliquid_cross
hyperliquid cross futures support
2025-10-02 18:06:47 +02:00
Matthias 4eba2c6a24 fix: bitvavo is now using tick-size for pricing and amount rounding 2025-10-02 07:20:30 +02:00
Matthias e654c29c82 chore: bump ccxt to 4.5.7 2025-10-02 07:20:30 +02:00
Matthias 0bcd6e078b Merge pull request #12316 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-10-02 06:39:42 +02:00
Freqtrade Bot 4698c0a066 chore: update pre-commit hooks 2025-10-02 03:12:18 +00:00
Robert Caulk 70fa12f1b2 chore: log a warning that the user is in territory that might not work. 2025-10-01 16:36:55 +02:00
Robert Caulk 8d86cc1173 fix: Allow users to override the exchange check for FreqAI incase they know that they dont need historic data for their system 2025-10-01 16:34:10 +02:00
Matthias c7aaa77e44 test: test cross margin calc for hyperliquid 2025-09-30 20:39:40 +02:00
Matthias 1e8252ffcc test: simplify hyperliquid test 2025-09-30 20:33:13 +02:00
Matthias 361b34641c chore: simplify hyperliquid dry-run calc 2025-09-30 20:33:03 +02:00
Matthias 88c0c3503f docs: Add cross margin warning note 2025-09-30 19:50:50 +02:00
Matthias 102fc3e184 test: add basic online tests for coinex exchange 2025-09-30 19:23:02 +02:00
Matthias abd02979dd feat: add coinex subclass
closes #12306
2025-09-30 19:22:52 +02:00
Matthias f6c4227ca6 feat: Add documentation to hyperliquid liquidation calc 2025-09-30 07:05:32 +02:00
Matthias d6bc8f4a24 docs: enable hyperliquid cross 2025-09-30 06:47:09 +02:00
Matthias a9c3799547 feat: enable hyperliquid cross futures 2025-09-30 06:34:05 +02:00
Matthias 3ea4603d1c Merge pull request #12305 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-09-30 06:26:21 +02:00
Freqtrade Bot 84dfb035b1 chore: update pre-commit hooks 2025-09-30 03:14:01 +00:00
Matthias aacd8f49f4 chore: bump develop version to 2025.10-dev 2025-09-29 19:36:39 +02:00
Matthias 5363ee7198 chore(deps): bump ft-pandas-ta from 0.3.15 to 0.3.16 2025-09-29 18:16:03 +02:00
Matthias 4b78ba42b1 Merge pull request #12302 from freqtrade/dependabot/pip/develop/ccxt-4.5.6
chore(deps): bump ccxt from 4.5.5 to 4.5.6
2025-09-29 06:32:55 +02:00
dependabot[bot] 567f118ce1 chore(deps): bump ccxt from 4.5.5 to 4.5.6
Bumps [ccxt](https://github.com/ccxt/ccxt) from 4.5.5 to 4.5.6.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg)
- [Commits](https://github.com/ccxt/ccxt/compare/v4.5.5...v4.5.6)

---
updated-dependencies:
- dependency-name: ccxt
  dependency-version: 4.5.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-29 04:32:53 +00:00
Matthias 230e892482 Merge pull request #12298 from freqtrade/dependabot/pip/develop/uvicorn-0.37.0
chore(deps): bump uvicorn from 0.36.0 to 0.37.0
2025-09-29 06:32:02 +02:00
Matthias 9e616e81ad Merge pull request #12303 from freqtrade/dependabot/pip/develop/python-telegram-bot-22.5
chore(deps): bump python-telegram-bot from 22.4 to 22.5
2025-09-29 06:31:39 +02:00
Matthias d1e055c015 Merge pull request #12301 from freqtrade/dependabot/pip/develop/ruff-0.13.2
chore(deps-dev): bump ruff from 0.13.1 to 0.13.2
2025-09-29 06:30:26 +02:00
Matthias 3bcd6694b7 Merge pull request #12300 from freqtrade/dependabot/pip/develop/numexpr-2.13.0
chore(deps): bump numexpr from 2.12.1 to 2.13.0
2025-09-29 06:30:18 +02:00
dependabot[bot] 86d8fc5ee3 chore(deps): bump python-telegram-bot from 22.4 to 22.5
Bumps [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) from 22.4 to 22.5.
- [Release notes](https://github.com/python-telegram-bot/python-telegram-bot/releases)
- [Commits](https://github.com/python-telegram-bot/python-telegram-bot/compare/v22.4...v22.5)

---
updated-dependencies:
- dependency-name: python-telegram-bot
  dependency-version: '22.5'
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-29 03:17:24 +00:00
dependabot[bot] 78f291264e chore(deps-dev): bump ruff from 0.13.1 to 0.13.2
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.13.1 to 0.13.2.
- [Release notes](https://github.com/astral-sh/ruff/releases)
- [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md)
- [Commits](https://github.com/astral-sh/ruff/compare/0.13.1...0.13.2)

---
updated-dependencies:
- dependency-name: ruff
  dependency-version: 0.13.2
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-29 03:13:53 +00:00
dependabot[bot] fdc3c7ba09 chore(deps): bump numexpr from 2.12.1 to 2.13.0
Bumps [numexpr](https://github.com/pydata/numexpr) from 2.12.1 to 2.13.0.
- [Release notes](https://github.com/pydata/numexpr/releases)
- [Changelog](https://github.com/pydata/numexpr/blob/master/RELEASE_NOTES.rst)
- [Commits](https://github.com/pydata/numexpr/compare/v2.12.1...v2.13.0)

---
updated-dependencies:
- dependency-name: numexpr
  dependency-version: 2.13.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-29 03:12:41 +00:00
dependabot[bot] f8621e850f chore(deps): bump uvicorn from 0.36.0 to 0.37.0
Bumps [uvicorn](https://github.com/Kludex/uvicorn) from 0.36.0 to 0.37.0.
- [Release notes](https://github.com/Kludex/uvicorn/releases)
- [Changelog](https://github.com/Kludex/uvicorn/blob/main/docs/release-notes.md)
- [Commits](https://github.com/Kludex/uvicorn/compare/0.36.0...0.37.0)

---
updated-dependencies:
- dependency-name: uvicorn
  dependency-version: 0.37.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-29 03:11:27 +00:00
mrpabloyeah c1cd14cad2 Remove internal or useless attributes and unnecessary text 2025-09-23 01:01:36 +02:00
mrpabloyeah 565b343dee Update documentation for Trade and Order objects 2025-09-22 19:38:49 +02:00
Matthias 0ca846b2c5 test: update test comment 2025-09-14 10:34:11 +02:00
Matthias 747eac0417 chore: update code to use at
which has better performance than chaining iloc and column selection
2025-09-14 10:33:43 +02:00
Matthias 88cc24c5b9 chore: fix odd code comment 2025-09-14 10:33:28 +02:00
Matthias 0111e97856 test: update test 2025-09-14 10:33:09 +02:00
Mihail 70d7dcd189 Made test_merge_informative_pair_monthly asserts data dependent. 2025-09-03 19:55:37 +00:00
Mihail d36fdc1d69 Added exact dates to test_merge_informative_pair_monthly. 2025-09-03 12:20:38 +00:00
Mihail b9482f420d Changed test_merge_informative_pair_monthly test to contain the data from previous informative candle on start too. 2025-09-02 19:25:08 +00:00
Mihail 3fe721a772 Fix for merge_informative_pair fix. 2025-09-02 18:33:23 +00:00
Mihail a53c4a3ed1 Fix the truncation of values by merge_ordered in the merge_informative_pair helper. 2025-09-02 15:35:20 +03:00
102 changed files with 9537 additions and 4036 deletions
+16
View File
@@ -1,6 +1,8 @@
version: 2
updates:
- package-ecosystem: docker
cooldown:
default-days: 4
directories:
- "/"
- "/docker"
@@ -11,8 +13,20 @@ updates:
update-types: ["version-update:semver-major"]
open-pull-requests-limit: 10
- package-ecosystem: devcontainers
directory: "/"
cooldown:
default-days: 4
schedule:
interval: daily
open-pull-requests-limit: 10
- package-ecosystem: pip
directory: "/"
cooldown:
default-days: 4
exclude:
- ccxt
schedule:
interval: weekly
time: "03:00"
@@ -36,6 +50,8 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
cooldown:
default-days: 4
schedule:
interval: "weekly"
open-pull-requests-limit: 10
+3 -3
View File
@@ -38,7 +38,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0
uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0
with:
activate-environment: true
enable-cache: true
@@ -248,7 +248,7 @@ jobs:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@b75a909f75acd358c2196fb9a5f1299a9a8868a4 # v6.7.0
uses: astral-sh/setup-uv@3259c6206f993105e3a61b142c2d97bf4b9ef83d # v7.1.0
with:
activate-environment: true
enable-cache: true
@@ -265,7 +265,7 @@ jobs:
- name: Tests incl. ccxt compatibility tests
env:
CI_WEB_PROXY: http://152.67.78.211:13128
CI_WEB_PROXY: http://152.67.66.8:13128
run: |
pytest --random-order --longrun --durations 20 -n auto
+1 -1
View File
@@ -28,7 +28,7 @@ jobs:
with:
persist-credentials: false
- name: Login to GitHub Container Registry
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
+3 -3
View File
@@ -42,7 +42,7 @@ jobs:
uses: ./.github/actions/docker-tags
- name: Login to Docker Hub
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
@@ -161,13 +161,13 @@ jobs:
uses: ./.github/actions/docker-tags
- name: Login to Docker Hub
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Login to github
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
persist-credentials: false
- name: Docker Hub Description
uses: peter-evans/dockerhub-description@432a30c9e07499fd01da9f8a49f0faf9e0ca5b77 # v4.0.2
uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5.0.0
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
+1 -1
View File
@@ -21,7 +21,7 @@ jobs:
# actions: read # only needed for private repos
steps:
- name: Checkout repository
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
with:
persist-credentials: false
+8 -8
View File
@@ -26,17 +26,17 @@ repos:
- id: mypy
exclude: build_helpers
additional_dependencies:
- types-cachetools==6.2.0.20250827
- types-cachetools==6.2.0.20251022
- types-filelock==3.2.7
- types-requests==2.32.4.20250913
- types-tabulate==0.9.0.20241207
- types-python-dateutil==2.9.0.20250822
- scipy-stubs==1.16.2.0
- SQLAlchemy==2.0.43
- types-python-dateutil==2.9.0.20251008
- scipy-stubs==1.16.2.4
- SQLAlchemy==2.0.44
# stages: [push]
- repo: https://github.com/pycqa/isort
rev: "6.0.1"
rev: "7.0.0"
hooks:
- id: isort
name: isort (python)
@@ -44,7 +44,7 @@ repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.13.1'
rev: 'v0.14.2'
hooks:
- id: ruff
- id: ruff-format
@@ -70,7 +70,7 @@ repos:
)$
- repo: https://github.com/stefmolin/exif-stripper
rev: 1.1.0
rev: 1.2.0
hooks:
- id: strip-exif
@@ -83,6 +83,6 @@ repos:
# Ensure github actions remain safe
- repo: https://github.com/woodruffw/zizmor-pre-commit
rev: v1.13.0
rev: v1.16.0
hooks:
- id: zizmor
+1 -1
View File
@@ -127,7 +127,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. Both 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.
+1 -1
View File
@@ -1,4 +1,4 @@
FROM python:3.13.7-slim-bookworm AS base
FROM python:3.13.8-slim-bookworm AS base
# Setup env
ENV LANG=C.UTF-8
+3 -1
View File
@@ -27,8 +27,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] [Bitmart](https://bitmart.com/)
- [X] [BingX](https://bingx.com/invite/0EM9RX)
- [X] [Bitget](https://www.bitget.com/)
- [X] [Bitmart](https://bitmart.com/)
- [X] [Bybit](https://bybit.com/)
- [X] [Gate.io](https://www.gate.io/ref/6266643)
- [X] [HTX](https://www.htx.com/)
@@ -41,6 +42,7 @@ Please read the [exchange specific notes](docs/exchanges.md) to learn about even
### Supported Futures Exchanges (experimental)
- [X] [Binance](https://www.binance.com/)
- [X] [Bitget](https://www.bitget.com/)
- [X] [Gate.io](https://www.gate.io/ref/6266643)
- [X] [Hyperliquid](https://hyperliquid.xyz/) (A decentralized exchange, or DEX)
- [X] [OKX](https://okx.com/)
+7 -1
View File
@@ -268,7 +268,8 @@
"day",
"week",
"month",
"year"
"year",
"weekday"
]
}
},
@@ -1461,6 +1462,11 @@
"type": "boolean",
"default": false
},
"override_exchange_check": {
"description": "Override the exchange check to force FreqAI to use exchanges that may not have enough historic data. Turn this to True if you know your FreqAI model and strategy do not require historical data.",
"type": "boolean",
"default": false
},
"feature_parameters": {
"description": "The parameters used to engineer the feature set",
"type": "object",
+2 -2
View File
@@ -134,10 +134,10 @@ The following systems have been tested and are known to work with freqtrade:
### PostgreSQL
Installation:
`pip install psycopg2-binary`
`pip install "psycopg[binary]"`
Usage:
`... --db-url postgresql+psycopg2://<username>:<password>@localhost:5432/<database>`
`... --db-url postgresql+psycopg://<username>:<password>@localhost:5432/<database>`
Freqtrade will automatically create the tables necessary upon startup.
+3 -3
View File
@@ -4,7 +4,7 @@ usage: freqtrade backtesting-show [-h] [-v] [--no-color] [--logfile FILE] [-V]
[--backtest-filename PATH]
[--backtest-directory PATH]
[--show-pair-list]
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
[--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]]
options:
-h, --help show this help message and exit
@@ -18,9 +18,9 @@ options:
Directory to use for backtest results. Example:
`--export-directory=user_data/backtest_results/`.
--show-pair-list Show backtesting pairlist sorted by profit.
--breakdown {day,week,month,year} [{day,week,month,year} ...]
--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]
Show backtesting breakdown per [day, week, month,
year].
year, weekday].
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
+3 -3
View File
@@ -17,7 +17,7 @@ usage: freqtrade backtesting [-h] [-v] [--no-color] [--logfile FILE] [-V]
[--export {none,trades,signals}]
[--backtest-filename PATH]
[--backtest-directory PATH]
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
[--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]]
[--cache {none,day,week,month}]
[--freqai-backtest-live-models] [--notes TEXT]
@@ -77,9 +77,9 @@ options:
--backtest-directory PATH, --export-directory PATH
Directory to use for backtest results. Example:
`--export-directory=user_data/backtest_results/`.
--breakdown {day,week,month,year} [{day,week,month,year} ...]
--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]
Show backtesting breakdown per [day, week, month,
year].
year, weekday].
--cache {none,day,week,month}
Load a cached backtest result no older than specified
age (default: day).
+3 -3
View File
@@ -4,7 +4,7 @@ usage: freqtrade hyperopt-show [-h] [-v] [--no-color] [--logfile FILE] [-V]
[--profitable] [-n INT] [--print-json]
[--hyperopt-filename FILENAME] [--no-header]
[--disable-param-export]
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
[--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]]
options:
-h, --help show this help message and exit
@@ -18,9 +18,9 @@ options:
--no-header Do not print epoch details header.
--disable-param-export
Disable automatic hyperopt parameter export.
--breakdown {day,week,month,year} [{day,week,month,year} ...]
--breakdown {day,week,month,year,weekday} [{day,week,month,year,weekday} ...]
Show backtesting breakdown per [day, week, month,
year].
year, weekday].
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
+4 -5
View File
@@ -571,9 +571,7 @@ Commonly used time in force are:
**GTC (Good Till Canceled):**
This is most of the time the default time in force. It means the order will remain
on exchange till it is cancelled by the user. It can be fully or partially fulfilled.
If partially fulfilled, the remaining will stay on the exchange till cancelled.
This is most of the time the default time in force. It means the order will remain on exchange till it is cancelled by the user. It can be fully or partially fulfilled. If partially fulfilled, the remaining will stay on the exchange till cancelled.
**FOK (Fill Or Kill):**
@@ -581,8 +579,9 @@ It means if the order is not executed immediately AND fully then it is cancelled
**IOC (Immediate Or Canceled):**
It is the same as FOK (above) except it can be partially fulfilled. The remaining part
is automatically cancelled by the exchange.
It is the same as FOK (above) except it can be partially fulfilled. The remaining part is automatically cancelled by the exchange.
Not necessarily recommended, as this can lead to partial fills below the minimum trade size.
**PO (Post only):**
+16 -5
View File
@@ -298,7 +298,14 @@ Without these permissions, the bot will not start correctly and show errors like
Bybit supports [time_in_force](configuration.md#understand-order_time_in_force) with settings "GTC" (good till cancelled), "FOK" (full-or-cancel), "IOC" (immediate-or-cancel) and "PO" (Post only) settings.
Futures trading on bybit is currently supported for isolated futures mode.
!!! Warning "Unified accounts"
Freqtrade assumes accounts to be dedicated to the bot.
We therefore recommend the usage of one subaccount per bot. This is especially important when using unified accounts.
Other configurations (multiple bots on one account, manual non-bot trades on the bot account) are not supported and may lead to unexpected behavior.
### Bybit Futures
Futures trading on bybit is supported for isolated futures mode.
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 manual changes to this setting may result in exceptions and errors.
@@ -312,10 +319,6 @@ API Keys for live futures trading must have the following permissions:
We do strongly recommend to limit all API keys to the IP you're going to use it from.
!!! Warning "Unified accounts"
Freqtrade assumes accounts to be dedicated to the bot.
We therefore recommend the usage of one subaccount per bot. This is especially important when using unified accounts.
Other configurations (multiple bots on one account, manual non-bot trades on the bot account) are not supported and may lead to unexpected behavior.
## Bitmart
@@ -355,6 +358,12 @@ Bitget supports [time_in_force](configuration.md#understand-order_time_in_force)
Bitget 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.
### Bitget Futures
Futures trading on bitget is supported for isolated futures mode.
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 manual changes to this setting may result in exceptions and errors.
## Hyperliquid
!!! Tip "Stoploss on Exchange"
@@ -478,3 +487,5 @@ For example, to test the order type `FOK` with Kraken, and modify candle limit t
!!! Warning
Please make sure to fully understand the impacts of these settings before modifying them.
Using `_ft_has_params` overrides may lead to unexpected behavior, and may even break your bot.
We will not be able to provide support for issues caused by custom settings in `_ft_has_params`.
+1 -1
View File
@@ -79,7 +79,7 @@ Mandatory parameters are marked as **Required** and have to be set in one of the
| `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 documentation. [PPO doc](https://stable-baselines3.readthedocs.io/en/master/modules/ppo.html) (external website) <br> **Datatype:** string.
| `policy_type` | One of the available policy types from stable_baselines3 <br> **Datatype:** string.
| `max_training_drawdown_pct` | The maximum drawdown that the agent is allowed to experience during training. <br> **Datatype:** float. <br> 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. <br> **Datatype:** int.
| `cpu_count` | Number of threads/cpus to dedicate to the Reinforcement Learning training process (depending on if `ReinforcementLearner_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. <br> **Datatype:** int.
| `model_reward_parameters` | Parameters used inside the customizable `calculate_reward()` function in `ReinforcementLearner.py` <br> **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. <br> **Datatype:** bool. <br> 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: `[<shared layers>, dict(vf=[<non-shared value network layers>], pi=[<non-shared policy network layers>])]`. By default this is set to `[128, 128]`, which defines 2 shared hidden layers with 128 units each.
+3 -3
View File
@@ -7,7 +7,7 @@
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/).
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:
@@ -81,9 +81,9 @@ If you are using docker, a dedicated tag with FreqAI dependencies is available a
!!! 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
### 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 "citizen 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.
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 "citizen 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
+3 -1
View File
@@ -5,13 +5,15 @@
| [Binance](exchanges.md#binance) | futures | isolated, cross | market, limit |
| [Bingx](exchanges.md#bingx) | spot | | market, limit |
| [Bitmart](exchanges.md#bitmart) | spot | | ❌ (not supported) |
| [Bitget](exchanges.md#bitget) | spot | | market, limit |
| [Bitget](exchanges.md#bitget) | futures | isolated | market, limit |
| [Bybit](exchanges.md#bybit) | spot | | ❌ (not supported) |
| [Bybit](exchanges.md#bybit) | futures | isolated | market, limit |
| [Gate.io](exchanges.md#gateio) | spot | | limit |
| [Gate.io](exchanges.md#gateio) | futures | isolated | limit |
| [HTX](exchanges.md#htx) | spot | | limit |
| [Hyperliquid](exchanges.md#hyperliquid) | spot | | ❌ (not supported) |
| [Hyperliquid](exchanges.md#hyperliquid) | futures | isolated | limit |
| [Hyperliquid](exchanges.md#hyperliquid) | futures | isolated, cross | limit |
| [Kraken](exchanges.md#kraken) | spot | | market, limit |
| [OKX](exchanges.md#okx) | spot | | limit |
| [OKX](exchanges.md#okx) | futures | isolated | limit |
+2
View File
@@ -39,6 +39,7 @@ Please read the [exchange specific notes](exchanges.md) to learn about eventual,
- [X] [Binance](https://www.binance.com/)
- [X] [BingX](https://bingx.com/invite/0EM9RX)
- [X] [Bitget](https://www.bitget.com/)
- [X] [Bitmart](https://bitmart.com/)
- [X] [Bybit](https://bybit.com/)
- [X] [Gate.io](https://www.gate.io/ref/6266643)
@@ -52,6 +53,7 @@ Please read the [exchange specific notes](exchanges.md) to learn about eventual,
### Supported Futures Exchanges (experimental)
- [X] [Binance](https://www.binance.com/)
- [X] [Bitget](https://www.bitget.com/)
- [X] [Bybit](https://bybit.com/)
- [X] [Gate.io](https://www.gate.io/ref/6266643)
- [X] [Hyperliquid](https://hyperliquid.xyz/) (A decentralized exchange, or DEX)
+1 -1
View File
@@ -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.11 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.
Either [uv](https://docs.astral.sh/uv/), or Python3.11 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<yourversion>-dev` / `python<yourversion>-devel`) must be available for the installation to complete successfully.
!!! Warning "Up-to-date clock"
+7 -2
View File
@@ -17,7 +17,7 @@ If you already have an existing strategy, please read the [strategy migration gu
## Shorting
Shorting is not possible when trading with [`trading_mode`](#leverage-trading-modes) set to `spot`. To short trade, `trading_mode` must be set to `margin`(currently unavailable) or [`futures`](#futures), with [`margin_mode`](#margin-mode) set to `cross`(currently unavailable) or [`isolated`](#isolated-margin-mode)
Shorting is not possible when trading with [`trading_mode`](#leverage-trading-modes) set to `spot`. To short trade, `trading_mode` must be set to `margin`(currently unavailable) or [`futures`](#futures), with [`margin_mode`](#margin-mode) set to [`cross`](#cross-margin-mode) or [`isolated`](#isolated-margin-mode)
For a strategy to short, the strategy class must set the class variable `can_short = True`
@@ -72,7 +72,7 @@ A futures pair will therefore have the naming of `base/quote:settle` (e.g. `ETH/
On top of `trading_mode` - you will also have to configure your `margin_mode`.
While freqtrade currently only supports one margin mode, this will change, and by configuring it now you're all set for future updates.
The possible values are: `isolated`, or `cross`(*currently unavailable*).
The possible values are: `isolated`, or `cross`.
#### Isolated margin mode
@@ -92,6 +92,11 @@ One account is used to share collateral between markets (trading pairs). Margin
Please read the [exchange specific notes](exchanges.md) for exchanges that support this mode and how they differ.
!!! Warning "Increased risk of liquidation"
Cross margin mode increases the risk of full account liquidation, as all trades share the same collateral.
A loss on one trade can affect the liquidation price of other trades.
Also, cross-position influence may not be fully simulated in dry-run or backtesting mode.
## Set leverage to use
Different strategies and risk profiles will require different levels of leverage.
+1 -1
View File
@@ -1,6 +1,6 @@
markdown==3.9
mkdocs==1.6.1
mkdocs-material==9.6.20
mkdocs-material==9.6.22
mdx_truly_sane_lists==1.3
pymdown-extensions==10.16.1
jinja2==3.1.6
+26 -4
View File
@@ -1253,9 +1253,13 @@ The plot annotations callback is called whenever freqUI requests data to display
This callback has no meaning in the trade cycle context and is only used for charting purposes.
The strategy can then return a list of `AnnotationType` objects to be displayed on the chart.
Depending on the content returned - the chart can display horizontal areas, vertical areas, or boxes.
Depending on the content returned - the chart can display horizontal areas, vertical areas, boxes or lines.
The full object looks like this:
### Annotation types
Currently two types of annotations are supported, `area` and `line`.
#### Area
``` json
{
@@ -1270,6 +1274,24 @@ The full object looks like this:
}
```
#### Line
``` json
{
"type": "line", // Type of the annotation, currently only "line" is supported
"start": "2024-01-01 15:00:00", // Start date of the line
"end": "2024-01-01 16:00:00", // End date of the line
"y_start": 94000.2, // Price / y axis value
"y_end": 98000, // Price / y axis value
"color": "",
"z_level": 5, // z-level, higher values are drawn on top of lower values. Positions relative to the Chart elements need to be set in freqUI.
"label": "some label",
"width": 2, // Optional, line width in pixels. Defaults to 1
"line_style": "dashed", // Optional, can be "solid", "dashed" or "dotted". Defaults to "solid"
}
```
The below example will mark the chart with areas for the hours 8 and 15, with a grey color, highlighting the market open and close hours.
This is obviously a very basic example.
@@ -1337,7 +1359,7 @@ Entries will be validated, and won't be passed to the UI if they don't correspon
while start_dt < end_date:
start_dt += timedelta(hours=1)
if (start_dt.hour % 4) == 0:
mark_areas.append(
annotations.append(
{
"type": "area",
"label": "4h",
@@ -1348,7 +1370,7 @@ Entries will be validated, and won't be passed to the UI if they don't correspon
)
elif (start_dt.hour % 2) == 0:
price = dataframe.loc[dataframe["date"] == start_dt, ["close"]].mean()
mark_areas.append(
annotations.append(
{
"type": "area",
"label": "2h",
+73 -5
View File
@@ -14,11 +14,20 @@ The following attributes / properties are available for each individual trade -
| Attribute | DataType | Description |
|------------|-------------|-------------|
| `pair` | string | Pair of this trade. |
| `safe_base_currency` | string | Compatibility layer for base currency . |
| `safe_quote_currency` | string | Compatibility layer for quote currency. |
| `is_open` | boolean | Is the trade currently open, or has it been concluded. |
| `exchange` | string | Exchange where this trade was executed. |
| `open_rate` | float | Rate this trade was entered at (Avg. entry rate in case of trade-adjustments). |
| `open_rate_requested` | float | The rate that was requested when the trade was opened. |
| `open_trade_value` | float | Value of the open trade including fees. |
| `close_rate` | float | Close rate - only set when is_open = False. |
| `close_rate_requested` | float | The close rate that was requested. |
| `safe_close_rate` | float | Close rate or `close_rate_requested` or 0.0 if neither is available. Only makes sense once the trade is closed. |
| `stake_amount` | float | Amount in Stake (or Quote) currency. |
| `max_stake_amount` | float | Maximum stake amount that was used in this trade (sum of all filled Entry orders). |
| `amount` | float | Amount in Asset / Base currency that is currently owned. Will be 0.0 until the initial order fills. |
| `amount_requested` | float | Amount that was originally requested for this trade as part of the first entry order. |
| `open_date` | datetime | Timestamp when trade was opened **use `open_date_utc` instead** |
| `open_date_utc` | datetime | Timestamp when trade was opened - in UTC. |
| `close_date` | datetime | Timestamp when trade was closed **use `close_date_utc` instead** |
@@ -28,15 +37,47 @@ The following attributes / properties are available for each individual trade -
| `realized_profit` | float | Absolute already realized profit (in stake currency) while the trade is still open. |
| `leverage` | float | Leverage used for this trade - defaults to 1.0 in spot markets. |
| `enter_tag` | string | Tag provided on entry via the `enter_tag` column in the dataframe. |
| `exit_reason` | string | Reason why the trade was exited. |
| `exit_order_status` | string | Status of the exit order. |
| `strategy` | string | Strategy name that was used for this trade. |
| `timeframe` | int | Timeframe used for this trade. |
| `is_short` | boolean | True for short trades, False otherwise. |
| `orders` | Order[] | List of order objects attached to this trade (includes both filled and cancelled orders). |
| `date_last_filled_utc` | datetime | Time of the last filled order. |
| `date_entry_fill_utc` | datetime | Date of the first filled entry order. |
| `entry_side` | "buy" / "sell" | Order Side the trade was entered. |
| `exit_side` | "buy" / "sell" | Order Side that will result in a trade exit / position reduction. |
| `trade_direction` | "long" / "short" | Trade direction in text - long or short. |
| `max_rate` | float | Highest price reached during this trade. Not 100% accurate. |
| `min_rate` | float | Lowest price reached during this trade. Not 100% accurate. |
| `nr_of_successful_entries` | int | Number of successful (filled) entry orders. |
| `nr_of_successful_exits` | int | Number of successful (filled) exit orders. |
| `has_open_position` | boolean | True if there is an open position (amount > 0) for this trade. Only false while the initial entry order is unfilled. |
| `has_open_orders` | boolean | Has the trade open orders (excluding stoploss orders). |
| `has_open_sl_orders` | boolean | True if there are open stoploss orders for this trade. |
| `open_orders` | Order[] | All open orders for this trade excluding stoploss orders. |
| `open_sl_orders` | Order[] | All open stoploss orders for this trade. |
| `fully_canceled_entry_order_count` | int | Number of fully canceled entry orders. |
| `canceled_exit_order_count` | int | Number of canceled exit orders. |
### Stop Loss related attributes
| Attribute | DataType | Description |
|------------|-------------|-------------|
| `stop_loss` | float | Absolute value of the stop loss. |
| `stop_loss_pct` | float | Relative value of the stop loss. |
| `initial_stop_loss` | float | Absolute value of the initial stop loss. |
| `initial_stop_loss_pct` | float | Relative value of the initial stop loss. |
| `stoploss_last_update_utc` | datetime | Timestamp of the last stoploss on exchange order update. |
| `stoploss_or_liquidation` | float | Returns the more restrictive of stoploss or liquidation price and corresponds to the price a stoploss would trigger at. |
### Futures/Margin trading attributes
| Attribute | DataType | Description |
|------------|-------------|-------------|
| `liquidation_price` | float | Liquidation price for leveraged trades. |
| `interest_rate` | float | Interest rate for margin trades. |
| `funding_fees` | float | Total funding fees for futures trades. |
## Class methods
@@ -102,6 +143,10 @@ from freqtrade.persistence import Trade
profit = Trade.total_open_trades_stakes()
```
## Class methods not supported in backtesting/hyperopt
The following class methods are not supported in backtesting/hyperopt mode.
### get_overall_performance
Retrieve the overall performance - similar to the `/performance` telegram command.
@@ -120,6 +165,17 @@ Sample return value: ETH/BTC had 5 trades, with a total profit of 1.5% (ratio of
{"pair": "ETH/BTC", "profit": 0.015, "count": 5}
```
### get_trading_volume
Get total trading volume based on orders.
``` python
from freqtrade.persistence import Trade
# ...
volume = Trade.get_trading_volume()
```
## Order Object
An `Order` object represents an order on the exchange (or a simulated order in dry-run mode).
@@ -135,6 +191,10 @@ Most properties here can be None as they are dependent on the exchange response.
| `trade` | Trade | Trade object this order is attached to |
| `ft_pair` | string | Pair this order is for |
| `ft_is_open` | boolean | is the order still open? |
| `ft_order_side` | string | Order side ('buy', 'sell', or 'stoploss') |
| `ft_cancel_reason` | string | Reason why the order was canceled |
| `ft_order_tag` | string | Custom order tag |
| `order_id` | string | Exchange order ID |
| `order_type` | string | Order type as defined on the exchange - usually market, limit or stoploss |
| `status` | string | Status as defined by [ccxt's order structure](https://docs.ccxt.com/#/README?id=order-structure). Usually open, closed, expired, canceled or rejected |
| `side` | string | buy or sell |
@@ -143,12 +203,20 @@ Most properties here can be None as they are dependent on the exchange response.
| `amount` | float | Amount in base currency |
| `filled` | float | Filled amount (in base currency) (use `safe_filled` instead) |
| `safe_filled` | float | Filled amount (in base currency) - guaranteed to not be None |
| `safe_amount` | float | Amount - falls back to ft_amount if None |
| `safe_price` | float | Price - falls back through average, price, stop_price, ft_price |
| `safe_placement_price` | float | Price at which the order was placed |
| `remaining` | float | Remaining amount (use `safe_remaining` instead) |
| `safe_remaining` | float | Remaining amount - either taken from the exchange or calculated. |
| `cost` | float | Cost of the order - usually average * filled (*Exchange dependent on futures, may contain the cost with or without leverage and may be in contracts.*) |
| `stake_amount` | float | Stake amount used for this order. *Added in 2023.7.* |
| `stake_amount_filled` | float | Filled Stake amount used for this order. *Added in 2024.11.* |
| `safe_cost` | float | Cost of the order - guaranteed to not be None |
| `safe_fee_base` | float | Fee in base currency - guaranteed to not be None |
| `safe_amount_after_fee` | float | Amount after deducting fees |
| `cost` | float | Cost of the order - usually average * filled (*Exchange dependent on futures trading, may contain the cost with or without leverage and may be in contracts.*) |
| `stop_price` | float | Stop price for stop orders. Empty for non-stoploss orders. |
| `stake_amount` | float | Stake amount used for this order. |
| `stake_amount_filled` | float | Filled Stake amount used for this order. |
| `order_date` | datetime | Order creation date **use `order_date_utc` instead** |
| `order_date_utc` | datetime | Order creation date (in UTC) |
| `order_fill_date` | datetime | Order fill date **use `order_fill_utc` instead** |
| `order_fill_date_utc` | datetime | Order fill date |
| `order_filled_date` | datetime | Order fill date **use `order_filled_utc` instead** |
| `order_filled_utc` | datetime | Order fill date |
| `order_update_date` | datetime | Last order update date |
+1 -1
View File
@@ -1,6 +1,6 @@
"""Freqtrade bot"""
__version__ = "2025.9.1"
__version__ = "2025.10"
if "dev" in __version__:
from pathlib import Path
-1
View File
@@ -64,7 +64,6 @@ ARGS_BACKTEST = [
ARGS_HYPEROPT = [
*ARGS_COMMON_OPTIMIZE,
"hyperopt",
"hyperopt_path",
"position_stacking",
"enable_protections",
+2 -8
View File
@@ -2,7 +2,7 @@
Definition of cli arguments used in arguments.py
"""
from argparse import SUPPRESS, ArgumentTypeError
from argparse import ArgumentTypeError
from freqtrade import constants
from freqtrade.constants import HYPEROPT_LOSS_BUILTIN
@@ -245,7 +245,7 @@ AVAILABLE_CLI_OPTIONS = {
),
"backtest_breakdown": Arg(
"--breakdown",
help="Show backtesting breakdown per [day, week, month, year].",
help="Show backtesting breakdown per [day, week, month, year, weekday].",
nargs="+",
choices=constants.BACKTEST_BREAKDOWNS,
),
@@ -256,12 +256,6 @@ AVAILABLE_CLI_OPTIONS = {
choices=constants.BACKTEST_CACHE_AGE,
),
# Hyperopt
"hyperopt": Arg(
"--hyperopt",
help=SUPPRESS,
metavar="NAME",
required=False,
),
"hyperopt_path": Arg(
"--hyperopt-path",
help="Specify additional lookup path for Hyperopt Loss functions.",
+9
View File
@@ -1142,6 +1142,15 @@ CONF_SCHEMA = {
"type": "boolean",
"default": False,
},
"override_exchange_check": {
"description": (
"Override the exchange check to force FreqAI to use exchanges "
"that may not have enough historic data. Turn this to True if "
"you know your FreqAI model and strategy do not require historical data."
),
"type": "boolean",
"default": False,
},
"feature_parameters": {
"description": "The parameters used to engineer the feature set",
"type": "object",
+2 -3
View File
@@ -12,7 +12,7 @@ from typing import Any
from freqtrade import constants
from freqtrade.configuration.deprecated_settings import process_temporary_deprecated_settings
from freqtrade.configuration.directory_operations import create_datadir, create_userdata_dir
from freqtrade.configuration.environment_vars import enironment_vars_to_dict
from freqtrade.configuration.environment_vars import environment_vars_to_dict
from freqtrade.configuration.load_config import load_file, load_from_files
from freqtrade.constants import Config
from freqtrade.enums import (
@@ -80,7 +80,7 @@ class Configuration:
from freqtrade.commands.arguments import NO_CONF_ALLOWED
if self.args.get("command") not in NO_CONF_ALLOWED:
env_data = enironment_vars_to_dict()
env_data = environment_vars_to_dict()
config = deep_merge_dicts(env_data, config)
# Normalize config
@@ -336,7 +336,6 @@ class Configuration:
# Hyperopt section
configurations = [
("hyperopt", "Using Hyperopt class name: {}"),
("hyperopt_path", "Using additional Hyperopt lookup path: {}"),
("hyperoptexportfilename", "Using hyperopt file: {}"),
("lookahead_analysis_exportfilename", "Saving lookahead analysis results into {} ..."),
+1 -1
View File
@@ -73,7 +73,7 @@ def _flat_vars_to_nested_dict(env_dict: dict[str, Any], prefix: str) -> dict[str
return relevant_vars
def enironment_vars_to_dict() -> dict[str, Any]:
def environment_vars_to_dict() -> dict[str, Any]:
"""
Read environment variables and return a nested dict for relevant variables
Relevant variables must follow the FREQTRADE__{section}__{key} pattern
+1 -1
View File
@@ -61,7 +61,7 @@ AVAILABLE_PAIRLISTS = [
"VolatilityFilter",
]
AVAILABLE_DATAHANDLERS = ["json", "jsongz", "feather", "parquet"]
BACKTEST_BREAKDOWNS = ["day", "week", "month", "year"]
BACKTEST_BREAKDOWNS = ["day", "week", "month", "year", "weekday"]
BACKTEST_CACHE_AGE = ["none", "day", "week", "month"]
BACKTEST_CACHE_DEFAULT = "day"
DRY_RUN_WALLET = 1000
+2 -2
View File
@@ -511,8 +511,8 @@ def trade_list_to_dataframe(trades: list[Trade] | list[LocalTrade]) -> pd.DataFr
"""
df = pd.DataFrame.from_records([t.to_json(True) for t in trades], columns=BT_DATA_COLUMNS)
if len(df) > 0:
df["close_date"] = pd.to_datetime(df["close_date"], utc=True)
df["open_date"] = pd.to_datetime(df["open_date"], utc=True)
df["close_date"] = pd.to_datetime(df["close_timestamp"], unit="ms", utc=True)
df["open_date"] = pd.to_datetime(df["open_timestamp"], unit="ms", utc=True)
df["close_rate"] = df["close_rate"].astype("float64")
return df
+2 -1
View File
@@ -11,6 +11,7 @@ from freqtrade.exchange.bitmart import Bitmart
from freqtrade.exchange.bitpanda import Bitpanda
from freqtrade.exchange.bitvavo import Bitvavo
from freqtrade.exchange.bybit import Bybit
from freqtrade.exchange.coinex import Coinex
from freqtrade.exchange.cryptocom import Cryptocom
from freqtrade.exchange.exchange_utils import (
ROUND_DOWN,
@@ -46,4 +47,4 @@ from freqtrade.exchange.kucoin import Kucoin
from freqtrade.exchange.lbank import Lbank
from freqtrade.exchange.luno import Luno
from freqtrade.exchange.modetrade import Modetrade
from freqtrade.exchange.okx import MyOkx, Okx
from freqtrade.exchange.okx import Myokx, Okx, Okxus
+4
View File
@@ -28,6 +28,10 @@ logger = logging.getLogger(__name__)
class Binance(Exchange):
"""Binance exchange class.
Contains adjustments needed for Freqtrade to work with this exchange.
"""
_ft_has: FtHas = {
"stoploss_on_exchange": True,
"stop_price_param": "stopPrice",
File diff suppressed because it is too large Load Diff
+118 -8
View File
@@ -3,7 +3,8 @@ from datetime import timedelta
import ccxt
from freqtrade.enums import CandleType
from freqtrade.constants import BuySell
from freqtrade.enums import CandleType, MarginMode, TradingMode
from freqtrade.exceptions import (
DDosProtection,
OperationalException,
@@ -20,27 +21,30 @@ logger = logging.getLogger(__name__)
class Bitget(Exchange):
"""
Bitget exchange class. Contains adjustments needed for Freqtrade to work
with this exchange.
Please note that this exchange is not included in the list of exchanges
officially supported by the Freqtrade development team. So some features
may still not work as expected.
"""Bitget exchange class.
Contains adjustments needed for Freqtrade to work with this exchange.
"""
_ft_has: FtHas = {
"stoploss_on_exchange": True,
"stop_price_param": "stopPrice",
"stop_price_prop": "stopPrice",
"stoploss_blocks_assets": False, # Stoploss orders do not block assets
"stoploss_order_types": {"limit": "limit", "market": "market"},
"ohlcv_candle_limit": 200, # 200 for historical candles, 1000 for recent ones.
"order_time_in_force": ["GTC", "FOK", "IOC", "PO"],
}
_ft_has_futures: FtHas = {
"mark_ohlcv_timeframe": "4h",
"funding_fee_candle_limit": 100,
}
_supported_trading_mode_margin_pairs: list[tuple[TradingMode, MarginMode]] = [
(TradingMode.SPOT, MarginMode.NONE),
(TradingMode.FUTURES, MarginMode.ISOLATED),
# (TradingMode.FUTURES, MarginMode.CROSS),
]
def ohlcv_candle_limit(
self, timeframe: str, candle_type: CandleType, since_ms: int | None = None
) -> int:
@@ -126,3 +130,109 @@ class Bitget(Exchange):
def cancel_stoploss_order(self, order_id: str, pair: str, params: dict | None = None) -> dict:
return self.cancel_order(order_id=order_id, pair=pair, params={"stop": True})
@retrier
def additional_exchange_init(self) -> None:
"""
Additional exchange initialization logic.
.api will be available at this point.
Must be overridden in child methods if required.
"""
try:
if not self._config["dry_run"]:
if self.trading_mode == TradingMode.FUTURES:
position_mode = self._api.set_position_mode(False)
self._log_exchange_response("set_position_mode", position_mode)
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.OperationFailed, ccxt.ExchangeError) as e:
raise TemporaryError(
f"Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}"
) from e
except ccxt.BaseError as e:
raise OperationalException(e) from e
def _lev_prep(self, pair: str, leverage: float, side: BuySell, accept_fail: bool = False):
if self.trading_mode != TradingMode.SPOT:
# Explicitly setting margin_mode is not necessary as marginMode can be set per order.
# self.set_margin_mode(pair, self.margin_mode, accept_fail)
self._set_leverage(leverage, pair, accept_fail)
def _get_params(
self,
side: BuySell,
ordertype: str,
leverage: float,
reduceOnly: bool,
time_in_force: str = "GTC",
) -> dict:
params = super()._get_params(
side=side,
ordertype=ordertype,
leverage=leverage,
reduceOnly=reduceOnly,
time_in_force=time_in_force,
)
if self.trading_mode == TradingMode.FUTURES and self.margin_mode:
params["marginMode"] = self.margin_mode.value.lower()
return params
def dry_run_liquidation_price(
self,
pair: str,
open_rate: float,
is_short: bool,
amount: float,
stake_amount: float,
leverage: float,
wallet_balance: float,
open_trades: list,
) -> float | None:
"""
Important: Must be fetching data from cached values as this is used by backtesting!
https://www.bitget.com/support/articles/12560603808759
MMR: Maintenance margin rate of the trading pair.
CoinMainIndexPrice: The index price for Coin-M futures. For USDT-M futures,
the index price is: 1.
TakerFeeRatio: The fee rate applied when placing taker orders.
Position direction: The current position direction of the trading pair.
1 indicates a long position, and -1 indicates a short position.
Formula:
Estimated liquidation price = [
position margin - position size x average entry price x position direction
] ÷ [position size x (MMR + TakerFeeRatio - position direction)]
:param pair: Pair to calculate liquidation price for
:param open_rate: Entry price of position
:param is_short: True if the trade is a short, false otherwise
:param amount: Absolute value of position size incl. leverage (in base currency)
:param stake_amount: Stake amount - Collateral in settle currency.
:param leverage: Leverage used for this position.
:param wallet_balance: Amount of margin_mode in the wallet being used to trade
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
:param open_trades: List of other open trades in the same wallet
"""
market = self.markets[pair]
taker_fee_rate = market["taker"] or self._api.describe().get("fees", {}).get(
"trading", {}
).get("taker", 0.001)
mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, stake_amount)
if self.trading_mode == TradingMode.FUTURES and self.margin_mode == MarginMode.ISOLATED:
position_direction = -1 if is_short else 1
return (wallet_balance - (amount * open_rate * position_direction)) / (
amount * (mm_ratio + taker_fee_rate - position_direction)
)
else:
raise OperationalException(
"Freqtrade currently only supports isolated futures for bitget"
)
+2 -7
View File
@@ -16,13 +16,8 @@ logger = logging.getLogger(__name__)
class Bybit(Exchange):
"""
Bybit exchange class. Contains adjustments needed for Freqtrade to work
with this exchange.
Please note that this exchange is not included in the list of exchanges
officially supported by the Freqtrade development team. So some features
may still not work as expected.
"""Bybit exchange class.
Contains adjustments needed for Freqtrade to work with this exchange.
"""
unified_account = False
+24
View File
@@ -0,0 +1,24 @@
import logging
from freqtrade.exchange import Exchange
from freqtrade.exchange.exchange_types import FtHas
logger = logging.getLogger(__name__)
class Coinex(Exchange):
"""
CoinEx exchange class. Contains adjustments needed for Freqtrade to work
with this exchange.
Please note that this exchange is not included in the list of exchanges
officially supported by the Freqtrade development team. So some features
may still not work as expected.
"""
_ft_has: FtHas = {
"l2_limit_range": [5, 10, 20, 50],
"tickers_have_bid_ask": False,
"tickers_have_quoteVolume": False,
}
+1 -2
View File
@@ -48,7 +48,6 @@ MAP_EXCHANGE_CHILDCLASS = {
"binanceus": "binance",
"binanceusdm": "binance",
"okex": "okx",
"okxus": "okx",
"gateio": "gate",
"huboi": "htx",
}
@@ -57,6 +56,7 @@ SUPPORTED_EXCHANGES = [
"binance",
"bingx",
"bitmart",
"bitget",
"bybit",
"gate",
"htx",
@@ -96,7 +96,6 @@ EXCHANGE_HAS_OPTIONAL = [
# 'fetchPositions', # Futures trading
# 'fetchLeverageTiers', # Futures initialization
# 'fetchMarketLeverageTiers', # Futures initialization
# 'fetchOpenOrder', 'fetchClosedOrder', # replacement for fetchOrder
# 'fetchOpenOrders', 'fetchClosedOrders', # 'fetchOrders', # Refinding balance...
# ccxt.pro
"watchOHLCV",
+18 -3
View File
@@ -300,7 +300,7 @@ class Exchange:
if self.trading_mode != TradingMode.SPOT and load_leverage_tiers:
self.fill_leverage_tiers()
self.additional_exchange_init()
self.ft_additional_exchange_init()
def __del__(self):
"""
@@ -455,6 +455,12 @@ class Exchange:
"""
return self._api.precisionMode
def ft_additional_exchange_init(self) -> None:
"""
Wrapper around additional_exchange_init to simplify testing
"""
self.additional_exchange_init()
def additional_exchange_init(self) -> None:
"""
Additional exchange initialization logic.
@@ -832,10 +838,16 @@ class Exchange:
def validate_freqai(self, config: Config) -> None:
freqai_enabled = config.get("freqai", {}).get("enabled", False)
if freqai_enabled and not self._ft_has["ohlcv_has_history"]:
override = config.get("freqai", {}).get("override_exchange_checks", False)
if not override and freqai_enabled and not self._ft_has["ohlcv_has_history"]:
raise ConfigurationError(
f"Historic OHLCV data not available for {self.name}. Can't use freqAI."
)
elif override and freqai_enabled and not self._ft_has["ohlcv_has_history"]:
logger.warning(
"Overriding exchange checks for freqAI. Make sure that your exchange supports "
"fetching historic OHLCV data, otherwise freqAI will not work."
)
def validate_required_startup_candles(self, startup_candles: int, timeframe: str) -> int:
"""
@@ -3873,7 +3885,10 @@ class Exchange:
"""
market = self.markets[pair]
taker_fee_rate = market["taker"]
# default to some default fee if not available from exchange
taker_fee_rate = market["taker"] or self._api.describe().get("fees", {}).get(
"trading", {}
).get("taker", 0.001)
mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, stake_amount)
if self.trading_mode == TradingMode.FUTURES and self.margin_mode == MarginMode.ISOLATED:
+2 -7
View File
@@ -18,13 +18,8 @@ logger = logging.getLogger(__name__)
class Gate(Exchange):
"""
Gate.io exchange class. Contains adjustments needed for Freqtrade to work
with this exchange.
Please note that this exchange is not included in the list of exchanges
officially supported by the Freqtrade development team. So some features
may still not work as expected.
"""Gate.io exchange class.
Contains adjustments needed for Freqtrade to work with this exchange.
"""
unified_account = False
+2 -3
View File
@@ -11,9 +11,8 @@ logger = logging.getLogger(__name__)
class Htx(Exchange):
"""
HTX exchange class. Contains adjustments needed for Freqtrade to work
with this exchange.
"""HTX exchange class.
Contains adjustments needed for Freqtrade to work with this exchange.
"""
_ft_has: FtHas = {
+9 -3
View File
@@ -44,6 +44,7 @@ class Hyperliquid(Exchange):
_supported_trading_mode_margin_pairs: list[tuple[TradingMode, MarginMode]] = [
(TradingMode.SPOT, MarginMode.NONE),
(TradingMode.FUTURES, MarginMode.ISOLATED),
(TradingMode.FUTURES, MarginMode.CROSS),
]
@property
@@ -99,7 +100,6 @@ class Hyperliquid(Exchange):
'SOL/USDC:USDC': 43}}
"""
# Defining/renaming variables to match the documentation
isolated_margin = wallet_balance
position_size = amount
price = open_rate
position_value = price * position_size
@@ -117,8 +117,14 @@ class Hyperliquid(Exchange):
# 3. Divide this by 2
maintenance_margin_required = position_value / max_leverage / 2
# Docs: margin_available (isolated) = isolated_margin - maintenance_margin_required
margin_available = isolated_margin - maintenance_margin_required
if self.margin_mode == MarginMode.ISOLATED:
# Docs: margin_available (isolated) = isolated_margin - maintenance_margin_required
margin_available = stake_amount - maintenance_margin_required
elif self.margin_mode == MarginMode.CROSS:
# Docs: margin_available (cross) = account_value - maintenance_margin_required
margin_available = wallet_balance - maintenance_margin_required
else:
raise OperationalException("Unsupported margin mode for liquidation price calculation")
# Docs: The maintenance margin is half of the initial margin at max leverage
# The docs don't explicitly specify maintenance leverage, but this works.
+4
View File
@@ -19,6 +19,10 @@ logger = logging.getLogger(__name__)
class Kraken(Exchange):
"""Kraken exchange class.
Contains adjustments needed for Freqtrade to work with this exchange.
"""
_params: dict = {"trading_agreement": "agree"}
_ft_has: FtHas = {
"stoploss_on_exchange": True,
+13 -9
View File
@@ -11,7 +11,7 @@ from freqtrade.exceptions import (
RetryableOrderError,
TemporaryError,
)
from freqtrade.exchange import Exchange, date_minus_candles
from freqtrade.exchange import Exchange
from freqtrade.exchange.common import API_RETRY_COUNT, retrier
from freqtrade.exchange.exchange_types import CcxtOrder, FtHas
from freqtrade.misc import safe_value_fallback2
@@ -80,11 +80,6 @@ class Okx(Exchange):
if candle_type in (CandleType.FUTURES, CandleType.SPOT):
return 300
if candle_type in (CandleType.MARK, CandleType.PREMIUMINDEX) and (
not since_ms or since_ms > (date_minus_candles(timeframe, 300).timestamp() * 1000)
):
return 300
return super().ohlcv_candle_limit(timeframe, candle_type, since_ms)
@retrier
@@ -296,12 +291,21 @@ class Okx(Exchange):
return orders
class MyOkx(Okx):
"""
MyOkx exchange class.
class Myokx(Okx):
"""MyOkx exchange class.
Minimal adjustment to disable futures trading for the EU subsidiary of Okx
"""
_supported_trading_mode_margin_pairs: list[tuple[TradingMode, MarginMode]] = [
(TradingMode.SPOT, MarginMode.NONE),
]
class Okxus(Okx):
"""Okxus exchange class.
Minimal adjustment to disable futures trading for the US subsidiary of Okx
"""
_supported_trading_mode_margin_pairs: list[tuple[TradingMode, MarginMode]] = [
(TradingMode.SPOT, MarginMode.NONE),
]
+3 -1
View File
@@ -1617,7 +1617,9 @@ class FreqtradeBot(LoggingMixin):
f"Emergency exiting trade {trade}, as the exit order "
f"timed out {max_timeouts} times. force selling {order['amount']}."
)
self.emergency_exit(trade, order["price"], order["amount"])
# Trade.session.refresh(order_obj)
self.emergency_exit(trade, order["price"], order_obj.safe_remaining)
return canceled
def emergency_exit(
+14 -3
View File
@@ -5,8 +5,7 @@ from pydantic import TypeAdapter
from typing_extensions import TypedDict
class AnnotationType(TypedDict, total=False):
type: Required[Literal["area"]]
class _BaseAnnotationType(TypedDict, total=False):
start: str | datetime
end: str | datetime
y_start: float
@@ -16,4 +15,16 @@ class AnnotationType(TypedDict, total=False):
z_level: int
AnnotationTypeTA = TypeAdapter(AnnotationType)
class AreaAnnotationType(_BaseAnnotationType, total=False):
type: Required[Literal["area"]]
class LineAnnotationType(_BaseAnnotationType, total=False):
type: Required[Literal["line"]]
width: int
line_style: Literal["solid", "dashed", "dotted"]
AnnotationType = AreaAnnotationType | LineAnnotationType
AnnotationTypeTA: TypeAdapter[AnnotationType] = TypeAdapter(AnnotationType)
+3 -1
View File
@@ -92,9 +92,11 @@ def _set_log_levels(
# Set default levels for third party libraries
third_party_loggers = {
"freqtrade": logging.INFO if verbosity <= 1 else logging.DEBUG,
"freqtrade": logging.INFO if verbosity < 1 else logging.DEBUG,
"freqtrade.exchange.exchange_ws": logging.INFO if verbosity <= 1 else logging.DEBUG,
"requests": logging.INFO if verbosity <= 1 else logging.DEBUG,
"urllib3": logging.INFO if verbosity <= 1 else logging.DEBUG,
"asyncio": logging.INFO if verbosity <= 1 else logging.DEBUG,
"httpcore": logging.INFO if verbosity <= 1 else logging.DEBUG,
"ccxt.base.exchange": logging.INFO if verbosity <= 2 else logging.DEBUG,
"telegram": logging.INFO,
+7 -1
View File
@@ -18,7 +18,12 @@ from freqtrade.commands import Arguments
from freqtrade.constants import DOCS_LINK
from freqtrade.exceptions import ConfigurationError, FreqtradeException, OperationalException
from freqtrade.loggers import setup_logging_pre
from freqtrade.system import asyncio_setup, gc_set_threshold, print_version_info
from freqtrade.system import (
asyncio_setup,
gc_set_threshold,
print_version_info,
set_mp_start_method,
)
logger = logging.getLogger("freqtrade")
@@ -44,6 +49,7 @@ def main(sysargv: list[str] | None = None) -> None:
elif "func" in args:
logger.info(f"freqtrade {__version__}")
gc_set_threshold()
set_mp_start_method()
return_code = args["func"](args)
else:
# No subcommand was issued.
+1 -1
View File
@@ -51,7 +51,7 @@ def file_dump_json(filename: Path, data: Any, is_zip: bool = False, log: bool =
with filename.open("w") as fp:
dump_json_to_file(fp, data)
logger.debug(f'done json to "{filename}"')
logger.debug(f'done writing json to "{filename}"')
def json_load(datafile: TextIO) -> Any:
+8
View File
@@ -8,6 +8,7 @@ from typing import Any
from pandas import DataFrame
from freqtrade.exceptions import ConfigurationError
from freqtrade.exchange import timeframe_to_minutes
from freqtrade.loggers.set_log_levels import (
reduce_verbosity_for_bias_tester,
@@ -152,6 +153,13 @@ class RecursiveAnalysis(BaseAnalysis):
strat = backtesting.strategy
self._strat_scc = strat.startup_candle_count
if self._strat_scc < 1:
raise ConfigurationError(
f"The strategy defines invalid startup candle count of {self._strat_scc}. "
f"This will lead to recursive issues on some indicators. "
f"Please define a proper startup_candle_count in the strategy."
)
if self._strat_scc not in self._startup_candle:
self._startup_candle.append(self._strat_scc)
self._startup_candle.sort()
+3 -3
View File
@@ -273,7 +273,7 @@ class Backtesting:
self.futures_data: dict[str, DataFrame] = {}
def init_backtest(self):
self.prepare_backtest(False)
self.reset_backtest(False)
self.wallets = Wallets(self.config, self.exchange, is_backtest=True)
@@ -427,7 +427,7 @@ class Backtesting:
def disable_database_use(self):
disable_database_use(self.timeframe)
def prepare_backtest(self, enable_protections):
def reset_backtest(self, enable_protections: bool = False):
"""
Backtesting setup method - called once for every call to "backtest()".
"""
@@ -1692,7 +1692,7 @@ class Backtesting:
:param end_date: backtesting timerange end datetime
:return: DataFrame with trades (results of backtesting)
"""
self.prepare_backtest(self.enable_protections)
self.reset_backtest(self.enable_protections)
# Ensure wallets are up-to-date (important for --strategy-list)
self.wallets.update()
# Use dict of lists with data for performance
+2 -32
View File
@@ -9,7 +9,6 @@ import logging
import random
from datetime import datetime
from math import ceil
from multiprocessing import Manager
from pathlib import Path
from typing import Any
@@ -19,9 +18,7 @@ from optuna.trial import FrozenTrial, Trial, TrialState
from freqtrade.constants import FTHYPT_FILEVERSION, LAST_BT_RESULT_FN, Config
from freqtrade.enums import HyperoptState
from freqtrade.exceptions import OperationalException
from freqtrade.misc import file_dump_json, plural
from freqtrade.optimize.hyperopt.hyperopt_logger import logging_mp_handle, logging_mp_setup
from freqtrade.optimize.hyperopt.hyperopt_optimizer import INITIAL_POINTS, HyperOptimizer
from freqtrade.optimize.hyperopt.hyperopt_output import HyperoptOutput
from freqtrade.optimize.hyperopt_tools import (
@@ -35,9 +32,6 @@ from freqtrade.util import get_progress_tracker
logger = logging.getLogger(__name__)
log_queue: Any
class Hyperopt:
"""
Hyperopt class, this class contains all the logic to run a hyperopt simulation
@@ -55,12 +49,6 @@ class Hyperopt:
self.analyze_per_epoch = self.config.get("analyze_per_epoch", False)
HyperoptStateContainer.set_state(HyperoptState.STARTUP)
if self.config.get("hyperopt"):
raise OperationalException(
"Using separate Hyperopt files has been removed in 2021.9. Please convert "
"your existing Hyperopt file to the new Hyperoptable strategy interface"
)
time_now = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
strategy = str(self.config["strategy"])
self.results_file: Path = (
@@ -149,15 +137,7 @@ class Hyperopt:
def run_optimizer_parallel(self, parallel: Parallel, asked: list[list]) -> list[dict[str, Any]]:
"""Start optimizer in a parallel way"""
def optimizer_wrapper(*args, **kwargs):
# global log queue. This must happen in the file that initializes Parallel
logging_mp_setup(
log_queue, logging.INFO if self.config["verbosity"] < 1 else logging.DEBUG
)
return self.hyperopter.generate_optimizer_wrapped(*args, **kwargs)
return parallel(optimizer_wrapper(v) for v in asked)
return parallel(self.hyperopter.generate_optimizer_wrapped(v) for v in asked)
def _set_random_state(self, random_state: int | None) -> int:
return random_state or random.randint(1, 2**16 - 1) # noqa: S311
@@ -236,15 +216,6 @@ class Hyperopt:
self._save_result(val)
def _setup_logging_mp_workaround(self) -> None:
"""
Workaround for logging in child processes.
local_queue must be a global in the file that initializes Parallel.
"""
global log_queue
m = Manager()
log_queue = m.Queue()
def start(self) -> None:
self.random_state = self._set_random_state(self.config.get("hyperopt_random_state"))
logger.info(f"Using optimizer random state: {self.random_state}")
@@ -257,7 +228,6 @@ class Hyperopt:
logger.info(f"Number of parallel jobs set as: {config_jobs}")
self.opt = self.hyperopter.get_optimizer(self.random_state)
self._setup_logging_mp_workaround()
try:
with Parallel(n_jobs=config_jobs) as parallel:
jobs = parallel._effective_n_jobs()
@@ -307,7 +277,7 @@ class Hyperopt:
self.evaluate_result(val, current, is_random[j])
pbar.update(task, advance=1)
logging_mp_handle(log_queue)
self.hyperopter.handle_mp_logging()
gc.collect()
if (
@@ -7,6 +7,7 @@ import logging
import sys
import warnings
from datetime import UTC, datetime
from multiprocessing import Manager
from pathlib import Path
from typing import Any
@@ -29,6 +30,7 @@ from freqtrade.optimize.backtesting import Backtesting
# Import IHyperOptLoss to allow unpickling classes from these modules
from freqtrade.optimize.hyperopt.hyperopt_auto import HyperOptAuto
from freqtrade.optimize.hyperopt.hyperopt_logger import logging_mp_handle, logging_mp_setup
from freqtrade.optimize.hyperopt_loss.hyperopt_loss_interface import IHyperOptLoss
from freqtrade.optimize.hyperopt_tools import HyperoptStateContainer, HyperoptTools
from freqtrade.optimize.optimize_reports import generate_strategy_stats
@@ -58,6 +60,8 @@ optuna_samplers_dict = {
"QMCSampler": optuna.samplers.QMCSampler,
}
log_queue: Any
class HyperOptimizer:
"""
@@ -85,13 +89,7 @@ class HyperOptimizer:
self.custom_hyperopt: HyperOptAuto
self.analyze_per_epoch = self.config.get("analyze_per_epoch", False)
if not self.config.get("hyperopt"):
self.custom_hyperopt = HyperOptAuto(self.config)
else:
raise OperationalException(
"Using separate Hyperopt files has been removed in 2021.9. Please convert "
"your existing Hyperopt file to the new Hyperoptable strategy interface"
)
self.custom_hyperopt = HyperOptAuto(self.config)
self.backtesting._set_strategy(self.backtesting.strategylist[0])
self.custom_hyperopt.strategy = self.backtesting.strategy
@@ -113,6 +111,24 @@ class HyperOptimizer:
if HyperoptTools.has_space(self.config, "sell"):
# Make sure use_exit_signal is enabled
self.config["use_exit_signal"] = True
self._setup_logging_mp_workaround()
def _setup_logging_mp_workaround(self) -> None:
"""
Workaround for logging in child processes.
local_queue must be a global and passed to the child process via inheritance.
"""
global log_queue
m = Manager()
log_queue = m.Queue()
logger.info(f"manager queue {type(log_queue)}")
def handle_mp_logging(self) -> None:
"""
Handle logging from child processes.
Must be called in the parent process to handle log messages from the child process.
"""
logging_mp_handle(log_queue)
def prepare_hyperopt(self) -> None:
# Initialize spaces ...
@@ -264,6 +280,7 @@ class HyperOptimizer:
@delayed
@wrap_non_picklable_objects
def generate_optimizer_wrapped(self, params_dict: dict[str, Any]) -> dict[str, Any]:
logging_mp_setup(log_queue, logging.INFO if self.config["verbosity"] < 1 else logging.DEBUG)
return self.generate_optimizer(params_dict)
def generate_optimizer(self, params_dict: dict[str, Any]) -> dict[str, Any]:
@@ -256,40 +256,66 @@ def _get_resample_from_period(period: str) -> str:
return "1ME"
if period == "year":
return "1YE"
if period == "weekday":
# Required to pass the test
return "weekday"
raise ValueError(f"Period {period} is not supported.")
def _calculate_stats_for_period(data: DataFrame) -> dict[str, Any]:
profit_abs = data["profit_abs"].sum().round(10)
wins = sum(data["profit_abs"] > 0)
draws = sum(data["profit_abs"] == 0)
losses = sum(data["profit_abs"] < 0)
trades = wins + draws + losses
winning_profit = data.loc[data["profit_abs"] > 0, "profit_abs"].sum()
losing_profit = data.loc[data["profit_abs"] < 0, "profit_abs"].sum()
profit_factor = winning_profit / abs(losing_profit) if losing_profit else 0.0
return {
"profit_abs": profit_abs,
"wins": wins,
"draws": draws,
"losses": losses,
"trades": trades,
"profit_factor": round(profit_factor, 8),
}
def generate_periodic_breakdown_stats(
trade_list: list | DataFrame, period: str
) -> list[dict[str, Any]]:
results = trade_list if not isinstance(trade_list, list) else DataFrame.from_records(trade_list)
if len(results) == 0:
return []
results["close_date"] = to_datetime(results["close_date"], utc=True)
resample_period = _get_resample_from_period(period)
resampled = results.resample(resample_period, on="close_date")
stats = []
for name, day in resampled:
profit_abs = day["profit_abs"].sum().round(10)
wins = sum(day["profit_abs"] > 0)
draws = sum(day["profit_abs"] == 0)
losses = sum(day["profit_abs"] < 0)
trades = wins + draws + losses
winning_profit = day.loc[day["profit_abs"] > 0, "profit_abs"].sum()
losing_profit = day.loc[day["profit_abs"] < 0, "profit_abs"].sum()
profit_factor = winning_profit / abs(losing_profit) if losing_profit else 0.0
stats.append(
{
"date": name.strftime("%d/%m/%Y"),
"date_ts": int(name.to_pydatetime().timestamp() * 1000),
"profit_abs": profit_abs,
"wins": wins,
"draws": draws,
"losses": losses,
"trades": trades,
"profit_factor": round(profit_factor, 8),
}
)
if period == "weekday":
day_names = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
results["weekday"] = results["close_date"].dt.dayofweek
stats = []
for day_num in range(7):
day_data = results[results["weekday"] == day_num]
if len(day_data) > 0:
period_stats = _calculate_stats_for_period(day_data)
stats.append({"date": day_names[day_num], "date_ts": day_num, **period_stats})
else:
resample_period = _get_resample_from_period(period)
resampled = results.resample(resample_period, on="close_date")
stats = []
for name, period_data in resampled:
period_stats = _calculate_stats_for_period(period_data)
stats.append(
{
"date": name.strftime("%d/%m/%Y"),
"date_ts": int(name.to_pydatetime().timestamp() * 1000),
**period_stats,
}
)
return stats
+8 -6
View File
@@ -86,13 +86,13 @@ class IResolver:
Tuple format: [Object, source]
"""
# Generate spec based on absolute path
# Pass object_name as first argument to have logging print a reasonable name.
with PathModifier(module_path.parent):
module_name = module_path.stem or ""
# Generate spec based on absolute path
# Pass object_name as first argument to have logging print a reasonable name.
spec = importlib.util.spec_from_file_location(module_name, str(module_path))
if not spec:
return iter([None])
return iter([])
module = importlib.util.module_from_spec(spec)
try:
@@ -149,9 +149,7 @@ class IResolver:
continue
module_path = entry.resolve()
obj = next(cls._get_valid_object(module_path, object_name), None)
if obj:
if obj := next(cls._get_valid_object(module_path, object_name), None):
obj[0].__file__ = str(entry)
if add_source:
obj[0].__source__ = obj[1]
@@ -164,6 +162,10 @@ class IResolver:
) -> Any | None:
"""
Try to load object from path list.
:param paths: list of absolute paths to search
:param object_name: name of the module to import
:param add_source: add the source code as __source__ attribute to theloaded object.
:param kwargs: keyword arguments to pass to the object constructor
"""
for _path in paths:
+3 -1
View File
@@ -150,7 +150,9 @@ class StrategyResolver(IResolver):
# Ensure necessary migrations are performed first.
validate_migrated_strategy_settings(strategy.config)
if not all(k in strategy.order_types for k in REQUIRED_ORDERTYPES):
if not strategy.order_types or not all(
k in strategy.order_types for k in REQUIRED_ORDERTYPES
):
raise ImportError(
f"Impossible to load Strategy '{strategy.__class__.__name__}'. "
f"Order-types mapping is incomplete."
+1 -1
View File
@@ -116,7 +116,7 @@ def __run_backtest_bg(btconfig: Config):
)
ApiBG.bt["bt"].results["metadata"][strategy_name]["filename"] = str(fn.stem)
ApiBG.bt["bt"].results["metadata"][strategy_name]["strategy"] = strategy_name
ApiBG.bt["bt"].reset_backtest()
logger.info("Backtest finished.")
except ConfigurationError as e:
+69 -58
View File
@@ -1009,12 +1009,16 @@ class RPC:
return {"result": "Created exit orders for all open trades."}
# Query for trade
trade = Trade.get_trades(
trade_filter=[
Trade.id == trade_id,
Trade.is_open.is_(True),
]
).first()
trade = (
Trade.get_trades(
trade_filter=[
Trade.id == int(trade_id),
Trade.is_open.is_(True),
]
).first()
if trade_id.isdigit()
else None
)
if not trade:
logger.warning("force_exit: Invalid argument received")
raise RPCException("invalid argument")
@@ -1557,69 +1561,76 @@ class RPC:
selected_cols: list[str] | None,
live: bool,
) -> dict[str, Any]:
"""
Analyzed dataframe in Dict form, with full history loading and strategy analysis.
Loads the full history from disk or exchange, and runs the strategy analysis on it.
Should only be used in webserver mode, as it can interfere with a running bot.
"""
timerange_parsed = TimeRange.parse_timerange(config.get("timerange"))
from freqtrade.data.converter import trim_dataframe
from freqtrade.data.dataprovider import DataProvider
from freqtrade.persistence.usedb_context import FtNoDBContext
from freqtrade.resolvers.strategy_resolver import StrategyResolver
strategy_name = ""
startup_candles = 0
if config.get("strategy"):
strategy = StrategyResolver.load_strategy(config)
startup_candles = strategy.startup_candle_count
strategy_name = strategy.get_strategy_name()
with FtNoDBContext():
strategy_name = ""
startup_candles = 0
if config.get("strategy"):
strategy = StrategyResolver.load_strategy(config)
startup_candles = strategy.startup_candle_count
strategy_name = strategy.get_strategy_name()
if live:
data = exchange.get_historic_ohlcv(
pair=pair,
timeframe=timeframe,
since_ms=timerange_parsed.startts * 1000
if timerange_parsed.startts
else dt_ts(dt_now() - timedelta(days=30)),
is_new_pair=True, # history is never available - so always treat as new pair
candle_type=config.get("candle_type_def", CandleType.SPOT),
until_ms=timerange_parsed.stopts,
)
else:
_data = load_data(
datadir=config["datadir"],
pairs=[pair],
timeframe=timeframe,
timerange=timerange_parsed,
data_format=config["dataformat_ohlcv"],
candle_type=config.get("candle_type_def", CandleType.SPOT),
startup_candles=startup_candles,
)
if pair not in _data:
raise RPCException(
f"No data for {pair}, {timeframe} in {config.get('timerange')} found."
if live:
data = exchange.get_historic_ohlcv(
pair=pair,
timeframe=timeframe,
since_ms=timerange_parsed.startts * 1000
if timerange_parsed.startts
else dt_ts(dt_now() - timedelta(days=30)),
is_new_pair=True, # history is never available - so always treat as new pair
candle_type=config.get("candle_type_def", CandleType.SPOT),
until_ms=timerange_parsed.stopts,
)
data = _data[pair]
else:
_data = load_data(
datadir=config["datadir"],
pairs=[pair],
timeframe=timeframe,
timerange=timerange_parsed,
data_format=config["dataformat_ohlcv"],
candle_type=config.get("candle_type_def", CandleType.SPOT),
startup_candles=startup_candles,
)
if pair not in _data:
raise RPCException(
f"No data for {pair}, {timeframe} in {config.get('timerange')} found."
)
data = _data[pair]
annotations = []
if config.get("strategy"):
strategy.dp = DataProvider(config, exchange=exchange, pairlists=None)
strategy.ft_bot_start()
annotations = []
if config.get("strategy"):
strategy.dp = DataProvider(config, exchange=exchange, pairlists=None)
strategy.ft_bot_start()
df_analyzed = strategy.analyze_ticker(data, {"pair": pair})
df_analyzed = trim_dataframe(
df_analyzed, timerange_parsed, startup_candles=startup_candles
df_analyzed = strategy.analyze_ticker(data, {"pair": pair})
df_analyzed = trim_dataframe(
df_analyzed, timerange_parsed, startup_candles=startup_candles
)
annotations = strategy.ft_plot_annotations(pair=pair, dataframe=df_analyzed)
else:
df_analyzed = data
return RPC._convert_dataframe_to_dict(
strategy_name,
pair,
timeframe,
df_analyzed.copy(),
dt_now(),
selected_cols,
annotations,
)
annotations = strategy.ft_plot_annotations(pair=pair, dataframe=df_analyzed)
else:
df_analyzed = data
return RPC._convert_dataframe_to_dict(
strategy_name,
pair,
timeframe,
df_analyzed.copy(),
dt_now(),
selected_cols,
annotations,
)
def _rpc_plot_config(self) -> dict[str, Any]:
if (
+5 -1
View File
@@ -1455,7 +1455,11 @@ class Telegram(RPCHandler):
await query.answer()
await query.edit_message_text(text="Force exit canceled.")
return
trade: Trade | None = Trade.get_trades(trade_filter=Trade.id == trade_id).first()
trade: Trade | None = (
Trade.get_trades(trade_filter=Trade.id == int(trade_id)).first()
if trade_id.isdigit()
else None
)
await query.answer()
if trade:
await query.edit_message_text(
+15
View File
@@ -92,6 +92,21 @@ def merge_informative_pair(
right_on=date_merge,
how="left",
)
if len(dataframe) > 1 and len(informative) > 0 and pd.isnull(dataframe.at[0, date_merge]):
# If the start dates of the dataframes are not aligned, the first rows will be NaN
# We can fill these with the last available informative candle before the start date
# while still avoiding lookahead bias - as only past data is used.
first_valid_idx = dataframe[date_merge].first_valid_index()
if first_valid_idx:
first_valid_date_merge = dataframe.at[first_valid_idx, date_merge]
matching_informative_raws = informative[
informative[date_merge] < first_valid_date_merge
]
if not matching_informative_raws.empty:
dataframe.loc[: first_valid_idx - 1] = dataframe.loc[
: first_valid_idx - 1
].fillna(matching_informative_raws.iloc[-1])
else:
dataframe = pd.merge(
dataframe, informative, left_on="date", right_on=date_merge, how="left"
+22 -2
View File
@@ -13,6 +13,21 @@ logger = logging.getLogger(__name__)
F = TypeVar("F", bound=Callable[..., Any])
def __format_traceback(error: Exception) -> str:
"""Format the traceback of an exception into a formatted string."""
tb = error.__traceback__
try:
while tb:
if tb.tb_frame.f_code.co_filename == __file__:
# Skip frames from this file
tb = tb.tb_next
continue
return f"{tb.tb_frame.f_code.co_qualname}:{tb.tb_lineno}"
except Exception:
return "<unavailable>"
return ""
def strategy_safe_wrapper(f: F, message: str = "", default_retval=None, supress_error=False) -> F:
"""
Wrapper around user-provided methods and functions.
@@ -30,12 +45,17 @@ def strategy_safe_wrapper(f: F, message: str = "", default_retval=None, supress_
kwargs["trade"] = deepcopy(kwargs["trade"])
return f(*args, **kwargs)
except ValueError as error:
logger.warning(f"{message}Strategy caused the following exception: {error}{f}")
traceback = __format_traceback(error)
name = f.__name__ if hasattr(f, "__name__") else str(f)
logger.warning(
f"{message}Strategy caused the following exception: {repr(error)} in "
f"{traceback}, calling {name}",
)
if default_retval is None and not supress_error:
raise StrategyError(str(error)) from error
return default_retval
except Exception as error:
logger.exception(f"{message}Unexpected error {error} calling {f}")
logger.exception(f"{message}Unexpected error {repr(error)} calling {f}")
if default_retval is None and not supress_error:
raise StrategyError(str(error)) from error
return default_retval
+1
View File
@@ -46,6 +46,7 @@ class StrategyUpdater:
"aliases": set(),
"replacements": [
("NaN", "nan"),
("NAN", "nan"),
],
}
}
+2 -1
View File
@@ -2,7 +2,8 @@
from freqtrade.system.asyncio_config import asyncio_setup
from freqtrade.system.gc_setup import gc_set_threshold
from freqtrade.system.set_mp_start_method import set_mp_start_method
from freqtrade.system.version_info import print_version_info
__all__ = ["asyncio_setup", "gc_set_threshold", "print_version_info"]
__all__ = ["asyncio_setup", "gc_set_threshold", "print_version_info", "set_mp_start_method"]
+14
View File
@@ -0,0 +1,14 @@
from multiprocessing import get_all_start_methods, get_start_method, set_start_method
def set_mp_start_method():
"""
Set multiprocessing start method to not be fork.
forkserver will become the default in 3.14 - and is deprecated in 3.13
"""
try:
sms = get_all_start_methods()
if "forkserver" in sms and get_start_method(True) is None:
set_start_method("forkserver")
except RuntimeError:
pass
+1 -1
View File
@@ -382,7 +382,7 @@ class Wallets:
max_stake_amount: float,
trade_amount: float | None,
):
if not stake_amount:
if not stake_amount or isinstance(stake_amount, str) or stake_amount <= 0:
self._local_log(
f"Stake amount is {stake_amount}, ignoring possible trade for {pair}.",
level="debug",
+1 -1
View File
@@ -1,7 +1,7 @@
from freqtrade_client.ft_rest_client import FtRestClient
__version__ = "2025.9.1"
__version__ = "2025.10"
if "dev" in __version__:
from pathlib import Path
+2 -2
View File
@@ -443,13 +443,13 @@ class FtRestClient:
"""Return available pair (backtest data) based on timeframe / stake_currency selection
:param timeframe: Only pairs with this timeframe available.
:param stake_currency: Only pairs that include this timeframe
:param stake_currency: Only pairs that include this stake currency.
:return: json object
"""
return self._get(
"available_pairs",
params={
"stake_currency": stake_currency if timeframe else "",
"stake_currency": stake_currency if stake_currency else "",
"timeframe": timeframe if timeframe else "",
},
)
+1 -1
View File
@@ -1,3 +1,3 @@
# Requirements for freqtrade client library
requests==2.32.5
python-rapidjson==1.21
python-rapidjson==1.22
+4 -4
View File
@@ -85,17 +85,17 @@ hyperopt = [
freqai = [
"scikit-learn",
"joblib",
'catboost; platform_machine != "aarch64"',
"catboost; platform_machine != 'arm'",
"lightgbm",
"xgboost",
"tensorboard",
"datasieve>=0.1.5",
]
freqai_rl = [
"torch",
"torch; sys_platform != 'darwin' or platform_machine != 'x86_64'",
"gymnasium",
"stable-baselines3",
"sb3-contrib",
"stable-baselines3; sys_platform != 'darwin' or platform_machine != 'x86_64'",
"sb3-contrib; sys_platform != 'darwin' or platform_machine != 'x86_64'",
"tqdm",
]
develop = [
+5 -5
View File
@@ -6,7 +6,7 @@
-r requirements-freqai-rl.txt
-r docs/requirements-docs.txt
ruff==0.13.1
ruff==0.14.1
mypy==1.18.2
pre-commit==4.3.0
pytest==8.4.2
@@ -16,7 +16,7 @@ pytest-mock==3.15.1
pytest-random-order==1.2.0
pytest-timeout==2.4.0
pytest-xdist==3.8.0
isort==6.0.1
isort==7.0.0
# For datetime mocking
time-machine==2.19.0
@@ -24,9 +24,9 @@ time-machine==2.19.0
nbconvert==7.16.6
# mypy types
scipy-stubs==1.16.2.0 # keep in sync with `scipy` in `requirements-hyperopt.txt`
types-cachetools==6.2.0.20250827
scipy-stubs==1.16.2.4 # keep in sync with `scipy` in `requirements-hyperopt.txt`
types-cachetools==6.2.0.20251022
types-filelock==3.2.7
types-requests==2.32.4.20250913
types-tabulate==0.9.0.20241207
types-python-dateutil==2.9.0.20250822
types-python-dateutil==2.9.0.20251008
+3 -3
View File
@@ -2,10 +2,10 @@
-r requirements-freqai.txt
# Required for freqai-rl
torch==2.8.0; sys_platform != 'darwin' or platform_machine != 'x86_64'
gymnasium==0.29.1
torch==2.9.0; sys_platform != 'darwin' or platform_machine != 'x86_64'
gymnasium==1.2.1
# SB3 >=2.5.0 depends on torch 2.3.0 - which implies it dropped support x86 macos
stable_baselines3==2.7.0; sys_platform != 'darwin' or platform_machine != 'x86_64'
sb3_contrib>=2.2.1
sb3_contrib>=2.2.1; sys_platform != 'darwin' or platform_machine != 'x86_64'
# Progress bar for stable-baselines3 and sb3-contrib
tqdm==4.67.1
+1 -1
View File
@@ -7,6 +7,6 @@ scikit-learn==1.7.2
joblib==1.5.2
catboost==1.2.8; 'arm' not in platform_machine
lightgbm==4.6.0
xgboost==3.0.5
xgboost==3.1.1
tensorboard==2.20.0
datasieve==0.1.9
+1 -1
View File
@@ -4,6 +4,6 @@
# Required for hyperopt
scipy==1.16.2
scikit-learn==1.7.2
filelock==3.19.1
filelock==3.20.0
optuna==4.5.0
cmaes==0.12.0
+1 -1
View File
@@ -1,4 +1,4 @@
# Include all requirements to run the bot.
-r requirements.txt
plotly==6.3.0
plotly==6.3.1
+19 -19
View File
@@ -1,36 +1,36 @@
numpy==2.3.3
pandas==2.3.2
numpy==2.3.4
pandas==2.3.3
bottleneck==1.6.0
numexpr==2.12.1
numexpr==2.14.1
# Indicator libraries
ft-pandas-ta==0.3.16
ta-lib==0.6.7
ta-lib==0.6.8
technical==1.5.3
ccxt==4.5.7
cryptography==46.0.1
aiohttp==3.12.15
SQLAlchemy==2.0.43
python-telegram-bot==22.4
ccxt==4.5.12
cryptography==46.0.3
aiohttp==3.13.1
SQLAlchemy==2.0.44
python-telegram-bot==22.5
# can't be hard-pinned due to telegram-bot pinning httpx with ~
httpx>=0.24.1
humanize==4.13.0
cachetools==6.2.0
humanize==4.14.0
cachetools==6.2.1
requests==2.32.5
urllib3==2.5.0
certifi==2025.8.3
certifi==2025.10.5
jsonschema==4.25.1
tabulate==0.9.0
pycoingecko==3.2.0
jinja2==3.1.6
joblib==1.5.2
rich==14.1.0
rich==14.2.0
pyarrow==21.0.0; platform_machine != 'armv7l' and platform_machine != "aarch64"
# TODO: downgrade for aarch64 until https://github.com/apache/arrow/issues/47229 is resolved
pyarrow==20.0.0; platform_machine == "aarch64"
# Load ticker files 30% faster
python-rapidjson==1.21
python-rapidjson==1.22
# Properly format api responses
orjson==3.11.3
@@ -38,12 +38,12 @@ orjson==3.11.3
sdnotify==0.3.2
# API Server
fastapi==0.117.1
pydantic==2.11.9
uvicorn==0.36.0
fastapi==0.119.1
pydantic==2.12.3
uvicorn==0.38.0
pyjwt==2.10.1
aiofiles==24.1.0
psutil==7.1.0
aiofiles==25.1.0
psutil==7.1.1
# Building config files interactively
questionary==2.1.1
+20 -6
View File
@@ -6,6 +6,7 @@ function echo_block() {
echo $1
echo "----------------------------"
}
UV=false
function check_installed_pip() {
${PYTHON} -m pip > /dev/null
@@ -24,6 +25,13 @@ function check_installed_python() {
echo "You can do this by running 'deactivate'."
exit 2
fi
if [ -x "$(command -v uv)" ]; then
echo "uv detected — using it instead of pip for faster installation."
PIP="uv pip"
PYTHON="python3.13"
UV=true
return
fi
for v in 13 12 11
do
@@ -32,6 +40,7 @@ function check_installed_python() {
if [ $? -eq 0 ]; then
echo "using ${PYTHON}"
check_installed_pip
PIP="${PYTHON} -m pip"
return
fi
done
@@ -49,7 +58,7 @@ function updateenv() {
source .venv/bin/activate
SYS_ARCH=$(uname -m)
echo "pip install in-progress. Please wait..."
${PYTHON} -m pip install --upgrade pip wheel setuptools
${PIP} install --upgrade pip wheel setuptools
REQUIREMENTS_HYPEROPT=""
REQUIREMENTS_PLOT=""
REQUIREMENTS_FREQAI=""
@@ -70,7 +79,7 @@ function updateenv() {
fi
if [ "${SYS_ARCH}" == "armv7l" ] || [ "${SYS_ARCH}" == "armv6l" ]; then
echo "Detected Raspberry, installing cython, skipping hyperopt installation."
${PYTHON} -m pip install --upgrade cython
${PIP} install --upgrade cython
else
# Is not Raspberry
read -p "Do you want to install hyperopt dependencies [y/N]? "
@@ -92,12 +101,12 @@ function updateenv() {
fi
fi
${PYTHON} -m pip install --upgrade -r ${REQUIREMENTS} ${REQUIREMENTS_HYPEROPT} ${REQUIREMENTS_PLOT} ${REQUIREMENTS_FREQAI} ${REQUIREMENTS_FREQAI_RL}
${PIP} install --upgrade -r ${REQUIREMENTS} ${REQUIREMENTS_HYPEROPT} ${REQUIREMENTS_PLOT} ${REQUIREMENTS_FREQAI} ${REQUIREMENTS_FREQAI_RL}
if [ $? -ne 0 ]; then
echo "Failed installing dependencies"
exit 1
fi
${PYTHON} -m pip install -e .
${PIP} install -e .
if [ $? -ne 0 ]; then
echo "Failed installing Freqtrade"
exit 1
@@ -179,7 +188,12 @@ function recreate_environments() {
fi
echo
${PYTHON} -m venv .venv
if [ "$UV" = true ] ; then
echo "- Creating new virtual environment with uv"
uv venv .venv --python=${PYTHON}
else
${PYTHON} -m venv .venv
fi
if [ $? -ne 0 ]; then
echo "Could not create virtual environment. Leaving now"
exit 1
@@ -252,7 +266,7 @@ function install() {
function plot() {
echo_block "Installing dependencies for Plotting scripts"
${PYTHON} -m pip install plotly --upgrade
${PIP} install plotly --upgrade
}
function help() {
+1 -1
View File
@@ -4,7 +4,7 @@ import time
from tests.conftest import is_arm, is_mac
MAXIMUM_STARTUP_TIME = 0.7 if is_mac() and not is_arm() else 0.5
MAXIMUM_STARTUP_TIME = 0.7 if is_mac() and not is_arm(True) else 0.5
def test_startup_time():
+14 -2
View File
@@ -21,6 +21,7 @@ from freqtrade.exchange import Exchange, timeframe_to_minutes, timeframe_to_seco
from freqtrade.freqtradebot import FreqtradeBot
from freqtrade.persistence import LocalTrade, Order, Trade, init_db
from freqtrade.resolvers import ExchangeResolver
from freqtrade.system import set_mp_start_method
from freqtrade.util import dt_now, dt_ts
from freqtrade.worker import Worker
from tests.conftest_trades import (
@@ -500,9 +501,20 @@ def patch_gc(mocker) -> None:
mocker.patch("freqtrade.main.gc_set_threshold")
def is_arm() -> bool:
@pytest.fixture(scope="session", autouse=True)
def fixture_set_mp_start_method():
"""
Patch multiprocessing start mode globally
Auto-used, runs once per session.
"""
set_mp_start_method()
def is_arm(include_aarch64: bool = False) -> bool:
machine = platform.machine()
return "arm" in machine or "aarch64" in machine
if include_aarch64:
return "aarch64" in machine or "arm" in machine
return "arm" in machine
def is_mac() -> bool:
+76 -3
View File
@@ -1,10 +1,10 @@
from datetime import timedelta
from unittest.mock import MagicMock
from unittest.mock import MagicMock, PropertyMock
import pytest
from freqtrade.enums import CandleType
from freqtrade.exceptions import RetryableOrderError
from freqtrade.enums import CandleType, MarginMode, TradingMode
from freqtrade.exceptions import OperationalException, RetryableOrderError
from freqtrade.exchange.common import API_RETRY_COUNT
from freqtrade.util import dt_now, dt_ts
from tests.conftest import EXMS, get_patched_exchange
@@ -120,3 +120,76 @@ def test_bitget_ohlcv_candle_limit(mocker, default_conf_usdt):
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == length
assert exch.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 200
def test_additional_exchange_init_bitget(default_conf, mocker):
default_conf["dry_run"] = False
default_conf["trading_mode"] = TradingMode.FUTURES
default_conf["margin_mode"] = MarginMode.ISOLATED
api_mock = MagicMock()
api_mock.set_position_mode = MagicMock(return_value={})
get_patched_exchange(mocker, default_conf, exchange="bitget", api_mock=api_mock)
assert api_mock.set_position_mode.call_count == 1
ccxt_exceptionhandlers(
mocker, default_conf, api_mock, "bitget", "additional_exchange_init", "set_position_mode"
)
def test_dry_run_liquidation_price_cross_bitget(default_conf, mocker):
default_conf["dry_run"] = True
default_conf["trading_mode"] = TradingMode.FUTURES
default_conf["margin_mode"] = MarginMode.CROSS
api_mock = MagicMock()
mocker.patch(f"{EXMS}.get_maintenance_ratio_and_amt", MagicMock(return_value=(0.005, 0.0)))
exchange = get_patched_exchange(mocker, default_conf, exchange="bitget", api_mock=api_mock)
with pytest.raises(
OperationalException, match="Freqtrade currently only supports isolated futures for bitget"
):
exchange.dry_run_liquidation_price(
"ETH/USDT:USDT",
100_000,
False,
0.1,
100,
10,
100,
[],
)
def test__lev_prep_bitget(default_conf, mocker):
api_mock = MagicMock()
api_mock.set_margin_mode = MagicMock()
api_mock.set_leverage = MagicMock()
type(api_mock).has = PropertyMock(return_value={"setMarginMode": True, "setLeverage": True})
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="bitget")
exchange._lev_prep("BTC/USDC:USDC", 3.2, "buy")
assert api_mock.set_margin_mode.call_count == 0
assert api_mock.set_leverage.call_count == 0
# test in futures mode
api_mock.set_margin_mode.reset_mock()
api_mock.set_leverage.reset_mock()
default_conf["dry_run"] = False
default_conf["trading_mode"] = "futures"
default_conf["margin_mode"] = "isolated"
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange="bitget")
exchange._lev_prep("BTC/USDC:USDC", 3.2, "buy")
assert api_mock.set_margin_mode.call_count == 0
assert api_mock.set_leverage.call_count == 1
api_mock.set_leverage.assert_called_with(symbol="BTC/USDC:USDC", leverage=3.2)
api_mock.reset_mock()
exchange._lev_prep("BTC/USDC:USDC", 19.99, "sell")
assert api_mock.set_margin_mode.call_count == 0
assert api_mock.set_leverage.call_count == 1
api_mock.set_leverage.assert_called_with(symbol="BTC/USDC:USDC", leverage=19.99)
+19 -19
View File
@@ -170,7 +170,7 @@ def test_init(default_conf, mocker, caplog):
def test_init_ccxt_kwargs(default_conf, mocker, caplog):
mocker.patch(f"{EXMS}.reload_markets")
mocker.patch(f"{EXMS}.validate_stakecurrency")
aei_mock = mocker.patch(f"{EXMS}.additional_exchange_init")
aei_mock = mocker.patch(f"{EXMS}.ft_additional_exchange_init")
caplog.set_level(logging.INFO)
conf = copy.deepcopy(default_conf)
@@ -2176,10 +2176,7 @@ def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_
since = date_minus_candles("5m", candle_limit)
ret = exchange.get_historic_ohlcv(pair, "5m", dt_ts(since), candle_type=candle_type)
if exchange_name == "okx" and candle_type == "mark":
expected = 4
else:
expected = 2
expected = 2
assert exchange._async_get_candle_history.call_count == expected
# Returns twice the above OHLCV data after truncating the open candle.
assert len(ret) == expected
@@ -5942,29 +5939,32 @@ def test_get_max_leverage_futures(default_conf, mocker, leverage_tiers):
assert exchange.get_max_leverage("TIA/USDT:USDT", 130.008) == 40
@pytest.mark.parametrize("exchange_name", ["binance", "kraken", "gate", "okx", "bybit"])
def test__get_params(mocker, default_conf, exchange_name):
@pytest.mark.parametrize(
"exchange_name, add_params_spot, add_params_futures",
[
("binance", {}, {}),
("kraken", {}, {"leverage": 3.0}),
("gate", {}, {}),
("okx", {}, {"tdMode": "isolated", "posSide": "net"}),
("bybit", {}, {"position_idx": 0}),
("bitget", {}, {"marginMode": "isolated"}),
],
)
def test__get_params(mocker, default_conf, exchange_name, add_params_spot, add_params_futures):
api_mock = MagicMock()
mocker.patch(f"{EXMS}.exchange_has", return_value=True)
exchange = get_patched_exchange(mocker, default_conf, api_mock, exchange=exchange_name)
exchange._params = {"test": True}
params1 = {"test": True}
params2 = {
params1.update(add_params_spot)
params_fut = {
"test": True,
"timeInForce": "IOC",
"reduceOnly": True,
}
if exchange_name == "kraken":
params2["leverage"] = 3.0
if exchange_name == "okx":
params2["tdMode"] = "isolated"
params2["posSide"] = "net"
if exchange_name == "bybit":
params2["position_idx"] = 0
params_fut.update(add_params_futures)
assert (
exchange._get_params(
@@ -6012,7 +6012,7 @@ def test__get_params(mocker, default_conf, exchange_name):
time_in_force="IOC",
leverage=3.0,
)
== params2
== params_fut
)
+26 -4
View File
@@ -6,7 +6,8 @@ import pytest
from tests.conftest import EXMS, get_mock_coro, get_patched_exchange
def test_hyperliquid_dry_run_liquidation_price(default_conf, mocker):
@pytest.mark.parametrize("margin_mode", ["isolated", "cross"])
def test_hyperliquid_dry_run_liquidation_price(default_conf, mocker, margin_mode):
# test if liq price calculated by dry_run_liquidation_price() is close to ccxt liq price
# testing different pairs with large/small prices, different leverages, long, short
markets = {
@@ -281,7 +282,7 @@ def test_hyperliquid_dry_run_liquidation_price(default_conf, mocker):
api_mock = MagicMock()
default_conf["trading_mode"] = "futures"
default_conf["margin_mode"] = "isolated"
default_conf["margin_mode"] = margin_mode
default_conf["stake_currency"] = "USDC"
api_mock.load_markets = get_mock_coro()
api_mock.markets = markets
@@ -299,11 +300,32 @@ def test_hyperliquid_dry_run_liquidation_price(default_conf, mocker):
position["contracts"],
position["collateral"],
position["leverage"],
position["collateral"],
[],
# isolated doesn't use wallet-balance
wallet_balance=0.0 if margin_mode == "isolated" else position["collateral"],
open_trades=[],
)
# Assume full position size is the wallet balance
assert pytest.approx(liq_price_returned, rel=0.0001) == liq_price_calculated
if margin_mode == "cross":
# test with larger wallet balance
liq_price_calculated_cross = exchange.dry_run_liquidation_price(
position["symbol"],
position["entryPrice"],
is_short,
position["contracts"],
position["collateral"],
position["leverage"],
wallet_balance=position["collateral"] * 2,
open_trades=[],
)
# Assume full position size is the wallet balance
# This
if position["side"] == "long":
assert liq_price_returned > liq_price_calculated_cross < position["entryPrice"]
else:
assert liq_price_returned < liq_price_calculated_cross > position["entryPrice"]
def test_hyperliquid_get_funding_fees(default_conf, mocker):
now = datetime.now(UTC)
+2 -2
View File
@@ -20,7 +20,7 @@ def test_okx_ohlcv_candle_limit(default_conf, mocker):
for timeframe in timeframes:
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK) == 100
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE) == 100
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == 300
@@ -36,7 +36,7 @@ def test_okx_ohlcv_candle_limit(default_conf, mocker):
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, one_call) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK, one_call) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK, one_call) == 100
one_call = int(
(
+18 -5
View File
@@ -153,6 +153,8 @@ EXCHANGES = {
"ADA.F": {"balance": "2.00000000", "hold_trade": "0.00000000"},
"XBT": {"balance": "0.00060000", "hold_trade": "0.00000000"},
"XBT.F": {"balance": "0.00100000", "hold_trade": "0.00000000"},
"ZEUR": {"balance": "1000.00000000", "hold_trade": "0.00000000"},
"ZUSD": {"balance": "1000.00000000", "hold_trade": "0.00000000"},
}
},
"expected": {
@@ -161,6 +163,8 @@ EXCHANGES = {
"BTC": {"free": 0.0006, "total": 0.0006, "used": 0.0},
# XBT.F should be mapped to BTC.F
"BTC.F": {"free": 0.001, "total": 0.001, "used": 0.0},
"EUR": {"free": 1000.0, "total": 1000.0, "used": 0.0},
"USD": {"free": 1000.0, "total": 1000.0, "used": 0.0},
},
},
},
@@ -418,6 +422,18 @@ EXCHANGES = {
"hasQuoteVolume": True,
"timeframe": "1h",
"candle_count": 1000,
"futures": True,
"futures_pair": "BTC/USDT:USDT",
"leverage_tiers_public": True,
"leverage_in_spot_market": True,
},
"coinex": {
"pair": "BTC/USDT",
"stake_currency": "USDT",
"hasQuoteVolume": False,
"timeframe": "1h",
"candle_count": 1000,
"orderbook_max_entries": 50,
},
# TODO: re-enable htx once certificates work again
# "htx": {
@@ -569,10 +585,7 @@ def get_futures_exchange(exchange_name, exchange_conf, class_mocker):
class_mocker.patch("freqtrade.exchange.binance.Binance.fill_leverage_tiers")
class_mocker.patch(f"{EXMS}.fetch_trading_fees")
class_mocker.patch("freqtrade.exchange.okx.Okx.additional_exchange_init")
class_mocker.patch("freqtrade.exchange.binance.Binance.additional_exchange_init")
class_mocker.patch("freqtrade.exchange.bybit.Bybit.additional_exchange_init")
class_mocker.patch("freqtrade.exchange.gate.Gate.additional_exchange_init")
class_mocker.patch(f"{EXMS}.ft_additional_exchange_init")
class_mocker.patch(f"{EXMS}.load_cached_leverage_tiers", return_value=None)
class_mocker.patch(f"{EXMS}.cache_leverage_tiers")
@@ -581,7 +594,7 @@ def get_futures_exchange(exchange_name, exchange_conf, class_mocker):
@pytest.fixture(params=EXCHANGES, scope="class")
def exchange(request, exchange_conf, class_mocker):
class_mocker.patch("freqtrade.exchange.bybit.Bybit.additional_exchange_init")
class_mocker.patch(f"{EXMS}.ft_additional_exchange_init")
exchange, name = get_exchange(request.param, exchange_conf)
yield exchange, name
exchange.close()
+1
View File
@@ -143,6 +143,7 @@ def test_extract_data_and_train_model_Standard(
("CatboostClassifierMultiTarget", "freqai_test_multimodel_classifier_strat"),
],
)
@pytest.mark.filterwarnings(r"ignore:.*__sklearn_tags__.*:DeprecationWarning")
def test_extract_data_and_train_model_MultiTargets(mocker, freqai_conf, model, strat):
can_run_model(model)
+12
View File
@@ -2267,6 +2267,18 @@ def test_manage_open_orders_exit_usercustom(
freqtrade.manage_open_orders()
assert log_has_re("Emergency exiting trade.*", caplog)
assert et_mock.call_count == 1
# Full exit
assert et_mock.call_args_list[0][1]["sub_trade_amt"] == 30
et_mock.reset_mock()
# Full partially filled order
# Only places the order for the remaining amount
limit_sell_order_old["remaining"] = open_trade_usdt.amount - 10
freqtrade.manage_open_orders()
assert log_has_re("Emergency exiting trade.*", caplog)
assert et_mock.call_count == 1
assert et_mock.call_args_list[0][1]["sub_trade_amt"] == 20.0
@pytest.mark.parametrize("is_short", [False, True])
+43 -43
View File
@@ -18,7 +18,7 @@ from tests.optimize import (
)
# Test 0: Sell with signal sell in candle 3
# Test 0: exit with exit signal in candle 3
# Test with Stop-loss at 1%
tc0 = BTContainer(
data=[
@@ -279,7 +279,7 @@ tc12 = BTContainer(
trades=[BTrade(exit_reason=ExitType.TRAILING_STOP_LOSS, open_tick=1, close_tick=2)],
)
# Test 13: Buy and sell ROI on same candle
# Test 13: Enter and exit ROI on same candle
# stop-loss: 10% (should not apply), ROI: 1%
tc13 = BTContainer(
data=[
@@ -296,7 +296,7 @@ tc13 = BTContainer(
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=1)],
)
# Test 14 - Buy and Stoploss on same candle
# Test 14 - Enter and Stoploss on same candle
# stop-loss: 5%, ROI: 10% (should not apply)
tc14 = BTContainer(
data=[
@@ -314,7 +314,7 @@ tc14 = BTContainer(
)
# Test 15 - Buy and ROI on same candle, followed by buy and Stoploss on next candle
# Test 15 - Enter and ROI on same candle, followed by entry and Stoploss on next candle
# stop-loss: 5%, ROI: 10% (should not apply)
tc15 = BTContainer(
data=[
@@ -334,8 +334,8 @@ tc15 = BTContainer(
],
)
# Test 16: Buy, hold for 65 min, then forceexit using roi=-1
# Causes negative profit even though sell-reason is ROI.
# Test 16: Enter, hold for 65 min, then forceexit using roi=-1
# Causes negative profit even though exit-reason is ROI.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 65 minutes (limits trade duration)
tc16 = BTContainer(
data=[
@@ -353,10 +353,10 @@ tc16 = BTContainer(
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)],
)
# Test 17: Buy, hold for 120 mins, then forceexit using roi=-1
# Causes negative profit even though sell-reason is ROI.
# Test 17: Enter, hold for 120 mins, then forceexit using roi=-1
# Causes negative profit even though exit-reason is ROI.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
# Uses open as sell-rate (special case) - since the roi-time is a multiple of the timeframe.
# Uses open as exit-rate (special case) - since the roi-time is a multiple of the timeframe.
tc17 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
@@ -374,16 +374,16 @@ tc17 = BTContainer(
)
# Test 18: Buy, hold for 120 mins, then drop ROI to 1%, causing a sell in candle 3.
# Test 18: Enter, hold for 120 mins, then drop ROI to 1%, causing an exit in candle 3.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
# uses open_rate as sell-price
# uses open_rate as exit price
tc18 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
[3, 5200, 5220, 4940, 4962, 6172, 0, 0], # Sell on ROI (sells on open)
[3, 5200, 5220, 4940, 4962, 6172, 0, 0], # Exit on ROI (exits on open)
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4950, 4975, 4925, 4950, 6172, 0, 0],
],
@@ -393,16 +393,16 @@ tc18 = BTContainer(
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)],
)
# Test 19: Buy, hold for 119 mins, then drop ROI to 1%, causing a sell in candle 3.
# Test 19: Enter, hold for 119 mins, then drop ROI to 1%, causing an exit in candle 3.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
# uses calculated ROI (1%) as sell rate, otherwise identical to tc18
# uses calculated ROI (1%) as exit rate, otherwise identical to tc18
tc19 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
[3, 5000, 5300, 4940, 4962, 6172, 0, 0], # Sell on ROI
[3, 5000, 5300, 4940, 4962, 6172, 0, 0], # Exit on ROI
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4550, 4975, 4550, 4950, 6172, 0, 0],
],
@@ -412,16 +412,16 @@ tc19 = BTContainer(
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)],
)
# Test 20: Buy, hold for 119 mins, then drop ROI to 1%, causing a sell in candle 3.
# Test 20: Enter, hold for 119 mins, then drop ROI to 1%, causing an exit in candle 3.
# stop-loss: 10%, ROI: 10% (should not apply), -100% after 100 minutes (limits trade duration)
# uses calculated ROI (1%) as sell rate, otherwise identical to tc18
# uses calculated ROI (1%) as exit rate, otherwise identical to tc18
tc20 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0],
[2, 4987, 5300, 4950, 5200, 6172, 0, 0],
[3, 5200, 5300, 4940, 4962, 6172, 0, 0], # Sell on ROI
[3, 5200, 5300, 4940, 4962, 6172, 0, 0], # Exit on ROI
[4, 4962, 4987, 4950, 4950, 6172, 0, 0],
[5, 4925, 4975, 4925, 4950, 6172, 0, 0],
],
@@ -434,7 +434,7 @@ tc20 = BTContainer(
# Test 21: trailing_stop ROI collision.
# Roi should trigger before Trailing stop - otherwise Trailing stop profits can be > ROI
# which cannot happen in reality
# stop-loss: 10%, ROI: 4%, Trailing stop adjusted at the sell candle
# stop-loss: 10%, ROI: 4%, Trailing stop adjusted at the exit candle
tc21 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
@@ -501,10 +501,10 @@ tc23 = BTContainer(
# Test 24: trailing_stop Raises in candle 2 (does not trigger)
# applying a positive trailing stop of 3% since stop_positive_offset is reached.
# ROI is changed after this to 4%, dropping ROI below trailing_stop_positive, causing a sell
# ROI is changed after this to 4%, dropping ROI below trailing_stop_positive, causing an exit
# in the candle after the raised stoploss candle with ROI reason.
# Stoploss would trigger in this candle too, but it's no longer relevant.
# stop-loss: 10%, ROI: 4%, stoploss adjusted candle 2, ROI adjusted in candle 3 (causing the sell)
# stop-loss: 10%, ROI: 4%, stoploss adjusted candle 2, ROI adjusted in candle 3 (causing the exit)
tc24 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
@@ -524,16 +524,16 @@ tc24 = BTContainer(
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)],
)
# Test 25: Sell with signal sell in candle 3 (stoploss also triggers on this candle)
# Test 25: Exit with exit signal in candle 3 (stoploss also triggers on this candle)
# Stoploss at 1%.
# Stoploss wins over Sell-signal (because sell-signal is acted on in the next candle)
# Stoploss wins over exit-signal (because exit-signal is acted on in the next candle)
tc25 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
[3, 5010, 5010, 4855, 5010, 6172, 0, 1], # Triggers stoploss + sellsignal
[3, 5010, 5010, 4855, 5010, 6172, 0, 1], # Triggers stoploss + exit-signal
[4, 5010, 5010, 4977, 4995, 6172, 0, 0],
[5, 4995, 4995, 4950, 4950, 6172, 0, 0],
],
@@ -544,9 +544,9 @@ tc25 = BTContainer(
trades=[BTrade(exit_reason=ExitType.STOP_LOSS, open_tick=1, close_tick=3)],
)
# Test 26: Sell with signal sell in candle 3 (stoploss also triggers on this candle)
# Test 26: Exit with exit signal in candle 3 (stoploss also triggers on this candle)
# Stoploss at 1%.
# Sell-signal wins over stoploss
# Exit-signal wins over stoploss
tc26 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
@@ -554,7 +554,7 @@ tc26 = BTContainer(
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
[3, 5010, 5010, 4986, 5010, 6172, 0, 1],
[4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on
[4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + exit-signal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0],
],
stop_loss=-0.01,
@@ -565,9 +565,9 @@ tc26 = BTContainer(
)
# Test 27: (copy of test26 with leverage)
# Sell with signal sell in candle 3 (stoploss also triggers on this candle)
# Exit with exit signal in candle 3 (stoploss also triggers on this candle)
# Stoploss at 1%.
# Sell-signal wins over stoploss
# exit-signal wins over stoploss
tc27 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
@@ -575,7 +575,7 @@ tc27 = BTContainer(
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
[3, 5010, 5010, 4986, 5010, 6172, 0, 1],
[4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + sellsignal acted on
[4, 5010, 5010, 4855, 4995, 6172, 0, 0], # Triggers stoploss + exit-signal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0],
],
stop_loss=-0.05,
@@ -587,9 +587,9 @@ tc27 = BTContainer(
)
# Test 28: (copy of test26 with leverage and as short)
# Sell with signal sell in candle 3 (stoploss also triggers on this candle)
# Exit with exit signal in candle 3 (stoploss also triggers on this candle)
# Stoploss at 1%.
# Sell-signal wins over stoploss
# Exit-signal wins over stoploss
tc28 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
@@ -597,7 +597,7 @@ tc28 = BTContainer(
[1, 5000, 5025, 4975, 4987, 6172, 0, 0, 0, 0], # enter trade (signal on last candle)
[2, 4987, 5012, 4986, 4986, 6172, 0, 0, 0, 0],
[3, 5010, 5010, 4986, 5010, 6172, 0, 0, 0, 1],
[4, 4990, 5010, 4855, 4995, 6172, 0, 0, 0, 0], # Triggers stoploss + sellsignal acted on
[4, 4990, 5010, 4855, 4995, 6172, 0, 0, 0, 0], # Triggers stoploss + exit-signal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0, 0, 0],
],
stop_loss=-0.05,
@@ -607,16 +607,16 @@ tc28 = BTContainer(
leverage=5.0,
trades=[BTrade(exit_reason=ExitType.EXIT_SIGNAL, open_tick=1, close_tick=4, is_short=True)],
)
# Test 29: Sell with signal sell in candle 3 (ROI at signal candle)
# Test 29: Exit with exit signal in candle 3 (ROI at signal candle)
# Stoploss at 10% (irrelevant), ROI at 5% (will trigger)
# Sell-signal wins over stoploss
# Exit-signal wins over stoploss
tc29 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
[3, 5010, 5251, 4986, 5010, 6172, 0, 1], # Triggers ROI, sell-signal
[3, 5010, 5251, 4986, 5010, 6172, 0, 1], # Triggers ROI, exit-signal
[4, 5010, 5010, 4855, 4995, 6172, 0, 0],
[5, 4995, 4995, 4950, 4950, 6172, 0, 0],
],
@@ -627,16 +627,16 @@ tc29 = BTContainer(
trades=[BTrade(exit_reason=ExitType.ROI, open_tick=1, close_tick=3)],
)
# Test 30: Sell with signal sell in candle 3 (ROI at signal candle)
# Stoploss at 10% (irrelevant), ROI at 5% (will trigger) - Wins over Sell-signal
# Test 30: Exit with exit signal in candle 3 (ROI at signal candle)
# Stoploss at 10% (irrelevant), ROI at 5% (will trigger) - Wins over exit-signal
tc30 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
[0, 5000, 5025, 4975, 4987, 6172, 1, 0],
[1, 5000, 5025, 4975, 4987, 6172, 0, 0], # enter trade (signal on last candle)
[2, 4987, 5012, 4986, 4986, 6172, 0, 0],
[3, 5010, 5012, 4986, 5010, 6172, 0, 1], # sell-signal
[4, 5010, 5251, 4855, 4995, 6172, 0, 0], # Triggers ROI, sell-signal acted on
[3, 5010, 5012, 4986, 5010, 6172, 0, 1], # exit-signal
[4, 5010, 5251, 4855, 4995, 6172, 0, 0], # Triggers ROI, exit-signal acted on
[5, 4995, 4995, 4950, 4950, 6172, 0, 0],
],
stop_loss=-0.10,
@@ -888,7 +888,7 @@ tc41 = BTContainer(
# Test 42: Custom-entry-price around candle low
# Would cause immediate ROI exit, but since the trade was entered
# below open, we treat this as cheating, and delay the sell by 1 candle.
# below open, we treat this as cheating, and delay the exit by 1 candle.
# details: https://github.com/freqtrade/freqtrade/issues/6261
tc42 = BTContainer(
data=[
@@ -945,7 +945,7 @@ tc44 = BTContainer(
)
# Test 45: Custom exit price above all candles
# causes sell signal timeout
# causes exit signal timeout
tc45 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
@@ -964,7 +964,7 @@ tc45 = BTContainer(
)
# Test 46: (Short of tc45) Custom short exit price above below candles
# causes sell signal timeout
# causes exit signal timeout
tc46 = BTContainer(
data=[
# D O H L C V EL XL ES Xs BT
+12 -30
View File
@@ -236,28 +236,6 @@ def test_start_not_installed(mocker, default_conf, import_fails) -> None:
start_hyperopt(pargs)
def test_start_no_hyperopt_allowed(mocker, hyperopt_conf, caplog) -> None:
start_mock = MagicMock()
patched_configuration_load_config_file(mocker, hyperopt_conf)
mocker.patch("freqtrade.optimize.hyperopt.Hyperopt.start", start_mock)
patch_exchange(mocker)
args = [
"hyperopt",
"--config",
"config.json",
"--hyperopt",
"HyperoptTestSepFile",
"--hyperopt-loss",
"SharpeHyperOptLossDaily",
"--epochs",
"5",
]
pargs = get_args(args)
with pytest.raises(OperationalException, match=r"Using separate Hyperopt files has been.*"):
start_hyperopt(pargs)
def test_start_no_data(mocker, hyperopt_conf, tmp_path) -> None:
hyperopt_conf["user_data_dir"] = tmp_path
patched_configuration_load_config_file(mocker, hyperopt_conf)
@@ -708,7 +686,7 @@ def test_print_json_spaces_all(mocker, hyperopt_conf, capsys) -> None:
hyperopt_conf.update(
{
"spaces": "all",
"spaces": ["all"],
"hyperopt_jobs": 1,
"print_json": True,
}
@@ -824,7 +802,7 @@ def test_print_json_spaces_roi_stoploss(mocker, hyperopt_conf, capsys) -> None:
hyperopt_conf.update(
{
"spaces": "roi stoploss",
"spaces": ["roi", "stoploss"],
"hyperopt_jobs": 1,
"print_json": True,
}
@@ -876,7 +854,7 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non
)
patch_exchange(mocker)
hyperopt_conf.update({"spaces": "roi stoploss"})
hyperopt_conf.update({"spaces": ["roi", "stoploss"]})
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
@@ -915,7 +893,7 @@ def test_simplified_interface_all_failed(mocker, hyperopt_conf, caplog) -> None:
hyperopt_conf.update(
{
"spaces": "all",
"spaces": ["all"],
}
)
@@ -969,7 +947,7 @@ def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None:
)
patch_exchange(mocker)
hyperopt_conf.update({"spaces": "buy"})
hyperopt_conf.update({"spaces": ["buy"]})
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
@@ -1025,7 +1003,7 @@ def test_simplified_interface_sell(mocker, hyperopt_conf, capsys) -> None:
hyperopt_conf.update(
{
"spaces": "sell",
"spaces": ["sell"],
}
)
@@ -1076,7 +1054,7 @@ def test_simplified_interface_failed(mocker, hyperopt_conf, space) -> None:
patch_exchange(mocker)
hyperopt_conf.update({"spaces": space})
hyperopt_conf.update({"spaces": [space]})
hyperopt = Hyperopt(hyperopt_conf)
hyperopt.hyperopter.backtesting.strategy.advise_all_indicators = MagicMock()
@@ -1132,7 +1110,9 @@ def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmp_path, fee) -> None
@pytest.mark.filterwarnings("ignore::DeprecationWarning")
def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmp_path, fee) -> None:
def test_in_strategy_auto_hyperopt_with_parallel(
mocker, hyperopt_conf, tmp_path, fee, caplog
) -> None:
mocker.patch(f"{EXMS}.validate_config", MagicMock())
mocker.patch(f"{EXMS}.get_fee", fee)
mocker.patch(f"{EXMS}.reload_markets")
@@ -1175,6 +1155,8 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmp_path
assert len(list(buy_rsi_range)) == 51
hyperopt.start()
# Test logs from parallel workers are shown.
assert log_has("Test: Bot loop started", caplog)
def test_in_strategy_auto_hyperopt_per_epoch(mocker, hyperopt_conf, tmp_path, fee) -> None:
+19
View File
@@ -634,11 +634,30 @@ def test_generate_periodic_breakdown_stats(testdatadir):
res = generate_periodic_breakdown_stats([], "day")
assert res == []
# Test weekday
reswd = generate_periodic_breakdown_stats(bt_data, "weekday")
assert isinstance(reswd, list)
assert len(reswd) == 7
assert reswd[0]["date"] == "Monday"
assert reswd[0]["date_ts"] == 0
assert reswd[1]["date"] == "Tuesday"
assert reswd[2]["date"] == "Wednesday"
assert reswd[3]["date"] == "Thursday"
assert reswd[4]["date"] == "Friday"
assert reswd[5]["date"] == "Saturday"
assert reswd[6]["date"] == "Sunday"
monday = reswd[0]
assert "draws" in monday
assert "losses" in monday
assert "wins" in monday
assert "profit_abs" in monday
def test__get_resample_from_period():
assert _get_resample_from_period("day") == "1d"
assert _get_resample_from_period("week") == "1W-MON"
assert _get_resample_from_period("month") == "1ME"
assert _get_resample_from_period("weekday") == "weekday"
with pytest.raises(ValueError, match=r"Period noooo is not supported."):
_get_resample_from_period("noooo")
+2 -1
View File
@@ -441,7 +441,8 @@ def test_migrate_pairlocks(mocker, default_conf, fee, caplog):
"dialect",
[
"sqlite",
"postgresql",
"postgresql", # test for psycopg2 compat
"postgresql.psycopg", # test for psycopg3 compat
"mysql",
"oracle",
"mssql",
+3 -3
View File
@@ -848,11 +848,11 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
freqtradebot.state = State.STOPPED
with pytest.raises(RPCException, match=r".*trader is not running*"):
rpc._rpc_force_exit(None)
rpc._rpc_force_exit("22222")
freqtradebot.state = State.RUNNING
with pytest.raises(RPCException, match=r".*invalid argument*"):
rpc._rpc_force_exit(None)
rpc._rpc_force_exit("22222")
msg = rpc._rpc_force_exit("all")
assert msg == {"result": "Created exit orders for all open trades."}
@@ -867,7 +867,7 @@ def test_rpc_force_exit(default_conf, ticker, fee, mocker) -> None:
freqtradebot.state = State.STOPPED
with pytest.raises(RPCException, match=r".*trader is not running*"):
rpc._rpc_force_exit(None)
rpc._rpc_force_exit("22222")
with pytest.raises(RPCException, match=r".*trader is not running*"):
rpc._rpc_force_exit("all")
+39 -14
View File
@@ -5,6 +5,7 @@ Unit test file for rpc/api_server.py
import asyncio
import logging
import time
from copy import deepcopy
from datetime import UTC, datetime, timedelta
from pathlib import Path
from unittest.mock import ANY, MagicMock, PropertyMock
@@ -1860,7 +1861,42 @@ def test_api_forceexit(botclient, mocker, ticker, fee, markets):
assert trade.is_open is False
def test_api_pair_candles(botclient, ohlcv_history):
def gen_annotation_params():
area_annotation = {
"type": "area",
"start": "2024-01-01 15:00:00",
"end": "2024-01-01 16:00:00",
"y_start": 94000.2,
"y_end": 98000,
"color": "",
"label": "some label",
}
line_annotation = {
"type": "line",
"start": "2024-01-01 15:00:00",
"end": "2024-01-01 16:00:00",
"y_start": 99000.2,
"y_end": 98000,
"color": "",
"label": "some label",
"width": 2,
"line_style": "dashed",
}
line_wrong = deepcopy(line_annotation)
line_wrong["line_style"] = "dashed2222"
return [
([area_annotation], [area_annotation]), # Only area
([line_annotation], [line_annotation]), # Only line
([area_annotation, line_annotation], [area_annotation, line_annotation]), # Both together
([], []), # Empty
([line_wrong], []), # Invalid line
([area_annotation, line_wrong], [area_annotation]), # Invalid line
]
@pytest.mark.parametrize("annotations,expected", gen_annotation_params())
def test_api_pair_candles(botclient, ohlcv_history, annotations, expected):
ftbot, client = botclient
timeframe = "5m"
amount = 3
@@ -1892,18 +1928,7 @@ def test_api_pair_candles(botclient, ohlcv_history):
ohlcv_history["exit_short"] = 0
ftbot.dataprovider._set_cached_df("XRP/BTC", timeframe, ohlcv_history, CandleType.SPOT)
fake_plot_annotations = [
{
"type": "area",
"start": "2024-01-01 15:00:00",
"end": "2024-01-01 16:00:00",
"y_start": 94000.2,
"y_end": 98000,
"color": "",
"label": "some label",
}
]
plot_annotations_mock = MagicMock(return_value=fake_plot_annotations)
plot_annotations_mock = MagicMock(return_value=annotations)
ftbot.strategy.plot_annotations = plot_annotations_mock
for call in ("get", "post"):
plot_annotations_mock.reset_mock()
@@ -1936,7 +1961,7 @@ def test_api_pair_candles(botclient, ohlcv_history):
assert resp["data_start_ts"] == 1511686200000
assert resp["data_stop"] == "2017-11-26 09:00:00+00:00"
assert resp["data_stop_ts"] == 1511686800000
assert resp["annotations"] == fake_plot_annotations
assert resp["annotations"] == expected
assert plot_annotations_mock.call_count == 1
assert isinstance(resp["columns"], list)
base_cols = {
+11 -32
View File
@@ -1,5 +1,7 @@
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
import logging
from pandas import DataFrame
from strategy_test_v3 import StrategyTestV3
@@ -7,6 +9,9 @@ import freqtrade.vendor.qtpylib.indicators as qtpylib
from freqtrade.strategy import BooleanParameter, DecimalParameter, IntParameter, RealParameter
logger = logging.getLogger(__name__)
class HyperoptableStrategy(StrategyTestV3):
"""
Default Strategy provided by freqtrade bot.
@@ -16,6 +21,7 @@ class HyperoptableStrategy(StrategyTestV3):
for samples and inspiration.
"""
INTERFACE_VERSION = 3
buy_params = {
"buy_rsi": 35,
# Intentionally not specified, so "default" is tested
@@ -54,34 +60,13 @@ class HyperoptableStrategy(StrategyTestV3):
def bot_loop_start(self, **kwargs):
self.bot_loop_started = True
logger.info("Test: Bot loop started")
def bot_start(self, **kwargs) -> None:
"""
Parameters can also be defined here ...
"""
self.bot_started = True
self.buy_rsi = IntParameter([0, 50], default=30, space="buy")
def informative_pairs(self):
"""
Define additional, informative pair/interval combinations to be cached from the exchange.
These pair/interval combinations are non-tradeable, unless they are part
of the whitelist as well.
For more information, please consult the documentation
:return: List of tuples in the format (pair, interval)
Sample: return [("ETH/USDT", "5m"),
("BTC/USDT", "15m"),
]
"""
return []
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the buy signal for the given dataframe
:param dataframe: DataFrame
:param metadata: Additional information, like the currently traded pair
:return: DataFrame with buy column
"""
def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(dataframe["rsi"] < self.buy_rsi.value)
@@ -90,18 +75,12 @@ class HyperoptableStrategy(StrategyTestV3):
& (dataframe["plus_di"] > self.buy_plusdi.value)
)
| ((dataframe["adx"] > 65) & (dataframe["plus_di"] > self.buy_plusdi.value)),
"buy",
"enter_long",
] = 1
return dataframe
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
"""
Based on TA indicators, populates the sell signal for the given dataframe
:param dataframe: DataFrame
:param metadata: Additional information, like the currently traded pair
:return: DataFrame with sell column
"""
def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
(
@@ -112,6 +91,6 @@ class HyperoptableStrategy(StrategyTestV3):
& (dataframe["minus_di"] > 0)
)
| ((dataframe["adx"] > 70) & (dataframe["minus_di"] > self.sell_minusdi.value)),
"sell",
"exit_long",
] = 1
return dataframe
+2 -2
View File
@@ -147,14 +147,14 @@ def test_get_signal_exception_valueerror(mocker, caplog, ohlcv_history):
mocker.patch.object(_STRATEGY.dp, "ohlcv", return_value=ohlcv_history)
mocker.patch.object(_STRATEGY, "_analyze_ticker_internal", side_effect=ValueError("xyz"))
_STRATEGY.analyze_pair("foo")
assert log_has_re(r"Strategy caused the following exception: xyz.*", caplog)
assert log_has_re(r"Strategy caused the following exception: ValueError\('xyz'\).*", caplog)
caplog.clear()
mocker.patch.object(
_STRATEGY, "analyze_ticker", side_effect=Exception("invalid ticker history ")
)
_STRATEGY.analyze_pair("foo")
assert log_has_re(r"Strategy caused the following exception: xyz.*", caplog)
assert log_has_re(r"Strategy caused the following exception: ValueError\('xyz'\).*", caplog)
def test_get_signal_old_dataframe(default_conf, mocker, caplog, ohlcv_history):
+27 -2
View File
@@ -34,7 +34,8 @@ def test_merge_informative_pair():
assert "volume_1h" in result.columns
assert result["volume"].equals(data["volume"])
# First 3 rows are empty
# First 3 rows are empty.
# Pre-fillup doesn't happen as there is no prior candlw in the informative dataframe
assert result.iloc[0]["date_1h"] is pd.NaT
assert result.iloc[1]["date_1h"] is pd.NaT
assert result.iloc[2]["date_1h"] is pd.NaT
@@ -109,13 +110,37 @@ def test_merge_informative_pair_monthly():
# Candle is empty, as the start-date did fail.
candle3 = result.loc[(result["date"] == "2022-11-30T22:00:00.000Z")]
assert candle3.iloc[0]["date"] == pd.Timestamp("2022-11-30T22:00:00.000Z")
assert candle3.iloc[0]["date_1M"] is pd.NaT
# Merged on prior month
assert candle3.iloc[0]["date_1M"] == pd.Timestamp("2022-10-01T00:00:00.000Z")
# First candle with 1M data merged.
candle4 = result.loc[(result["date"] == "2022-11-30T23:00:00.000Z")]
assert candle4.iloc[0]["date"] == pd.Timestamp("2022-11-30T23:00:00.000Z")
assert candle4.iloc[0]["date_1M"] == pd.Timestamp("2022-11-01T00:00:00.000Z")
# Very first candle in the result dataframe
# Merged the latest informative candle before the start-date
candle5 = result.iloc[0]
assert candle5["date"] == pd.Timestamp("2022-11-28T00:00:00.000Z")
assert candle5["date_1M"] == pd.Timestamp("2022-10-01T00:00:00.000Z")
def test_merge_informative_pair_no_overlap():
# Covers roughly a day
data = generate_test_data("1m", 1440, "2022-11-28")
# Data stops WAY before the main data starts
informative = generate_test_data("1h", 40, "2022-11-01")
result = merge_informative_pair(data, informative, "1m", "1h", ffill=True)
assert isinstance(result, pd.DataFrame)
assert len(result) == len(data)
assert "date" in result.columns
assert result["date"].equals(data["date"])
assert "date_1h" in result.columns
# If there's no overlap, forward filling should not fill anything
assert result["date_1h"].isnull().all()
def test_merge_informative_pair_same():
data = generate_test_data("15m", 40)

Some files were not shown because too many files have changed in this diff Show More