Compare commits

..

287 Commits

Author SHA1 Message Date
Matthias 9c079ccdfd Merge pull request #12182 from freqtrade/new_release
New release 2025.8
2025-08-31 08:25:25 +02:00
Matthias 5407c2efec fix: list-data --trades no longer working when used with --pairs filter 2025-08-30 19:58:37 +02:00
Matthias cee8855dca chore: bump version to 2025.8 2025-08-30 17:45:29 +02:00
Matthias 1196237f82 Merge branch 'stable' into new_release 2025-08-30 17:45:09 +02:00
Matthias 71e1c91148 docs: wider docs page 2025-08-30 17:26:16 +02:00
Matthias e9718e064f chore: remove outdated comment about ta-lib 2025-08-30 15:40:52 +02:00
Matthias 3e8bb29c9f test: move test to usdt 2025-08-30 15:40:52 +02:00
Matthias 2fd703fcc5 Merge pull request #12170 from mrpabloyeah/some-improvements-to-backtest-summary-metrics
Some improvements to backtest summary metrics
2025-08-30 15:40:35 +02:00
Matthias 2a84b00dad docs: fix/improve developer docs 2025-08-30 15:17:06 +02:00
Matthias 711ebfea28 docs: update backtest-result to reproducible result 2025-08-30 15:12:54 +02:00
Matthias 8cd2ee95f9 feat: add developer documentation to generate backtest results 2025-08-30 14:56:23 +02:00
Matthias 539937c0eb refactor: move base_analysis to where it belongs 2025-08-30 11:47:38 +02:00
Matthias fefd698e96 Merge pull request #12179 from freqtrade/deps/loky
CI: Bump joblib to latest version
2025-08-30 11:39:00 +02:00
Matthias 3512d788dc chore: bump technical to 1.5.3 to align talib version 2025-08-30 11:19:36 +02:00
Matthias 54c4dd1ce6 chore: run CI against 3.13 unconditionally again
Pinning to 3.13.6 was a workaround for the loky bug
2025-08-30 11:18:02 +02:00
Matthias daaff66ff0 chore: Bump joblib dependency to 1.5.2 2025-08-30 11:14:15 +02:00
Matthias 8610f9883d feat: enable PostOnly orders for binance futures 2025-08-30 10:13:10 +02:00
Matthias e503d4a9c0 fix: downgrade pyarrow to 20 to work around pyarrow compilation error
related: https://github.com/apache/arrow/issues/47229
2025-08-29 20:31:06 +02:00
Matthias 1cf1d9e3d7 chore: remove unused ignore 2025-08-28 20:37:41 +02:00
Matthias 6b250f9dfe feat: reduce log verbosity of recursive and lookahead bias commands 2025-08-28 20:19:47 +02:00
Matthias 3d24ef66d8 refactor: have backtesting init use self.config instead of the passed in config 2025-08-28 20:13:27 +02:00
Matthias ef0fc13235 chore: reduce data-load verbosity 2025-08-28 20:11:28 +02:00
Matthias 394ff1bbf6 chore: improve variable wording 2025-08-28 19:51:43 +02:00
Matthias 5cdd087465 fix: type error 2025-08-28 19:34:45 +02:00
Matthias 93051f4f97 test: update test for dynamic pairlist expansion in list-data 2025-08-28 19:21:54 +02:00
mrpabloyeah 1c2eed1421 Merge branch 'freqtrade:develop' into some-improvements-to-backtest-summary-metrics 2025-08-28 18:44:37 +02:00
mrpabloyeah 532f5ab080 Update backtesting documentation 2025-08-28 18:32:24 +02:00
Matthias e3ffe56549 feat: add dynamic PL expansion to list-data 2025-08-28 18:29:44 +02:00
Matthias 25d4cabe3b Merge pull request #12171 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-08-28 06:36:39 +02:00
Freqtrade Bot 7539b6ffda chore: update pre-commit hooks 2025-08-28 03:16:20 +00:00
mrpabloyeah 8e623ee64c Some improvements to backtest summary metrics 2025-08-28 02:04:39 +02:00
Matthias 22ddd9a7d4 Merge pull request #12169 from freqtrade/deps/ccxt
Bump ccxt version to 4.5.2
2025-08-27 10:00:44 +02:00
Matthias 128ea45fee chore: bump ccxt version to 4.5.2 2025-08-27 09:42:42 +02:00
Matthias 2495f68751 chore: remove no-longer working badge 2025-08-26 20:47:31 +02:00
Matthias 70ee652be5 fix: cut-off (too short) timeframe-detail bug
If the detail data stops short, this shouldn't cause an exception.
instead, we should continue with "parent only" logic.
2025-08-26 19:39:15 +02:00
Matthias bb1d34c33d Merge pull request #12077 from mrpabloyeah/allow-pairs-with-prefix-in-marketcap-pairList
Allow pairs with prefix in MarketCapPairList
2025-08-26 19:12:46 +02:00
Matthias 8f6d64f5e1 test: add test for 1000 / k logic 2025-08-26 07:21:09 +02:00
Matthias b40848373d docs: add line about 1000 / K testing logic 2025-08-26 07:13:17 +02:00
Matthias 2824bcff41 chore(ci): prevent failure on PR's 2025-08-26 07:08:12 +02:00
Matthias e8b967d634 Merge pull request #12167 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-08-26 06:02:10 +02:00
Freqtrade Bot 12d617cf8d chore: update pre-commit hooks 2025-08-26 03:20:03 +00:00
mrpabloyeah 48ab5ed990 Replace get_markets_cache() with get_markets_exchange() 2025-08-25 14:24:38 +02:00
mrpabloyeah 3363b1062e Merge branch 'freqtrade:develop' into allow-pairs-with-prefix-in-marketcap-pairList 2025-08-25 13:51:16 +02:00
Matthias d35dde6757 Merge pull request #12158 from freqtrade/dependabot/pip/develop/pandas-2.3.2
chore(deps): bump pandas from 2.3.1 to 2.3.2
2025-08-25 10:20:51 +02:00
Matthias 6016d4886e Merge pull request #12155 from freqtrade/dependabot/pip/develop/jsonschema-4.25.1
chore(deps): bump jsonschema from 4.25.0 to 4.25.1
2025-08-25 09:40:16 +02:00
Matthias f77eaa4083 chore: bump pre-commit scipy-stubs 2025-08-25 09:39:00 +02:00
Matthias 460d88ced7 Merge pull request #12154 from freqtrade/dependabot/pip/develop/types-eabe4663e9
chore(deps-dev): bump types-python-dateutil from 2.9.0.20250809 to 2.9.0.20250822 in the types group
2025-08-25 09:37:03 +02:00
Matthias 6bb559f1b0 Merge pull request #12163 from freqtrade/dependabot/pip/develop/time-machine-2.19.0
chore(deps-dev): bump time-machine from 2.17.0 to 2.19.0
2025-08-25 09:30:12 +02:00
Matthias 7c91eb0091 Merge pull request #12161 from freqtrade/dependabot/pip/develop/optuna-4.5.0
chore(deps): bump optuna from 4.4.0 to 4.5.0
2025-08-25 09:29:51 +02:00
Matthias ae672e1110 Merge pull request #12164 from freqtrade/dependabot/github_actions/develop/astral-sh/setup-uv-6.6.0
chore(deps): bump astral-sh/setup-uv from 6.5.0 to 6.6.0
2025-08-25 09:12:32 +02:00
dependabot[bot] 1c4bf67e29 chore(deps): bump jsonschema from 4.25.0 to 4.25.1
Bumps [jsonschema](https://github.com/python-jsonschema/jsonschema) from 4.25.0 to 4.25.1.
- [Release notes](https://github.com/python-jsonschema/jsonschema/releases)
- [Changelog](https://github.com/python-jsonschema/jsonschema/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/python-jsonschema/jsonschema/compare/v4.25.0...v4.25.1)

---
updated-dependencies:
- dependency-name: jsonschema
  dependency-version: 4.25.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 07:12:10 +00:00
Matthias c4e671fdc3 Merge pull request #12162 from freqtrade/dependabot/pip/develop/requests-2.32.5
chore(deps): bump requests from 2.32.4 to 2.32.5
2025-08-25 09:03:46 +02:00
Matthias c5c5198fb3 Merge pull request #12160 from freqtrade/dependabot/pip/develop/ccxt-4.5.1
chore(deps): bump ccxt from 4.5.0 to 4.5.1
2025-08-25 09:03:07 +02:00
dependabot[bot] 634ec3c85f chore(deps-dev): bump time-machine from 2.17.0 to 2.19.0
Bumps [time-machine](https://github.com/adamchainz/time-machine) from 2.17.0 to 2.19.0.
- [Changelog](https://github.com/adamchainz/time-machine/blob/main/docs/changelog.rst)
- [Commits](https://github.com/adamchainz/time-machine/compare/2.17.0...2.19.0)

---
updated-dependencies:
- dependency-name: time-machine
  dependency-version: 2.19.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 07:02:34 +00:00
Matthias d15aa4b337 Merge pull request #12157 from freqtrade/dependabot/pip/develop/ruff-0.12.10
chore(deps-dev): bump ruff from 0.12.9 to 0.12.10
2025-08-25 08:59:07 +02:00
Matthias e160739a28 Merge pull request #12159 from freqtrade/dependabot/pip/develop/mkdocs-c7429a2ade
chore(deps): bump mkdocs-material from 9.6.17 to 9.6.18 in the mkdocs group
2025-08-25 08:51:58 +02:00
Matthias 030e07030c Merge pull request #12156 from freqtrade/dependabot/pip/develop/scipy-420df9eef1
chore(deps-dev): bump scipy-stubs from 1.16.1.0 to 1.16.1.1 in the scipy group
2025-08-25 08:40:44 +02:00
Matthias a50a15ebc6 chore(deps): Don't bump pandas for armv7 for now. 2025-08-25 08:11:16 +02:00
Matthias 514452c4ec chore: update date-util in pre-commit config 2025-08-25 08:07:14 +02:00
dependabot[bot] f091db3b0e chore(deps): bump astral-sh/setup-uv from 6.5.0 to 6.6.0
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.5.0 to 6.6.0.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1...4959332f0f014c5280e7eac8b70c90cb574c9f9b)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:45:29 +00:00
dependabot[bot] caf1d6e7f2 chore(deps): bump requests from 2.32.4 to 2.32.5
Bumps [requests](https://github.com/psf/requests) from 2.32.4 to 2.32.5.
- [Release notes](https://github.com/psf/requests/releases)
- [Changelog](https://github.com/psf/requests/blob/main/HISTORY.md)
- [Commits](https://github.com/psf/requests/compare/v2.32.4...v2.32.5)

---
updated-dependencies:
- dependency-name: requests
  dependency-version: 2.32.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:30:18 +00:00
dependabot[bot] 81f6637803 chore(deps): bump optuna from 4.4.0 to 4.5.0
Bumps [optuna](https://github.com/optuna/optuna) from 4.4.0 to 4.5.0.
- [Release notes](https://github.com/optuna/optuna/releases)
- [Commits](https://github.com/optuna/optuna/compare/v4.4.0...v4.5.0)

---
updated-dependencies:
- dependency-name: optuna
  dependency-version: 4.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:30:01 +00:00
dependabot[bot] f764f1fc10 chore(deps): bump ccxt from 4.5.0 to 4.5.1
Bumps [ccxt](https://github.com/ccxt/ccxt) from 4.5.0 to 4.5.1.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ccxt/ccxt/compare/v4.5.0...v4.5.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:29:10 +00:00
dependabot[bot] 9a8ef17c73 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.17 to 9.6.18
- [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.17...9.6.18)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:27:30 +00:00
dependabot[bot] 8fe582a7a7 chore(deps): bump pandas from 2.2.3 to 2.3.2
Bumps [pandas](https://github.com/pandas-dev/pandas) from 2.2.3 to 2.3.2.
- [Release notes](https://github.com/pandas-dev/pandas/releases)
- [Commits](https://github.com/pandas-dev/pandas/compare/v2.2.3...v2.3.2)

---
updated-dependencies:
- dependency-name: pandas
  dependency-version: 2.3.2
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:27:29 +00:00
dependabot[bot] 5cf3a2256a chore(deps-dev): bump ruff from 0.12.9 to 0.12.10
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.12.9 to 0.12.10.
- [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.12.9...0.12.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:27:10 +00:00
dependabot[bot] caf4ffbc0b 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.1.0 to 1.16.1.1
- [Release notes](https://github.com/scipy/scipy-stubs/releases)
- [Commits](https://github.com/scipy/scipy-stubs/compare/v1.16.1.0...v1.16.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:25:49 +00:00
dependabot[bot] d156f36f99 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.20250809 to 2.9.0.20250822
- [Commits](https://github.com/typeshed-internal/stub_uploader/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-25 05:24:53 +00:00
Matthias 4390324d22 docs: improve exchange doc for time_in_force 2025-08-25 07:03:25 +02:00
Matthias 8d7ef1929e docs: improve bybit documentation structure 2025-08-25 07:00:56 +02:00
Matthias 08fb8e42f7 docs: improve time_in_force section 2025-08-25 06:57:37 +02:00
Matthias eaf6abecc8 fix: DecimalParameter shouldn't have floating point errors
closes #12152
2025-08-24 17:03:55 +02:00
Matthias b4796cbf73 test: improve decimal parameter test 2025-08-24 17:03:11 +02:00
Matthias e042b2e07b test: improve parameter naming 2025-08-24 16:12:10 +02:00
Matthias 9f021cbee6 test: remove combined test 2025-08-24 16:11:46 +02:00
Matthias bf615e415b test: split parameter tests to one test per parameter 2025-08-24 16:11:44 +02:00
Matthias c72f5b79fe refactor: extract hyperopt-params test to separate file 2025-08-24 16:02:59 +02:00
Matthias 51c1674663 Merge pull request #12153 from freqtrade/update_action
Update_action
2025-08-24 15:54:36 +02:00
Matthias e445452d35 Merge pull request #12128 from freqtrade/windows_ci
Windows ci against 2022 and 2025 respectively
2025-08-24 15:45:38 +02:00
Matthias 9fff38d0a3 chore: update Permission check action to supported version 2025-08-24 15:34:16 +02:00
Matthias bdd69dbfbc Merge pull request #12146 from stash86/main-stash
Fix calc_profit_ratio
2025-08-24 15:28:42 +02:00
Matthias ec4767acd5 chore: Simplify code slightly 2025-08-24 14:44:22 +02:00
Matthias 78c8054954 chore(ci): Split windows ci tests to 2022 and 2025 respectively 2025-08-24 14:36:24 +02:00
Stefano 24f5096ec6 modify test_handle_trade to test several cases of calc_profit_ratio 2025-08-23 17:23:56 +09:00
Stefano 030bc8641b Merge branch 'main-stash' of https://github.com/stash86/freqtrade into main-stash 2025-08-22 08:40:17 +09:00
Stefano c9403eb946 fix calc_profit_ratio to correctly fallback to available values when amount or open_rate is None 2025-08-22 08:40:14 +09:00
Matthias 87b0a6d3f3 Merge pull request #12144 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-08-21 07:15:18 +02:00
Matthias c0d404edb5 chore: try downgrading python on windows ci 2025-08-21 06:59:20 +02:00
Freqtrade Bot a7a16d1e1e chore: update pre-commit hooks 2025-08-21 03:18:27 +00:00
Matthias 1f21d5e2c2 Merge pull request #12126 from stash86/main-stash
Improve lookahead analysis to use full dataframe comparison instead of just the last row
2025-08-20 06:45:13 +02:00
Stefano a531f8644d update the docs to show the modified approach in comparing dataframes 2025-08-20 09:32:02 +09:00
Matthias 765a0b52cb fix: api-pairlist bug with candle-type-def 2025-08-19 21:14:11 +02:00
Matthias 4919d6944e chore: use available attribute 2025-08-19 21:14:11 +02:00
Matthias ac20596f10 chore: remove unused property 2025-08-19 21:14:11 +02:00
Matthias 5e79a93235 Merge pull request #12143 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-08-19 07:01:18 +02:00
Freqtrade Bot 2e8decbb6d chore: update pre-commit hooks 2025-08-19 03:20:42 +00:00
Matthias 196e599dc8 Merge pull request #12131 from freqtrade/dependabot/pip/develop/mkdocs-ed34fe0103
chore(deps): bump mkdocs-material from 9.6.16 to 9.6.17 in the mkdocs group
2025-08-18 09:01:41 +02:00
Matthias 485cad2dc6 Merge pull request #12140 from freqtrade/dependabot/github_actions/develop/zizmorcore/zizmor-action-0.1.2
chore(deps): bump zizmorcore/zizmor-action from 0.1.1 to 0.1.2
2025-08-18 08:46:18 +02:00
Matthias 61cbe0c4b1 Merge pull request #12133 from freqtrade/dependabot/pip/develop/sqlalchemy-2.0.43
chore(deps): bump sqlalchemy from 2.0.42 to 2.0.43
2025-08-18 08:40:44 +02:00
Matthias 5510e138db Merge pull request #12135 from freqtrade/dependabot/pip/develop/plotly-6.3.0
chore(deps): bump plotly from 6.2.0 to 6.3.0
2025-08-18 08:31:57 +02:00
Matthias c9e9f9bd82 Merge pull request #12141 from freqtrade/dependabot/github_actions/develop/astral-sh/setup-uv-6.5.0
chore(deps): bump astral-sh/setup-uv from 6.4.3 to 6.5.0
2025-08-18 08:25:46 +02:00
Matthias 768ba1baaf Merge pull request #12137 from freqtrade/dependabot/pip/develop/xgboost-3.0.4
chore(deps): bump xgboost from 3.0.3 to 3.0.4
2025-08-18 08:24:21 +02:00
Matthias ad25a60149 Merge pull request #12132 from freqtrade/dependabot/pip/develop/ccxt-4.5.0
chore(deps): bump ccxt from 4.4.99 to 4.5.0
2025-08-18 08:23:09 +02:00
Matthias 3fdcd6e8f1 Merge pull request #12138 from freqtrade/dependabot/pip/develop/filelock-3.19.1
chore(deps): bump filelock from 3.18.0 to 3.19.1
2025-08-18 08:20:59 +02:00
Matthias be0c0761e3 Merge pull request #12139 from freqtrade/dependabot/github_actions/develop/actions/checkout-5
chore(deps): bump actions/checkout from 4 to 5
2025-08-18 08:18:16 +02:00
Matthias 00dd3f05ac Merge pull request #12134 from freqtrade/dependabot/pip/develop/ruff-0.12.9
chore(deps-dev): bump ruff from 0.12.8 to 0.12.9
2025-08-18 08:12:29 +02:00
Matthias c6f30989c9 Merge pull request #12136 from freqtrade/dependabot/pip/develop/orjson-3.11.2
chore(deps): bump orjson from 3.11.1 to 3.11.2
2025-08-18 08:00:40 +02:00
Matthias 4ab6fba9e7 chore: bump sqlalchemy in pre-commit-config 2025-08-18 07:04:44 +02:00
dependabot[bot] 3ef082e2d9 chore(deps): bump astral-sh/setup-uv from 6.4.3 to 6.5.0
Bumps [astral-sh/setup-uv](https://github.com/astral-sh/setup-uv) from 6.4.3 to 6.5.0.
- [Release notes](https://github.com/astral-sh/setup-uv/releases)
- [Commits](https://github.com/astral-sh/setup-uv/compare/e92bafb6253dcd438e0484186d7669ea7a8ca1cc...d9e0f98d3fc6adb07d1e3d37f3043649ddad06a1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:56:09 +00:00
dependabot[bot] cccf44cd68 chore(deps): bump zizmorcore/zizmor-action from 0.1.1 to 0.1.2
Bumps [zizmorcore/zizmor-action](https://github.com/zizmorcore/zizmor-action) from 0.1.1 to 0.1.2.
- [Release notes](https://github.com/zizmorcore/zizmor-action/releases)
- [Commits](https://github.com/zizmorcore/zizmor-action/compare/f52a838cfabf134edcbaa7c8b3677dde20045018...5ca5fc7a4779c5263a3ffa0e1f693009994446d1)

---
updated-dependencies:
- dependency-name: zizmorcore/zizmor-action
  dependency-version: 0.1.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:55:35 +00:00
dependabot[bot] 506d665a43 chore(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:54:29 +00:00
dependabot[bot] 8514e35ad0 chore(deps): bump filelock from 3.18.0 to 3.19.1
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.18.0 to 3.19.1.
- [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.18.0...3.19.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:53:25 +00:00
dependabot[bot] af0a3f9a8d chore(deps): bump xgboost from 3.0.3 to 3.0.4
Bumps [xgboost](https://github.com/dmlc/xgboost) from 3.0.3 to 3.0.4.
- [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.3...v3.0.4)

---
updated-dependencies:
- dependency-name: xgboost
  dependency-version: 3.0.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:52:18 +00:00
dependabot[bot] 2df1a93dfc chore(deps): bump orjson from 3.11.1 to 3.11.2
Bumps [orjson](https://github.com/ijl/orjson) from 3.11.1 to 3.11.2.
- [Release notes](https://github.com/ijl/orjson/releases)
- [Changelog](https://github.com/ijl/orjson/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ijl/orjson/compare/3.11.1...3.11.2)

---
updated-dependencies:
- dependency-name: orjson
  dependency-version: 3.11.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:52:11 +00:00
dependabot[bot] 75e39d3154 chore(deps): bump plotly from 6.2.0 to 6.3.0
Bumps [plotly](https://github.com/plotly/plotly.py) from 6.2.0 to 6.3.0.
- [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.2.0...v6.3.0)

---
updated-dependencies:
- dependency-name: plotly
  dependency-version: 6.3.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:52:04 +00:00
dependabot[bot] 5d755e3ca0 chore(deps-dev): bump ruff from 0.12.8 to 0.12.9
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.12.8 to 0.12.9.
- [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.12.8...0.12.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:51:11 +00:00
dependabot[bot] fbeb2e4789 chore(deps): bump sqlalchemy from 2.0.42 to 2.0.43
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.42 to 2.0.43.
- [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.43
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:50:46 +00:00
dependabot[bot] 6b288d46af chore(deps): bump ccxt from 4.4.99 to 4.5.0
Bumps [ccxt](https://github.com/ccxt/ccxt) from 4.4.99 to 4.5.0.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ccxt/ccxt/compare/v4.4.99...v4.5.0)

---
updated-dependencies:
- dependency-name: ccxt
  dependency-version: 4.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:50:30 +00:00
dependabot[bot] 394cdfcc15 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.16 to 9.6.17
- [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.16...9.6.17)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:50:09 +00:00
Matthias 28df02da82 Merge pull request #12129 from freqtrade/dependabot/docker/python-3.13.7-slim-bookworm
chore(deps): bump python from 3.13.6-slim-bookworm to 3.13.7-slim-bookworm
2025-08-18 06:49:59 +02:00
Matthias d4ee725747 Merge pull request #12127 from freqtrade/backtest-filename
Backtest filename
2025-08-18 06:47:12 +02:00
dependabot[bot] 6617d3bb46 chore(deps): bump python
Bumps python from 3.13.6-slim-bookworm to 3.13.7-slim-bookworm.

---
updated-dependencies:
- dependency-name: python
  dependency-version: 3.13.7-slim-bookworm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 04:35:05 +00:00
Matthias 2453e344f4 docs: improve documentation 2025-08-17 17:25:06 +02:00
Matthias 7f0e886cfd chore: update config message naming 2025-08-17 15:31:48 +02:00
Matthias e34ea393d9 docs: improved help wording 2025-08-17 15:15:55 +02:00
Matthias a00a5e52c4 docs: update backtest-filename wording 2025-08-17 15:15:37 +02:00
Matthias 6abc0a3fb9 docs: update wording in documentation 2025-08-17 15:13:05 +02:00
Matthias 7e4b9d7481 docs: update doc segments with new help text 2025-08-17 15:09:12 +02:00
Matthias e3f241acb7 chore: improve help text wording 2025-08-17 15:08:55 +02:00
Matthias eee233f894 fix: ensure exportfilename is always set 2025-08-17 15:02:28 +02:00
Matthias 615095c780 feat: add exportdirectory to entry/exit analysis 2025-08-17 15:02:28 +02:00
Matthias b22bce3dd8 feat: Support split directory and filename for backteststats loading 2025-08-17 15:02:28 +02:00
Matthias 9f1d9add18 chore: improve docstring 2025-08-17 15:02:28 +02:00
Matthias 36f2bef6b8 test: update test for split backtest-show reality 2025-08-17 15:02:28 +02:00
Matthias 07906d2576 test: update api backtest test 2025-08-17 15:02:28 +02:00
Matthias 5c977c212b test: drop test part using --export-filename to determine backtest result naming 2025-08-17 15:02:28 +02:00
Matthias 09b084e85a chore: adjust backtest-optimize reports tests 2025-08-17 15:02:28 +02:00
Matthias aefc72554a chore: ensure filename is a path object 2025-08-17 15:02:28 +02:00
Matthias 33c2cc806a refactor: extract bt file normalization to separate function 2025-08-17 15:02:28 +02:00
Matthias 74aa17d534 feat: support both relative filenames, as well as just the filename 2025-08-17 15:02:28 +02:00
Matthias 4de1501c68 fix: argument load stability 2025-08-17 15:02:28 +02:00
Matthias dc12b3e750 feat: improved support for split "export-directory" and export-filenames 2025-08-17 15:02:28 +02:00
Matthias dacd09db8b chore: improved code logic 2025-08-17 15:02:28 +02:00
Matthias c63d0e167c chore: switch to using exportdirectory 2025-08-17 15:02:28 +02:00
Matthias 6ccd98d795 feat: introduce --export-directory 2025-08-17 15:02:28 +02:00
Stefano 52b0e64950 revert back to use list instead of set 2025-08-17 16:25:01 +09:00
Stefano 5e5137edc1 compare full dataframe instead of only last row 2025-08-17 16:05:22 +09:00
Matthias 5d4edb5ec0 fix: list-strategies shouldn't fail when no strategy is found
closes #12124
2025-08-16 19:38:45 +02:00
Matthias 6dccab9bfe refactor: simplify backtest analysis data loading 2025-08-16 14:50:36 +02:00
Matthias 653c160d76 chore: analyze-commands shouldn't identify as backtest 2025-08-16 13:27:29 +02:00
Matthias 3f65ed452e chore: improve typesafety 2025-08-16 13:23:51 +02:00
Matthias 09cdc7ceca chore: improve docker job namings 2025-08-15 19:41:49 +02:00
Matthias e98e6d8aee chore: remove --no-build-isolation from docker builds 2025-08-15 18:29:01 +02:00
Matthias f10223bf13 chore: temporarily downgrade armhf dependencies
Allow piwheels to apply - which should make the armhf build a lot faster.
2025-08-15 18:29:01 +02:00
Matthias 38b3062653 chore: fix armhf build 2025-08-15 16:18:24 +02:00
Matthias 6063e4accb Merge pull request #12101 from freqtrade/dependabot/pip/develop/ta-lib-0.6.5
chore(deps): bump ta-lib from 0.5.5 to 0.6.5
2025-08-15 13:10:22 +02:00
Matthias 06e249f569 chore: bump pre-built armhf ta-lib binary 2025-08-15 08:22:25 +02:00
Matthias d064bd4f34 chore: prefer --backtest-filename over --export-filename! 2025-08-14 15:20:46 +02:00
Matthias 765d2c332c docs: update Documentation about export-filename 2025-08-14 15:20:12 +02:00
Matthias 8857c77645 Merge pull request #12116 from stash86/fix-recursive
move strategy load to after candle_type_def has been defined
2025-08-14 14:20:38 +02:00
Matthias 1ff4e40824 chore: remove ta-lib install scripts and helpers 2025-08-14 11:15:48 +02:00
Matthias 09d59c79a7 chore(ci): cleanup CI ta-lib specials 2025-08-14 11:15:36 +02:00
Matthias dd6ac4b196 chore: remove ta-lib install from dockerfile 2025-08-14 10:22:56 +02:00
Matthias 67fe3682b5 docs: remove ta-lib special steps 2025-08-14 10:22:50 +02:00
Matthias a07e6183bb chore: simplify setup.sh 2025-08-14 10:17:53 +02:00
Matthias ac99537c25 chore: simplify setup.ps1 removing ta-lib install 2025-08-14 10:16:46 +02:00
Matthias 734a6f0442 chore: remove ta-lib install workaround for windows 2025-08-14 10:15:41 +02:00
Matthias c934535dc8 chore: remove now pointless ta-lib wheels 2025-08-14 10:07:10 +02:00
Matthias 3e3f092f0c test: reduce ta-lib test accuracy to align with ta-lib 0.6.5
Precision for ta-lib 0.6.x was increased
but is lower by 0001 than what was in the freqtrade ta-lib fix

https://github.com/TA-Lib/ta-lib/blob/main/src/ta_func/ta_utility.h#L257

This won't be a problem for any normal usdt pair.
shitcoins on some exchanges (e.g gate) with 12 zeros before the first significant digit wouldn't have worked today, either.
2025-08-14 09:59:07 +02:00
Matthias 834aafb8f2 test: non-freqai tests should run without torch installed 2025-08-14 09:37:07 +02:00
Stefano df19c77bcf better fallback 2025-08-14 16:09:43 +09:00
Stefano 6edcda1e42 fallback if strat don't specify startup candle 2025-08-14 16:06:15 +09:00
Matthias fe8c367bce Merge pull request #12115 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-08-14 07:47:26 +02:00
Stefano a37edf8c62 remove unused import 2025-08-14 12:51:27 +09:00
Stefano 09ef2c9dea move strategy load after candle type has been defined 2025-08-14 12:45:34 +09:00
Freqtrade Bot 42b1d8ecf8 chore: update pre-commit hooks 2025-08-14 03:26:18 +00:00
Matthias 32437a95f3 chore: remove unused import 2025-08-13 19:42:01 +02:00
Matthias 2e29d3523b test: empty pairlist is now handled by config schema 2025-08-13 13:17:16 +02:00
Matthias 530300a951 chore: clearer validation error handling 2025-08-13 13:15:02 +02:00
Matthias 612a09634c test: use appropriate error handlers 2025-08-13 13:08:58 +02:00
Matthias fd6a2456d0 chore: improved validation error handling 2025-08-13 13:08:51 +02:00
Matthias 1ad0e7e365 fix: force one pairlist handler via config
closes #12112
2025-08-13 13:08:41 +02:00
Matthias 055ee5c88f fix: gracefully handle telegram startup error
closes #12112
2025-08-13 12:02:12 +02:00
Matthias ae676d8e03 chore: small code refactoring, simplifying the code 2025-08-12 07:09:37 +02:00
Matthias 0dc665e45b Merge pull request #12098 from freqtrade/feat/bitget_stoploss
add bitget stoploss  support
2025-08-12 06:57:36 +02:00
Matthias bc6ea16db8 Merge pull request #12108 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-08-12 06:43:59 +02:00
Freqtrade Bot a1d0528adb chore: update pre-commit hooks 2025-08-12 03:24:31 +00:00
mrpabloyeah ecfa1fd5b5 Adjust expectation for get_markets calls in test_MarketCapPairList_timing 2025-08-11 23:54:50 +02:00
mrpabloyeah eaf76047e3 Correct syntax 2025-08-11 22:51:35 +02:00
mrpabloyeah 761d3f216e Simplify resolve_marketcap_pair() 2025-08-11 22:40:49 +02:00
mrpabloyeah e7d9ac2247 Merge branch 'freqtrade:develop' into allow-pairs-with-prefix-in-marketcap-pairList 2025-08-11 22:36:37 +02:00
Matthias 842e651928 Merge pull request #12103 from freqtrade/dependabot/pip/develop/types-aabf979877
chore(deps-dev): bump the types group with 2 updates
2025-08-11 08:36:55 +02:00
dependabot[bot] 091d1c2d55 chore(deps): bump ta-lib from 0.5.5 to 0.6.5
Bumps [ta-lib](https://github.com/ta-lib/ta-lib-python) from 0.5.5 to 0.6.5.
- [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.5.5...v0.6.5)

---
updated-dependencies:
- dependency-name: ta-lib
  dependency-version: 0.6.5
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 06:16:57 +00:00
Matthias 47bf2d1f26 chore: bump types in pre-commit config 2025-08-11 08:14:42 +02:00
Matthias 758392c206 Merge pull request #12100 from freqtrade/dependabot/pip/develop/torch-2.8.0
chore(deps): bump torch from 2.7.1 to 2.8.0
2025-08-11 08:13:48 +02:00
Matthias 647011bf0c Merge pull request #12106 from freqtrade/dependabot/github_actions/develop/actions/download-artifact-5
chore(deps): bump actions/download-artifact from 4 to 5
2025-08-11 08:13:34 +02:00
Matthias 580413b5f8 Merge pull request #12099 from freqtrade/dependabot/pip/develop/cryptography-45.0.6
chore(deps): bump cryptography from 45.0.5 to 45.0.6
2025-08-11 08:12:47 +02:00
Matthias c8c9e5167e Merge pull request #12105 from freqtrade/dependabot/pip/develop/pre-commit-4.3.0
chore(deps-dev): bump pre-commit from 4.2.0 to 4.3.0
2025-08-11 08:02:17 +02:00
dependabot[bot] 2e8707059d chore(deps): bump actions/download-artifact from 4 to 5
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 05:40:44 +00:00
dependabot[bot] e0d9d01493 chore(deps-dev): bump pre-commit from 4.2.0 to 4.3.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 4.2.0 to 4.3.0.
- [Release notes](https://github.com/pre-commit/pre-commit/releases)
- [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pre-commit/pre-commit/compare/v4.2.0...v4.3.0)

---
updated-dependencies:
- dependency-name: pre-commit
  dependency-version: 4.3.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 05:38:29 +00:00
Matthias 45bf1ace7d Merge pull request #12102 from freqtrade/dependabot/pip/develop/time-machine-2.17.0
chore(deps-dev): bump time-machine from 2.16.0 to 2.17.0
2025-08-11 07:36:46 +02:00
Matthias 39a5328f5a Merge pull request #12104 from freqtrade/dependabot/pip/develop/ruff-0.12.8
chore(deps-dev): bump ruff from 0.12.7 to 0.12.8
2025-08-11 07:36:38 +02:00
dependabot[bot] 9f82738c96 chore(deps-dev): bump ruff from 0.12.7 to 0.12.8
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.12.7 to 0.12.8.
- [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.12.7...0.12.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 04:47:32 +00:00
dependabot[bot] f69f6ec8be chore(deps-dev): bump the types group with 2 updates
Bumps the types group with 2 updates: [types-requests](https://github.com/typeshed-internal/stub_uploader) and [types-python-dateutil](https://github.com/typeshed-internal/stub_uploader).


Updates `types-requests` from 2.32.4.20250611 to 2.32.4.20250809
- [Commits](https://github.com/typeshed-internal/stub_uploader/commits)

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

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 04:47:15 +00:00
dependabot[bot] 8b3fb11f14 chore(deps-dev): bump time-machine from 2.16.0 to 2.17.0
Bumps [time-machine](https://github.com/adamchainz/time-machine) from 2.16.0 to 2.17.0.
- [Changelog](https://github.com/adamchainz/time-machine/blob/main/docs/changelog.rst)
- [Commits](https://github.com/adamchainz/time-machine/compare/2.16.0...2.17.0)

---
updated-dependencies:
- dependency-name: time-machine
  dependency-version: 2.17.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 04:46:55 +00:00
dependabot[bot] b0f4c57fa8 chore(deps): bump torch from 2.7.1 to 2.8.0
Bumps [torch](https://github.com/pytorch/pytorch) from 2.7.1 to 2.8.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.7.1...v2.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 04:43:29 +00:00
dependabot[bot] d759deae8f chore(deps): bump cryptography from 45.0.5 to 45.0.6
Bumps [cryptography](https://github.com/pyca/cryptography) from 45.0.5 to 45.0.6.
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/45.0.5...45.0.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-11 04:41:22 +00:00
Matthias b695b5a83c Merge pull request #12095 from freqtrade/dependabot/docker/python-3.13.6-slim-bookworm
chore(deps): bump python from 3.13.5-slim-bookworm to 3.13.6-slim-bookworm
2025-08-10 16:39:27 +02:00
Matthias b8883b790e test: adjust stoploss order getting for bitget 2025-08-10 16:35:53 +02:00
dependabot[bot] 423197cb23 chore(deps): bump python
Bumps python from 3.13.5-slim-bookworm to 3.13.6-slim-bookworm.

---
updated-dependencies:
- dependency-name: python
  dependency-version: 3.13.6-slim-bookworm
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-10 06:52:45 +00:00
Matthias 38107664b5 feat(bitget): Add triggered stoploss detection logic 2025-08-09 17:40:21 +02:00
Matthias 42d3f557bc chore(ci): fix windows install
temporarily pin ta-lib to <0.6.0 when searching for wheels
2025-08-09 16:11:42 +02:00
Matthias 1a3c913176 feat(bitget): Align bitget candle limits 2025-08-09 15:49:44 +02:00
Matthias 83de41ad0e test(bitget): add test for bitget ohlcv limit 2025-08-09 15:49:29 +02:00
Matthias 8cc4664823 chore: fix imports 2025-08-07 20:10:01 +02:00
Matthias aaecbc2206 test(bitget): add test for stoploss emulation 2025-08-07 20:10:01 +02:00
Matthias e36df7eff5 feat(bitget): correctly cancel stop orders 2025-08-07 20:10:01 +02:00
Matthias 95f58b2b8c feat(bitget): add stoploss support properly 2025-08-07 20:10:01 +02:00
Matthias 8df0ce3fb5 docs: add stoploss on exchange bitget 2025-08-07 20:10:01 +02:00
Matthias 4177809f71 feat(bitget): stoploss order fetching attempts 2025-08-07 20:10:01 +02:00
Matthias 96aa214fc5 Merge pull request #12092 from freqtrade/update/binance-leverage-tiers
Update Binance Leverage Tiers
2025-08-07 06:01:21 +02:00
Matthias a3c1c8c1b4 Merge pull request #12091 from freqtrade/deps/ccxt
Bump ccxt to 4.4.99
2025-08-07 06:00:35 +02:00
Freqtrade Bot 2bf3494cbc chore: update pre-commit hooks 2025-08-07 03:31:40 +00:00
Matthias e3dd3478bb chore: bump ccxt to 4.4.99 2025-08-06 21:12:29 +02:00
Matthias 457af15b35 chore: safe basic freqAI infos to backtest result 2025-08-06 20:24:43 +02:00
Matthias 1eef1675cc Merge pull request #12084 from freqtrade/fix/backtest_feature_handling
fix: Ensure pipelines that modify feature set are supported for fast backtesting
2025-08-05 20:19:18 +02:00
Robert Caulk 89ef31b381 fix: Ensure pipelines that modify feature set are supported for fast backtesting 2025-08-05 12:49:27 +02:00
mrpabloyeah c00472c42d Merge branch 'freqtrade:develop' into allow-pairs-with-prefix-in-marketcap-pairList 2025-08-05 11:25:15 +02:00
mrpabloyeah c0143b04c8 Refactor pair resolution logic for improved clarity and modularity 2025-08-05 11:14:02 +02:00
Matthias d1c901ae94 Merge pull request #12083 from freqtrade/update/pre-commit-hooks
Update pre-commit hooks
2025-08-05 07:16:42 +02:00
Matthias dd0aeaf380 Merge pull request #12080 from freqtrade/dependabot/github_actions/develop/docker/login-action-3.5.0
chore(deps): bump docker/login-action from 3.4.0 to 3.5.0
2025-08-05 07:10:25 +02:00
Freqtrade Bot 3e8e250a65 chore: update pre-commit hooks 2025-08-05 04:46:39 +00:00
dependabot[bot] a34b580444 chore(deps): bump docker/login-action from 3.4.0 to 3.5.0
Bumps [docker/login-action](https://github.com/docker/login-action) from 3.4.0 to 3.5.0.
- [Release notes](https://github.com/docker/login-action/releases)
- [Commits](https://github.com/docker/login-action/compare/74a5d142397b4f367a81961eba4e8cd7edddf772...184bdaa0721073962dff0199f1fb9940f07167d1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-05 04:46:30 +00:00
Matthias e7ea9d09c9 chore: fix typo 2025-08-05 06:45:35 +02:00
Matthias e4e11be331 chore: temporarily disable htx due to certificate issues 2025-08-05 06:34:56 +02:00
Matthias 9774c51a97 Merge pull request #12074 from freqtrade/dependabot/pip/develop/scipy-stubs-1.16.1.0
chore(deps-dev): bump scipy-stubs from 1.16.0.2 to 1.16.1.0
2025-08-04 19:57:46 +02:00
Matthias 87ff8dc7bc chore(deps-dev): update scipy-stubs in pre-commit config 2025-08-04 19:34:43 +02:00
Matthias 2434ae5476 chore: make scipy it's own group to update scipy-stubs together 2025-08-04 19:34:27 +02:00
dependabot[bot] e474294d55 chore(deps-dev): bump scipy-stubs from 1.16.0.2 to 1.16.1.0
Bumps [scipy-stubs](https://github.com/scipy/scipy-stubs) from 1.16.0.2 to 1.16.1.0.
- [Release notes](https://github.com/scipy/scipy-stubs/releases)
- [Commits](https://github.com/scipy/scipy-stubs/compare/v1.16.0.2...v1.16.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 17:33:34 +00:00
Matthias b081716df7 Merge pull request #12075 from freqtrade/dependabot/pip/develop/sqlalchemy-2.0.42
chore(deps): bump sqlalchemy from 2.0.41 to 2.0.42
2025-08-04 19:31:26 +02:00
Matthias e1af43b133 Merge branch 'develop' into dependabot/pip/develop/sqlalchemy-2.0.42 2025-08-04 19:17:39 +02:00
mrpabloyeah 1ea6a99c48 Allow pairs with prefix in MarketCapPairList 2025-08-04 11:54:03 +02:00
Matthias 79fc80957f Merge pull request #12071 from freqtrade/dependabot/pip/develop/ruff-0.12.7
chore(deps-dev): bump ruff from 0.12.5 to 0.12.7
2025-08-04 08:42:02 +02:00
Matthias 937eedd8ca Merge pull request #12073 from freqtrade/dependabot/pip/develop/aiohttp-3.12.15
chore(deps): bump aiohttp from 3.12.14 to 3.12.15
2025-08-04 07:37:51 +02:00
dependabot[bot] 93ae45dcbb chore(deps): bump aiohttp from 3.12.14 to 3.12.15
---
updated-dependencies:
- dependency-name: aiohttp
  dependency-version: 3.12.15
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 05:13:21 +00:00
Matthias 1adbd525bc Merge pull request #12072 from freqtrade/dependabot/pip/develop/pymdown-extensions-10.16.1
chore(deps): bump pymdown-extensions from 10.16 to 10.16.1
2025-08-04 07:13:09 +02:00
Matthias ced7465c1f Merge pull request #12069 from freqtrade/dependabot/pip/develop/xgboost-3.0.3
chore(deps): bump xgboost from 3.0.2 to 3.0.3
2025-08-04 07:04:25 +02:00
Matthias d635cb8516 Merge pull request #12068 from freqtrade/dependabot/pip/develop/ccxt-4.4.98
chore(deps): bump ccxt from 4.4.96 to 4.4.98
2025-08-04 07:01:33 +02:00
Matthias 2b578633ab Merge pull request #12070 from freqtrade/dependabot/pip/develop/certifi-2025.8.3
chore(deps): bump certifi from 2025.7.14 to 2025.8.3
2025-08-04 06:52:59 +02:00
dependabot[bot] 824f555d48 chore(deps-dev): bump ruff from 0.12.5 to 0.12.7
Bumps [ruff](https://github.com/astral-sh/ruff) from 0.12.5 to 0.12.7.
- [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.12.5...0.12.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 04:50:05 +00:00
Matthias 999fd15bee Merge pull request #12067 from freqtrade/dependabot/pip/develop/mypy-1.17.1
chore(deps-dev): bump mypy from 1.17.0 to 1.17.1
2025-08-04 06:42:38 +02:00
Matthias be07879a1e chore: bump sqlalchemy in pre-commit-config 2025-08-04 06:25:36 +02:00
dependabot[bot] ab543c2680 chore(deps): bump sqlalchemy from 2.0.41 to 2.0.42
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.41 to 2.0.42.
- [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.42
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 04:06:27 +00:00
dependabot[bot] 79aa0bce5a chore(deps): bump pymdown-extensions from 10.16 to 10.16.1
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.16 to 10.16.1.
- [Release notes](https://github.com/facelessuser/pymdown-extensions/releases)
- [Commits](https://github.com/facelessuser/pymdown-extensions/compare/10.16...10.16.1)

---
updated-dependencies:
- dependency-name: pymdown-extensions
  dependency-version: 10.16.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 03:59:05 +00:00
dependabot[bot] 05a76c0297 chore(deps): bump certifi from 2025.7.14 to 2025.8.3
Bumps [certifi](https://github.com/certifi/python-certifi) from 2025.7.14 to 2025.8.3.
- [Commits](https://github.com/certifi/python-certifi/compare/2025.07.14...2025.08.03)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 03:58:33 +00:00
dependabot[bot] 15eeac3c48 chore(deps): bump xgboost from 3.0.2 to 3.0.3
Bumps [xgboost](https://github.com/dmlc/xgboost) from 3.0.2 to 3.0.3.
- [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.2...v3.0.3)

---
updated-dependencies:
- dependency-name: xgboost
  dependency-version: 3.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 03:57:56 +00:00
dependabot[bot] d8a84a7d6b chore(deps): bump ccxt from 4.4.96 to 4.4.98
Bumps [ccxt](https://github.com/ccxt/ccxt) from 4.4.96 to 4.4.98.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ccxt/ccxt/compare/v4.4.96...v4.4.98)

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

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 03:54:29 +00:00
dependabot[bot] 863a5b7b81 chore(deps-dev): bump mypy from 1.17.0 to 1.17.1
Bumps [mypy](https://github.com/python/mypy) from 1.17.0 to 1.17.1.
- [Changelog](https://github.com/python/mypy/blob/master/CHANGELOG.md)
- [Commits](https://github.com/python/mypy/compare/v1.17.0...v1.17.1)

---
updated-dependencies:
- dependency-name: mypy
  dependency-version: 1.17.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-04 03:53:13 +00:00
Matthias 4ad049aec3 test: add test-case for futures filter 2025-08-03 19:50:24 +02:00
Matthias 03c16d034d test: add test for --dex filter 2025-08-03 19:46:43 +02:00
Matthias c1f8dce109 docs: re-extract list-exchanges command partial 2025-08-03 19:46:31 +02:00
Matthias 887f513438 feat: filter list-exchanges by dex 2025-08-03 19:44:52 +02:00
Matthias 12fbae7204 chore: remove pointless dockerfile template
Noticed in #12063 - it serves no paractical use.
Developers should use the devcontainer instead.
2025-08-03 19:38:34 +02:00
Matthias a05cb8f1c5 feat: support filtering exchanges by trade mode 2025-08-03 18:25:51 +02:00
Matthias cffee80b0e chore: remove binanceje mapping 2025-08-03 17:41:55 +02:00
Matthias 0c0f2e43e8 feat: disable myOkx futures support
it's a product that doesn't exist.
2025-08-03 17:38:22 +02:00
Matthias 35456a1f32 feat: link okxus to the okx freqtrade base class
closes #12061
2025-08-03 17:34:22 +02:00
Matthias b6a6bca41b Merge pull request #12060 from freqtrade/test/kraken
Improved kraken test
2025-08-03 09:47:32 +02:00
Matthias 102cc87618 Merge pull request #12059 from freqtrade/feat/bitget
Add bitget base support
2025-08-03 09:47:19 +02:00
Matthias 1ec45dcf19 test: improve kraken fetch trades compatibility test 2025-08-03 09:15:45 +02:00
Matthias f2fb1b7919 docs(bitget): fix typo 2025-08-03 09:01:03 +02:00
Matthias 78c5b18937 docs(bitget): add bitget documentation 2025-08-03 08:51:53 +02:00
Matthias 86de1dee29 feat(bitget): add support for order time in force 2025-08-03 08:51:53 +02:00
Matthias 7afd3cb730 feat(bitget): configure mark timeframe 2025-08-03 08:51:53 +02:00
Matthias b887e2ad21 test: cleanup conftest file 2025-08-03 08:51:53 +02:00
Matthias ea2350f1ed test: add test for bitget ohlcv specifics 2025-08-03 08:51:53 +02:00
Matthias 786c858452 test: enable testing bitget spot markets 2025-08-03 08:51:53 +02:00
Matthias a6b643a33f feat: add ohlcv candle limit specific for bitget 2025-08-03 08:51:53 +02:00
Matthias 0e5235e6dc chore: add basic bitget exchange 2025-08-03 08:51:53 +02:00
Matthias c93c97c2de fix: tick_size_over_time must not use scientific notion
closes 12054
2025-08-02 11:22:19 +02:00
Matthias 271ba462b1 test: improved formatting for simplified digestion
part of #12054
2025-08-02 11:22:14 +02:00
Matthias 690918f8d3 test: add test for historic_tick_size with small numbers
part of #12054
2025-08-02 11:22:04 +02:00
Matthias de5dd66512 fix: update decimal_to_precision usage to new interface
The keyword parameter name changed in
https://github.com/ccxt/ccxt/pull/26289
Breaking how we call decimal_to_precision.
2025-08-01 06:58:32 +02:00
Matthias c8593b2307 feat: add missing keys to config schema 2025-08-01 06:58:32 +02:00
Matthias fc21757e40 Merge pull request #12055 from stash86/fix-recursive
Temporary fix in recursive analysis for candle_type_def issue
2025-08-01 06:39:20 +02:00
Stefano b6d0cde29f temporary fix until better solution is found 2025-08-01 11:24:45 +09:00
Matthias f0dfc23a5f chore: bump dev version to 2025.8 2025-07-31 19:48:24 +02:00
116 changed files with 8823 additions and 6247 deletions
+4
View File
@@ -29,6 +29,10 @@ updates:
mkdocs:
patterns:
- "mkdocs*"
scipy:
patterns:
- "scipy"
- "scipy-stubs"
- package-ecosystem: "github-actions"
directory: "/"
@@ -15,7 +15,7 @@ jobs:
environment:
name: develop
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
+24 -67
View File
@@ -28,7 +28,7 @@ jobs:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -38,7 +38,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0
with:
activate-environment: true
enable-cache: true
@@ -47,24 +47,9 @@ jobs:
cache-suffix: "${{ matrix.python-version }}"
prune-cache: false
- name: Cache_dependencies
uses: actions/cache@v4
id: cache
with:
path: ~/dependencies/
key: ${{ runner.os }}-dependencies
- name: TA binary *nix
if: steps.cache.outputs.cache-hit != 'true'
run: |
cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd ..
- name: Installation - *nix
run: |
uv pip install --upgrade wheel
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
export TA_INCLUDE_PATH=${HOME}/dependencies/include
uv pip install -r requirements-dev.txt
uv pip install -e ft_client/
uv pip install -e .
@@ -163,7 +148,7 @@ jobs:
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -174,7 +159,7 @@ jobs:
check-latest: true
- name: Install uv
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0
with:
activate-environment: true
enable-cache: true
@@ -183,18 +168,6 @@ jobs:
cache-suffix: "${{ matrix.python-version }}"
prune-cache: false
- name: Cache_dependencies
uses: actions/cache@v4
id: cache
with:
path: ~/dependencies/
key: ${{ matrix.os }}-dependencies
- name: TA binary *nix
if: steps.cache.outputs.cache-hit != 'true'
run: |
cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd ..
- name: Installation - macOS (Brew)
run: |
# brew update
@@ -222,9 +195,6 @@ jobs:
- name: Installation (python)
run: |
uv pip install wheel
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
export TA_INCLUDE_PATH=${HOME}/dependencies/include
uv pip install -r requirements-dev.txt
uv pip install -e ft_client/
uv pip install -e .
@@ -287,11 +257,11 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ windows-latest ]
os: [ "windows-2022", "windows-2025" ]
python-version: ["3.11", "3.12", "3.13"]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -301,7 +271,7 @@ jobs:
python-version: ${{ matrix.python-version }}
- name: Install uv
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0
with:
activate-environment: true
enable-cache: true
@@ -315,7 +285,9 @@ jobs:
function uvpipFunction { uv pip $args }
Set-Alias -name pip -value uvpipFunction
./build_helpers/install_windows.ps1
python -m pip install --upgrade pip
pip install -r requirements-dev.txt
pip install -e .
- name: Tests
run: |
@@ -379,7 +351,7 @@ jobs:
mypy-version-check:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -396,7 +368,7 @@ jobs:
pre-commit:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -408,7 +380,7 @@ jobs:
docs-check:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -439,7 +411,7 @@ jobs:
# Run pytest with "live" checks
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -449,7 +421,7 @@ jobs:
python-version: "3.12"
- name: Install uv
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
uses: astral-sh/setup-uv@4959332f0f014c5280e7eac8b70c90cb574c9f9b # v6.6.0
with:
activate-environment: true
enable-cache: true
@@ -458,25 +430,9 @@ jobs:
cache-suffix: "3.12"
prune-cache: false
- name: Cache_dependencies
uses: actions/cache@v4
id: cache
with:
path: ~/dependencies/
key: ${{ runner.os }}-dependencies
- name: TA binary *nix
if: steps.cache.outputs.cache-hit != 'true'
run: |
cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies/; cd ..
- name: Installation - *nix
run: |
uv pip install --upgrade wheel
export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
export TA_LIBRARY_PATH=${HOME}/dependencies/lib
export TA_INCLUDE_PATH=${HOME}/dependencies/include
uv pip install -r requirements-dev.txt
uv pip install -e ft_client/
uv pip install -e .
@@ -508,15 +464,16 @@ jobs:
- name: Check user permission
id: check
uses: scherermichael-oss/action-has-permission@136e061bfe093832d87f090dd768e14e27a740d3 # 1.0.6
continue-on-error: true
uses: prince-chrismc/check-actor-permissions-action@d504e74ba31658f4cdf4fcfeb509d4c09736d88e # v3.0.2
with:
required-permission: write
permission: "write"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Discord notification
uses: rjstone/discord-webhook-notify@c2597273488aeda841dd1e891321952b51f7996f #v2.2.1
if: always() && steps.check.outputs.has-permission && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
if: steps.check.outputs.permitted == 'true' && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
with:
severity: info
details: Test Completed!
@@ -528,7 +485,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -575,12 +532,12 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Download artifact 📦
uses: actions/download-artifact@v4
uses: actions/download-artifact@v5
with:
pattern: freqtrade*-build
path: dist
@@ -604,12 +561,12 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Download artifact 📦
uses: actions/download-artifact@v4
uses: actions/download-artifact@v5
with:
pattern: freqtrade*-build
path: dist
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
name: Deploy Docs through mike
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: true
+2 -2
View File
@@ -24,11 +24,11 @@ jobs:
packages: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
- name: Login to GitHub Container Registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
registry: ghcr.io
username: ${{ github.actor }}
+4 -3
View File
@@ -22,11 +22,12 @@ permissions:
jobs:
deploy-docker:
name: "Deploy Docker x64 and armv7l"
runs-on: ubuntu-22.04
if: github.repository == 'freqtrade/freqtrade'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
@@ -74,7 +75,7 @@ jobs:
build_helpers/publish_docker_multi.sh
deploy-arm:
name: "Deploy Docker"
name: "Deploy Docker ARM64"
permissions:
packages: write
needs: [ deploy-docker ]
@@ -83,7 +84,7 @@ jobs:
if: github.repository == 'freqtrade/freqtrade'
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
+1 -1
View File
@@ -11,7 +11,7 @@ jobs:
dockerHubDescription:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
auto-update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
persist-credentials: false
+2 -2
View File
@@ -21,9 +21,9 @@ jobs:
# actions: read # only needed for private repos
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@ff7abcd0c3c05ccf6adc123a8cd1fd4fb30fb493 # v4.2.2
with:
persist-credentials: false
- name: Run zizmor 🌈
uses: zizmorcore/zizmor-action@f52a838cfabf134edcbaa7c8b3677dde20045018 # v0.1.1
uses: zizmorcore/zizmor-action@5ca5fc7a4779c5263a3ffa0e1f693009994446d1 # v0.1.2
+8 -8
View File
@@ -21,18 +21,18 @@ repos:
# stages: [push]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v1.17.0"
rev: "v1.17.1"
hooks:
- id: mypy
exclude: build_helpers
additional_dependencies:
- types-cachetools==6.1.0.20250717
- types-filelock==3.2.7
- types-requests==2.32.4.20250611
- types-requests==2.32.4.20250809
- types-tabulate==0.9.0.20241207
- types-python-dateutil==2.9.0.20250708
- scipy-stubs==1.16.0.2
- SQLAlchemy==2.0.41
- types-python-dateutil==2.9.0.20250822
- scipy-stubs==1.16.1.1
- SQLAlchemy==2.0.43
# stages: [push]
- repo: https://github.com/pycqa/isort
@@ -44,13 +44,13 @@ repos:
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.12.5'
rev: 'v0.12.10'
hooks:
- id: ruff
- id: ruff-format
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
rev: v6.0.0
hooks:
- id: end-of-file-fixer
exclude: |
@@ -83,6 +83,6 @@ repos:
# Ensure github actions remain safe
- repo: https://github.com/woodruffw/zizmor-pre-commit
rev: v1.11.0
rev: v1.12.1
hooks:
- id: zizmor
+2 -7
View File
@@ -1,4 +1,4 @@
FROM python:3.13.5-slim-bookworm AS base
FROM python:3.13.7-slim-bookworm AS base
# Setup env
ENV LANG=C.UTF-8
@@ -27,11 +27,6 @@ RUN apt-get update \
&& apt-get clean \
&& pip install --upgrade pip wheel
# Install TA-lib
COPY build_helpers/* /tmp/
RUN cd /tmp && /tmp/install_ta-lib.sh && rm -r /tmp/*ta-lib*
ENV LD_LIBRARY_PATH=/usr/local/lib
# Install dependencies
COPY --chown=ftuser:ftuser requirements.txt requirements-hyperopt.txt /freqtrade/
USER ftuser
@@ -49,7 +44,7 @@ USER ftuser
# Install and execute
COPY --chown=ftuser:ftuser . /freqtrade/
RUN pip install -e . --user --no-cache-dir --no-build-isolation \
RUN pip install -e . --user --no-cache-dir \
&& mkdir /freqtrade/user_data/ \
&& freqtrade install-ui
-1
View File
@@ -4,7 +4,6 @@
[![DOI](https://joss.theoj.org/papers/10.21105/joss.04864/status.svg)](https://doi.org/10.21105/joss.04864)
[![Coverage Status](https://coveralls.io/repos/github/freqtrade/freqtrade/badge.svg?branch=develop&service=github)](https://coveralls.io/github/freqtrade/freqtrade?branch=develop)
[![Documentation](https://readthedocs.org/projects/freqtrade/badge/)](https://www.freqtrade.io)
[![Maintainability](https://api.codeclimate.com/v1/badges/5737e6d668200b7518ff/maintainability)](https://codeclimate.com/github/freqtrade/freqtrade/maintainability)
Freqtrade is a free and open source crypto trading bot written in Python. It is designed to support all major exchanges and be controlled via Telegram or webUI. It contains backtesting, plotting and money management tools as well as strategy optimization by machine learning.
-35
View File
@@ -1,35 +0,0 @@
if [ -z "$1" ]; then
INSTALL_LOC=/usr/local
else
INSTALL_LOC=${1}
fi
echo "Installing to ${INSTALL_LOC}"
if [ -n "$2" ] || [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then
tar zxvf ta-lib-0.4.0-src.tar.gz
cd ta-lib \
&& sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \
&& echo "Downloading gcc config.guess and config.sub" \
&& curl -s 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.guess' -o config.guess \
&& curl -s 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.sub' -o config.sub \
&& ./configure --prefix=${INSTALL_LOC}/ \
&& make
if [ $? -ne 0 ]; then
echo "Failed building ta-lib."
cd .. && rm -rf ./ta-lib/
exit 1
fi
if [ -z "$2" ]; then
which sudo && sudo make install || make install
if [ -x "$(command -v apt-get)" ]; then
echo "Updating library path using ldconfig"
sudo ldconfig
fi
else
# Don't install with sudo
make install
fi
cd .. && rm -rf ./ta-lib/
else
echo "TA-lib already installed, skipping installation"
fi
-10
View File
@@ -1,10 +0,0 @@
# vendored Wheels compiled via https://github.com/xmatthias/ta-lib-python/tree/ta_bundled_040
python -m pip install --upgrade pip
python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"
pip install -U wheel "numpy<3.0"
pip install --only-binary ta-lib --find-links=build_helpers\ "ta-lib<0.6.0"
pip install -r requirements-dev.txt
pip install -e .
+11
View File
@@ -180,6 +180,16 @@
"description": "Offset for profit exit. \nUsually specified in the strategy and missing in the configuration.",
"type": "number"
},
"recursive_strategy_search": {
"description": "Enable recursive strategy search.",
"type": "boolean"
},
"user_data_dir": {
"description": "Path to the user data directory."
},
"datadir": {
"description": "Path to the data directory."
},
"fee": {
"description": "Trading fee percentage. Can help to simulate slippage in backtesting",
"type": "number",
@@ -562,6 +572,7 @@
"pairlists": {
"description": "Configuration for pairlists.",
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -34,7 +34,7 @@ COPY build_helpers/* /tmp/
# Install dependencies
COPY --chown=ftuser:ftuser requirements.txt /freqtrade/
USER ftuser
RUN pip install --user --no-cache-dir "numpy<3.0" \
RUN pip install --user --prefer-binary --no-cache-dir "numpy<3.0" build \
&& pip install --user --no-index --find-links /tmp/ pyarrow TA-Lib \
&& pip install --user --no-cache-dir -r requirements.txt
@@ -49,7 +49,7 @@ USER ftuser
# Install and execute
COPY --chown=ftuser:ftuser . /freqtrade/
RUN pip install -e . --user --no-cache-dir --no-build-isolation\
RUN pip install -e . --user --no-cache-dir \
&& mkdir /freqtrade/user_data/ \
&& freqtrade install-ui
-10
View File
@@ -1,10 +0,0 @@
FROM freqtradeorg/freqtrade:develop
# Install dependencies
COPY requirements-dev.txt /freqtrade/
RUN pip install numpy --user --no-cache-dir \
&& pip install -r requirements-dev.txt --user --no-cache-dir
# Empty the ENTRYPOINT to allow all commands
ENTRYPOINT []
+12 -9
View File
@@ -46,29 +46,32 @@ ranging from the simplest (0) to the most detailed per pair, per buy and per sel
More options are available by running with the `-h` option.
### Using export-filename
### Using backtest-filename
Normally, `backtesting-analysis` uses the latest backtest results, but if you wanted to go
back to a previous backtest output, you need to supply the `--export-filename` option.
You can supply the same parameter to `backtest-analysis` with the name of the final backtest
output file. This allows you to keep historical versions of backtest results and re-analyse
them at a later date:
By default, `backtesting-analysis` processes the most recent backtest results in the `user_data/backtest_results` directory.
If you want to analyze results from an earlier backtest, use the `--backtest-filename` option to specify the desired file. This lets you revisit and re-analyze historical backtest outputs at any time by providing the filename of the relevant backtest result:
``` bash
freqtrade backtesting -c <config.json> --timeframe <tf> --strategy <strategy_name> --timerange=<timerange> --export=signals --export-filename=/tmp/mystrat_backtest.json
freqtrade backtesting-analysis -c <config.json> --timeframe <tf> --strategy <strategy_name> --timerange <timerange> --export signals --backtest-filename backtest-result-2025-03-05_20-38-34.zip
```
You should see some output similar to below in the logs with the name of the timestamped
filename that was exported:
```
2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "/tmp/mystrat_backtest-2022-06-14_16-28-32.json"
2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "mystrat_backtest-2022-06-14_16-28-32.json"
```
You can then use that filename in `backtesting-analysis`:
```
freqtrade backtesting-analysis -c <config.json> --export-filename=/tmp/mystrat_backtest-2022-06-14_16-28-32.json
freqtrade backtesting-analysis -c <config.json> --backtest-filename=mystrat_backtest-2022-06-14_16-28-32.json
```
To use a result from a different results directory, you can use `--backtest-directory` to specify the directory
``` bash
freqtrade backtesting-analysis -c <config.json> --backtest-directory custom_results/ --backtest-filename mystrat_backtest-2022-06-14_16-28-32.json
```
### Tuning the buy tags and sell tags to display
+235 -204
View File
@@ -105,12 +105,14 @@ Only use this if you're sure you'll not want to plot or analyze your results fur
---
Exporting trades to file specifying a custom filename
Exporting trades to file specifying a custom directory
```bash
freqtrade backtesting --strategy backtesting --export trades --export-filename=backtest_samplestrategy.json
freqtrade backtesting --strategy backtesting --export trades --backtest-directory=user_data/custom-backtest-results
```
---
Please also read about the [strategy startup period](strategy-customization.md#strategy-startup-period).
---
@@ -158,117 +160,136 @@ The most important in the backtesting is to understand the result.
A backtesting result will look like that:
```
================================================ BACKTESTING REPORT =================================================
| Pair | Trades | Avg Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Wins Draws Loss Win% |
|----------+--------+----------------+------------------+----------------+--------------+--------------------------|
| ADA/BTC | 35 | -0.11 | -0.00019428 | -1.94 | 4:35:00 | 14 0 21 40.0 |
| ARK/BTC | 11 | -0.41 | -0.00022647 | -2.26 | 2:03:00 | 3 0 8 27.3 |
| BTS/BTC | 32 | 0.31 | 0.00048938 | 4.89 | 5:05:00 | 18 0 14 56.2 |
| DASH/BTC | 13 | -0.08 | -0.00005343 | -0.53 | 4:39:00 | 6 0 7 46.2 |
| ENG/BTC | 18 | 1.36 | 0.00122807 | 12.27 | 2:50:00 | 8 0 10 44.4 |
| EOS/BTC | 36 | 0.08 | 0.00015304 | 1.53 | 3:34:00 | 16 0 20 44.4 |
| ETC/BTC | 26 | 0.37 | 0.00047576 | 4.75 | 6:14:00 | 11 0 15 42.3 |
| ETH/BTC | 33 | 0.30 | 0.00049856 | 4.98 | 7:31:00 | 16 0 17 48.5 |
| IOTA/BTC | 32 | 0.03 | 0.00005444 | 0.54 | 3:12:00 | 14 0 18 43.8 |
| LSK/BTC | 15 | 1.75 | 0.00131413 | 13.13 | 2:58:00 | 6 0 9 40.0 |
| LTC/BTC | 32 | -0.04 | -0.00006886 | -0.69 | 4:49:00 | 11 0 21 34.4 |
| NANO/BTC | 17 | 1.26 | 0.00107058 | 10.70 | 1:55:00 | 10 0 7 58.5 |
| NEO/BTC | 23 | 0.82 | 0.00094936 | 9.48 | 2:59:00 | 10 0 13 43.5 |
| REQ/BTC | 9 | 1.17 | 0.00052734 | 5.27 | 3:47:00 | 4 0 5 44.4 |
| XLM/BTC | 16 | 1.22 | 0.00097800 | 9.77 | 3:15:00 | 7 0 9 43.8 |
| XMR/BTC | 23 | -0.18 | -0.00020696 | -2.07 | 5:30:00 | 12 0 11 52.2 |
| XRP/BTC | 35 | 0.66 | 0.00114897 | 11.48 | 3:49:00 | 12 0 23 34.3 |
| ZEC/BTC | 22 | -0.46 | -0.00050971 | -5.09 | 2:22:00 | 7 0 15 31.8 |
| TOTAL | 429 | 0.36 | 0.00762792 | 76.20 | 4:12:00 | 186 0 243 43.4 |
============================================= LEFT OPEN TRADES REPORT =============================================
| Pair | Trades | Avg Profit % | Tot Profit BTC | Tot Profit % | Avg Duration | Win Draw Loss Win% |
|----------+---------+----------------+------------------+----------------+----------------+---------------------|
| ADA/BTC | 1 | 0.89 | 0.00004434 | 0.44 | 6:00:00 | 1 0 0 100 |
| LTC/BTC | 1 | 0.68 | 0.00003421 | 0.34 | 2:00:00 | 1 0 0 100 |
| TOTAL | 2 | 0.78 | 0.00007855 | 0.78 | 4:00:00 | 2 0 0 100 |
==================== EXIT REASON STATS ====================
| Exit Reason | Exits | Wins | Draws | Losses |
|--------------------+---------+-------+--------+---------|
| trailing_stop_loss | 205 | 150 | 0 | 55 |
| stop_loss | 166 | 0 | 0 | 166 |
| exit_signal | 56 | 36 | 0 | 20 |
| force_exit | 2 | 0 | 0 | 2 |
BACKTESTING REPORT
┏━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ LTC/USDT:USDT │ 16 │ 1.0 │ 56.176 │ 5.62 │ 16:16:00 │ 16 0 0 100 │
│ ETC/USDT:USDT │ 12 0.72 │ 30.936 │ 3.09 │ 9:55:00 │ 11 0 1 91.7 │
│ ETH/USDT:USDT │ 8 │ 0.66 │ 17.864 │ 1.79 │ 1 day, 13:55:00 7 0 1 87.5 │
│ XLM/USDT:USDT │ 10 │ 0.31 │ 11.054 │ 1.11 │ 12:08:00 │ 9 0 1 90.0 │
│ BTC/USDT:USDT │ 8 │ 0.21 │ 7.289 │ 0.73 3 days, 1:24:00 6 0 2 75.0 │
│ XRP/USDT:USDT │ 9 │ -0.14 │ -7.261 │ -0.73 │ 21:18:00 8 0 1 88.9 │
│ DOT/USDT:USDT │ 6 │ -0.4 │ -9.187 │ -0.92 │ 5:35:00 4 0 2 66.7 │
│ ADA/USDT:USDT │ 8 │ -1.76 │ -52.098 │ -5.21 │ 11:38:00 │ 6 0 2 75.0 │
TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0
└───────────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
LEFT OPEN TRADES REPORT
┏━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Pair ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
┡━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ BTC/USDT:USDT │ 1 │ -4.14 │ -9.930 │ -0.99 │ 17 days, 8:00:00 0 0 1 0 │
│ ETC/USDT:USDT │ 1 │ -4.24 │ -15.365 │ -1.54 │ 10:40:00 0 0 1 0 │
│ DOT/USDT:USDT │ 1 │ -5.29 │ -19.125 │ -1.91 │ 11:30:00 │ 0 0 1 0 │
│ TOTAL │ 3 │ -4.56 │ -44.420 │ -4.44 │ 6 days, 2:03:00 0 0 3 0 │
└───────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────────┴────────────────────────┘
ENTER TAG STATS
┏━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Enter Tag ┃ Entries ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
┡━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ OTHER │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
└───────────┴─────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┘
EXIT REASON STATS
┏━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Exit Reason ┃ Exits ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
┡━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ roi │ 67 │ 1.05 │ 242.179 │ 24.22 │ 15:49:00 67 0 0 100 │
│ exit_signal │ 4 │ -2.23 │ -31.217 │ -3.12 │ 1 day, 8:38:00 │ 0 0 4 0 │
│ force_exit │ 3 │ -4.56 │ -44.420 │ -4.44 │ 6 days, 2:03:00 │ 0 0 3 0 │
│ stop_loss │ 3 │ -10.14 │ -111.768 │ -11.18 │ 1 day, 3:05:00 │ 0 0 3 0 │
│ TOTAL │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
└─────────────┴───────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
MIXED TAG STATS
┏━━━━━━━━━━━┳━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Enter Tag ┃ Exit Reason ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ │ roi │ 67 │ 1.05 │ 242.179 │ 24.22 │ 15:49:00 │ 67 0 0 100 │
│ │ exit_signal │ 4 │ -2.23 │ -31.217 │ -3.12 │ 1 day, 8:38:00 │ 0 0 4 0 │
│ │ force_exit │ 3 │ -4.56 │ -44.420 │ -4.44 │ 6 days, 2:03:00 │ 0 0 3 0 │
│ │ stop_loss │ 3 │ -10.14 │ -111.768 │ -11.18 │ 1 day, 3:05:00 │ 0 0 3 0 │
│ TOTAL │ │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │
└───────────┴─────────────┴────────┴──────────────┴─────────────────┴──────────────┴─────────────────┴────────────────────────┘
SUMMARY METRICS
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Metric ┃ Value ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ Backtesting from │ 2025-07-01 00:00:00 │
│ Backtesting to │ 2025-08-01 00:00:00 │
│ Trading Mode │ Isolated Futures │
│ Max open trades │ 3 │
│ │ │
│ Total/Daily Avg Trades │ 77 / 2.48 │
│ Starting balance │ 1000 USDT │
│ Final balance │ 1054.774 USDT │
│ Absolute profit │ 54.774 USDT │
│ Total profit % │ 5.48% │
│ CAGR % │ 87.36% │
│ Sortino │ 2.48 │
│ Sharpe │ 3.75 │
│ Calmar │ 40.99 │
│ SQN │ 0.69 │
│ Profit factor │ 1.29 │
│ Expectancy (Ratio) │ 0.71 (0.04) │
│ Avg. daily profit │ 1.767 USDT │
│ Avg. stake amount │ 345.016 USDT │
│ Total trade volume │ 53316.954 USDT │
│ │ │
│ Long / Short trades │ 67 / 10 │
│ Long / Short profit % │ 8.94% / -3.47% │
│ Long / Short profit USDT │ 89.425 / -34.651 │
│ │ │
│ Best Pair │ LTC/USDT:USDT 5.62% │
│ Worst Pair │ ADA/USDT:USDT -5.21% │
│ Best trade │ ETC/USDT:USDT 2.00% │
│ Worst trade │ ADA/USDT:USDT -10.17% │
│ Best day │ 26.91 USDT │
│ Worst day │ -47.741 USDT │
│ Days win/draw/lose │ 20 / 6 / 5 │
│ Min/Max/Avg. Duration Winners │ 0d 00:35 / 5d 18:15 / 0d 15:49 │
│ Min/Max/Avg. Duration Losers │ 0d 10:40 / 17d 08:00 / 2d 17:00 │
│ Max Consecutive Wins / Loss │ 36 / 3 │
│ Rejected Entry signals │ 258 │
│ Entry/Exit Timeouts │ 0 / 0 │
│ │ │
│ Min balance │ 1003.168 USDT │
│ Max balance │ 1149.421 USDT │
│ Max % of account underwater │ 8.23% │
│ Absolute drawdown │ 94.647 USDT (8.23%) │
│ Drawdown duration │ 9 days 08:50:00 │
│ Profit at drawdown start │ 149.421 USDT │
│ Profit at drawdown end │ 54.774 USDT │
│ Drawdown start │ 2025-07-22 15:10:00 │
│ Drawdown end │ 2025-08-01 00:00:00 │
│ Market change │ 30.51% │
└───────────────────────────────┴─────────────────────────────────┘
================== SUMMARY METRICS ==================
| Metric | Value |
|-----------------------------+---------------------|
| Backtesting from | 2019-01-01 00:00:00 |
| Backtesting to | 2019-05-01 00:00:00 |
| Trading Mode | Spot |
| Max open trades | 3 |
| | |
| Total/Daily Avg Trades | 429 / 3.575 |
| Starting balance | 0.01000000 BTC |
| Final balance | 0.01762792 BTC |
| Absolute profit | 0.00762792 BTC |
| Total profit % | 76.2% |
| CAGR % | 460.87% |
| Sortino | 1.88 |
| Sharpe | 2.97 |
| Calmar | 6.29 |
| SQN | 2.45 |
| Profit factor | 1.11 |
| Expectancy (Ratio) | -0.15 (-0.05) |
| Avg. stake amount | 0.001 BTC |
| Total trade volume | 0.429 BTC |
| | |
| Long / Short | 352 / 77 |
| Total profit Long % | 1250.58% |
| Total profit Short % | -15.02% |
| Absolute profit Long | 0.00838792 BTC |
| Absolute profit Short | -0.00076 BTC |
| | |
| Best Pair | LSK/BTC 26.26% |
| Worst Pair | ZEC/BTC -10.18% |
| Best Trade | LSK/BTC 4.25% |
| Worst Trade | ZEC/BTC -10.25% |
| Best day | 0.00076 BTC |
| Worst day | -0.00036 BTC |
| Days win/draw/lose | 12 / 82 / 25 |
| Avg. Duration Winners | 4:23:00 |
| Avg. Duration Loser | 6:55:00 |
| Max Consecutive Wins / Loss | 3 / 4 |
| Rejected Entry signals | 3089 |
| Entry/Exit Timeouts | 0 / 0 |
| Canceled Trade Entries | 34 |
| Canceled Entry Orders | 123 |
| Replaced Entry Orders | 89 |
| | |
| Min balance | 0.00945123 BTC |
| Max balance | 0.01846651 BTC |
| Max % of account underwater | 25.19% |
| Absolute Drawdown (Account) | 13.33% |
| Drawdown | 0.0015 BTC |
| Drawdown high | 0.0013 BTC |
| Drawdown low | -0.0002 BTC |
| Drawdown Start | 2019-02-15 14:10:00 |
| Drawdown End | 2019-04-11 18:15:00 |
| Market change | -5.88% |
=====================================================
Backtested 2025-07-01 00:00:00 -> 2025-08-01 00:00:00 | Max open trades : 3
STRATEGY SUMMARY
┏━━━━━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━┓
┃ Strategy ┃ Trades ┃ Avg Profit % ┃ Tot Profit USDT ┃ Tot Profit % ┃ Avg Duration ┃ Win Draw Loss Win% ┃ Drawdown ┃
┡━━━━━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━┩
│ SampleStrategy │ 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 │ 67 0 10 87.0 │ 94.647 USDT 8.23% │
└────────────────┴────────┴──────────────┴─────────────────┴──────────────┴──────────────┴────────────────────────┴────────────────────┘
```
### Backtesting report table
The 1st table contains all trades the bot made, including "left open trades".
The first table contains all trades the bot made, including "left open trades".
The last line will give you the overall performance of your strategy,
here:
```
| TOTAL | 429 | 0.36 | 152.41 | 0.00762792 | 76.20 | 4:12:00 | 186 0 243 43.4 |
TOTAL 77 │ 0.22 │ 54.774 │ 5.48 │ 22:12:00 67 0 10 87.0 │
```
The bot has made `429` trades for an average duration of `4:12:00`, with a performance of `76.20%` (profit), that means it has
earned a total of `0.00762792 BTC` starting with a capital of 0.01 BTC.
The bot has made `77` trades for an average duration of `22:12:00`, with a performance of `5.48%` (profit), that means it has earned a total of `54.774 USDT` starting with a capital of 1000 USDT.
The column `Avg Profit %` shows the average profit for all trades made.
The column `Tot Profit %` shows instead the total profit % in relation to the starting balance.
In the above results, we have a starting balance of 0.01 BTC and an absolute profit of 0.00762792 BTC - so the `Tot Profit %` will be `(0.00762792 / 0.01) * 100 ~= 76.2%`.
In the above results, we have a starting balance of 1000 USDT and an absolute profit of 54.774 USDT - so the `Tot Profit %` will be `(54.774 / 1000) * 100 ~= 5.48%`.
Your strategy performance is influenced by your entry strategy, your exit strategy, and also by the `minimal_roi` and `stop_loss` you have set.
@@ -284,86 +305,83 @@ On the other hand, if you set a too high `minimal_roi` like `"0": 0.55`
(55%), there is almost no chance that the bot will ever reach this profit.
Hence, keep in mind that your performance is an integral mix of all different elements of the strategy, your configuration, and the crypto-currency pairs you have set up.
### Exit reasons table
The 2nd table contains a recap of exit reasons.
This table can tell you which area needs some additional work (e.g. all or many of the `exit_signal` trades are losses, so you should work on improving the exit signal, or consider disabling it).
### Left open trades table
The 3rd table contains all trades the bot had to `force_exit` at the end of the backtesting period to present you the full picture.
The second table contains all trades the bot had to `force_exit` at the end of the backtesting period to present you the full picture.
This is necessary to simulate realistic behavior, since the backtest period has to end at some point, while realistically, you could leave the bot running forever.
These trades are also included in the first table, but are also shown separately in this table for clarity.
### Enter tag stats table
The third table provides a breakdown of trades by their entry tags (e.g., `enter_long`, `enter_short`), showing the number of entries, average profit percentage, total profit in the stake currency, total profit percentage, average duration, and the number of wins, draws, and losses for each tag.
### Exit reason stats table
The fourth table contains a recap of exit reasons (e.g., `exit_signal`, `roi`, `stop_loss`, `force_exit`). This table can tell you which area needs additional work (e.g., if many `exit_signal` trades are losses, you should work on improving the exit signal or consider disabling it).
### Mixed tag stats table
The fifth table combines entry tags and exit reasons, providing a detailed view of how different entry tags performed with specific exit reasons. This can help identify which combinations of entry and exit strategies are most effective.
### Summary metrics
The last element of the backtest report is the summary metrics table.
It contains some useful key metrics about performance of your strategy on backtesting data.
It contains key metrics about the performance of your strategy on backtesting data.
```
================== SUMMARY METRICS ==================
| Metric | Value |
|-----------------------------+---------------------|
| Backtesting from | 2019-01-01 00:00:00 |
| Backtesting to | 2019-05-01 00:00:00 |
| Trading Mode | Spot |
| Max open trades | 3 |
| | |
| Total/Daily Avg Trades | 429 / 3.575 |
| Starting balance | 0.01000000 BTC |
| Final balance | 0.01762792 BTC |
| Absolute profit | 0.00762792 BTC |
| Total profit % | 76.2% |
| CAGR % | 460.87% |
| Sortino | 1.88 |
| Sharpe | 2.97 |
| Calmar | 6.29 |
| SQN | 2.45 |
| Profit factor | 1.11 |
| Expectancy (Ratio) | -0.15 (-0.05) |
| Avg. daily profit | 0.0001 BTC |
| Avg. stake amount | 0.001 BTC |
| Total trade volume | 0.429 BTC |
| | |
| Long / Short | 352 / 77 |
| Total profit Long % | 1250.58% |
| Total profit Short % | -15.02% |
| Absolute profit Long | 0.00838792 BTC |
| Absolute profit Short | -0.00076 BTC |
| | |
| Best Pair | LSK/BTC 26.26% |
| Worst Pair | ZEC/BTC -10.18% |
| Best Trade | LSK/BTC 4.25% |
| Worst Trade | ZEC/BTC -10.25% |
| Best day | 0.00076 BTC |
| Worst day | -0.00036 BTC |
| Days win/draw/lose | 12 / 82 / 25 |
| Avg. Duration Winners | 4:23:00 |
| Avg. Duration Loser | 6:55:00 |
| Max Consecutive Wins / Loss | 3 / 4 |
| Rejected Entry signals | 3089 |
| Entry/Exit Timeouts | 0 / 0 |
| Canceled Trade Entries | 34 |
| Canceled Entry Orders | 123 |
| Replaced Entry Orders | 89 |
| | |
| Min balance | 0.00945123 BTC |
| Max balance | 0.01846651 BTC |
| Max % of account underwater | 25.19% |
| Absolute Drawdown (Account) | 13.33% |
| Drawdown | 0.0015 BTC |
| Drawdown high | 0.0013 BTC |
| Drawdown low | -0.0002 BTC |
| Drawdown Start | 2019-02-15 14:10:00 |
| Drawdown End | 2019-04-11 18:15:00 |
| Market change | -5.88% |
=====================================================
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
Metric Value
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
Backtesting from 2025-07-01 00:00:00
Backtesting to 2025-08-01 00:00:00
Trading Mode │ Isolated Futures
Max open trades 3
│ │ │
Total/Daily Avg Trades │ 72 / 2.32 │
Starting balance │ 1000 USDT │
Final balance │ 1106.734 USDT
Absolute profit │ 106.734 USDT
Total profit % │ 10.67%
CAGR % │ 230.04%
Sortino │ 4.99
Sharpe │ 8.00
Calmar │ 77.76
SQN │ 1.52
Profit factor │ 1.79
Expectancy (Ratio) │ 1.48 (0.07)
Avg. daily profit │ 3.443 USDT
Avg. stake amount │ 363.133 USDT
Total trade volume │ 52466.174 USDT
│ │ │
│ Best Pair │ LTC/USDT:USDT 4.48% │
│ Worst Pair │ ADA/USDT:USDT -1.78%
│ Best trade │ ETC/USDT:USDT 2.00%
│ Worst trade │ ADA/USDT:USDT -10.17% │
│ Best day │ 23.535 USDT │
│ Worst day │ -49.813 USDT │
│ Days win/draw/lose │ 21 / 6 / 4 │
│ Min/Max/Avg. Duration Winners │ 0d 00:35 / 5d 18:15 / 0d 15:30 │
│ Min/Max/Avg. Duration Losers │ 0d 12:00 / 17d 08:00 / 3d 23:28 │
│ Max Consecutive Wins / Loss │ 58 / 4 │
│ Rejected Entry signals │ 254 │
│ Entry/Exit Timeouts │ 0 / 0 │
│ │ │
│ Min balance │ 1003.168 USDT │
│ Max balance │ 1209 USDT │
Max % of account underwater │ 8.46%
│ Absolute drawdown │ 102.266 USDT (8.46%) │
│ Drawdown duration │ 9 days 08:50:00
│ Profit at drawdown start │ 209 USDT │
│ Profit at drawdown end 106.734 USDT
│ Drawdown start │ 2025-07-22 15:10:00 │
│ Drawdown end │ 2025-08-01 00:00:00 │
Market change │ 30.51% │
└───────────────────────────────┴─────────────────────────────────┘
```
- `Backtesting from` / `Backtesting to`: Backtesting range (usually defined with the `--timerange` option).
- `Max open trades`: Setting of `max_open_trades` (or `--max-open-trades`) - or number of pairs in the pairlist (whatever is lower).
- `Trading Mode`: Spot or Futures trading.
- `Max open trades`: Setting of `max_open_trades` (or `--max-open-trades`) - or number of pairs in the pairlist (whatever is lower).
- `Total/Daily Avg Trades`: Identical to the total trades of the backtest output table / Total trades divided by the backtesting duration in days (this will give you information about how many trades to expect from the strategy).
- `Starting balance`: Start balance - as given by dry-run-wallet (config or command line).
- `Final balance`: Final balance - starting balance + absolute profit.
@@ -374,58 +392,71 @@ It contains some useful key metrics about performance of your strategy on backte
- `Sharpe`: Annualized Sharpe ratio.
- `Calmar`: Annualized Calmar ratio.
- `SQN`: System Quality Number (SQN) - by Van Tharp.
- `Profit factor`: profit / loss.
- `Profit factor`: Sum of the profits of all winning trades divided by the sum of the losses of all losing trades.
- `Expectancy (Ratio)`: Expectancy ratio, which is the average profit or loss per trade. A negative expectancy ratio means that your strategy is not profitable.
- `Avg. daily profit`: Average profit per day, calculated as `(Total Profit / Backtest Days)`.
- `Avg. stake amount`: Average stake amount, either `stake_amount` or the average when using dynamic stake amount.
- `Total trade volume`: Volume generated on the exchange to reach the above profit.
- `Best Pair` / `Worst Pair`: Best and worst performing pair (based on absolute profit), and it's corresponding `Tot Profit %`.
- `Best Trade` / `Worst Trade`: Biggest single winning trade and biggest single losing trade.
- `Long / Short trades`: Split long/short trade counts (only shown when short trades were made).
- `Long / Short profit %`: Profit percentage for long and short trades (only shown when short trades were made).
- `Long / Short profit USDT`: Profit in stake currency for long and short trades (only shown when short trades were made).
- `Best Pair` / `Worst Pair`: Best and worst performing pair (based on total profit percentage), and its corresponding `Tot Profit %`.
- `Best trade` / `Worst trade`: Biggest single winning trade and biggest single losing trade.
- `Best day` / `Worst day`: Best and worst day based on daily profit.
- `Days win/draw/lose`: Winning / Losing days (draws are usually days without closed trade).
- `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades.
- `Days win/draw/lose`: Winning / Losing days (draws are usually days without closed trades).
- `Min/Max/Avg. Duration Winners`: Minimum, maximum, and average durations for winning trades.
- `Min/Max/Avg. Duration Losers`: Minimum, maximum, and average durations for losing trades.
- `Max Consecutive Wins / Loss`: Maximum consecutive wins/losses in a row.
- `Rejected Entry signals`: Trade entry signals that could not be acted upon due to `max_open_trades` being reached.
- `Entry/Exit Timeouts`: Entry/exit orders which did not fill (only applicable if custom pricing is used).
- `Canceled Trade Entries`: Number of trades that have been canceled by user request via `adjust_entry_price`.
- `Canceled Entry Orders`: Number of entry orders that have been canceled by user request via `adjust_entry_price`.
- `Replaced Entry Orders`: Number of entry orders that have been replaced by user request via `adjust_entry_price`.
- `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period.
- `Max % of account underwater`: Maximum percentage your account has decreased from the top since the simulation started.
Calculated as the maximum of `(Max Balance - Current Balance) / (Max Balance)`.
- `Absolute Drawdown (Account)`: Maximum Account Drawdown experienced. Calculated as `(Absolute Drawdown) / (DrawdownHigh + startingBalance)`.
- `Drawdown`: Maximum, absolute drawdown experienced. Difference between Drawdown High and Subsequent Low point.
- `Drawdown high` / `Drawdown low`: Profit at the beginning and end of the largest drawdown period. A negative low value means initial capital lost.
- `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
- `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column.
- `Long / Short`: Split long/short values (Only shown when short trades were made).
- `Total profit Long %` / `Absolute profit Long`: Profit long trades only (Only shown when short trades were made).
- `Total profit Short %` / `Absolute profit Short`: Profit short trades only (Only shown when short trades were made).
- `Max % of account underwater`: Maximum percentage your account has decreased from the top since the simulation started. Calculated as the maximum of `(Max Balance - Current Balance) / (Max Balance)`.
- `Absolute drawdown`: Maximum absolute drawdown experienced, including percentage relative to the account calculated as `(Absolute Drawdown) / (DrawdownHigh + startingBalance)`..
- `Drawdown duration`: Duration of the largest drawdown period.
- `Profit at drawdown start` / `Profit at drawdown end`: Profit at the beginning and end of the largest drawdown period.
- `Drawdown start` / `Drawdown end`: Start and end datetime for the largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
- `Market change`: Change of the market during the backtest period. Calculated as the average of all pairs' changes from the first to the last candle using the "close" column.
### Daily / Weekly / Monthly breakdown
### Daily / Weekly / Monthly / Yearly breakdown
You can get an overview over daily / weekly or monthly results by using the `--breakdown <>` switch.
You can get an overview over daily, weekly, monthly, or yearly results by using the `--breakdown <>` switch.
To visualize daily and weekly breakdowns, you can use the following:
To visualize monthly and yearly breakdowns, you can use the following:
``` bash
freqtrade backtesting --strategy MyAwesomeStrategy --breakdown day week
freqtrade backtesting --strategy MyAwesomeStrategy --breakdown month year
```
``` output
======================== DAY BREAKDOWN =========================
| Day | Tot Profit USDT | Wins | Draws | Losses |
|------------+-------------------+--------+---------+----------|
| 03/07/2021 | 200.0 | 2 | 0 | 0 |
| 04/07/2021 | -50.31 | 0 | 0 | 2 |
| 05/07/2021 | 220.611 | 3 | 2 | 0 |
| 06/07/2021 | 150.974 | 3 | 0 | 2 |
| 07/07/2021 | -70.193 | 1 | 0 | 2 |
| 08/07/2021 | 212.413 | 2 | 0 | 3 |
MONTH BREAKDOWN
┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Month ┃ Trades ┃ Tot Profit USDT ┃ Profit Factor ┃ Win Draw Loss Win% ┃
┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ 31/01/2020 │ 12 │ 44.451 │ 7.28 │ 10 0 2 83.3 │
│ 29/02/2020 │ 30 │ 45.41 │ 2.36 │ 17 0 13 56.7 │
│ 31/03/2020 │ 35 │ 142.024 2.42 │ 14 0 21 40.0 │
│ 30/04/2020 │ 67 │ -23.692 │ 0.81 │ 24 0 43 35.8 │
...
...
│ 30/04/2025 │ 203 │ -63.43 │ 0.81 │ 73 0 130 36.0 │
│ 31/05/2025 │ 142 │ 104.675 │ 1.28 │ 59 0 83 41.5 │
│ 30/06/2025 │ 177 │ -1.014 │ 1.0 │ 85 0 92 48.0 │
│ 31/07/2025 │ 155 │ 232.762 │ 1.6 │ 63 0 92 40.6 │
└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘
YEAR BREAKDOWN
┏━━━━━━━━━━━━┳━━━━━━━━┳━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Year ┃ Trades ┃ Tot Profit USDT ┃ Profit Factor ┃ Win Draw Loss Win% ┃
┡━━━━━━━━━━━━╇━━━━━━━━╇━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━┩
│ 31/12/2020 │ 896 │ 868.889 │ 1.46 │ 351 0 545 39.2 │
│ 31/12/2021 │ 1778 │ 4487.163 │ 1.93 │ 745 0 1033 41.9 │
│ 31/12/2022 │ 1736 │ 938.27 │ 1.27 │ 698 0 1038 40.2 │
│ 31/12/2023 │ 1712 │ 1677.126 │ 1.68 │ 670 0 1042 39.1 │
│ 31/12/2024 │ 1609 │ 3198.424 │ 2.22 │ 773 0 836 48.0 │
│ 31/12/2025 │ 1042 │ 716.174 │ 1.33 │ 420 0 622 40.3 │
└────────────┴────────┴─────────────────┴───────────────┴────────────────────────┘
```
The output will show a table containing the realized absolute Profit (in stake currency) for the given timeperiod, as well as wins, draws and losses that materialized (closed) on this day. Below that there will be a second table for the summarized values of weeks indicated by the date of the closing Sunday. The same would apply to a monthly breakdown indicated by the last day of the month.
The output will display tables containing the realized absolute profit (in stake currency) for the selected period, along with additional statistics such as number of trades, profit factor, and distribution of wins, draws, and losses that materialized (closed) on this period.
### Backtest result caching
@@ -449,10 +480,10 @@ For this mode - `--notes "<notes>"` can be used to add notes to the backtest res
The output file freqtrade produces is a zip file containing the following files:
- The backtest report in json format
- the market change data in feather format
- a copy of the strategy file
- a copy of the strategy parameters (if a parameter file was used)
- a sanitized copy of the config file
- The market change data in feather format
- A copy of the strategy file
- A copy of the strategy parameters (if a parameter file was used)
- A sanitized copy of the config file
This will ensure results are reproducible - under the assumption that the same data is available.
@@ -470,7 +501,7 @@ Since backtesting lacks some detailed information about what happens within a ca
- Exit-signal is favored over Stoploss, because exit-signals are assumed to trigger on candle's open
- ROI
- Exits are compared to high - but the ROI value is used (e.g. ROI = 2%, high=5% - so the exit will be at 2%)
- Exits are never "below the candle", so a ROI of 2% may result in a exit at 2.4% if low was at 2.4% profit
- Exits are never "below the candle", so a ROI of 2% may result in an exit at 2.4% if low was at 2.4% profit
- ROI entries which came into effect on the triggering candle (e.g. `120: 0.02` for 1h candles, from `60: 0.05`) will use the candle's open as exit rate
- Force-exits caused by `<N>=-1` ROI entries use low as exit value, unless N falls on the candle open (e.g. `120: -1` for 1h candles)
- Stoploss exits happen exactly at stoploss price, even if low was lower, but the loss will be `2 * fees` higher than the stoploss price
@@ -536,7 +567,7 @@ freqtrade backtesting --strategy AwesomeStrategy --timeframe 1h --timeframe-deta
This will load 1h data (the main timeframe) as well as 5m data (detail timeframe) for the selected timerange.
The strategy will be analyzed with the 1h timeframe.
Candles where activity may take place (there's an active signal, the pair is in a trade) are evaluated at the 5m timeframe.
Candles where activity may take place (there's an active signal, the pair is in a trade) are evaluated at the 5m timeframe.
This will allow for a more accurate simulation of intra-candle movements - and can lead to different results, especially on higher timeframes.
Entries will generally still happen at the main candle's open, however freed trade slots may be freed earlier (if the exit signal is triggered on the 5m candle), which can then be used for a new trade of a different pair.
@@ -599,5 +630,5 @@ Detailed output for all strategies one after the other will be available, so mak
## Next step
Great, your strategy is profitable. What if the bot can give your the optimal parameters to use for your strategy?
Great, your strategy is profitable. What if the bot can give you the optimal parameters to use for your strategy?
Your next step is to learn [how to find optimal parameters with Hyperopt](hyperopt.md)
+11 -5
View File
@@ -2,7 +2,8 @@
usage: freqtrade backtesting-analysis [-h] [-v] [--no-color] [--logfile FILE]
[-V] [-c PATH] [-d PATH]
[--userdir PATH]
[--export-filename PATH]
[--backtest-filename PATH]
[--backtest-directory PATH]
[--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]]
[--enter-reason-list ENTER_REASON_LIST [ENTER_REASON_LIST ...]]
[--exit-reason-list EXIT_REASON_LIST [EXIT_REASON_LIST ...]]
@@ -14,10 +15,15 @@ usage: freqtrade backtesting-analysis [-h] [-v] [--no-color] [--logfile FILE]
options:
-h, --help show this help message and exit
--export-filename PATH, --backtest-filename PATH
Use this filename for backtest results.Requires
`--export` to be set as well. Example: `--export-filen
ame=user_data/backtest_results/backtest_today.json`
--backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example:
`--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--backtest-directory PATH, --export-directory PATH
Directory to use for backtest results. Example:
`--export-directory=user_data/backtest_results/`.
--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]
grouping output - 0: simple wins/losses by enter tag,
1: by enter_tag, 2: by enter_tag and exit_tag, 3: by
+12 -5
View File
@@ -1,15 +1,22 @@
```
usage: freqtrade backtesting-show [-h] [-v] [--no-color] [--logfile FILE] [-V]
[-c PATH] [-d PATH] [--userdir PATH]
[--export-filename PATH] [--show-pair-list]
[--backtest-filename PATH]
[--backtest-directory PATH]
[--show-pair-list]
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
options:
-h, --help show this help message and exit
--export-filename PATH, --backtest-filename PATH
Use this filename for backtest results.Requires
`--export` to be set as well. Example: `--export-filen
ame=user_data/backtest_results/backtest_today.json`
--backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example:
`--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--backtest-directory PATH, --export-directory PATH
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} ...]
Show backtesting breakdown per [day, week, month,
+11 -5
View File
@@ -14,7 +14,8 @@ usage: freqtrade backtesting [-h] [-v] [--no-color] [--logfile FILE] [-V]
[--timeframe-detail TIMEFRAME_DETAIL]
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
[--export {none,trades,signals}]
[--export-filename PATH]
[--backtest-filename PATH]
[--backtest-directory PATH]
[--breakdown {day,week,month,year} [{day,week,month,year} ...]]
[--cache {none,day,week,month}]
[--freqai-backtest-live-models] [--notes TEXT]
@@ -61,10 +62,15 @@ options:
becomes `backtest-data-SampleStrategy.json`
--export {none,trades,signals}
Export backtest results (default: trades).
--export-filename PATH, --backtest-filename PATH
Use this filename for backtest results.Requires
`--export` to be set as well. Example: `--export-filen
ame=user_data/backtest_results/backtest_today.json`
--backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example:
`--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--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} ...]
Show backtesting breakdown per [day, week, month,
year].
+5
View File
@@ -1,11 +1,16 @@
```
usage: freqtrade list-exchanges [-h] [-v] [--no-color] [--logfile FILE] [-V]
[-c PATH] [-d PATH] [--userdir PATH] [-1] [-a]
[--trading-mode {spot,margin,futures}]
[--dex-exchanges]
options:
-h, --help show this help message and exit
-1, --one-column Print output in one column.
-a, --all Print all exchanges known to the ccxt library.
--trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures}
Select Trading mode
--dex-exchanges Print only DEX exchanges.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
+11 -5
View File
@@ -15,7 +15,8 @@ usage: freqtrade lookahead-analysis [-h] [-v] [--no-color] [--logfile FILE]
[--timeframe-detail TIMEFRAME_DETAIL]
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
[--export {none,trades,signals}]
[--export-filename PATH]
[--backtest-filename PATH]
[--backtest-directory PATH]
[--freqai-backtest-live-models]
[--minimum-trade-amount INT]
[--targeted-trade-amount INT]
@@ -60,10 +61,15 @@ options:
becomes `backtest-data-SampleStrategy.json`
--export {none,trades,signals}
Export backtest results (default: trades).
--export-filename PATH, --backtest-filename PATH
Use this filename for backtest results.Requires
`--export` to be set as well. Example: `--export-filen
ame=user_data/backtest_results/backtest_today.json`
--backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example:
`--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--backtest-directory PATH, --export-directory PATH
Directory to use for backtest results. Example:
`--export-directory=user_data/backtest_results/`.
--freqai-backtest-live-models
Run backtest with ready models.
--minimum-trade-amount INT
+7 -5
View File
@@ -10,7 +10,7 @@ usage: freqtrade plot-dataframe [-h] [-v] [--no-color] [--logfile FILE] [-V]
[--plot-limit INT] [--db-url PATH]
[--trade-source {DB,file}]
[--export {none,trades,signals}]
[--export-filename PATH]
[--backtest-filename PATH]
[--timerange TIMERANGE] [-i TIMEFRAME]
[--no-trades]
@@ -38,10 +38,12 @@ options:
(backtest file)) Default: file
--export {none,trades,signals}
Export backtest results (default: trades).
--export-filename PATH, --backtest-filename PATH
Use this filename for backtest results.Requires
`--export` to be set as well. Example: `--export-filen
ame=user_data/backtest_results/backtest_today.json`
--backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example:
`--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--timerange TIMERANGE
Specify what timerange of data to use.
-i TIMEFRAME, --timeframe TIMEFRAME
+7 -5
View File
@@ -6,7 +6,7 @@ usage: freqtrade plot-profit [-h] [-v] [--no-color] [--logfile FILE] [-V]
[--freqaimodel NAME] [--freqaimodel-path PATH]
[-p PAIRS [PAIRS ...]] [--timerange TIMERANGE]
[--export {none,trades,signals}]
[--export-filename PATH] [--db-url PATH]
[--backtest-filename PATH] [--db-url PATH]
[--trade-source {DB,file}] [-i TIMEFRAME]
[--auto-open]
@@ -19,10 +19,12 @@ options:
Specify what timerange of data to use.
--export {none,trades,signals}
Export backtest results (default: trades).
--export-filename PATH, --backtest-filename PATH
Use this filename for backtest results.Requires
`--export` to be set as well. Example: `--export-filen
ame=user_data/backtest_results/backtest_today.json`
--backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example:
`--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--db-url PATH Override trades database URL, this is useful in custom
deployments (default: `sqlite:///tradesv3.sqlite` for
Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for
+6 -4
View File
@@ -566,8 +566,8 @@ Configuration:
### Understand order_time_in_force
The `order_time_in_force` configuration parameter defines the policy by which the order
is executed on the exchange. Three commonly used time in force are:
The `order_time_in_force` configuration parameter defines the policy by which the order is executed on the exchange.
Commonly used time in force are:
**GTC (Good Till Canceled):**
@@ -589,11 +589,13 @@ is automatically cancelled by the exchange.
Post only order. The order is either placed as a maker order, or it is canceled.
This means the order must be placed on orderbook for at least time in an unfilled state.
Please check the [Exchange documentation](exchanges.md) for supported time in force values for your exchange.
#### time_in_force config
The `order_time_in_force` parameter contains a dict with entry and exit time in force policy values.
This can be set in the configuration file or in the strategy.
Values set in the configuration file overwrites values set in the strategy.
Values set in the configuration file overwrite values from in the strategy, following the regular [precedence rules](#configuration-option-prevalence).
The possible values are: `GTC` (default), `FOK` or `IOC`.
@@ -605,9 +607,9 @@ The possible values are: `GTC` (default), `FOK` or `IOC`.
```
!!! Warning
This is ongoing work. For now, it is supported only for binance, gate and kucoin.
Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange.
### Fiat conversion
Freqtrade uses the Coingecko API to convert the coin value to it's corresponding fiat value for the Telegram reports.
+16 -1
View File
@@ -408,6 +408,22 @@ jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace freqtrade/tem
jupyter nbconvert --ClearOutputPreprocessor.enabled=True --to markdown freqtrade/templates/strategy_analysis_example.ipynb --stdout > docs/strategy_analysis_example.md
```
## Backtest documentation results
To generate backtest outputs, please use the following commands:
``` bash
# Assume a dedicated user directory for this output
freqtrade create-userdir --userdir user_data_bttest/
# set can_short = True
sed -i "s/can_short: bool = False/can_short: bool = True/" user_data_bttest/strategies/sample_strategy.py
freqtrade download-data --timerange 20250625-20250801 --config tests/testdata/config.tests.usdt.json --userdir user_data_bttest/ -t 5m
freqtrade backtesting --config tests/testdata/config.tests.usdt.json -s SampleStrategy --userdir user_data_bttest/ --cache none --timerange 20250701-20250801
```
## Continuous integration
This documents some decisions taken for the CI Pipeline.
@@ -418,7 +434,6 @@ This documents some decisions taken for the CI Pipeline.
* Docker images contain a file, `/freqtrade/freqtrade_commit` containing the commit this image is based of.
* Full docker image rebuilds are run once a week via schedule.
* Deployments run on ubuntu.
* ta-lib binaries are contained in the build_helpers directory to avoid fails related to external unavailability.
* All tests must pass for a PR to be merged to `stable` or `develop`.
## Creating a release
+32 -9
View File
@@ -227,7 +227,7 @@ Kucoin requires a passphrase for each api key, you will therefore need to add th
}
```
Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force).
Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force) with settings "GTC" (good till cancelled), "FOK" (full-or-cancel) and "IOC" (immediate-or-cancel) settings.
!!! Tip "Stoploss on Exchange"
Kucoin 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.
@@ -271,7 +271,9 @@ Using the wrong exchange will result in the error "OKX Error 50119: API key does
## Gate.io
!!! Tip "Stoploss on Exchange"
Gate.io supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange..
Gate.io supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange.
Gate.io supports [time_in_force](configuration.md#understand-order_time_in_force) with settings "GTC" (good till cancelled), and "IOC" (immediate-or-cancel) settings.
Gate.io allows the use of `POINT` to pay for fees. As this is not a tradable currency (no regular market available), automatic fee calculations will fail (and default to a fee of 0).
The configuration parameter `exchange.unknown_fee_rate` can be used to specify the exchange rate between Point and the stake currency. Obviously, changing the stake-currency will also require changes to this value.
@@ -286,9 +288,15 @@ Without these permissions, the bot will not start correctly and show errors like
## Bybit
Futures trading on bybit is currently supported for USDT markets, and will use isolated futures mode.
!!! Tip "Stoploss on Exchange"
Bybit (futures only) supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange.
On futures, Bybit supports both `stop-limit` as well as `stop-market` orders. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use.
On startup, freqtrade will set the position mode to "One-way Mode" for the whole (sub)account. This avoids making this call over and over again (slowing down bot operations), but means that changes to this setting may result in exceptions and errors.
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.
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.
As bybit doesn't provide funding rate history, the dry-run calculation is used for live trades as well.
@@ -305,11 +313,6 @@ We do strongly recommend to limit all API keys to the IP you're going to use it
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.
!!! Tip "Stoploss on Exchange"
Bybit (futures only) supports `stoploss_on_exchange` and uses `stop-loss-limit` orders. It provides great advantages, so we recommend to benefit from it by enabling stoploss on exchange.
On futures, Bybit supports both `stop-limit` as well as `stop-market` orders. You can use either `"limit"` or `"market"` in the `order_types.stoploss` configuration setting to decide which type to use.
## Bitmart
Bitmart requires the API key Memo (the name you give the API key) to go along with the exchange key and secret.
@@ -328,6 +331,26 @@ It's therefore required to pass the UID as well.
!!! Warning "Necessary Verification"
Bitmart requires Verification Lvl2 to successfully trade on the spot market through the API - even though trading via UI works just fine with just Lvl1 verification.
## Bitget
Bitget requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows:
```json
"exchange": {
"name": "bitget",
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"password": "your_exchange_api_key_password",
// ...
}
```
Bitget 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.
!!! Tip "Stoploss on Exchange"
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.
## Hyperliquid
!!! Tip "Stoploss on Exchange"
+2
View File
@@ -389,6 +389,8 @@ The `refresh_period` setting defines the interval (in seconds) at which the mark
The `categories` setting specifies the [coingecko categories](https://www.coingecko.com/en/categories) from which to select coins from. The default is an empty list `[]`, meaning no category filtering is applied.
If an incorrect category string is chosen, the plugin will print the available categories from CoinGecko and fail. The category should be the ID of the category, for example, for `https://www.coingecko.com/en/categories/layer-1`, the category ID would be `layer-1`. You can pass multiple categories such as `["layer-1", "meme-token"]` to select from several categories.
Coins like 1000PEPE/USDT or KPEPE/USDT:USDT are detected on a best effort basis, with the prefixes `1000` and `K` being used to identify them.
!!! Warning "Many categories"
Each added category corresponds to one API call to CoinGecko. The more categories you add, the longer the pairlist generation will take, potentially causing rate limit issues.
-1
View File
@@ -3,7 +3,6 @@
[![Freqtrade CI](https://github.com/freqtrade/freqtrade/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/freqtrade/freqtrade/actions/)
[![DOI](https://joss.theoj.org/papers/10.21105/joss.04864/status.svg)](https://doi.org/10.21105/joss.04864)
[![Coverage Status](https://coveralls.io/repos/github/freqtrade/freqtrade/badge.svg?branch=develop&service=github)](https://coveralls.io/github/freqtrade/freqtrade?branch=develop)
[![Maintainability](https://api.codeclimate.com/v1/badges/5737e6d668200b7518ff/maintainability)](https://codeclimate.com/github/freqtrade/freqtrade/maintainability)
<!-- GitHub action buttons -->
[:octicons-star-16: Star](https://github.com/freqtrade/freqtrade){ .md-button .md-button--sm }
-40
View File
@@ -46,7 +46,6 @@ These requirements apply to both [Script Installation](#script-installation) and
* [pip](https://pip.pypa.io/en/stable/installing/)
* [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
* [virtualenv](https://virtualenv.pypa.io/en/stable/installation.html) (Recommended)
* [TA-Lib](https://ta-lib.github.io/ta-lib-python/) (install instructions [below](#install-ta-lib))
### Install code
@@ -201,35 +200,6 @@ This option will hard reset your branch (only if you are on either `stable` or `
Make sure you fulfill the [Requirements](#requirements) and have downloaded the [Freqtrade repository](#freqtrade-repository).
### Install TA-Lib
#### TA-Lib script installation
```bash
sudo ./build_helpers/install_ta-lib.sh
```
!!! Note
This will use the ta-lib tar.gz included in this repository.
##### TA-Lib manual installation
[Official installation guide](https://ta-lib.github.io/ta-lib-python/install.html)
```bash
wget http://prdownloads.sourceforge.net/ta-lib/ta-lib-0.4.0-src.tar.gz
tar xvzf ta-lib-0.4.0-src.tar.gz
cd ta-lib
sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h
./configure --prefix=/usr/local
make
sudo make install
# On debian based systems (debian, ubuntu, ...) - updating ldconfig might be necessary.
sudo ldconfig
cd ..
rm -rf ./ta-lib*
```
### Setup Python virtual environment (virtualenv)
You will run freqtrade in separated `virtual environment`
@@ -332,16 +302,6 @@ python3 -m pip install -r requirements.txt
python3 -m pip install -e .
```
Patch conda libta-lib (Linux only)
```bash
# Ensure that the environment is active!
conda activate freqtrade
cd build_helpers
bash install_ta-lib.sh ${CONDA_PREFIX} nosudo
```
[You are now ready](#you-are-ready) to run the bot.
### Important shortcuts
+4 -5
View File
@@ -38,7 +38,7 @@ Many strategies, without the programmer knowing, have fallen prey to lookahead b
This typically makes the strategy backtest look profitable, sometimes to extremes, but this is not realistic as the strategy is "cheating" by looking at data it would not have in dry or live modes.
The reason why strategies can "cheat" is because the freqtrade backtesting process populates the full dataframe including all candle timestamps at the outset.
If the programmer is not careful or oblivious how things work internally
If the programmer is not careful or oblivious how things work internally
(which sometimes can be really hard to find out) then the strategy will look into the future.
This command is made to try to verify the validity in the form of the aforementioned lookahead bias.
@@ -50,8 +50,7 @@ After this initial backtest runs, it will look if the `minimum-trade-amount` is
If this happens, use a wider timerange to get more trades for the analysis, or use a timerange where more trades occur.
After setting the baseline it will then do additional backtest runs for every entry and exit separately.
When these verification backtests complete, it will compare the indicators at the signal candles (both entry or exit)
and report the bias.
When these verification backtests complete, it will compare both dataframes (baseline and sliced) for any difference in columns' value and report the bias.
After all signals have been verified or falsified a result table will be generated for the user to see.
### How to find and remove bias? How can I salvage a biased strategy?
@@ -98,8 +97,8 @@ If the strategy has many different signals / signal types, it's up to you to sel
This would lead to a false-negative, i.e. the strategy will be reported as non-biased.
- `lookahead-analysis` has access to the same backtesting options and this can introduce problems.
Please don't use any options like enabling position stacking as this will distort the number of checked signals.
If you decide to do so, then make doubly sure that you won't ever run out of `max_open_trades` slots,
If you decide to do so, then make doubly sure that you won't ever run out of `max_open_trades` slots,
and that you have enough capital in the backtest wallet configuration.
- In the results table, the `biased_indicators` column
- In the results table, the `biased_indicators` column
will falsely flag FreqAI target indicators defined in `set_freqai_targets()` as biased.
**These are not biased and can safely be ignored.**
+2 -2
View File
@@ -1,7 +1,7 @@
markdown==3.8.2
mkdocs==1.6.1
mkdocs-material==9.6.16
mkdocs-material==9.6.18
mdx_truly_sane_lists==1.3
pymdown-extensions==10.16
pymdown-extensions==10.16.1
jinja2==3.1.6
mike==2.1.3
+1
View File
@@ -31,6 +31,7 @@ The Order-type will be ignored if only one mode is available.
| Binance | limit |
| Binance Futures | market, limit |
| Bingx | market, limit |
| Bitget | market, limit |
| HTX | limit |
| kraken | market, limit |
| Gate | limit |
+5
View File
@@ -47,3 +47,8 @@
border-color: #afb8c1;
box-shadow: inset 0 1px 0 rgba(175, 184, 193, 0.2);
}
.md-grid {
/* default is max-width: 61rem; */
max-width: 75rem;
}
-4
View File
@@ -42,7 +42,3 @@ freqtrade install-ui
Update-problems usually come missing dependencies (you didn't follow the above instructions) - or from updated dependencies, which fail to install (for example TA-lib).
Please refer to the corresponding installation sections (common problems linked below)
Common problems and their solutions:
* [ta-lib update on windows](windows_installation.md#install-ta-lib)
-24
View File
@@ -38,30 +38,6 @@ cd freqtrade
!!! Hint
Using the [Anaconda Distribution](https://www.anaconda.com/distribution/) under Windows can greatly help with installation problems. Check out the [Anaconda installation section](installation.md#installation-with-conda) in the documentation for more information.
### Install ta-lib
Install ta-lib according to the [ta-lib documentation](https://github.com/TA-Lib/ta-lib-python#windows).
As compiling from source on windows has heavy dependencies (requires a partial visual studio installation), Freqtrade provides these dependencies (in the binary wheel format) for the latest 3 Python versions (3.11, 3.12 and 3.13) and for 64bit Windows.
These Wheels are also used by CI running on windows, and are therefore tested together with freqtrade.
Other versions must be downloaded from the above link.
``` powershell
cd \path\freqtrade
python -m venv .venv
.venv\Scripts\activate.ps1
# optionally install ta-lib from wheel
# Eventually adjust the below filename to match the downloaded wheel
pip install --find-links build_helpers\ TA-Lib -U
pip install -r requirements.txt
pip install -e .
freqtrade
```
!!! Note "Use Powershell"
The above installation script assumes you're using powershell on a 64bit windows.
Commands for the legacy CMD windows console may differ.
### Error during installation on Windows
+1 -1
View File
@@ -1,6 +1,6 @@
"""Freqtrade bot"""
__version__ = "2025.7"
__version__ = "2025.8"
if "dev" in __version__:
from pathlib import Path
+1 -1
View File
@@ -17,7 +17,7 @@ def start_analysis_entries_exits(args: dict[str, Any]) -> None:
from freqtrade.data.entryexitanalysis import process_entry_exit_reasons
# Initialize configuration
config = setup_utils_configuration(args, RunMode.BACKTEST)
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
logger.info("Starting freqtrade in analysis mode")
+9 -2
View File
@@ -54,6 +54,7 @@ ARGS_BACKTEST = [
"strategy_list",
"export",
"exportfilename",
"exportdirectory",
"backtest_breakdown",
"backtest_cache",
"freqai_backtest_live_models",
@@ -94,9 +95,14 @@ ARGS_LIST_FREQAIMODELS = ["freqaimodel_path", "print_one_column"]
ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column"]
ARGS_BACKTEST_SHOW = ["exportfilename", "backtest_show_pair_list", "backtest_breakdown"]
ARGS_BACKTEST_SHOW = [
"exportfilename",
"exportdirectory",
"backtest_show_pair_list",
"backtest_breakdown",
]
ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"]
ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all", "trading_mode", "dex_exchanges"]
ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"]
@@ -233,6 +239,7 @@ ARGS_HYPEROPT_SHOW = [
ARGS_ANALYZE_ENTRIES_EXITS = [
"exportfilename",
"exportdirectory",
"analysis_groups",
"enter_reason_list",
"exit_reason_list",
+20 -8
View File
@@ -199,22 +199,29 @@ AVAILABLE_CLI_OPTIONS = {
"(so `backtest-data.json` becomes `backtest-data-SampleStrategy.json`",
nargs="+",
),
"export": Arg(
"--export",
help="Export backtest results (default: trades).",
choices=constants.EXPORT_OPTIONS,
),
"backtest_notes": Arg(
"--notes",
help="Add notes to the backtest results.",
metavar="TEXT",
),
"export": Arg(
"--export",
help="Export backtest results (default: trades).",
choices=constants.EXPORT_OPTIONS,
),
"exportdirectory": Arg(
"--backtest-directory",
"--export-directory",
help="Directory to use for backtest results. "
"Example: `--export-directory=user_data/backtest_results/`. ",
metavar="PATH",
),
"exportfilename": Arg(
"--export-filename",
"--backtest-filename",
"--export-filename",
help="Use this filename for backtest results."
"Requires `--export` to be set as well. "
"Example: `--export-filename=user_data/backtest_results/backtest_today.json`",
"Example: `--backtest-filename=backtest_results_2020-09-27_16-20-48.json`. "
"Assumes either `user_data/backtest_results/` or `--export-directory` as base directory.",
metavar="PATH",
),
"disableparamexport": Arg(
@@ -369,6 +376,11 @@ AVAILABLE_CLI_OPTIONS = {
help="Print all exchanges known to the ccxt library.",
action="store_true",
),
"dex_exchanges": Arg(
"--dex-exchanges",
help="Print only DEX exchanges.",
action="store_true",
),
# List pairs / markets
"list_pairs_all": Arg(
"-a",
+5 -3
View File
@@ -6,7 +6,7 @@ from typing import Any
from freqtrade.constants import DATETIME_PRINT_FORMAT, DL_DATA_TIMEFRAMES, Config
from freqtrade.enums import CandleType, RunMode, TradingMode
from freqtrade.exceptions import ConfigurationError
from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist
from freqtrade.plugins.pairlist.pairlist_helpers import dynamic_expand_pairlist, expand_pairlist
logger = logging.getLogger(__name__)
@@ -134,7 +134,8 @@ def start_list_data(args: dict[str, Any]) -> None:
config["datadir"], config.get("trading_mode", TradingMode.SPOT)
)
if args["pairs"]:
paircombs = [comb for comb in paircombs if comb[0] in args["pairs"]]
pl = expand_pairlist(args["pairs"], [p[0] for p in paircombs], keep_invalid=True)
paircombs = [comb for comb in paircombs if comb[0] in pl]
title = f"Found {len(paircombs)} pair / timeframe combinations."
if not config.get("show_timerange"):
groupedpair = defaultdict(list)
@@ -197,7 +198,8 @@ def start_list_trades_data(args: dict[str, Any]) -> None:
)
if args["pairs"]:
paircombs = [comb for comb in paircombs if comb in args["pairs"]]
pl = expand_pairlist(args["pairs"], [p for p in paircombs], keep_invalid=True)
paircombs = [comb for comb in paircombs if comb in pl]
title = f"Found trades data for {len(paircombs)} {plural(len(paircombs), 'pair')}."
if not config.get("show_timerange"):
+14
View File
@@ -46,7 +46,18 @@ def start_list_exchanges(args: dict[str, Any]) -> None:
table.add_column("Markets")
table.add_column("Reason")
trading_mode = args.get("trading_mode", None)
dex_only = args.get("dex_exchanges", False)
for exchange in available_exchanges:
if trading_mode and not any(
a["trading_mode"] == trading_mode for a in exchange["trade_modes"]
):
# If trading_mode is specified, only show exchanges that support it
continue
if dex_only and not exchange.get("dex", False):
# If dex_only is specified, only show DEX exchanges
continue
name = Text(exchange["name"])
if exchange["supported"]:
name.append(" (Supported)", style="italic")
@@ -135,6 +146,9 @@ def start_list_strategies(args: dict[str, Any]) -> None:
strategy_objs = StrategyResolver.search_all_objects(
config, not args["print_one_column"], config.get("recursive_strategy_search", False)
)
if not strategy_objs:
logger.warning("No strategies found.")
return
# Sort alphabetically
strategy_objs = sorted(strategy_objs, key=lambda x: x["name"])
for obj in strategy_objs:
+1 -1
View File
@@ -72,7 +72,7 @@ def start_backtesting_show(args: dict[str, Any]) -> None:
from freqtrade.data.btanalysis import load_backtest_stats
from freqtrade.optimize.optimize_reports import show_backtest_results, show_sorted_pairlist
results = load_backtest_stats(config["exportfilename"])
results = load_backtest_stats(config["exportdirectory"], config["exportfilename"])
show_backtest_results(config, results)
show_sorted_pairlist(config, results)
+13
View File
@@ -157,6 +157,16 @@ CONF_SCHEMA = {
"description": f"Offset for profit exit. {__IN_STRATEGY}",
"type": "number",
},
"recursive_strategy_search": {
"description": "Enable recursive strategy search.",
"type": "boolean",
},
"user_data_dir": {
"description": "Path to the user data directory.",
},
"datadir": {
"description": "Path to the data directory.",
},
"fee": {
"description": "Trading fee percentage. Can help to simulate slippage in backtesting",
"type": "number",
@@ -443,6 +453,7 @@ CONF_SCHEMA = {
"pairlists": {
"description": "Configuration for pairlists.",
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"properties": {
@@ -1371,6 +1382,7 @@ SCHEMA_TRADE_REQUIRED = [
"entry_pricing",
"stoploss",
"minimal_roi",
"pairlists",
"internals",
"dataformat_ohlcv",
"dataformat_trades",
@@ -1380,6 +1392,7 @@ SCHEMA_BACKTEST_REQUIRED = [
"exchange",
"stake_currency",
"stake_amount",
"pairlists",
"dry_run_wallet",
"dataformat_ohlcv",
"dataformat_trades",
+2 -1
View File
@@ -66,7 +66,8 @@ def validate_config_schema(conf: dict[str, Any], preliminary: bool = False) -> d
return conf
except ValidationError as e:
logger.critical(f"Invalid configuration. Reason: {e}")
raise ValidationError(best_match(Draft4Validator(conf_schema).iter_errors(conf)).message)
result = best_match(FreqtradeValidator(conf_schema).iter_errors(conf))
raise ConfigurationError(result.message)
def validate_config_consistency(conf: dict[str, Any], *, preliminary: bool = False) -> None:
+17 -5
View File
@@ -84,9 +84,6 @@ class Configuration:
if "internals" not in config:
config["internals"] = {}
if "pairlists" not in config:
config["pairlists"] = []
# Keep a copy of the original configuration file
config["original_config"] = deepcopy(config)
@@ -212,13 +209,28 @@ class Configuration:
config.update({"datadir": create_datadir(config, self.args.get("datadir"))})
logger.info("Using data directory: %s ...", config.get("datadir"))
self._args_to_config(
config, argname="exportdirectory", logstring="Using {} as backtest directory ..."
)
if self.args.get("exportfilename"):
self._args_to_config(
config, argname="exportfilename", logstring="Storing backtest results to {} ..."
)
config["exportfilename"] = Path(config["exportfilename"])
else:
config["exportfilename"] = config["user_data_dir"] / "backtest_results"
if config.get("exportdirectory") and Path(config["exportdirectory"]).is_dir():
logger.warning(
"DEPRECATED: Using `--export-filename` with directories is deprecated, "
"use `--backtest-directory` instead."
)
if config.get("exportdirectory") is None:
# Fallback - assign export-directory directly.
config["exportdirectory"] = config["exportfilename"]
if not config.get("exportdirectory"):
config["exportdirectory"] = config["user_data_dir"] / "backtest_results"
if not config.get("exportfilename"):
config["exportfilename"] = None
config["exportdirectory"] = Path(config["exportdirectory"])
if self.args.get("show_sensitive"):
logger.warning(
-3
View File
@@ -16,10 +16,7 @@ from .bt_fileutils import (
load_backtest_data,
load_backtest_metadata,
load_backtest_stats,
load_exit_signal_candles,
load_file_from_zip,
load_rejected_signals,
load_signal_candles,
load_trades,
load_trades_from_db,
trade_list_to_dataframe,
+59 -50
View File
@@ -155,33 +155,55 @@ def load_backtest_metadata(filename: Path | str) -> dict[str, Any]:
raise OperationalException("Unexpected error while loading backtest metadata.") from e
def load_backtest_stats(filename: Path | str) -> BacktestResultType:
def _normalize_filename(file_or_directory: Path | str, filename: Path | str | None) -> Path:
"""
Normalize the filename by ensuring it is a Path object.
:param file_or_directory: The directory or file to normalize.
:param filename: The filename to normalize.
:return: A Path object representing the normalized filename.
"""
if isinstance(file_or_directory, str):
file_or_directory = Path(file_or_directory)
if file_or_directory.is_dir():
if not filename:
filename = get_latest_backtest_filename(file_or_directory)
if Path(filename).is_file():
fn = Path(filename)
else:
fn = file_or_directory / filename
else:
fn = file_or_directory
return fn
def load_backtest_stats(
file_or_directory: Path | str, filename: Path | str | None = None
) -> BacktestResultType:
"""
Load backtest statistics file.
:param filename: pathlib.Path object, or string pointing to the file.
:param file_or_directory: pathlib.Path object, or string pointing to the directory,
or absolute/relative path to the backtest results file.
:param filename: Optional filename to load from (if different from the main filename).
Only valid when loading from a directory.
:return: a dictionary containing the resulting file.
"""
if isinstance(filename, str):
filename = Path(filename)
if filename.is_dir():
filename = filename / get_latest_backtest_filename(filename)
if not filename.is_file():
raise ValueError(f"File {filename} does not exist.")
logger.info(f"Loading backtest result from {filename}")
fn = _normalize_filename(file_or_directory, filename)
if filename.suffix == ".zip":
if not fn.is_file():
raise ValueError(f"File or directory {fn} does not exist.")
logger.info(f"Loading backtest result from {fn}")
if fn.suffix == ".zip":
data = json_load(
StringIO(
load_file_from_zip(filename, filename.with_suffix(".json").name).decode("utf-8")
)
StringIO(load_file_from_zip(fn, fn.with_suffix(".json").name).decode("utf-8"))
)
else:
with filename.open() as file:
with fn.open() as file:
data = json_load(file)
# Legacy list format does not contain metadata.
if isinstance(data, dict):
data["metadata"] = load_backtest_metadata(filename)
data["metadata"] = load_backtest_metadata(fn)
return data
@@ -362,16 +384,21 @@ def _load_backtest_data_df_compatibility(df: pd.DataFrame) -> pd.DataFrame:
return df
def load_backtest_data(filename: Path | str, strategy: str | None = None) -> pd.DataFrame:
def load_backtest_data(
file_or_directory: Path | str, strategy: str | None = None, filename: Path | str | None = None
) -> pd.DataFrame:
"""
Load backtest data file.
:param filename: pathlib.Path object, or string pointing to a file or directory
Load backtest data file, returns a dataframe with the individual trades.
:param file_or_directory: pathlib.Path object, or string pointing to the directory,
or absolute/relative path to the backtest results file.
:param strategy: Strategy to load - mainly relevant for multi-strategy backtests
Can also serve as protection to load the correct result.
:param filename: Optional filename to load from (if different from the main filename).
Only valid when loading from a directory.
:return: a dataframe with the analysis results
:raise: ValueError if loading goes wrong.
"""
data = load_backtest_stats(filename)
data = load_backtest_stats(file_or_directory, filename)
if not isinstance(data, list):
# new, nested format
if "strategy" not in data:
@@ -430,20 +457,23 @@ def load_file_from_zip(zip_path: Path, filename: str) -> bytes:
raise ValueError(f"Bad zip file: {zip_path}.") from None
def load_backtest_analysis_data(backtest_dir: Path, name: str):
def load_backtest_analysis_data(
file_or_directory: Path,
name: Literal["signals", "rejected", "exited"],
filename: Path | str | None = None,
):
"""
Load backtest analysis data either from a pickle file or from within a zip file
:param backtest_dir: Directory containing backtest results
:param file_or_directory: pathlib.Path object, or string pointing to the directory,
or absolute/relative path to the backtest results file.
:param name: Name of the analysis data to load (signals, rejected, exited)
:param filename: Optional filename to load from (if different from the main filename).
Only valid when loading from a directory.
:return: Analysis data
"""
import joblib
if backtest_dir.is_dir():
lbf = Path(get_latest_backtest_filename(backtest_dir))
zip_path = backtest_dir / lbf
else:
zip_path = backtest_dir
zip_path = _normalize_filename(file_or_directory, filename)
if zip_path.suffix == ".zip":
# Load from zip file
@@ -458,10 +488,10 @@ def load_backtest_analysis_data(backtest_dir: Path, name: str):
else:
# Load from separate pickle file
if backtest_dir.is_dir():
scpf = Path(backtest_dir, f"{zip_path.stem}_{name}.pkl")
if file_or_directory.is_dir():
scpf = Path(file_or_directory, f"{zip_path.stem}_{name}.pkl")
else:
scpf = Path(backtest_dir.parent / f"{backtest_dir.stem}_{name}.pkl")
scpf = Path(file_or_directory.parent / f"{file_or_directory.stem}_{name}.pkl")
try:
with scpf.open("rb") as scp:
@@ -473,27 +503,6 @@ def load_backtest_analysis_data(backtest_dir: Path, name: str):
return None
def load_rejected_signals(backtest_dir: Path):
"""
Load rejected signals from backtest directory
"""
return load_backtest_analysis_data(backtest_dir, "rejected")
def load_signal_candles(backtest_dir: Path):
"""
Load signal candles from backtest directory
"""
return load_backtest_analysis_data(backtest_dir, "signals")
def load_exit_signal_candles(backtest_dir: Path) -> dict[str, dict[str, pd.DataFrame]]:
"""
Load exit signal candles from backtest directory
"""
return load_backtest_analysis_data(backtest_dir, "exited")
def trade_list_to_dataframe(trades: list[Trade] | list[LocalTrade]) -> pd.DataFrame:
"""
Convert list of Trade objects to pandas Dataframe
@@ -11,7 +11,7 @@ def get_tick_size_over_time(candles: DataFrame) -> Series:
# count the number of significant digits for the open and close prices
for col in ["open", "high", "low", "close"]:
candles[f"{col}_count"] = (
candles[col].round(14).astype(str).str.extract(r"\.(\d*[1-9])")[0].str.len()
candles[col].round(14).apply("{:.15f}".format).str.extract(r"\.(\d*[1-9])")[0].str.len()
)
candles["max_count"] = candles[["open_count", "close_count", "high_count", "low_count"]].max(
axis=1
+17 -9
View File
@@ -7,11 +7,9 @@ from freqtrade.configuration import TimeRange
from freqtrade.constants import Config
from freqtrade.data.btanalysis import (
BT_DATA_COLUMNS,
load_backtest_analysis_data,
load_backtest_data,
load_backtest_stats,
load_exit_signal_candles,
load_rejected_signals,
load_signal_candles,
)
from freqtrade.exceptions import ConfigurationError, OperationalException
from freqtrade.util import print_df_rich_table
@@ -332,7 +330,7 @@ def process_entry_exit_reasons(config: Config):
do_rejected = config.get("analysis_rejected", False)
to_csv = config.get("analysis_to_csv", False)
csv_path = Path(
config.get("analysis_csv_path", config["exportfilename"]), # type: ignore[arg-type]
config.get("analysis_csv_path", config["exportdirectory"]), # type: ignore[arg-type]
)
if entry_only is True and exit_only is True:
@@ -346,20 +344,30 @@ def process_entry_exit_reasons(config: Config):
None if config.get("timerange") is None else str(config.get("timerange"))
)
try:
backtest_stats = load_backtest_stats(config["exportfilename"])
backtest_stats = load_backtest_stats(
config["exportdirectory"], config["exportfilename"]
)
except ValueError as e:
raise ConfigurationError(e) from e
for strategy_name, results in backtest_stats["strategy"].items():
trades = load_backtest_data(config["exportfilename"], strategy_name)
trades = load_backtest_data(
config["exportdirectory"], strategy_name, config["exportfilename"]
)
if trades is not None and not trades.empty:
signal_candles = load_signal_candles(config["exportfilename"])
exit_signals = load_exit_signal_candles(config["exportfilename"])
signal_candles = load_backtest_analysis_data(
config["exportdirectory"], "signals", config["exportfilename"]
)
exit_signals = load_backtest_analysis_data(
config["exportdirectory"], "exited", config["exportfilename"]
)
rej_df = None
if do_rejected:
rejected_signals_dict = load_rejected_signals(config["exportfilename"])
rejected_signals_dict = load_backtest_analysis_data(
config["exportdirectory"], "rejected", config["exportfilename"]
)
rej_df = prepare_results(
rejected_signals_dict,
strategy_name,
+1 -1
View File
@@ -97,7 +97,7 @@ def load_data(
"""
result: dict[str, DataFrame] = {}
if startup_candles > 0 and timerange:
logger.info(f"Using indicator startup period: {startup_candles} ...")
logger.debug(f"Using indicator startup period: {startup_candles} ...")
data_handler = get_datahandler(datadir, data_format)
+2 -1
View File
@@ -6,6 +6,7 @@ from freqtrade.exchange.exchange import Exchange
# isort: on
from freqtrade.exchange.binance import Binance
from freqtrade.exchange.bingx import Bingx
from freqtrade.exchange.bitget import Bitget
from freqtrade.exchange.bitmart import Bitmart
from freqtrade.exchange.bitpanda import Bitpanda
from freqtrade.exchange.bitvavo import Bitvavo
@@ -45,4 +46,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 Okx
from freqtrade.exchange.okx import MyOkx, Okx
-1
View File
@@ -45,7 +45,6 @@ class Binance(Exchange):
"funding_fee_candle_limit": 1000,
"stoploss_order_types": {"limit": "stop", "market": "stop_market"},
"stoploss_blocks_assets": False, # Stoploss orders do not block assets
"order_time_in_force": ["GTC", "FOK", "IOC"],
"tickers_have_price": False,
"floor_leverage": True,
"fetch_orders_limit_minutes": 7 * 1440, # "fetch_orders" is limited to 7 days
File diff suppressed because it is too large Load Diff
+128
View File
@@ -0,0 +1,128 @@
import logging
from datetime import timedelta
import ccxt
from freqtrade.enums import CandleType
from freqtrade.exceptions import (
DDosProtection,
OperationalException,
RetryableOrderError,
TemporaryError,
)
from freqtrade.exchange import Exchange
from freqtrade.exchange.common import API_RETRY_COUNT, retrier
from freqtrade.exchange.exchange_types import CcxtOrder, FtHas
from freqtrade.util.datetime_helpers import dt_now, dt_ts
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.
"""
_ft_has: FtHas = {
"stoploss_on_exchange": True,
"stop_price_param": "stopPrice",
"stop_price_prop": "stopPrice",
"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",
}
def ohlcv_candle_limit(
self, timeframe: str, candle_type: CandleType, since_ms: int | None = None
) -> int:
"""
Exchange ohlcv candle limit
bitget has the following behaviour:
* 1000 candles for up-to-date data
* 200 candles for historic data (prior to a certain date)
:param timeframe: Timeframe to check
:param candle_type: Candle-type
:param since_ms: Starting timestamp
:return: Candle limit as integer
"""
timeframe_map = self._api.options["fetchOHLCV"]["maxRecentDaysPerTimeframe"]
days = timeframe_map.get(timeframe, 30)
if candle_type in (CandleType.FUTURES, CandleType.SPOT, CandleType.MARK) and (
not since_ms or dt_ts(dt_now() - timedelta(days=days)) < since_ms
):
return 1000
return super().ohlcv_candle_limit(timeframe, candle_type, since_ms)
def _convert_stop_order(self, pair: str, order_id: str, order: CcxtOrder) -> CcxtOrder:
if order.get("status", "open") == "closed":
# Use orderID as cliendOrderId filter to fetch the regular followup order.
# Could be done with "fetch_order" - but clientOid as filter doesn't seem to work
# https://www.bitget.com/api-doc/spot/trade/Get-Order-Info
for method in (
self._api.fetch_canceled_and_closed_orders,
self._api.fetch_open_orders,
):
orders = method(pair)
orders_f = [order for order in orders if order["clientOrderId"] == order_id]
if orders_f:
order_reg = orders_f[0]
self._log_exchange_response("fetch_stoploss_order1", order_reg)
order_reg["id_stop"] = order_reg["id"]
order_reg["id"] = order_id
order_reg["type"] = "stoploss"
order_reg["status_stop"] = "triggered"
return order_reg
order = self._order_contracts_to_amount(order)
order["type"] = "stoploss"
return order
def _fetch_stop_order_fallback(self, order_id: str, pair: str) -> CcxtOrder:
params2 = {
"stop": True,
}
for method in (
self._api.fetch_open_orders,
self._api.fetch_canceled_and_closed_orders,
):
try:
orders = method(pair, params=params2)
orders_f = [order for order in orders if order["id"] == order_id]
if orders_f:
order = orders_f[0]
self._log_exchange_response("get_stop_order_fallback", order)
return self._convert_stop_order(pair, order_id, order)
except (ccxt.OrderNotFound, ccxt.InvalidOrder):
pass
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.OperationFailed, ccxt.ExchangeError) as e:
raise TemporaryError(
f"Could not get order due to {e.__class__.__name__}. Message: {e}"
) from e
except ccxt.BaseError as e:
raise OperationalException(e) from e
raise RetryableOrderError(f"StoplossOrder not found (pair: {pair} id: {order_id}).")
@retrier(retries=API_RETRY_COUNT)
def fetch_stoploss_order(
self, order_id: str, pair: str, params: dict | None = None
) -> CcxtOrder:
if self._config["dry_run"]:
return self.fetch_dry_run_order(order_id)
return self._fetch_stop_order_fallback(order_id, pair)
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})
+2 -2
View File
@@ -46,10 +46,9 @@ BAD_EXCHANGES = {
MAP_EXCHANGE_CHILDCLASS = {
"binanceus": "binance",
"binanceje": "binance",
"binanceusdm": "binance",
"okex": "okx",
"myokx": "okx",
"okxus": "okx",
"gateio": "gate",
"huboi": "htx",
}
@@ -64,6 +63,7 @@ SUPPORTED_EXCHANGES = [
"hyperliquid",
"kraken",
"okx",
"myokx",
]
# either the main, or replacement methods (array) is required
+7 -7
View File
@@ -213,9 +213,9 @@ def amount_to_precision(
amount = float(
decimal_to_precision(
amount,
rounding_mode=TRUNCATE,
precision=precision,
counting_mode=precisionMode,
TRUNCATE, # rounding_mode
precision, # numPrecisionDigits
precisionMode, # counting_mode
)
)
@@ -311,11 +311,11 @@ def price_to_precision(
return float(
decimal_to_precision(
price,
rounding_mode=rounding_mode,
precision=int(price_precision)
rounding_mode, # rounding mode
int(price_precision)
if precisionMode != TICK_SIZE
else price_precision,
counting_mode=precisionMode,
else price_precision, # numPrecisionDigits
precisionMode, # counting_mode
)
)
+11
View File
@@ -287,3 +287,14 @@ class Okx(Exchange):
orders_open = self._api.fetch_open_orders(pair, since=since_ms)
orders.extend(orders_open)
return orders
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),
]
+1 -1
View File
@@ -493,7 +493,7 @@ class FreqaiDataDrawer:
dk.data["data_path"] = str(dk.data_path)
dk.data["model_filename"] = str(dk.model_filename)
dk.data["training_features_list"] = list(dk.data_dictionary["train_features"].columns)
dk.data["training_features_list"] = dk.training_features_list
dk.data["label_list"] = dk.label_list
with (save_path / f"{dk.model_filename}_{METADATA}.json").open("w") as fp:
+1 -6
View File
@@ -514,12 +514,7 @@ class IFreqaiModel(ABC):
current coin/bot loop
"""
if "training_features_list_raw" in dk.data:
feature_list = dk.data["training_features_list_raw"]
else:
feature_list = dk.data["training_features_list"]
if dk.training_features_list != feature_list:
if dk.training_features_list != dk.data["training_features_list"]:
raise OperationalException(
"Trying to access pretrained model with `identifier` "
"but found different features furnished by current strategy. "
+33 -32
View File
@@ -13,8 +13,8 @@ from freqtrade.loggers.set_log_levels import (
reduce_verbosity_for_bias_tester,
restore_verbosity_for_bias_tester,
)
from freqtrade.optimize.analysis.base_analysis import BaseAnalysis, VarHolder
from freqtrade.optimize.backtesting import Backtesting
from freqtrade.optimize.base_analysis import BaseAnalysis, VarHolder
logger = logging.getLogger(__name__)
@@ -70,34 +70,29 @@ class LookaheadAnalysis(BaseAnalysis):
cut_df: DataFrame = cut_vars.indicators[current_pair]
full_df: DataFrame = full_vars.indicators[current_pair]
# cut longer dataframe to length of the shorter
full_df_cut = full_df[(full_df.date == cut_vars.compared_dt)].reset_index(drop=True)
cut_df_cut = cut_df[(cut_df.date == cut_vars.compared_dt)].reset_index(drop=True)
# trim full_df to the same index and length as cut_df
cut_full_df = full_df.loc[cut_df.index]
compare_df = cut_full_df.compare(cut_df)
# check if dataframes are not empty
if full_df_cut.shape[0] != 0 and cut_df_cut.shape[0] != 0:
# compare dataframes
compare_df = full_df_cut.compare(cut_df_cut)
if compare_df.shape[0] > 0:
for col_name in compare_df:
col_idx = compare_df.columns.get_loc(col_name)
compare_df_row = compare_df.iloc[0]
# compare_df now comprises tuples with [1] having either 'self' or 'other'
if "other" in col_name[1]:
continue
self_value = compare_df_row.iloc[col_idx]
other_value = compare_df_row.iloc[col_idx + 1]
if compare_df.shape[0] > 0:
for col_name, values in compare_df.items():
col_idx = compare_df.columns.get_loc(col_name)
compare_df_row = compare_df.iloc[0]
# compare_df now comprises tuples with [1] having either 'self' or 'other'
if "other" in col_name[1]:
continue
self_value = compare_df_row.iloc[col_idx]
other_value = compare_df_row.iloc[col_idx + 1]
# output differences
if self_value != other_value:
if not self.current_analysis.false_indicators.__contains__(col_name[0]):
self.current_analysis.false_indicators.append(col_name[0])
logger.info(
f"=> found look ahead bias in indicator "
f"{col_name[0]}. "
f"{str(self_value)} != {str(other_value)}"
)
# output differences
if self_value != other_value:
if not self.current_analysis.false_indicators.__contains__(col_name[0]):
self.current_analysis.false_indicators.append(col_name[0])
logger.info(
f"=> found look ahead bias in column "
f"{col_name[0]}. "
f"{str(self_value)} != {str(other_value)}"
)
def prepare_data(self, varholder: VarHolder, pairs_to_load: list[DataFrame]):
if "freqai" in self.local_config and "identifier" in self.local_config["freqai"]:
@@ -132,7 +127,13 @@ class LookaheadAnalysis(BaseAnalysis):
varholder.data, varholder.timerange = backtesting.load_bt_data()
varholder.timeframe = backtesting.timeframe
varholder.indicators = backtesting.strategy.advise_all_indicators(varholder.data)
temp_indicators = backtesting.strategy.advise_all_indicators(varholder.data)
filled_indicators = dict()
for pair, dataframe in temp_indicators.items():
filled_indicators[pair] = backtesting.strategy.ft_advise_signals(
dataframe, {"pair": pair}
)
varholder.indicators = filled_indicators
varholder.result = self.get_result(backtesting, varholder.indicators)
def fill_entry_and_exit_varHolders(self, result_row):
@@ -171,23 +172,23 @@ class LookaheadAnalysis(BaseAnalysis):
self.fill_entry_and_exit_varHolders(result_row)
# this will trigger a logger-message
buy_or_sell_biased: bool = False
entry_or_exit_biased: bool = False
# register if buy signal is broken
if not self.report_signal(
self.entry_varHolders[idx].result, "open_date", self.entry_varHolders[idx].compared_dt
):
self.current_analysis.false_entry_signals += 1
buy_or_sell_biased = True
entry_or_exit_biased = True
# register if buy or sell signal is broken
if not self.report_signal(
self.exit_varHolders[idx].result, "close_date", self.exit_varHolders[idx].compared_dt
):
self.current_analysis.false_exit_signals += 1
buy_or_sell_biased = True
entry_or_exit_biased = True
if buy_or_sell_biased:
if entry_or_exit_biased:
logger.info(
f"found lookahead-bias in trade "
f"pair: {result_row['pair']}, "
+9 -9
View File
@@ -13,9 +13,8 @@ from freqtrade.loggers.set_log_levels import (
reduce_verbosity_for_bias_tester,
restore_verbosity_for_bias_tester,
)
from freqtrade.optimize.analysis.base_analysis import BaseAnalysis, VarHolder
from freqtrade.optimize.backtesting import Backtesting
from freqtrade.optimize.base_analysis import BaseAnalysis, VarHolder
from freqtrade.resolvers import StrategyResolver
logger = logging.getLogger(__name__)
@@ -33,13 +32,6 @@ class RecursiveAnalysis(BaseAnalysis):
super().__init__(config, strategy_obj)
strat = StrategyResolver.load_strategy(config)
self._strat_scc = strat.startup_candle_count
if self._strat_scc not in self._startup_candle:
self._startup_candle.append(self._strat_scc)
self._startup_candle.sort()
self.partial_varHolder_array: list[VarHolder] = []
self.partial_varHolder_lookahead_array: list[VarHolder] = []
@@ -146,8 +138,16 @@ class RecursiveAnalysis(BaseAnalysis):
backtesting = Backtesting(prepare_data_config, self.exchange)
self.exchange = backtesting.exchange
self.local_config["candle_type_def"] = prepare_data_config["candle_type_def"]
backtesting._set_strategy(backtesting.strategylist[0])
strat = backtesting.strategy
self._strat_scc = strat.startup_candle_count
if self._strat_scc not in self._startup_candle:
self._startup_candle.append(self._strat_scc)
self._startup_candle.sort()
varholder.data, varholder.timerange = backtesting.load_bt_data()
varholder.timeframe = backtesting.timeframe
@@ -17,7 +17,7 @@ class RecursiveAnalysisSubFunctions:
@staticmethod
def text_table_recursive_analysis_instances(recursive_instances: list[RecursiveAnalysis]):
startups = recursive_instances[0]._startup_candle
strat_scc = recursive_instances[0]._strat_scc
strat_scc = getattr(recursive_instances[0], "_strat_scc", 0) or 0
headers = ["Indicators"]
for candle in startups:
if candle == strat_scc:
+30 -18
View File
@@ -124,7 +124,7 @@ class Backtesting:
self.trade_id_counter: int = 0
self.order_id_counter: int = 0
config["dry_run"] = True
self.config["dry_run"] = True
self.price_pair_prec: dict[str, Series] = {}
self.run_ids: dict[str, str] = {}
self.strategylist: list[IStrategy] = []
@@ -137,6 +137,7 @@ class Backtesting:
self.rejected_dict: dict[str, list] = {}
self._exchange_name = self.config["exchange"]["name"]
self.__initial_backtest = exchange is None
if not exchange:
exchange = ExchangeResolver.load_exchange(self.config, load_leverage_tiers=True)
self.exchange = exchange
@@ -179,20 +180,7 @@ class Backtesting:
if len(self.pairlists.whitelist) == 0:
raise OperationalException("No pair in whitelist.")
if config.get("fee", None) is not None:
self.fee = config["fee"]
logger.info(f"Using fee {self.fee:.4%} from config.")
else:
fees = [
self.exchange.get_fee(
symbol=self.pairlists.whitelist[0],
taker_or_maker=mt, # type: ignore
)
for mt in ("taker", "maker")
]
self.fee = max(fee for fee in fees if fee is not None)
logger.info(f"Using fee {self.fee:.4%} - worst case fee from exchange (lowest tier).")
self.set_fee()
self.precision_mode = self.exchange.precisionMode
self.precision_mode_price = self.exchange.precision_mode_price
@@ -217,8 +205,8 @@ class Backtesting:
# This value should NOT be written to startup_candle_count
self.required_startup = self.dataprovider.get_required_startup(self.timeframe)
self.trading_mode: TradingMode = config.get("trading_mode", TradingMode.SPOT)
self.margin_mode: MarginMode = config.get("margin_mode", MarginMode.ISOLATED)
self.trading_mode: TradingMode = self.config.get("trading_mode", TradingMode.SPOT)
self.margin_mode: MarginMode = self.config.get("margin_mode", MarginMode.ISOLATED)
# strategies which define "can_short=True" will fail to load in Spot mode.
self._can_short = self.trading_mode != TradingMode.SPOT
self._position_stacking: bool = self.config.get("position_stacking", False)
@@ -238,6 +226,30 @@ class Backtesting:
"PrecisionFilter not allowed for backtesting multiple strategies."
)
def log_once(self, msg: str) -> None:
"""
Partial reimplementation of log_once from the Login mixin.
only used by recursive, as __initial_backtest is false in all other cases.
"""
if self.__initial_backtest:
logger.info(msg)
def set_fee(self):
if self.config.get("fee", None) is not None:
self.fee = self.config["fee"]
self.log_once(f"Using fee {self.fee:.4%} from config.")
else:
fees = [
self.exchange.get_fee(
symbol=self.pairlists.whitelist[0],
taker_or_maker=mt,
)
for mt in ("taker", "maker")
]
self.fee = max(fee for fee in fees if fee is not None)
self.log_once(f"Using fee {self.fee:.4%} - worst case fee from exchange (lowest tier).")
@staticmethod
def cleanup():
LoggingMixin.show_output = True
@@ -1649,7 +1661,7 @@ class Backtesting:
pair_detail = self.get_detail_data(pair, row)
if pair_detail is not None:
pair_detail_cache[pair] = pair_detail
row = pair_detail_cache[pair][idx]
row = pair_detail_cache[pair][idx]
is_last_row = current_time_det == end_date
@@ -194,6 +194,7 @@ def text_table_strategy(strategy_results, stake_currency: str, title: str):
def text_table_add_metrics(strat_results: dict) -> None:
stake = strat_results["stake_currency"]
if len(strat_results["trades"]) > 0:
best_trade = max(strat_results["trades"], key=lambda x: x["profit_ratio"])
worst_trade = min(strat_results["trades"], key=lambda x: x["profit_ratio"])
@@ -202,23 +203,19 @@ def text_table_add_metrics(strat_results: dict) -> None:
[
("", ""), # Empty line to improve readability
(
"Long / Short",
"Long / Short trades",
f"{strat_results.get('trade_count_long', 'total_trades')} / "
f"{strat_results.get('trade_count_short', 0)}",
),
("Total profit Long %", f"{strat_results['profit_total_long']:.2%}"),
("Total profit Short %", f"{strat_results['profit_total_short']:.2%}"),
(
"Absolute profit Long",
fmt_coin(
strat_results["profit_total_long_abs"], strat_results["stake_currency"]
),
"Long / Short profit %",
f"{strat_results['profit_total_long']:.2%} / "
f"{strat_results['profit_total_short']:.2%}",
),
(
"Absolute profit Short",
fmt_coin(
strat_results["profit_total_short_abs"], strat_results["stake_currency"]
),
f"Long / Short profit {stake}",
f"{strat_results['profit_total_long_abs']:.{decimals_per_coin(stake)}f} / "
f"{strat_results['profit_total_short_abs']:.{decimals_per_coin(stake)}f}",
),
]
if strat_results.get("trade_count_short", 0) > 0
@@ -231,27 +228,34 @@ def text_table_add_metrics(strat_results: dict) -> None:
drawdown_metrics.append(
("Max % of account underwater", f"{strat_results['max_relative_drawdown']:.2%}")
)
drawdown_account = (
strat_results["max_drawdown_account"]
if "max_drawdown_account" in strat_results
else strat_results["max_drawdown"]
)
drawdown_metrics.extend(
[
(
("Absolute Drawdown (Account)", f"{strat_results['max_drawdown_account']:.2%}")
if "max_drawdown_account" in strat_results
else ("Drawdown", f"{strat_results['max_drawdown']:.2%}")
"Absolute drawdown",
f"{fmt_coin(strat_results['max_drawdown_abs'], stake)} "
f"({drawdown_account:.2%})",
),
(
"Absolute Drawdown",
fmt_coin(strat_results["max_drawdown_abs"], strat_results["stake_currency"]),
"Drawdown duration",
strat_results["drawdown_duration"]
if "drawdown_duration" in strat_results
else "N/A",
),
(
"Drawdown high",
fmt_coin(strat_results["max_drawdown_high"], strat_results["stake_currency"]),
"Profit at drawdown start",
fmt_coin(strat_results["max_drawdown_high"], stake),
),
(
"Drawdown low",
fmt_coin(strat_results["max_drawdown_low"], strat_results["stake_currency"]),
"Profit at drawdown end",
fmt_coin(strat_results["max_drawdown_low"], stake),
),
("Drawdown Start", strat_results["drawdown_start"]),
("Drawdown End", strat_results["drawdown_end"]),
("Drawdown start", strat_results["drawdown_start"]),
("Drawdown end", strat_results["drawdown_end"]),
]
)
@@ -299,15 +303,15 @@ def text_table_add_metrics(strat_results: dict) -> None:
),
(
"Starting balance",
fmt_coin(strat_results["starting_balance"], strat_results["stake_currency"]),
fmt_coin(strat_results["starting_balance"], stake),
),
(
"Final balance",
fmt_coin(strat_results["final_balance"], strat_results["stake_currency"]),
fmt_coin(strat_results["final_balance"], stake),
),
(
"Absolute profit ",
fmt_coin(strat_results["profit_total_abs"], strat_results["stake_currency"]),
fmt_coin(strat_results["profit_total_abs"], stake),
),
("Total profit %", f"{strat_results['profit_total']:.2%}"),
("CAGR %", f"{strat_results['cagr']:.2%}" if "cagr" in strat_results else "N/A"),
@@ -335,16 +339,16 @@ def text_table_add_metrics(strat_results: dict) -> None:
"Avg. daily profit",
fmt_coin(
(strat_results["profit_total_abs"] / strat_results["backtest_days"]),
strat_results["stake_currency"],
stake,
),
),
(
"Avg. stake amount",
fmt_coin(strat_results["avg_stake_amount"], strat_results["stake_currency"]),
fmt_coin(strat_results["avg_stake_amount"], stake),
),
(
"Total trade volume",
fmt_coin(strat_results["total_volume"], strat_results["stake_currency"]),
fmt_coin(strat_results["total_volume"], stake),
),
*short_metrics,
("", ""), # Empty line to improve readability
@@ -362,11 +366,11 @@ def text_table_add_metrics(strat_results: dict) -> None:
("Worst trade", f"{worst_trade['pair']} {worst_trade['profit_ratio']:.2%}"),
(
"Best day",
fmt_coin(strat_results["backtest_best_day_abs"], strat_results["stake_currency"]),
fmt_coin(strat_results["backtest_best_day_abs"], stake),
),
(
"Worst day",
fmt_coin(strat_results["backtest_worst_day_abs"], strat_results["stake_currency"]),
fmt_coin(strat_results["backtest_worst_day_abs"], stake),
),
(
"Days win/draw/lose",
@@ -404,17 +408,17 @@ def text_table_add_metrics(strat_results: dict) -> None:
),
*entry_adjustment_metrics,
("", ""), # Empty line to improve readability
("Min balance", fmt_coin(strat_results["csum_min"], strat_results["stake_currency"])),
("Max balance", fmt_coin(strat_results["csum_max"], strat_results["stake_currency"])),
("Min balance", fmt_coin(strat_results["csum_min"], stake)),
("Max balance", fmt_coin(strat_results["csum_max"], stake)),
*drawdown_metrics,
("Market change", f"{strat_results['market_change']:.2%}"),
]
print_rich_table(metrics, ["Metric", "Value"], summary="SUMMARY METRICS", justify="left")
else:
start_balance = fmt_coin(strat_results["starting_balance"], strat_results["stake_currency"])
start_balance = fmt_coin(strat_results["starting_balance"], stake)
stake_amount = (
fmt_coin(strat_results["stake_amount"], strat_results["stake_currency"])
fmt_coin(strat_results["stake_amount"], stake)
if strat_results["stake_amount"] != UNLIMITED_STAKE_AMOUNT
else "unlimited"
)
@@ -64,7 +64,7 @@ def store_backtest_results(
:param market_change_data: Dataframe containing market change data
:param analysis_results: Dictionary containing analysis results
"""
recordfilename: Path = config["exportfilename"]
recordfilename: Path = config["exportdirectory"]
zip_filename = _generate_filename(recordfilename, dtappendix, ".zip")
base_filename = _generate_filename(recordfilename, dtappendix, "")
json_filename = _generate_filename(recordfilename, dtappendix, ".json")
@@ -598,6 +598,8 @@ def generate_strategy_stats(
"timerange": config.get("timerange", ""),
"enable_protections": config.get("enable_protections", False),
"strategy_name": strategy,
"freqaimodel": config.get("freqaimodel", None),
"freqai_identifier": config.get("freqai", {}).get("identifier", None),
# Parameters relevant for backtesting
"stoploss": config["stoploss"],
"trailing_stop": config.get("trailing_stop", False),
@@ -625,6 +627,7 @@ def generate_strategy_stats(
underwater = calculate_max_drawdown(
results, value_col="profit_abs", starting_balance=start_balance, relative=True
)
drawdown_duration = drawdown.low_date - drawdown.high_date
strat_stats.update(
{
@@ -635,6 +638,8 @@ def generate_strategy_stats(
"drawdown_start_ts": drawdown.high_date.timestamp() * 1000,
"drawdown_end": drawdown.low_date.strftime(DATETIME_PRINT_FORMAT),
"drawdown_end_ts": drawdown.low_date.timestamp() * 1000,
"drawdown_duration": drawdown_duration,
"drawdown_duration_s": drawdown_duration.total_seconds(),
"max_drawdown_low": drawdown.low_value,
"max_drawdown_high": drawdown.high_value,
}
+5 -2
View File
@@ -1187,10 +1187,13 @@ class LocalTrade:
"""
close_trade_value = self.calc_close_trade_value(rate, amount)
if amount is None or open_rate is None:
if (amount is None) and (open_rate is None):
open_trade_value = self.open_trade_value
else:
open_trade_value = self._calc_open_trade_value(amount, open_rate)
# Fall back to trade.amount and self.open_rate if necessary
open_trade_value = self._calc_open_trade_value(
amount or self.amount, open_rate or self.open_rate
)
if open_trade_value == 0.0:
return 0.0
+5 -4
View File
@@ -31,8 +31,9 @@ class AgeFilter(IPairList):
self._min_days_listed = self._pairlistconfig.get("min_days_listed", 10)
self._max_days_listed = self._pairlistconfig.get("max_days_listed")
self._def_candletype = self._config["candle_type_def"]
candle_limit = self._exchange.ohlcv_candle_limit("1d", self._config["candle_type_def"])
candle_limit = self._exchange.ohlcv_candle_limit("1d", self._def_candletype)
if self._min_days_listed < 1:
raise OperationalException("AgeFilter requires min_days_listed to be >= 1")
if self._min_days_listed > candle_limit:
@@ -100,7 +101,7 @@ class AgeFilter(IPairList):
:return: new allowlist
"""
needed_pairs: ListPairsWithTimeframes = [
(p, "1d", self._config["candle_type_def"])
(p, "1d", self._def_candletype)
for p in pairlist
if p not in self._symbolsChecked and p not in self._symbolsCheckFailed
]
@@ -116,8 +117,8 @@ class AgeFilter(IPairList):
if self._enabled:
for p in deepcopy(pairlist):
daily_candles = (
candles[(p, "1d", self._config["candle_type_def"])]
if (p, "1d", self._config["candle_type_def"]) in candles
candles[(p, "1d", self._def_candletype)]
if (p, "1d", self._def_candletype) in candles
else None
)
if not self._validate_pair_loc(p, daily_candles):
+48 -14
View File
@@ -37,7 +37,6 @@ class MarketCapPairList(IPairList):
self._refresh_period = self._pairlistconfig.get("refresh_period", 86400)
self._categories = self._pairlistconfig.get("categories", [])
self._marketcap_cache: TTLCache = TTLCache(maxsize=1, ttl=self._refresh_period)
self._def_candletype = self._config["candle_type_def"]
_coingecko_config = self._config.get("coingecko", {})
@@ -118,6 +117,16 @@ class MarketCapPairList(IPairList):
},
}
def get_markets_exchange(self):
markets = [
k
for k in self._exchange.get_markets(
quote_currencies=[self._stake_currency], tradable_only=True, active_only=True
).keys()
]
return markets
def gen_pairlist(self, tickers: Tickers) -> list[str]:
"""
Generate the pairlist
@@ -133,12 +142,8 @@ class MarketCapPairList(IPairList):
else:
# Use fresh pairlist
# Check if pair quote currency equals to the stake currency.
_pairlist = [
k
for k in self._exchange.get_markets(
quote_currencies=[self._stake_currency], tradable_only=True, active_only=True
).keys()
]
_pairlist = self.get_markets_exchange()
# No point in testing for blacklisted pairs...
_pairlist = self.verify_blacklist(_pairlist, logger.info)
@@ -147,6 +152,31 @@ class MarketCapPairList(IPairList):
return pairlist
# Prefixes to test to discover coins like 1000PEPE/USDDT:USDT or KPEPE/USDC (hyperliquid)
prefixes = ("1000", "K")
def resolve_marketcap_pair(
self,
pair: str,
pairlist: list[str],
markets: list[str],
filtered_pairlist: list[str],
) -> str | None:
if pair in filtered_pairlist:
return None
if pair in pairlist:
return pair
if pair not in markets:
for prefix in self.prefixes:
test_prefix = f"{prefix}{pair}"
if test_prefix in pairlist:
return test_prefix
return None
def filter_pairlist(self, pairlist: list[str], tickers: dict) -> list[str]:
"""
Filters and sorts pairlist and returns the whitelist again.
@@ -189,21 +219,25 @@ class MarketCapPairList(IPairList):
self._marketcap_cache["marketcap"] = marketcap_list
if marketcap_list:
filtered_pairlist = []
filtered_pairlist: list[str] = []
market = self._config["trading_mode"]
market = self._exchange._config["trading_mode"]
pair_format = f"{self._stake_currency.upper()}"
if market == "futures":
pair_format += f":{self._stake_currency.upper()}"
top_marketcap = marketcap_list[: self._max_rank :]
markets = self.get_markets_exchange()
for mc_pair in top_marketcap:
test_pair = f"{mc_pair.upper()}/{pair_format}"
if test_pair in pairlist and test_pair not in filtered_pairlist:
filtered_pairlist.append(test_pair)
if len(filtered_pairlist) == self._number_assets:
break
pair = f"{mc_pair.upper()}/{pair_format}"
resolved = self.resolve_marketcap_pair(pair, pairlist, markets, filtered_pairlist)
if resolved:
filtered_pairlist.append(resolved)
if len(filtered_pairlist) == self._number_assets:
break
if len(filtered_pairlist) > 0:
return filtered_pairlist
@@ -91,7 +91,7 @@ class PercentChangePairList(IPairList):
)
candle_limit = self._exchange.ohlcv_candle_limit(
self._lookback_timeframe, self._config["candle_type_def"]
self._lookback_timeframe, self._def_candletype
)
if self._lookback_period > candle_limit:
@@ -40,7 +40,7 @@ class VolatilityFilter(IPairList):
self._pair_cache: TTLCache = TTLCache(maxsize=1000, ttl=self._refresh_period)
candle_limit = self._exchange.ohlcv_candle_limit("1d", self._config["candle_type_def"])
candle_limit = self._exchange.ohlcv_candle_limit("1d", self._def_candletype)
if self._days < 1:
raise OperationalException("VolatilityFilter requires lookback_days to be >= 1")
if self._days > candle_limit:
+1 -1
View File
@@ -89,7 +89,7 @@ class VolumePairList(IPairList):
raise OperationalException(f"key {self._sort_key} not in {SORT_VALUES}")
candle_limit = self._exchange.ohlcv_candle_limit(
self._lookback_timeframe, self._config["candle_type_def"]
self._lookback_timeframe, self._def_candletype
)
if self._lookback_period < 0:
raise OperationalException("VolumeFilter requires lookback_period to be >= 0")
@@ -34,7 +34,7 @@ class RangeStabilityFilter(IPairList):
self._pair_cache: TTLCache = TTLCache(maxsize=1000, ttl=self._refresh_period)
candle_limit = self._exchange.ohlcv_candle_limit("1d", self._config["candle_type_def"])
candle_limit = self._exchange.ohlcv_candle_limit("1d", self._def_candletype)
if self._days < 1:
raise OperationalException("RangeStabilityFilter requires lookback_days to be >= 1")
if self._days > candle_limit:
@@ -54,6 +54,7 @@ def __run_pairlist(job_id: str, config_loc: Config):
with FtNoDBContext():
exchange = get_exchange(config_loc)
config_loc["candle_type_def"] = exchange._config["candle_type_def"]
pairlists = PairListManager(exchange, config_loc)
pairlists.refresh_pairlist()
ApiBG.jobs[job_id]["result"] = {
+16 -2
View File
@@ -342,8 +342,22 @@ class Telegram(RPCHandler):
self._loop.run_until_complete(self._startup_telegram())
async def _startup_telegram(self) -> None:
await self._app.initialize()
await self._app.start()
retries = 3
attempt = 0
while attempt < retries:
try:
await self._app.initialize()
await self._app.start()
break
except Exception as ex:
logger.error(
"Error starting Telegram bot (attempt %d/%d): %s", attempt + 1, retries, ex
)
attempt += 1
if attempt == retries:
logger.warning("Telegram init failed.")
return
await asyncio.sleep(2)
if self._app.updater:
await self._app.updater.start_polling(
bootstrap_retries=-1,
+8 -1
View File
@@ -225,7 +225,6 @@ class RealParameter(NumericParameter):
class DecimalParameter(NumericParameter):
default: float
value: float
def __init__(
self,
@@ -259,6 +258,14 @@ class DecimalParameter(NumericParameter):
low=low, high=high, default=default, space=space, optimize=optimize, load=load, **kwargs
)
@property
def value(self) -> float:
return self._value
@value.setter
def value(self, new_value: float):
self._value = round(new_value, self._decimals)
def get_space(self, name: str) -> "SKDecimal":
"""
Create optimization space.
+1 -1
View File
@@ -1,7 +1,7 @@
from freqtrade_client.ft_rest_client import FtRestClient
__version__ = "2025.7"
__version__ = "2025.8"
if "dev" in __version__:
from pathlib import Path
+1 -1
View File
@@ -1,3 +1,3 @@
# Requirements for freqtrade client library
requests==2.32.4
requests==2.32.5
python-rapidjson==1.21
+1 -1
View File
@@ -40,7 +40,7 @@ dependencies = [
"jsonschema",
"numpy>2.0,<3.0",
"pandas>=2.2.0,<3.0",
"TA-Lib<0.6",
"TA-Lib<0.7",
"ft-pandas-ta",
"technical",
"tabulate",
+7 -7
View File
@@ -6,9 +6,9 @@
-r requirements-freqai-rl.txt
-r docs/requirements-docs.txt
ruff==0.12.5
mypy==1.17.0
pre-commit==4.2.0
ruff==0.12.10
mypy==1.17.1
pre-commit==4.3.0
pytest==8.4.1
pytest-asyncio==1.1.0
pytest-cov==6.2.1
@@ -18,15 +18,15 @@ pytest-timeout==2.4.0
pytest-xdist==3.8.0
isort==6.0.1
# For datetime mocking
time-machine==2.16.0
time-machine==2.19.0
# Convert jupyter notebooks to markdown documents
nbconvert==7.16.6
# mypy types
scipy-stubs==1.16.0.2 # keep in sync with `scipy` in `requirements-hyperopt.txt`
scipy-stubs==1.16.1.1 # keep in sync with `scipy` in `requirements-hyperopt.txt`
types-cachetools==6.1.0.20250717
types-filelock==3.2.7
types-requests==2.32.4.20250611
types-requests==2.32.4.20250809
types-tabulate==0.9.0.20241207
types-python-dateutil==2.9.0.20250708
types-python-dateutil==2.9.0.20250822
+1 -1
View File
@@ -2,7 +2,7 @@
-r requirements-freqai.txt
# Required for freqai-rl
torch==2.7.1; sys_platform != 'darwin' or platform_machine != 'x86_64'
torch==2.8.0; sys_platform != 'darwin' or platform_machine != 'x86_64'
gymnasium==0.29.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'
+2 -2
View File
@@ -4,9 +4,9 @@
# Required for freqai
scikit-learn==1.7.1
joblib==1.5.1
joblib==1.5.2
catboost==1.2.8; 'arm' not in platform_machine
lightgbm==4.6.0
xgboost==3.0.2
xgboost==3.0.4
tensorboard==2.20.0
datasieve==0.1.9
+2 -2
View File
@@ -4,6 +4,6 @@
# Required for hyperopt
scipy==1.16.1
scikit-learn==1.7.1
filelock==3.18.0
optuna==4.4.0
filelock==3.19.1
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.2.0
plotly==6.3.0
+18 -14
View File
@@ -1,36 +1,40 @@
numpy==2.3.2
pandas==2.3.1
numpy==2.3.2; platform_machine != 'armv7l'
numpy==2.2.4; platform_machine == 'armv7l'
pandas==2.3.2; platform_machine != 'armv7l'
pandas==2.2.3; platform_machine == 'armv7l'
bottleneck==1.5.0
numexpr==2.11.0
# Indicator libraries
ft-pandas-ta==0.3.15
ta-lib==0.5.5
technical==1.5.2
ta-lib==0.6.5
technical==1.5.3
ccxt==4.4.96
cryptography==45.0.5
aiohttp==3.12.14
SQLAlchemy==2.0.41
ccxt==4.5.2
cryptography==45.0.6
aiohttp==3.12.15
SQLAlchemy==2.0.43
python-telegram-bot==22.3
# can't be hard-pinned due to telegram-bot pinning httpx with ~
httpx>=0.24.1
humanize==4.12.3
cachetools==6.1.0
requests==2.32.4
requests==2.32.5
urllib3==2.5.0
certifi==2025.7.14
jsonschema==4.25.0
certifi==2025.8.3
jsonschema==4.25.1
tabulate==0.9.0
pycoingecko==3.2.0
jinja2==3.1.6
joblib==1.5.1
joblib==1.5.2
rich==14.1.0
pyarrow==21.0.0; platform_machine != 'armv7l'
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
# Properly format api responses
orjson==3.11.1
orjson==3.11.2
# Notify systemd
sdnotify==0.3.2
-10
View File
@@ -228,16 +228,6 @@ function Main {
}
}
if (-not (Test-Path "$VenvDir\Lib\site-packages\talib")) {
# Install TA-Lib using the virtual environment's pip
Write-Log "Installing TA-Lib using virtual environment's pip..."
python -m pip install --find-links=build_helpers\ --prefer-binary TA-Lib 2>&1 | Out-File $LogFilePath -Append
if ($LASTEXITCODE -ne 0) {
Write-Log "Failed to install TA-Lib." -Level 'ERROR'
Exit-Script -exitCode 1
}
}
# Present options for requirement files
$SelectedIndices = Get-UserSelection -prompt "Select which requirement files to install:" -options $RequirementFiles -defaultChoice 'A'
+1 -21
View File
@@ -91,7 +91,6 @@ function updateenv() {
fi
fi
fi
install_talib
${PYTHON} -m pip install --upgrade -r ${REQUIREMENTS} ${REQUIREMENTS_HYPEROPT} ${REQUIREMENTS_PLOT} ${REQUIREMENTS_FREQAI} ${REQUIREMENTS_FREQAI_RL}
if [ $? -ne 0 ]; then
@@ -118,25 +117,6 @@ function updateenv() {
fi
}
# Install tab lib
function install_talib() {
if [ -f /usr/local/lib/libta_lib.a ] || [ -f /usr/local/lib/libta_lib.so ] || [ -f /usr/lib/libta_lib.so ]; then
echo "ta-lib already installed, skipping"
return
fi
cd build_helpers && ./install_ta-lib.sh
if [ $? -ne 0 ]; then
echo "Quitting. Please fix the above error before continuing."
cd ..
exit 1
fi;
cd ..
}
# Install bot MacOS
function install_macos() {
if [ ! -x "$(command -v brew)" ]
@@ -257,7 +237,7 @@ function install() {
install_redhat
else
echo "This script does not support your OS."
echo "If you have Python version 3.11 - 3.13, pip, virtualenv, ta-lib you can continue."
echo "If you have Python version 3.11 - 3.13, pip, virtualenv installed you can continue."
echo "Wait 10 seconds to continue the next install steps or use ctrl+c to interrupt this shell."
sleep 10
fi
+52 -1
View File
@@ -133,6 +133,8 @@ def test_list_exchanges(capsys):
captured = capsys.readouterr()
assert re.search(r"^binance$", captured.out, re.MULTILINE)
assert re.search(r"^bybit$", captured.out, re.MULTILINE)
# An exchange not supporting futures
assert re.search(r"^kraken$", captured.out, re.MULTILINE)
# Test with --all
args = [
@@ -160,6 +162,32 @@ def test_list_exchanges(capsys):
assert re.search(r"^bingx$", captured.out, re.MULTILINE)
assert re.search(r"^bitmex$", captured.out, re.MULTILINE)
# Only dex
args = [
"list-exchanges",
"--dex",
]
start_list_exchanges(get_args(args))
captured = capsys.readouterr()
assert re.search(r"Exchanges available for Freqtrade.*", captured.out)
assert not re.search(r".*binance.*", captured.out)
assert not re.search(r".*bingx.*", captured.out)
assert re.search(r".*hyperliquid.*", captured.out)
# Only futures
args = [
"list-exchanges",
"--trading-mode",
"futures",
]
start_list_exchanges(get_args(args))
captured = capsys.readouterr()
assert re.search(r"Exchanges available for Freqtrade.*", captured.out)
assert re.search(r".*binance.*", captured.out)
assert not re.search(r".*kraken.*", captured.out)
def test_list_timeframes(mocker, capsys):
api_mock = MagicMock()
@@ -1748,6 +1776,27 @@ def test_start_list_data(testdatadir, capsys):
captured.out,
)
# Test with regex
args = [
"list-data",
"--pairs",
"XMR/.*",
"--datadir",
str(testdatadir),
"--show-timerange",
]
pargs = get_args(args)
pargs["config"] = None
start_list_data(pargs)
captured = capsys.readouterr()
assert "Found 1 pair / timeframe combinations." in captured.out
assert re.search(r".*Pair.*Timeframe.*Type.*From .* To .* Candles .*\n", captured.out)
assert "UNITTEST/BTC" not in captured.out
assert re.search(
r"\n.* XMR/USDT .* 5m .* spot .* 2019-10-11 00:00:00 .* 2019-10-13 11:19:00 .* 2469 |\n",
captured.out,
)
def test_start_list_trades_data(testdatadir, capsys):
args = [
@@ -1834,8 +1883,10 @@ def test_backtesting_show(mocker, testdatadir, capsys):
sbr = mocker.patch("freqtrade.optimize.optimize_reports.show_backtest_results")
args = [
"backtesting-show",
"--export-directory",
f"{testdatadir / 'backtest_results'}",
"--export-filename",
f"{testdatadir / 'backtest_results/backtest-result.json'}",
"backtest-result.json",
"--show-pair-list",
]
pargs = get_args(args)
+5 -1
View File
@@ -521,7 +521,11 @@ def patch_torch_initlogs(mocker) -> None:
mocked_module = types.ModuleType(module_name)
sys.modules[module_name] = mocked_module
else:
mocker.patch("torch._logging._init_logs")
try:
mocker.patch("torch._logging._init_logs")
except ModuleNotFoundError:
# Allow running limited tests to run without freqAI dependencies
pass
@pytest.fixture(autouse=True)

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