Compare commits

..

657 Commits

Author SHA1 Message Date
Robert Caulk
cae8c3a7a8 Update freqtrade/freqai/data_drawer.py
Co-authored-by: Matthias <xmatthias@outlook.com>
2023-03-27 07:00:20 -04:00
robcaulk
1fe58c3938 ensure the backup folder will overwrite existing folders 2023-03-25 14:12:06 +01:00
robcaulk
630cdcb99f reduce duplicated code 2023-03-25 13:27:41 +01:00
robcaulk
b383654378 create a separate folder for the historic_predictions parquet files. Modify save/load functions to accommodate new structure 2023-03-25 13:19:53 +01:00
robcaulk
0883198f40 use parquet in favor of pickle to improve performance for historic_prediction saving, loading, and active post processing 2023-03-25 11:38:16 +01:00
Matthias
4053ee4581 Merge pull request #8380 from freqtrade/fix/talibinstall
use github to download guess instead of gnu.org
2023-03-25 09:22:43 +01:00
Matthias
56170dba19 use github to download guess instead of gnu.org
gnu.org seems down rn (dns does no longer resolve),
and doesn't have good uptime history
2023-03-25 08:55:36 +01:00
Matthias
79a2de7a64 Reduce impact of short outages 2023-03-25 08:31:35 +01:00
Matthias
b317524ed7 protect adjust_trade_position from crashing in case of unsafe code 2023-03-24 20:27:45 +01:00
Matthias
469166636c Set initial stoploss when creating the order
This ensures that a trade never has "None" as stoploss
2023-03-24 07:27:45 +01:00
Matthias
150c5510c7 Don''t fully fail bot when invalid price value is reached
closes #8300
2023-03-22 19:46:07 +01:00
Matthias
8cf3e9f91b Accept "insufficient funds" error on set_leverage from stop calls
closes #8341
2023-03-21 19:29:27 +01:00
Matthias
ebebcb886c Move build-system to the top of pyproject.toml 2023-03-21 19:28:26 +01:00
Matthias
36c45fd14f Remove unused argument from set_leverage 2023-03-21 19:14:09 +01:00
Matthias
97c420b2df Add explicit test for okx lev_prep 2023-03-20 19:27:48 +01:00
Matthias
7b5e322ef2 Merge pull request #8360 from freqtrade/okx_stop
Okx stoploss on exchange
2023-03-20 19:19:59 +01:00
Matthias
639987cbab Prevent parameter reuse 2023-03-20 18:19:17 +01:00
Matthias
56c2aa89bc Merge pull request #8344 from freqtrade/fix/db_concurrent
Fix db concurrent problem
2023-03-20 18:17:09 +01:00
Matthias
4f4bfdac4d Adjustments to okx stoploss 2023-03-20 09:00:00 +01:00
Matthias
8b6ea32c4c Merge pull request #8357 from freqtrade/dependabot/pip/develop/pytest-asyncio-0.21.0
Bump pytest-asyncio from 0.20.3 to 0.21.0
2023-03-20 08:59:19 +01:00
Matthias
ff497d5c90 Merge pull request #8356 from freqtrade/dependabot/pip/develop/fastapi-0.95.0
Bump fastapi from 0.94.0 to 0.95.0
2023-03-20 08:54:49 +01:00
Matthias
c05db6742c Merge pull request #8351 from freqtrade/dependabot/pip/develop/ccxt-3.0.23
Bump ccxt from 2.9.12 to 3.0.23
2023-03-20 08:52:12 +01:00
Matthias
75f75f3881 Merge pull request #8358 from freqtrade/dependabot/pip/develop/ast-comments-1.0.1
Bump ast-comments from 1.0.0 to 1.0.1
2023-03-20 08:51:56 +01:00
dependabot[bot]
a4e4310d40 Bump pytest-asyncio from 0.20.3 to 0.21.0
Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.20.3 to 0.21.0.
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.20.3...v0.21.0)

---
updated-dependencies:
- dependency-name: pytest-asyncio
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 07:11:18 +00:00
Matthias
dfc3524334 Merge pull request #8355 from freqtrade/dependabot/github_actions/develop/pypa/gh-action-pypi-publish-1.8.1
Bump pypa/gh-action-pypi-publish from 1.7.1 to 1.8.1
2023-03-20 08:10:17 +01:00
Matthias
a0913588b8 Merge pull request #8353 from freqtrade/dependabot/pip/develop/pre-commit-3.2.0
Bump pre-commit from 3.1.1 to 3.2.0
2023-03-20 08:10:04 +01:00
Matthias
c56b344077 Merge pull request #8354 from freqtrade/dependabot/pip/develop/ruff-0.0.257
Bump ruff from 0.0.255 to 0.0.257
2023-03-20 08:09:08 +01:00
dependabot[bot]
cb1f971d4b Bump ccxt from 2.9.12 to 3.0.23
Bumps [ccxt](https://github.com/ccxt/ccxt) from 2.9.12 to 3.0.23.
- [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/2.9.12...3.0.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 06:39:13 +00:00
Matthias
78e64be04e Merge pull request #8349 from freqtrade/dependabot/pip/develop/sqlalchemy-2.0.7
Bump sqlalchemy from 2.0.5.post1 to 2.0.7
2023-03-20 07:38:07 +01:00
dependabot[bot]
3175121030 Bump ast-comments from 1.0.0 to 1.0.1
Bumps [ast-comments](https://github.com/t3rn0/ast-comments) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/t3rn0/ast-comments/releases)
- [Commits](https://github.com/t3rn0/ast-comments/compare/1.0.0...1.0.1)

---
updated-dependencies:
- dependency-name: ast-comments
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 05:47:55 +00:00
dependabot[bot]
8d649988ca Bump fastapi from 0.94.0 to 0.95.0
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.94.0 to 0.95.0.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.94.0...0.95.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 05:47:47 +00:00
Matthias
ec7e7e744b Merge pull request #8352 from freqtrade/dependabot/pip/develop/uvicorn-0.21.1
Bump uvicorn from 0.21.0 to 0.21.1
2023-03-20 06:46:46 +01:00
Matthias
5c754eb4d3 Merge pull request #8350 from freqtrade/dependabot/pip/develop/mkdocs-material-9.1.3
Bump mkdocs-material from 9.1.2 to 9.1.3
2023-03-20 06:46:25 +01:00
Matthias
54d8aa7782 Test stoploss_adjust okx 2023-03-20 06:46:00 +01:00
Matthias
4690244673 Enable okx stop-price types 2023-03-20 06:40:57 +01:00
Matthias
2de5a59d89 Add test for dry-run fetching 2023-03-20 06:38:42 +01:00
Matthias
98685f1c98 Merge pull request #8348 from freqtrade/dependabot/pip/develop/python-rapidjson-1.10
Bump python-rapidjson from 1.9 to 1.10
2023-03-20 06:29:35 +01:00
Matthias
88e93b4902 Merge pull request #8346 from freqtrade/dependabot/pip/develop/nbconvert-7.2.10
Bump nbconvert from 7.2.9 to 7.2.10
2023-03-20 06:29:02 +01:00
Matthias
dcca51985d sqlalchemy - pre-commit 2023-03-20 06:27:39 +01:00
Matthias
21f2f67ffa Merge pull request #8347 from freqtrade/dependabot/pip/develop/filelock-3.10.0
Bump filelock from 3.9.0 to 3.10.0
2023-03-20 06:24:50 +01:00
dependabot[bot]
c78342b194 Bump pypa/gh-action-pypi-publish from 1.7.1 to 1.8.1
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.7.1 to 1.8.1.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.7.1...v1.8.1)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:58:15 +00:00
dependabot[bot]
29b9be9bd0 Bump ruff from 0.0.255 to 0.0.257
Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.255 to 0.0.257.
- [Release notes](https://github.com/charliermarsh/ruff/releases)
- [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md)
- [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.255...v0.0.257)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:57:47 +00:00
dependabot[bot]
4543a1fe02 Bump pre-commit from 3.1.1 to 3.2.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.1.1 to 3.2.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/v3.1.1...v3.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:57:33 +00:00
dependabot[bot]
fc7c8cce3c Bump uvicorn from 0.21.0 to 0.21.1
Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.21.0 to 0.21.1.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.21.0...0.21.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:57:28 +00:00
dependabot[bot]
7d1559f319 Bump mkdocs-material from 9.1.2 to 9.1.3
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.1.2 to 9.1.3.
- [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.1.2...9.1.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:57:13 +00:00
dependabot[bot]
a43502093d Bump sqlalchemy from 2.0.5.post1 to 2.0.7
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.5.post1 to 2.0.7.
- [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-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:57:07 +00:00
dependabot[bot]
47e84ad106 Bump python-rapidjson from 1.9 to 1.10
Bumps [python-rapidjson](https://github.com/python-rapidjson/python-rapidjson) from 1.9 to 1.10.
- [Release notes](https://github.com/python-rapidjson/python-rapidjson/releases)
- [Changelog](https://github.com/python-rapidjson/python-rapidjson/blob/master/CHANGES.rst)
- [Commits](https://github.com/python-rapidjson/python-rapidjson/compare/v1.9...v1.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:56:54 +00:00
dependabot[bot]
5ade5777e8 Bump filelock from 3.9.0 to 3.10.0
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.9.0 to 3.10.0.
- [Release notes](https://github.com/tox-dev/py-filelock/releases)
- [Changelog](https://github.com/tox-dev/py-filelock/blob/main/docs/changelog.rst)
- [Commits](https://github.com/tox-dev/py-filelock/compare/3.9.0...3.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:56:49 +00:00
dependabot[bot]
fb0e824a83 Bump nbconvert from 7.2.9 to 7.2.10
Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 7.2.9 to 7.2.10.
- [Release notes](https://github.com/jupyter/nbconvert/releases)
- [Changelog](https://github.com/jupyter/nbconvert/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jupyter/nbconvert/compare/v7.2.9...v7.2.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-20 03:56:45 +00:00
Matthias
a7c7f720c0 Add test for okx fetch_stop 2023-03-19 20:03:34 +01:00
Matthias
224f289ec8 OKX Stop: Add some more okx specific logic 2023-03-19 19:45:30 +01:00
Matthias
d84ece7258 Use conditional orders for stop orders 2023-03-19 19:44:35 +01:00
Matthias
6c5dc7e0a9 OKX: improve stop order handling 2023-03-19 19:44:35 +01:00
Matthias
df20757d21 OKX stop: implement proper stoploss fetching 2023-03-19 19:44:35 +01:00
Matthias
a2ce288241 Add okx stoploss on exchange (non-working for futures). 2023-03-19 19:44:35 +01:00
Matthias
ce3efa8f00 Remove pointless asserts 2023-03-19 18:05:08 +01:00
Matthias
c92f28bf6f ruff: Activate UP ruleset 2023-03-19 17:57:56 +01:00
Matthias
222ecdecd2 Improve code quality 2023-03-19 17:50:08 +01:00
Matthias
236499a195 Reorder push logic for ghcr 2023-03-19 15:47:42 +01:00
Matthias
3d91dd8a98 Support post-only orders for Binance spot
closes #8044
2023-03-19 15:36:35 +01:00
Matthias
9ccc3e52ec Simplify time in force code structure 2023-03-19 15:30:27 +01:00
Matthias
f5f151fcc5 Fix typing error 2023-03-19 15:06:56 +01:00
Matthias
7aa56adf15 Merge pull request #7951 from hippocritical/strategy_utils
strategy_updater
2023-03-19 14:28:36 +01:00
Matthias
bf3f2e4de4 Fix failing test 2023-03-19 11:16:54 +01:00
hippocritical
763f4f4a3e Merge branch 'freqtrade:develop' into strategy_utils 2023-03-18 20:15:12 +01:00
hippocritical
4925d8f580 Merge remote-tracking branch 'origin/strategy_utils' into strategy_utils 2023-03-18 20:07:34 +01:00
hippocritical
b1f88e8861 fixed typo from trades to trade 2023-03-18 20:02:55 +01:00
Matthias
62c8dd98d5 Use combination of thread-local and asyncio-aware session context 2023-03-18 19:28:22 +01:00
Matthias
b0a7b64d44 Close sessions after telegram calls 2023-03-18 19:28:22 +01:00
Matthias
d808dd49e8 Fix ruff violation 2023-03-18 19:28:13 +01:00
Matthias
818d2bf92a Fix stoploss on exchange value in /show_config call 2023-03-18 18:02:46 +01:00
Matthias
f98a12c26c Merge pull request #8343 from freqtrade/freqai/add_pair
Add pair output to "tossed" messages
2023-03-18 18:02:36 +01:00
Matthias
477dc50425 Add pair output to "tossed" messages 2023-03-18 16:32:07 +00:00
Robert Caulk
186fe5933b Merge pull request #8338 from freqtrade/freqai_exception
Fix exceptions when training fails
2023-03-18 12:56:25 +01:00
Matthias
8ab35bbaf3 Merge pull request #8340 from freqtrade/sqlalchemy2_queyr
remove Sqlalchemy .query usage
2023-03-18 08:10:56 +01:00
Matthias
9044052b4e Fix exceptions when training fails 2023-03-17 18:29:10 +01:00
hippocritical
209811d23a Merge branch 'freqtrade:develop' into strategy_utils 2023-03-17 08:48:52 +01:00
Matthias
764d5507a3 Fix typo in docker param 2023-03-17 07:05:13 +01:00
Matthias
628f6b8b7c Fix crane docker permissions 2023-03-17 07:05:13 +01:00
Matthias
0d3de07012 use Crane to move images around 2023-03-17 07:05:13 +01:00
Matthias
db0f449d93 Use docker manifest for GHCR builds 2023-03-17 07:05:13 +01:00
Matthias
774eacc561 Attempt push to ghcr.io 2023-03-17 07:05:13 +01:00
Matthias
e3e4fbd5ba Minor test fix 2023-03-16 19:24:37 +01:00
Matthias
b7709126f9 remove .query completely 2023-03-16 18:07:22 +01:00
Matthias
4cfbc55d34 Update remaining tests to get rid of .query 2023-03-16 18:07:06 +01:00
Robert Caulk
00054dcfde Merge pull request #8307 from initrv/tensorboard-category
Improve tensorboard_log
2023-03-16 11:10:29 +01:00
Matthias
9d6e973e5b remove .query from most tests 2023-03-16 07:25:04 +01:00
Matthias
6ed337faa3 Update several tests to remove .query 2023-03-16 07:04:15 +01:00
Matthias
e579ff9532 Simplify pairlock querying 2023-03-16 06:48:12 +01:00
Matthias
ae361e1d5d Update more .query usages 2023-03-16 06:44:53 +01:00
Matthias
8865af9104 Remove .query from pairlock 2023-03-15 21:21:00 +01:00
Matthias
aa54b77702 Rename _session to sessoin 2023-03-15 21:12:06 +01:00
Matthias
8073989c98 Remove more usages of .query 2023-03-15 21:10:47 +01:00
Matthias
d45599ca3b Fix some type errors 2023-03-15 21:09:25 +01:00
Matthias
b469addffb remove usage of .query from regular models 2023-03-15 21:00:30 +01:00
Matthias
47ab285252 Minor test fix 2023-03-15 20:49:35 +01:00
Matthias
95ff59a21c Improve documentation for get_trades_proxy 2023-03-15 07:23:54 +01:00
Matthias
7e08e3a59a Update example to use get_trades_proxy 2023-03-15 07:22:07 +01:00
Matthias
8f29312c9e Minimum re-entry stake should not include stoploss 2023-03-14 08:14:01 +01:00
Matthias
5c280d5649 Improve emergency_exit handling 2023-03-13 20:28:13 +01:00
Matthias
b23cea6e59 Bump ruff to 0.0.255 2023-03-13 20:16:12 +01:00
Matthias
487469680f Use correct exception type for ccxt.InvalidOrder 2023-03-13 20:13:12 +01:00
Matthias
8fd13933c3 Improve variable naming 2023-03-13 19:51:03 +01:00
Matthias
cf70deaf8d Disallow negative liquidation prices
part of #8300
2023-03-13 19:41:39 +01:00
Matthias
3d31eca365 Update Exception to contain more info
part of #8300
2023-03-13 19:40:52 +01:00
Matthias
d723979c42 Move total_trades to explicit variable 2023-03-13 19:21:53 +01:00
Matthias
1947fab3d7 Merge pull request #8315 from freqtrade/dependabot/pip/develop/uvicorn-0.21.0
Bump uvicorn from 0.20.0 to 0.21.0
2023-03-13 18:11:13 +01:00
Matthias
cdb97e64ab Merge pull request #8323 from freqtrade/dependabot/github_actions/develop/pypa/gh-action-pypi-publish-1.7.1
Bump pypa/gh-action-pypi-publish from 1.6.4 to 1.7.1
2023-03-13 18:10:04 +01:00
Matthias
daa59f6248 Merge pull request #8322 from freqtrade/dependabot/pip/develop/mkdocs-material-9.1.2
Bump mkdocs-material from 9.1.1 to 9.1.2
2023-03-13 18:08:08 +01:00
initrv
f3a1177bad bring inc back 2023-03-13 17:53:35 +03:00
dependabot[bot]
ad5afd3047 Bump uvicorn from 0.20.0 to 0.21.0
Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.20.0 to 0.21.0.
- [Release notes](https://github.com/encode/uvicorn/releases)
- [Changelog](https://github.com/encode/uvicorn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/encode/uvicorn/compare/0.20.0...0.21.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 08:08:57 +00:00
Matthias
458bfcc89b Merge pull request #8324 from freqtrade/dependabot/pip/develop/urllib3-1.26.15
Bump urllib3 from 1.26.14 to 1.26.15
2023-03-13 09:02:17 +01:00
Matthias
d4122c36ac Merge pull request #8317 from freqtrade/dependabot/pip/develop/fastapi-0.94.0
Bump fastapi from 0.92.0 to 0.94.0
2023-03-13 09:01:59 +01:00
Matthias
0e663a5bf8 Refresh binance cached leverage tiers 2023-03-13 07:06:59 +01:00
Matthias
562efd1841 Merge pull request #8320 from freqtrade/dependabot/pip/develop/pytest-7.2.2
Bump pytest from 7.2.1 to 7.2.2
2023-03-13 06:59:00 +01:00
Matthias
7baa2b9005 Merge pull request #8321 from freqtrade/dependabot/pip/develop/mypy-1.1.1
Bump mypy from 1.0.1 to 1.1.1
2023-03-13 06:58:32 +01:00
dependabot[bot]
10c5adfa50 Bump fastapi from 0.92.0 to 0.94.0
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.92.0 to 0.94.0.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.92.0...0.94.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 05:37:55 +00:00
Matthias
44c4729a9d Merge pull request #8319 from freqtrade/dependabot/pip/develop/pydantic-1.10.6
Bump pydantic from 1.10.5 to 1.10.6
2023-03-13 06:28:28 +01:00
dependabot[bot]
dc6af9a1a7 Bump urllib3 from 1.26.14 to 1.26.15
Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.14 to 1.26.15.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/1.26.14...1.26.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 03:57:54 +00:00
dependabot[bot]
82707be7d0 Bump pypa/gh-action-pypi-publish from 1.6.4 to 1.7.1
Bumps [pypa/gh-action-pypi-publish](https://github.com/pypa/gh-action-pypi-publish) from 1.6.4 to 1.7.1.
- [Release notes](https://github.com/pypa/gh-action-pypi-publish/releases)
- [Commits](https://github.com/pypa/gh-action-pypi-publish/compare/v1.6.4...v1.7.1)

---
updated-dependencies:
- dependency-name: pypa/gh-action-pypi-publish
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 03:57:48 +00:00
dependabot[bot]
b800f27092 Bump mkdocs-material from 9.1.1 to 9.1.2
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.1.1 to 9.1.2.
- [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.1.1...9.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 03:57:46 +00:00
dependabot[bot]
31daf72cc6 Bump mypy from 1.0.1 to 1.1.1
Bumps [mypy](https://github.com/python/mypy) from 1.0.1 to 1.1.1.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v1.0.1...v1.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 03:57:40 +00:00
dependabot[bot]
22ebf04daa Bump pytest from 7.2.1 to 7.2.2
Bumps [pytest](https://github.com/pytest-dev/pytest) from 7.2.1 to 7.2.2.
- [Release notes](https://github.com/pytest-dev/pytest/releases)
- [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest/compare/7.2.1...7.2.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 03:57:29 +00:00
dependabot[bot]
52a091e063 Bump pydantic from 1.10.5 to 1.10.6
Bumps [pydantic](https://github.com/pydantic/pydantic) from 1.10.5 to 1.10.6.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/v1.10.6/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v1.10.5...v1.10.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-13 03:57:23 +00:00
Matthias
fbca8e6587 Allow empty pairlock reasons through api
closes #8312
2023-03-12 21:31:08 +01:00
initrv
a10f78e3ef fix increment in case of 0 2023-03-12 23:29:27 +03:00
hippocritical
8987e5f108 Merge branch 'freqtrade:develop' into strategy_utils 2023-03-12 20:14:40 +01:00
Matthias
f584edf809 Improve tests by simply running a full strategy through everything 2023-03-12 16:45:56 +01:00
Matthias
f5848ea891 Add test for successful_buys 2023-03-12 16:29:18 +01:00
Matthias
b5c4f9ebe2 Split updater_tests to be clearer 2023-03-12 16:27:54 +01:00
Matthias
0911cd72a2 Add test for strategy-updater start method 2023-03-12 15:59:14 +01:00
Matthias
d2a412d2c6 Simplify start_strategy_update 2023-03-12 15:47:03 +01:00
Matthias
cb086f79ff Improve doc wording and command parameters 2023-03-12 15:46:44 +01:00
Matthias
d9bff68501 Merge pull request #8311 from froggleston/develop
Fix None limit on pair_candles RPC call
2023-03-12 15:25:30 +01:00
Matthias
5bfee44bba Whitespace fix 2023-03-12 15:24:27 +01:00
hippocritical
d186f8f1e1 Merge branch 'freqtrade:develop' into strategy_utils 2023-03-12 14:40:02 +01:00
froggleston
aa283a0447 Fix None limit on pair_candles RPC call 2023-03-12 12:44:12 +00:00
initrv
82cb107520 add tensorboard category 2023-03-12 01:32:55 +03:00
Matthias
b23841fbfe Bump ccxt to 2.9.12 2023-03-11 17:35:30 +01:00
Matthias
8726a4645d Don't use deprecated Type construct 2023-03-11 15:15:32 +01:00
Matthias
59d2ff3ffa Simplify handle_cancel_exit 2023-03-11 15:15:10 +01:00
Matthias
39c651e40c Remove pointless reset of close_profit 2023-03-11 15:15:02 +01:00
Matthias
a2336f256b Add profit descriptions
closes #8234
2023-03-11 08:25:45 +01:00
Matthias
a76ca771f8 telegram: Fix sending telegram message with exception 2023-03-10 18:09:05 +01:00
hippocritical
f722823b0d Merge remote-tracking branch 'origin/strategy_utils' into strategy_utils 2023-03-10 09:24:08 +01:00
hippocritical
a3988f56b2 Sorry matthias, did not see that you already committed something and did overwrite you.
Added your version to it instead of mine and pushed again (since it was already overwritten by me).
2023-03-10 09:23:56 +01:00
hippocritical
5a467eb969 Merge branch 'freqtrade:develop' into strategy_utils 2023-03-10 09:18:44 +01:00
hippocritical
5f8202e1b5 Merge remote-tracking branch 'origin/strategy_utils' into strategy_utils
# Conflicts:
#	freqtrade/commands/strategy_utils_commands.py
#	tests/test_strategy_updater.py
2023-03-10 09:00:00 +01:00
hippocritical
bfc7f48f17 added checks for python3.8 or lower since ast_comments.unparse() needs python 3.9 or higher.
testing with python 3.8 would make the build fail tests, skipping it there.
2023-03-10 08:59:07 +01:00
Matthias
5b2a291109 Merge pull request #8273 from freqtrade/stop_from_open_lev
Stop from open lev
2023-03-09 19:44:16 +01:00
Matthias
d3a3ddbc61 Check if exchang provides bid/ask via fetch_tickers - and fail with spread filter if it doesn't.
closes #8286
2023-03-09 19:42:43 +01:00
Matthias
30fd1e742e Add 3.8 block for strategyUpdater 2023-03-09 07:46:58 +00:00
Matthias
4d8e3c25bd Merge branch 'develop' into strategy_utils 2023-03-09 07:12:48 +00:00
Matthias
29dfb5c169 Merge pull request #8291 from freqtrade/allow-ohlc-removal
allow user to drop ohlc from features in RL
2023-03-08 21:04:34 +01:00
robcaulk
d10ee0979a ensure training_features_list is updated properly 2023-03-08 19:37:11 +01:00
Matthias
0318486bee Update stoploss_from_open documentation for leverage adjustment 2023-03-08 19:35:26 +01:00
Robert Caulk
85e345fc48 Update BaseReinforcementLearningModel.py 2023-03-08 19:29:39 +01:00
robcaulk
29d337fa02 ensure ohlc is dropped from both train and predict 2023-03-08 11:26:28 +01:00
Matthias
2c7ae756f5 Improve mock behavior 2023-03-08 07:05:59 +01:00
robcaulk
d9dc831772 allow user to drop ohlc from features in RL 2023-03-07 11:33:54 +01:00
Matthias
b710bdaf6c Merge pull request #8284 from freqtrade/dependabot/pip/develop/ccxt-2.9.4
Bump ccxt from 2.8.98 to 2.9.4
2023-03-06 10:49:10 +01:00
Matthias
27fa297209 Merge pull request #8282 from freqtrade/dependabot/pip/develop/types-python-dateutil-2.8.19.10
Bump types-python-dateutil from 2.8.19.9 to 2.8.19.10
2023-03-06 09:13:42 +01:00
dependabot[bot]
85e64cd121 Bump ccxt from 2.8.98 to 2.9.4
Bumps [ccxt](https://github.com/ccxt/ccxt) from 2.8.98 to 2.9.4.
- [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/2.8.98...2.9.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 07:21:23 +00:00
Matthias
0d876d7a89 Merge branch 'develop' into dependabot/pip/develop/types-python-dateutil-2.8.19.10 2023-03-06 08:20:59 +01:00
Matthias
69e5377f3d Merge pull request #8280 from freqtrade/dependabot/pip/develop/sqlalchemy-2.0.5.post1
Bump sqlalchemy from 2.0.4 to 2.0.5.post1
2023-03-06 08:20:17 +01:00
Matthias
532ecaf2c8 Merge pull request #8276 from freqtrade/dependabot/pip/develop/pymdown-extensions-9.10
Bump pymdown-extensions from 9.9.2 to 9.10
2023-03-06 08:07:20 +01:00
Matthias
d779d60812 Expose total_profit_ratio through API 2023-03-06 07:10:02 +01:00
Matthias
c4a80e33ea Fix missing newline in telegram /status 2023-03-06 07:01:25 +01:00
Matthias
cab1b750b3 Improve test accuracy 2023-03-06 06:39:05 +01:00
Matthias
9d285e3dc0 Add total_profit_ratio to telegram output
part of #8234
2023-03-06 06:39:05 +01:00
Matthias
fff08f737f /status msg - improve formatting further 2023-03-06 06:39:05 +01:00
Matthias
ca789b3282 /status - whitespace 2023-03-06 06:39:05 +01:00
Matthias
11eea9b4e1 Fix formatting for /status Realized profit 2023-03-06 06:39:05 +01:00
Matthias
de015a2d7e Improve telegram message formatting 2023-03-06 06:39:05 +01:00
Matthias
4cfc7e4427 Merge pull request #8275 from freqtrade/dependabot/pip/develop/ruff-0.0.254
Bump ruff from 0.0.253 to 0.0.254
2023-03-06 06:38:57 +01:00
Matthias
0a525c6d32 Merge pull request #8274 from freqtrade/dependabot/pip/develop/orjson-3.8.7
Bump orjson from 3.8.6 to 3.8.7
2023-03-06 06:37:43 +01:00
Matthias
ae8c426025 Merge pull request #8278 from freqtrade/dependabot/pip/develop/prompt-toolkit-3.0.38
Bump prompt-toolkit from 3.0.37 to 3.0.38
2023-03-06 06:37:21 +01:00
dependabot[bot]
0fe72510d5 Bump pymdown-extensions from 9.9.2 to 9.10
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 9.9.2 to 9.10.
- [Release notes](https://github.com/facelessuser/pymdown-extensions/releases)
- [Commits](https://github.com/facelessuser/pymdown-extensions/compare/9.9.2...9.10)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 05:36:16 +00:00
Matthias
fecb9db072 Merge pull request #8277 from freqtrade/dependabot/pip/develop/cryptography-39.0.2
Bump cryptography from 39.0.1 to 39.0.2
2023-03-06 06:36:16 +01:00
Matthias
30ac648539 Merge pull request #8279 from freqtrade/dependabot/pip/develop/mkdocs-material-9.1.1
Bump mkdocs-material from 9.0.15 to 9.1.1
2023-03-06 06:35:31 +01:00
Matthias
25fd4a04d6 Update sqlalchemy QueryPropertyDescriptor to match latest version 2023-03-06 06:34:37 +01:00
Matthias
9750e9ca4e pre-commit python-dateutil 2023-03-06 06:32:33 +01:00
dependabot[bot]
a57b033745 Bump types-python-dateutil from 2.8.19.9 to 2.8.19.10
Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.19.9 to 2.8.19.10.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 03:57:27 +00:00
dependabot[bot]
48e16f6aba Bump sqlalchemy from 2.0.4 to 2.0.5.post1
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 2.0.4 to 2.0.5.post1.
- [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-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 03:57:18 +00:00
dependabot[bot]
d1d9e25c2e Bump mkdocs-material from 9.0.15 to 9.1.1
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.0.15 to 9.1.1.
- [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.0.15...9.1.1)

---
updated-dependencies:
- dependency-name: mkdocs-material
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 03:57:03 +00:00
dependabot[bot]
57969f8b01 Bump prompt-toolkit from 3.0.37 to 3.0.38
Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.37 to 3.0.38.
- [Release notes](https://github.com/prompt-toolkit/python-prompt-toolkit/releases)
- [Changelog](https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/CHANGELOG)
- [Commits](https://github.com/prompt-toolkit/python-prompt-toolkit/compare/3.0.37...3.0.38)

---
updated-dependencies:
- dependency-name: prompt-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 03:56:58 +00:00
dependabot[bot]
8484427cf8 Bump cryptography from 39.0.1 to 39.0.2
Bumps [cryptography](https://github.com/pyca/cryptography) from 39.0.1 to 39.0.2.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/39.0.1...39.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 03:56:54 +00:00
dependabot[bot]
f4c17be8de Bump ruff from 0.0.253 to 0.0.254
Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.253 to 0.0.254.
- [Release notes](https://github.com/charliermarsh/ruff/releases)
- [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md)
- [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.253...v0.0.254)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 03:56:44 +00:00
dependabot[bot]
0bdd238d7f Bump orjson from 3.8.6 to 3.8.7
Bumps [orjson](https://github.com/ijl/orjson) from 3.8.6 to 3.8.7.
- [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.8.6...3.8.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-06 03:56:37 +00:00
hippocritical
1bb697e58c Merge remote-tracking branch 'origin/strategy_utils' into strategy_utils 2023-03-05 18:48:54 +01:00
hippocritical
b072fae507 added strategy-updater compartment inside utils.md 2023-03-05 18:48:32 +01:00
hippocritical
9fa6bfa655 Merge branch 'freqtrade:develop' into strategy_utils 2023-03-05 16:25:17 +01:00
hippocritical
da44b39423 Merge remote-tracking branch 'origin/strategy_utils' into strategy_utils 2023-03-05 16:20:46 +01:00
hippocritical
d0d6f53dec fixed github formatting errors 2023-03-05 16:19:26 +01:00
Matthias
d80760d20c bump ccxt to 2.8.98 2023-03-05 14:16:53 +01:00
hippocritical
5dd919b7ad Merge branch 'freqtrade:develop' into strategy_utils 2023-03-05 12:30:26 +01:00
Matthias
108a578772 Update tests to latest rpc changes 2023-03-04 20:17:19 +01:00
Matthias
9444bbb6f3 /maxentries should be in single tics. 2023-03-04 20:09:39 +01:00
Matthias
7c0c98a368 Properly format first entry value, too. 2023-03-04 20:08:20 +01:00
Matthias
c1d395a7d8 Revert "Bump ccxt to 2.8.88"
This reverts commit 51c15d894b.
2023-03-04 20:02:20 +01:00
Matthias
3f6795962f Update bybit orderbook test 2023-03-04 19:49:59 +01:00
Matthias
60e651b481 Updat bybit ohlcv data to v5 2023-03-04 19:49:37 +01:00
Matthias
548db18857 Improve wording on partial exit notifications 2023-03-04 19:27:55 +01:00
Matthias
aec11618ce Telegram improved formatting 2023-03-04 18:28:15 +01:00
Matthias
f0cbb4f949 Expose relative realized profit 2023-03-04 18:20:31 +01:00
Matthias
027e023443 Stop from open with leverage 2023-03-04 18:02:47 +01:00
Matthias
51c15d894b Bump ccxt to 2.8.88
closes #8270
2023-03-04 15:27:01 +01:00
Matthias
d0045673fa Add explicit test for stoploss_from_open 2023-03-03 20:32:33 +01:00
hippocritical
d92971cca1 Merge branch 'freqtrade:develop' into strategy_utils 2023-03-03 18:56:00 +01:00
hippocritical
87b7513401 fixed --strategy-list
moved ast comments to requirements.txt >=1.0.0 (since that is the first version that adds the comments unparsing)
2023-03-03 18:53:09 +01:00
Matthias
c03c3a5706 improve order REPR display 2023-03-03 18:12:41 +01:00
Matthias
9573974c47 Update deprecations document 2023-03-03 06:36:35 +01:00
Matthias
6e9ff5fdd8 Merge pull request #8202 from freqtrade/remove-populate-any-indicators
remove populate_any_indicators
2023-03-03 06:33:25 +01:00
Matthias
022f85095e Show Number of exits
part of #8234
2023-03-03 06:31:40 +01:00
Matthias
6a0848a3a9 Merge pull request #8267 from freqtrade/python_3.11
Python 3.11
2023-03-03 06:31:33 +01:00
Matthias
13376fdad8 Merge pull request #8220 from eSAMTrade/remove-redundant-dependencies
removed redundant dependencies from environment.yml
2023-03-03 06:25:22 +01:00
Matthias
5b0c143713 Update some comments about 3.11 2023-03-02 19:39:31 +01:00
Matthias
5d0e14b564 Don't mock full modules 2023-03-02 18:23:49 +01:00
Matthias
38050b5346 Simplify "model-run" conditions 2023-03-02 18:23:49 +01:00
Matthias
b1a5776f14 Skip reinforcement learning for python 3.11 2023-03-02 18:23:49 +01:00
Matthias
7a7f16b658 Skip catboost tests on py3.11 2023-03-02 18:23:49 +01:00
Matthias
684d310ea0 Limit catboost to python <3.11 2023-03-02 18:23:49 +01:00
Matthias
49bfa556bf Update CI to test against python 3.11 2023-03-02 18:23:49 +01:00
Matthias
e228733f1a Merge pull request #8264 from xmatthias/sqlalchemy_2
Sqlalchemy 2
2023-03-02 18:23:01 +01:00
Matthias
103bd9e2f2 keep Trade.session private 2023-03-02 07:26:50 +01:00
Matthias
ba38a826e9 Update missing mocks 2023-03-02 06:46:17 +01:00
Matthias
8103656ae1 Bump mypy in pre-commit 2023-03-02 06:36:03 +01:00
Matthias
b980f45b2b Fix test mypy errors 2023-03-02 06:23:01 +01:00
Matthias
b4b8dde4fb Add sqlalchemy to pre-commit dependencies 2023-03-01 20:41:49 +01:00
Matthias
59d57d3466 Improve test resiliance 2023-03-01 20:32:56 +01:00
Matthias
f0f72fdd33 Don't define "mapped" on LocalTrade class 2023-03-01 20:32:32 +01:00
Matthias
388dfec50b Remove last type error 2023-03-01 20:32:32 +01:00
Matthias
874413ccc5 Fix some style violations 2023-03-01 20:32:32 +01:00
Matthias
4a35d32b6a Improve trade stop types 2023-03-01 20:32:32 +01:00
Matthias
a1166b1077 allow null fee on calc_base_close 2023-03-01 20:32:32 +01:00
Matthias
e5c9cde36f Update trades_proxy typing 2023-03-01 20:32:32 +01:00
Matthias
b5f55c9b14 Improve type safety in backtesting 2023-03-01 20:32:32 +01:00
Matthias
7c09c01788 Add some more typehints 2023-03-01 20:32:32 +01:00
Matthias
0f914cf2bd Use Mapped for LocalTrade
this won't initialize sqlalchemy, as the base class is not inheriting from sqlalchemy.
2023-03-01 20:32:32 +01:00
Matthias
d175ab495b Move SessionType to base module 2023-03-01 20:32:32 +01:00
Matthias
f2f4158974 Bump sqlalchemy to 2.0.4 2023-03-01 20:32:32 +01:00
Matthias
764001a4c2 Don't reuse variable 2023-03-01 20:32:32 +01:00
Matthias
b65cff0adc Update "Query" type 2023-03-01 20:32:32 +01:00
Matthias
db4f4498dc Experimentally type query property ... 2023-03-01 20:32:32 +01:00
Matthias
c2c039151c Improve typesafety around trade object 2023-03-01 20:32:32 +01:00
Matthias
8765e3a4d6 Fix some Type issues 2023-03-01 20:32:32 +01:00
Matthias
f6b3998bbd Fix backtesting type incompatibilities 2023-03-01 20:32:32 +01:00
Matthias
0691bbaad9 Update some db types 2023-03-01 20:32:32 +01:00
Matthias
101d9ab87f Improvements - tests runnable again 2023-03-01 20:32:32 +01:00
Matthias
65a5cf64df Re-type session 2023-03-01 20:32:32 +01:00
Matthias
608a7c2d38 Add safe_close_rate 2023-03-01 20:32:31 +01:00
Matthias
e59eaf33e0 Update _session to session 2023-03-01 20:32:31 +01:00
Matthias
47b66f3220 More fun with types 2023-03-01 20:32:31 +01:00
Matthias
491f49388c "Mapped" for trade_model 2023-03-01 20:32:31 +01:00
Matthias
bb116456a9 Update Types for Order object 2023-03-01 20:32:31 +01:00
Matthias
13b1a3e737 Properly pairlock columns using mapped 2023-03-01 20:32:31 +01:00
Matthias
98791752a9 Update TradeModels to mapped_column 2023-03-01 20:32:31 +01:00
Matthias
0bd9b00132 Pairlock to mappedColumn 2023-03-01 20:32:31 +01:00
Matthias
39a658eac2 Update DeclarativeBase 2023-03-01 20:32:31 +01:00
Matthias
3c019e0e16 tentative augmented typing of Trade object 2023-03-01 20:32:31 +01:00
Matthias
41e27ba621 Enhance some type info 2023-03-01 20:32:31 +01:00
Matthias
3a9d83f86c Mypy: define sqlalchemy plugin 2023-03-01 20:32:31 +01:00
Matthias
9d455f58b1 Improve some trade model Types 2023-03-01 20:32:31 +01:00
Matthias
829e10ff87 Improve Type for models.py 2023-03-01 20:32:31 +01:00
Matthias
b62830031f Dummy-type query objects 2023-03-01 20:32:31 +01:00
Matthias
a553a9923a Update types for pairlock 2023-03-01 20:32:31 +01:00
dependabot[bot]
a629d455fb Bump sqlalchemy from 1.4.46 to 2.0.3
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.46 to 2.0.3.
- [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-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-01 20:32:31 +01:00
Matthias
feabed30a3 Update remaining exchange mock occurances 2023-03-01 20:27:15 +01:00
Matthias
2ca8b0b12e Update more exchange mocks to use EXMS 2023-03-01 20:27:15 +01:00
Matthias
bcdf4e0fe8 Use variable for exchange mocks to shorten lines 2023-03-01 20:27:15 +01:00
Matthias
78e5ec13bb Use absolute path for generic mocks 2023-03-01 20:27:15 +01:00
Matthias
8b51f5f563 Lowercase exchange ID 2023-03-01 20:27:15 +01:00
Matthias
756c284ecd Merge pull request #8225 from freqtrade/ruff2
Ruff - add PTH rule and subsequent changes
2023-03-01 20:27:06 +01:00
Matthias
d1b2e38ae9 if a stoploss order exists, always allow canceling that 2023-02-28 20:39:17 +01:00
Matthias
dd10dec73d Improve variable wording 2023-02-28 20:31:02 +01:00
Matthias
f822f1795a Reduce /status verbosity 2023-02-28 19:54:56 +01:00
Matthias
386915378b Improve /status message (show Total profit) 2023-02-28 19:54:47 +01:00
Matthias
2f1c5cf143 Remove pointless pylint rules 2023-02-28 18:22:17 +01:00
Matthias
3706d28125 use pytest.approx in favor of "prec_satoshi" ... 2023-02-28 18:20:37 +01:00
Matthias
0707e70183 Remove deprecated current_profit from api responses 2023-02-28 18:20:37 +01:00
Matthias
bebee15d10 Improve TradeSchema readability 2023-02-28 18:20:36 +01:00
Matthias
5660036f47 Merge pull request #8245 from eSAMTrade/bugfix-8244
Fix last_process related bug in RPC.health (BUG-#8231)
2023-02-28 18:18:53 +01:00
Matthias
262f03bc92 Add backtest warning for market_direction feature 2023-02-28 17:26:38 +01:00
Matthias
244fd0e731 Merge pull request #8184 from LangLazy/feature
Feature market direction
2023-02-28 17:22:31 +01:00
Matthias
fe6af0ef5d Merge pull request #8258 from freqtrade/dependabot/pip/develop/xgboost-1.7.4
Bump xgboost from 1.7.3 to 1.7.4
2023-02-28 12:06:17 +01:00
Matthias
fd63f50221 Merge pull request #8257 from freqtrade/dependabot/pip/develop/ccxt-2.8.54
Bump ccxt from 2.8.17 to 2.8.54
2023-02-28 12:05:42 +01:00
Matthias
5c13fbb0b8 Merge pull request #8256 from freqtrade/dependabot/pip/develop/types-cachetools-5.3.0.4
Bump types-cachetools from 5.3.0.0 to 5.3.0.4
2023-02-28 12:02:39 +01:00
Matthias
9a5b090894 pre-commit cachetools 2023-02-28 11:23:11 +01:00
dependabot[bot]
5a3f23f00c Bump types-cachetools from 5.3.0.0 to 5.3.0.4
Bumps [types-cachetools](https://github.com/python/typeshed) from 5.3.0.0 to 5.3.0.4.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 09:26:32 +00:00
Matthias
8b347dfdcf Merge pull request #8259 from freqtrade/dependabot/pip/develop/types-python-dateutil-2.8.19.9
Bump types-python-dateutil from 2.8.19.8 to 2.8.19.9
2023-02-28 10:25:35 +01:00
Matthias
deca5479f0 pre-commit dateutil-types 2023-02-28 10:05:38 +01:00
Matthias
2ea71d466c Merge pull request #8255 from freqtrade/dependabot/pip/develop/prompt-toolkit-3.0.37
Bump prompt-toolkit from 3.0.36 to 3.0.37
2023-02-28 09:53:24 +01:00
Matthias
200f5ac157 Merge pull request #8252 from freqtrade/dependabot/pip/develop/ruff-0.0.253
Bump ruff from 0.0.252 to 0.0.253
2023-02-28 09:53:06 +01:00
Matthias
9e77effacb Merge pull request #8253 from freqtrade/dependabot/pip/develop/pre-commit-3.1.1
Bump pre-commit from 3.1.0 to 3.1.1
2023-02-28 09:52:35 +01:00
Matthias
f5f883202d Merge pull request #8254 from freqtrade/dependabot/pip/develop/plotly-5.13.1
Bump plotly from 5.13.0 to 5.13.1
2023-02-28 09:52:02 +01:00
dependabot[bot]
594757d27d Bump types-python-dateutil from 2.8.19.8 to 2.8.19.9
Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.19.8 to 2.8.19.9.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 05:52:58 +00:00
dependabot[bot]
fed5d87cfd Bump xgboost from 1.7.3 to 1.7.4
Bumps [xgboost](https://github.com/dmlc/xgboost) from 1.7.3 to 1.7.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/v1.7.3...v1.7.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 05:52:55 +00:00
dependabot[bot]
adf5b7f233 Bump ccxt from 2.8.17 to 2.8.54
Bumps [ccxt](https://github.com/ccxt/ccxt) from 2.8.17 to 2.8.54.
- [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/2.8.17...2.8.54)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 05:52:48 +00:00
dependabot[bot]
1b4c831469 Bump prompt-toolkit from 3.0.36 to 3.0.37
Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.36 to 3.0.37.
- [Release notes](https://github.com/prompt-toolkit/python-prompt-toolkit/releases)
- [Changelog](https://github.com/prompt-toolkit/python-prompt-toolkit/blob/master/CHANGELOG)
- [Commits](https://github.com/prompt-toolkit/python-prompt-toolkit/compare/3.0.36...3.0.37)

---
updated-dependencies:
- dependency-name: prompt-toolkit
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 05:52:40 +00:00
dependabot[bot]
78e7ab92d8 Bump plotly from 5.13.0 to 5.13.1
Bumps [plotly](https://github.com/plotly/plotly.py) from 5.13.0 to 5.13.1.
- [Release notes](https://github.com/plotly/plotly.py/releases)
- [Changelog](https://github.com/plotly/plotly.py/blob/master/CHANGELOG.md)
- [Commits](https://github.com/plotly/plotly.py/compare/v5.13.0...v5.13.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 05:52:35 +00:00
dependabot[bot]
6e45e998ac Bump pre-commit from 3.1.0 to 3.1.1
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.1.0 to 3.1.1.
- [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/v3.1.0...v3.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 05:52:29 +00:00
dependabot[bot]
a75e9f193f Bump ruff from 0.0.252 to 0.0.253
Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.252 to 0.0.253.
- [Release notes](https://github.com/charliermarsh/ruff/releases)
- [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md)
- [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.252...v0.0.253)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-28 05:52:21 +00:00
Matthias
0899e5cb83 Improve documentation wording 2023-02-28 06:41:18 +01:00
Rahul
39331b59ed Fixed issues raised in PR 2023-02-27 22:51:22 +00:00
Matthias
65d1598a90 Show absolute profit in /status command 2023-02-27 21:17:02 +01:00
Matthias
46b987042b Include realized_profit in api output 2023-02-27 20:47:07 +01:00
Matthias
75d1dd2793 Properly round Stake currencies in telegram message 2023-02-27 20:47:07 +01:00
Matthias
e5c68661fe Simplify code line wrapping 2023-02-27 19:57:28 +01:00
Matthias
e482feed7d Further improve behavior for telegram /status with stop on exchange 2023-02-27 19:40:02 +01:00
Matthias
87fe4108a2 Fix order numeration to also work with stoploss on exchange 2023-02-27 18:24:19 +01:00
Matthias
02c831a4e7 Improve Note wording
closes #8235
2023-02-27 18:04:21 +01:00
ASU
bcd416c83d Removed unresolved FreqTrade typehint 2023-02-27 16:18:24 +02:00
ASU
1d5608d627 Fix last_process related bug in RPC.health 2023-02-27 12:14:38 +02:00
Matthias
79a14bcbe7 Merge pull request #8237 from freqtrade/dependabot/pip/develop/types-tabulate-0.9.0.1
Bump types-tabulate from 0.9.0.0 to 0.9.0.1
2023-02-27 10:44:54 +01:00
Matthias
81bc515e5d Bump tabulate types for pre-commit 2023-02-27 10:00:41 +01:00
dependabot[bot]
201522f1b1 Bump types-tabulate from 0.9.0.0 to 0.9.0.1
Bumps [types-tabulate](https://github.com/python/typeshed) from 0.9.0.0 to 0.9.0.1.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

---
updated-dependencies:
- dependency-name: types-tabulate
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 07:10:51 +00:00
Matthias
44b1005077 Merge pull request #8240 from freqtrade/dependabot/pip/develop/types-requests-2.28.11.15
Bump types-requests from 2.28.11.13 to 2.28.11.15
2023-02-27 08:02:57 +01:00
Matthias
48b21d00d2 bump pre-commit requests 2023-02-27 07:12:12 +01:00
dependabot[bot]
e83eefb71d Bump types-requests from 2.28.11.13 to 2.28.11.15
Bumps [types-requests](https://github.com/python/typeshed) from 2.28.11.13 to 2.28.11.15.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

---
updated-dependencies:
- dependency-name: types-requests
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 06:10:08 +00:00
Matthias
345a47ede7 Merge pull request #8238 from freqtrade/dependabot/pip/develop/types-python-dateutil-2.8.19.8
Bump types-python-dateutil from 2.8.19.6 to 2.8.19.8
2023-02-27 07:06:51 +01:00
Matthias
03d41bdf46 Merge pull request #8243 from freqtrade/dependabot/pip/develop/mkdocs-material-9.0.15
Bump mkdocs-material from 9.0.13 to 9.0.15
2023-02-27 06:32:31 +01:00
Matthias
05f3884722 bump pre-commit dateutil 2023-02-27 06:25:13 +01:00
Matthias
aaa0f49f31 Merge pull request #8241 from freqtrade/dependabot/pip/develop/ruff-0.0.252
Bump ruff from 0.0.251 to 0.0.252
2023-02-27 06:24:24 +01:00
Matthias
303c628998 Merge pull request #8239 from freqtrade/dependabot/pip/develop/pre-commit-3.1.0
Bump pre-commit from 3.0.4 to 3.1.0
2023-02-27 06:23:26 +01:00
Matthias
8cab2e85be Merge pull request #8236 from freqtrade/dependabot/pip/develop/pydantic-1.10.5
Bump pydantic from 1.10.4 to 1.10.5
2023-02-27 06:23:04 +01:00
dependabot[bot]
a4423778d5 Bump mkdocs-material from 9.0.13 to 9.0.15
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.0.13 to 9.0.15.
- [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.0.13...9.0.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 03:58:01 +00:00
dependabot[bot]
2a7f86bfb4 Bump ruff from 0.0.251 to 0.0.252
Bumps [ruff](https://github.com/charliermarsh/ruff) from 0.0.251 to 0.0.252.
- [Release notes](https://github.com/charliermarsh/ruff/releases)
- [Changelog](https://github.com/charliermarsh/ruff/blob/main/BREAKING_CHANGES.md)
- [Commits](https://github.com/charliermarsh/ruff/compare/v0.0.251...v0.0.252)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 03:57:22 +00:00
dependabot[bot]
7add902bc7 Bump pre-commit from 3.0.4 to 3.1.0
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 3.0.4 to 3.1.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/v3.0.4...v3.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 03:57:04 +00:00
dependabot[bot]
cc78054b8c Bump types-python-dateutil from 2.8.19.6 to 2.8.19.8
Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.19.6 to 2.8.19.8.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 03:56:57 +00:00
dependabot[bot]
533f97f080 Bump pydantic from 1.10.4 to 1.10.5
Bumps [pydantic](https://github.com/pydantic/pydantic) from 1.10.4 to 1.10.5.
- [Release notes](https://github.com/pydantic/pydantic/releases)
- [Changelog](https://github.com/pydantic/pydantic/blob/v1.10.5/HISTORY.md)
- [Commits](https://github.com/pydantic/pydantic/compare/v1.10.4...v1.10.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-27 03:56:50 +00:00
Matthias
5b0bc5bbc5 Don't "fix" dry-run kucoin orders
closes #8229
2023-02-26 16:17:41 +01:00
Matthias
6f7ab97fc3 Improve bybit test coverage 2023-02-26 16:17:41 +01:00
Matthias
27676f4aa2 Add explicit bybit test 2023-02-26 16:17:41 +01:00
Matthias
79dc972e5a Add explicit test for kucoin 2023-02-26 16:17:41 +01:00
Matthias
66c2e145cb Merge pull request #7975 from freqtrade/improve-freqai-gap-handling
handle data gaps between FreqAI and DP better
2023-02-26 15:26:46 +01:00
Matthias
d3d7cb1b14 Merge pull request #8216 from freqtrade/close-rl-env
Close training and eval environments in ReinforcementLearner_multiproc
2023-02-26 15:20:32 +01:00
Matthias
e88bb4e05c Revert small change - otherwise the data is never updated. 2023-02-26 15:09:25 +01:00
ASU
7e7ae144a9 Merge branch 'develop' into remove-redundant-dependencies 2023-02-26 04:29:30 +02:00
Matthias
305eda74e2 Enable Complexity for ruff 2023-02-25 20:50:26 +01:00
Matthias
84d905a648 Fix missed test 2023-02-25 17:39:18 +01:00
ASU
32ce819889 Removed environment.yml and updated documentation 2023-02-25 18:23:07 +02:00
Matthias
26315b6bc2 add PTH ruff selection 2023-02-25 17:17:05 +01:00
Matthias
d014e4590e use Path.open() instead of open 2023-02-25 17:15:54 +01:00
Matthias
c8a4a773ee Fix _pairs_last_refresh_time storing the wrong date
Depending on the drop_incomplete settings, this can lead to implicit bugs
2023-02-25 16:18:46 +01:00
Matthias
ff3aa7c1a9 Bump Version to 2023.3.dev 2023-02-25 16:18:33 +01:00
Matthias
84b8cee004 Merge branch 'stable' into develop 2023-02-25 16:18:25 +01:00
Matthias
6d9e50d60c Merge pull request #8209 from freqtrade/ruff
Ruff
2023-02-25 16:14:26 +01:00
Matthias
be352ae014 Update more enums 2023-02-25 15:49:45 +01:00
Matthias
563742f13c Fix enum behavior for python 3.11
closes #8221
closes #8217
2023-02-25 15:49:45 +01:00
Matthias
dc2cfee056 Don't request sorted candles from HitBTC.
Apparently hitBTC cannot properly handle this anymore.

closes #8214
2023-02-25 13:49:16 +01:00
Matthias
c6455c4131 Pin scikit-learn to <1.2.0 for conda as well
closes #8223
2023-02-25 13:39:48 +01:00
ASU
7bcae7b665 removed redundant dependencies from environment.yml 2023-02-25 00:26:20 +02:00
Matthias
3471f5204b Don't reuse variable 2023-02-24 14:34:41 +01:00
Matthias
521025037d Merge pull request #8203 from freqtrade/add-bufer-train-data-candles
Add buffer_train_data_candles feature
2023-02-24 13:25:18 +01:00
Matthias
ac2a2512ef Merge pull request #8210 from freqtrade/clean-data-drawer
Allow user to control number of historical model files
2023-02-24 13:19:38 +01:00
Robert Caulk
607d90ca5d Merge pull request #8215 from freqtrade/fix-freqai-index
fix link in freqai index.md
2023-02-24 12:38:56 +01:00
robcaulk
cb80d7c26f close the multi_proc env before creating new ones in an attempt to avoid increasing processes 2023-02-24 11:19:54 +01:00
robcaulk
c283e22325 fix purge_old_models description in parameter table 2023-02-24 10:54:43 +01:00
robcaulk
5ac4b81a5d fix link in freqai index.md 2023-02-24 10:50:39 +01:00
Matthias
34c42be74f Fix minor stylistic errors 2023-02-23 20:06:10 +01:00
Matthias
659140e190 Add bt-error to UI backtest method. 2023-02-23 20:06:10 +01:00
Matthias
63e5d33028 Better handle backtest errors 2023-02-23 20:06:10 +01:00
Matthias
2fed924a0d Merge pull request #8211 from TheJoeSchr/refactor-1
refactor(if-gate): use temp variable instead of if-gate
2023-02-23 18:14:21 +01:00
Joe Schr
7d906fd4c2 refactor(if-gate): use temp variable instead of if-gate 2023-02-23 10:58:43 +01:00
Matthias
6b829d839b Improve ruff config 2023-02-23 07:12:54 +01:00
Matthias
bf968a9fd8 Use actions as documented 2023-02-23 06:51:03 +01:00
Matthias
cdc96136bc Merge pull request #8207 from freqtrade/add-freqai-disclaimer
add imposter disclaimer to FreqAI front page
2023-02-23 06:49:18 +01:00
Matthias
23a71680de Update Doc-box typo 2023-02-23 06:29:58 +01:00
robcaulk
150b7f9c87 lighten the disclaimer message 2023-02-22 22:33:41 +01:00
robcaulk
b8f011a2ab give users ability to decide how many models to keep in dry/live 2023-02-22 22:27:56 +01:00
robcaulk
9633081c31 remove remnants of follower, clean data-drawer, improve doc 2023-02-22 22:01:41 +01:00
Matthias
b4ea37d598 Remove flake8 in favor of ruff 2023-02-22 21:08:17 +01:00
Matthias
549a0e1c44 Add ruff linting - initial configuration 2023-02-22 21:06:11 +01:00
Matthias
2bc9413be1 Fix minor stylistic errors 2023-02-22 20:58:24 +01:00
Matthias
e6766b9b82 Add bt-error to UI backtest method. 2023-02-22 20:22:59 +01:00
Matthias
75bc5809a9 Better handle backtest errors 2023-02-22 20:02:51 +01:00
Matthias
0f878daa98 Remove some too generic noqa statements 2023-02-22 19:56:32 +01:00
Matthias
01d51aa979 Add necesary noqa statements 2023-02-22 19:56:32 +01:00
Matthias
f8fa5bd969 Fix gone wrong noqa ... 2023-02-22 19:56:32 +01:00
Matthias
18bbfa10e5 Reduce amount of variables for API backtesting 2023-02-22 19:56:32 +01:00
Matthias
ff1258fd20 Better handle random UI backtest errors 2023-02-22 19:56:32 +01:00
Matthias
e56bf067c4 Merge pull request #8205 from amalysh/develop
* fixed filename in model_exists
2023-02-22 17:43:57 +01:00
robcaulk
3fbbc57a37 add imposter disclaimer to FreqAI front page 2023-02-22 17:08:30 +01:00
Alexander Malysh
070a7efd73 * fixed filename in model_exists 2023-02-22 14:52:20 +01:00
robcaulk
986bc63e54 raise OperationalException if latest historical data candle is older than earliest dataprovider candle 2023-02-21 21:23:58 +01:00
robcaulk
2b5c11c7b4 allow users to buffer train data with buffer_train_data_candles parameter 2023-02-21 21:08:34 +01:00
Matthias
62e120a602 Remove special treatment of cryptography for raspberries 2023-02-21 20:34:55 +01:00
Matthias
48ecc7f6dc Update freqai-reinforcement-learning docs
closes #8199
2023-02-21 19:55:32 +01:00
Matthias
43962476aa Remove non-working links, update links to https 2023-02-21 19:53:09 +01:00
Matthias
a4a3d27ac6 Improve FAQ page 2023-02-21 19:52:22 +01:00
Matthias
f4bd424226 Remove deprecated ubuntu image
Follows anouncement in https://github.blog/changelog/2022-08-09-github-actions-the-ubuntu-18-04-actions-runner-image-is-being-deprecated-and-will-be-removed-by-12-1-22/
2023-02-21 18:29:00 +01:00
Matthias
af137188f4 Update wrong FAQ entry 2023-02-21 18:05:20 +01:00
robcaulk
fd4e27d889 remove populate_any_indicators 2023-02-21 14:22:40 +01:00
Rahul Gudise
2261cbd92e fixed command regex and updated documentation 2023-02-20 16:22:17 -05:00
Rahul Gudise
3033e27466 Added documentation for new telegram command 2023-02-20 15:53:29 -05:00
Matthias
352f4962da Merge pull request #8198 from AchmadFathoni/develop
Fix outdated systemd related exception text.
2023-02-20 11:05:42 +01:00
Achmad Fathoni
789c867c8f Fix outdated systemd related exception text. 2023-02-20 16:30:23 +07:00
Matthias
4f794aae61 Merge pull request #8191 from freqtrade/dependabot/pip/develop/mkdocs-material-9.0.13
Bump mkdocs-material from 9.0.12 to 9.0.13
2023-02-20 08:06:53 +01:00
Matthias
bf6560e45b Merge pull request #8194 from freqtrade/dependabot/pip/develop/types-requests-2.28.11.13
Bump types-requests from 2.28.11.12 to 2.28.11.13
2023-02-20 08:06:37 +01:00
Matthias
ccf4fbed60 Merge pull request #8192 from freqtrade/dependabot/pip/develop/ccxt-2.8.17
Bump ccxt from 2.7.93 to 2.8.17
2023-02-20 07:11:49 +01:00
Matthias
250faf012d Bump types-requests for pre-commit 2023-02-20 06:55:58 +01:00
Matthias
3a9ffdf135 Merge pull request #8190 from freqtrade/dependabot/pip/develop/fastapi-0.92.0
Bump fastapi from 0.91.0 to 0.92.0
2023-02-20 06:55:17 +01:00
Matthias
ec1991d165 Merge pull request #8189 from freqtrade/dependabot/pip/develop/scipy-1.10.1
Bump scipy from 1.10.0 to 1.10.1
2023-02-20 06:54:16 +01:00
Matthias
4e1f5354fe Merge pull request #8196 from freqtrade/dependabot/pip/develop/mypy-1.0.1
Bump mypy from 1.0.0 to 1.0.1
2023-02-20 06:53:28 +01:00
dependabot[bot]
0cd28e2cab Bump mypy from 1.0.0 to 1.0.1
Bumps [mypy](https://github.com/python/mypy) from 1.0.0 to 1.0.1.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v1.0.0...v1.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-20 03:58:03 +00:00
dependabot[bot]
eb08ef6ced Bump types-requests from 2.28.11.12 to 2.28.11.13
Bumps [types-requests](https://github.com/python/typeshed) from 2.28.11.12 to 2.28.11.13.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

---
updated-dependencies:
- dependency-name: types-requests
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-20 03:57:41 +00:00
dependabot[bot]
a4e69574d3 Bump ccxt from 2.7.93 to 2.8.17
Bumps [ccxt](https://github.com/ccxt/ccxt) from 2.7.93 to 2.8.17.
- [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/2.7.93...2.8.17)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-20 03:57:17 +00:00
dependabot[bot]
c85fc6c8ca Bump mkdocs-material from 9.0.12 to 9.0.13
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.0.12 to 9.0.13.
- [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.0.12...9.0.13)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-20 03:57:10 +00:00
dependabot[bot]
f19128ad21 Bump fastapi from 0.91.0 to 0.92.0
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.91.0 to 0.92.0.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.91.0...0.92.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-20 03:56:55 +00:00
dependabot[bot]
2ef656fac0 Bump scipy from 1.10.0 to 1.10.1
Bumps [scipy](https://github.com/scipy/scipy) from 1.10.0 to 1.10.1.
- [Release notes](https://github.com/scipy/scipy/releases)
- [Commits](https://github.com/scipy/scipy/compare/v1.10.0...v1.10.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-20 03:56:50 +00:00
Matthias
e9c64c5839 Update dependency to cysystemd
closes #8187
2023-02-19 19:30:27 +01:00
Rahul
8927a92eaf fixed lint issue 2023-02-19 16:11:21 +00:00
Matthias
b0ec35d526 Merge pull request #7904 from freqtrade/feat/shuffle_after_split
add shuffle_after_split option
2023-02-19 15:03:04 +01:00
Rahul
5fb539190d addressed some issues mentioned in PR 2023-02-18 23:50:02 +00:00
Matthias
f89b63b0c5 Fix dry-run stoploss orders filling "in place" after restart. 2023-02-18 19:25:11 +01:00
Matthias
2c0fbd8500 Simplify test slightly 2023-02-18 18:07:35 +01:00
Rahul Gudise
ade64f25d3 fixed formatting 2023-02-17 17:08:39 -05:00
Rahul
72af1912ca added new text 2023-02-17 22:01:00 +00:00
hippocritical
08ca0f7c0f Merge branch 'freqtrade:develop' into strategy_utils 2023-02-17 21:07:23 +01:00
hippocritical
bcef00edee changed to ast_comments, added tests for comments. 2023-02-17 21:04:26 +01:00
hippocritical
06edc5c044 changed to ast_comments, added tests for comments. 2023-02-17 21:01:09 +01:00
Matthias
c4ec4db050 Merge pull request #8183 from th0rntwig/improve-freqai-docs
fix minor typos
2023-02-17 07:14:39 +01:00
Matthias
31c7b3e136 Update binance leverage tiers 2023-02-17 06:37:03 +01:00
Matthias
22700527ac Convert limit orders to market orders if they cross a threshold
closes #7786
2023-02-17 06:37:03 +01:00
Matthias
9600039686 Update dry-run fill method naming 2023-02-17 06:37:03 +01:00
Rahul
1a74ede126 Merge branch 'feature' of github.com:LangLazy/freqtrade into feature 2023-02-16 17:54:20 -05:00
Rahul Gudise
07c886a2b1 Merge branch 'freqtrade:develop' into feature 2023-02-16 17:54:14 -05:00
Rahul
b73089deb8 fixed a test 2023-02-16 17:51:50 -05:00
thorntwig
35fe37199d fix minor typos 2023-02-16 20:04:42 +01:00
robcaulk
351c5fbf7f add shuffle_after_split to conftest 2023-02-16 19:48:22 +01:00
Robert Caulk
f68543b151 Merge pull request #8182 from freqtrade/generalize-model-exists
generalize model_exists() for RL and Keras
2023-02-16 19:41:07 +01:00
robcaulk
be85ef2707 add documentation for shuffle_after_split, add to constants 2023-02-16 18:50:11 +01:00
robcaulk
b6a741b421 merge develop into feat/shuffle_after_split 2023-02-16 18:46:01 +01:00
robcaulk
36d65e00f9 generalize model_exists() for RL and Keras 2023-02-16 18:33:40 +01:00
Matthias
a2e1389943 Update Binance leverage code 2023-02-16 18:06:34 +01:00
Matthias
8ef110cc5f Rename ob variable to orderbook 2023-02-16 06:38:58 +01:00
Matthias
de7d274fcf Pass orderbook to dry-run fill logic 2023-02-16 06:38:58 +01:00
Matthias
7c10921564 Improve Orderbook typing to align for diff. exchanges 2023-02-16 06:38:58 +01:00
Matthias
a11f081d2d Merge pull request #8176 from freqtrade/robcaulk-patch-1
Update freqai.md
2023-02-16 06:14:56 +01:00
Robert Caulk
020c9a5cec Update freqai.md 2023-02-15 21:54:45 +01:00
Matthias
ecff21ac21 type Orderbook 2023-02-15 07:01:36 +01:00
Matthias
3397e47ccf Rename stoploss() to create_stoploss() 2023-02-14 20:42:08 +01:00
Matthias
6e55a873b3 Rename edge.stoploss to get_stoploss
this will make it clear that it's different from
2023-02-14 07:18:11 +01:00
Matthias
bddec476f9 Fix missing typehint in hyper.py 2023-02-13 20:13:26 +01:00
Matthias
cdd324d0a9 Rename stoploss_reached to ft_stoploss_reached 2023-02-13 20:08:54 +01:00
Matthias
ce7d24f529 Extract ft_stoploss_adjust to seperate method 2023-02-13 19:53:04 +01:00
Matthias
a0e2f98086 Merge pull request #8164 from freqtrade/dependabot/pip/develop/tensorboard-2.12.0
Bump tensorboard from 2.11.2 to 2.12.0
2023-02-13 19:34:14 +01:00
Matthias
69d5459460 Improve stop behavior in SIGTERM cases (docker). 2023-02-13 18:25:15 +01:00
Matthias
aafaff877b Merge pull request #8170 from freqtrade/dependabot/pip/develop/ccxt-2.7.93
Bump ccxt from 2.7.80 to 2.7.93
2023-02-13 18:17:29 +01:00
dependabot[bot]
9061c04f1d Bump ccxt from 2.7.80 to 2.7.93
Bumps [ccxt](https://github.com/ccxt/ccxt) from 2.7.80 to 2.7.93.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg)
- [Commits](https://github.com/ccxt/ccxt/compare/2.7.80...2.7.93)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 16:09:57 +00:00
Matthias
9a2f6d2416 Merge pull request #8165 from freqtrade/dependabot/pip/develop/aiofiles-23.1.0
Bump aiofiles from 22.1.0 to 23.1.0
2023-02-13 09:50:11 +01:00
Matthias
b5121d3f4c Merge pull request #8166 from freqtrade/dependabot/pip/develop/aiohttp-3.8.4
Bump aiohttp from 3.8.3 to 3.8.4
2023-02-13 09:49:56 +01:00
Matthias
f3a6897870 Bump Docker images to latest minor version 2023-02-13 07:12:46 +01:00
Matthias
f16fd0ad23 Reenable binanceus active test 2023-02-13 07:12:46 +01:00
dependabot[bot]
f681ee7942 Bump aiohttp from 3.8.3 to 3.8.4
Bumps [aiohttp](https://github.com/aio-libs/aiohttp) from 3.8.3 to 3.8.4.
- [Release notes](https://github.com/aio-libs/aiohttp/releases)
- [Changelog](https://github.com/aio-libs/aiohttp/blob/master/CHANGES.rst)
- [Commits](https://github.com/aio-libs/aiohttp/compare/v3.8.3...v3.8.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 06:11:49 +00:00
dependabot[bot]
50a9df9b29 Bump aiofiles from 22.1.0 to 23.1.0
Bumps [aiofiles](https://github.com/Tinche/aiofiles) from 22.1.0 to 23.1.0.
- [Release notes](https://github.com/Tinche/aiofiles/releases)
- [Commits](https://github.com/Tinche/aiofiles/compare/v22.1.0...v23.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 06:11:37 +00:00
dependabot[bot]
2a87ad044d Bump tensorboard from 2.11.2 to 2.12.0
Bumps [tensorboard](https://github.com/tensorflow/tensorboard) from 2.11.2 to 2.12.0.
- [Release notes](https://github.com/tensorflow/tensorboard/releases)
- [Changelog](https://github.com/tensorflow/tensorboard/blob/master/RELEASE.md)
- [Commits](https://github.com/tensorflow/tensorboard/compare/2.11.2...2.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 06:11:33 +00:00
Matthias
a573976406 Merge pull request #8158 from freqtrade/dependabot/pip/develop/types-requests-2.28.11.12
Bump types-requests from 2.28.11.8 to 2.28.11.12
2023-02-13 07:09:58 +01:00
Matthias
0b5b8e4c97 Merge pull request #8163 from freqtrade/dependabot/pip/develop/fastapi-0.91.0
Bump fastapi from 0.89.1 to 0.91.0
2023-02-13 07:09:44 +01:00
Matthias
ee158c1f55 Merge pull request #8162 from freqtrade/dependabot/pip/develop/mypy-1.0.0
Bump mypy from 0.991 to 1.0.0
2023-02-13 07:08:53 +01:00
Matthias
bf242ac4a2 Merge pull request #8156 from freqtrade/dependabot/pip/develop/mkdocs-material-9.0.12
Bump mkdocs-material from 9.0.11 to 9.0.12
2023-02-13 06:39:34 +01:00
Matthias
a800c19c14 Merge pull request #8157 from freqtrade/dependabot/pip/develop/orjson-3.8.6
Bump orjson from 3.8.5 to 3.8.6
2023-02-13 06:37:39 +01:00
Matthias
d14283b0e7 types-requests - precommit 2023-02-13 06:22:13 +01:00
dependabot[bot]
9faa926803 Bump fastapi from 0.89.1 to 0.91.0
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.89.1 to 0.91.0.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.89.1...0.91.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 03:58:55 +00:00
dependabot[bot]
48c331785c Bump mypy from 0.991 to 1.0.0
Bumps [mypy](https://github.com/python/mypy) from 0.991 to 1.0.0.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v0.991...v1.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 03:58:34 +00:00
dependabot[bot]
bbb62c8a4b Bump types-requests from 2.28.11.8 to 2.28.11.12
Bumps [types-requests](https://github.com/python/typeshed) from 2.28.11.8 to 2.28.11.12.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

---
updated-dependencies:
- dependency-name: types-requests
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 03:57:16 +00:00
dependabot[bot]
b05999f6d5 Bump orjson from 3.8.5 to 3.8.6
Bumps [orjson](https://github.com/ijl/orjson) from 3.8.5 to 3.8.6.
- [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.8.5...3.8.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 03:57:11 +00:00
dependabot[bot]
ee209e3b44 Bump mkdocs-material from 9.0.11 to 9.0.12
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.0.11 to 9.0.12.
- [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.0.11...9.0.12)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-13 03:56:56 +00:00
hippocritical
69a63975c1 Merge branch 'freqtrade:develop' into strategy_utils 2023-02-12 20:11:15 +01:00
Rahul
a3cc001f1b initial commit 2023-02-11 18:31:25 -05:00
Matthias
b3fbb263ce Merge pull request #8152 from Shadyzpop/patch-1
Typo on freqai docs
2023-02-11 20:22:16 +01:00
Shadyzpop
b95ff827d3 Typo on freqai docs
1. `a the` - there is an extra "a" before `the features`
2. `historic` - it should be "historical" to match the correct adjective form.
2023-02-11 17:12:57 +03:00
Matthias
a3b4678ad6 stoploss_price_type for gate 2023-02-11 13:02:55 +01:00
Matthias
a2759b495b Merge pull request #8149 from freqtrade/gate_rename
Update gateio terminology to Gate
2023-02-11 12:40:58 +01:00
Matthias
bedd3688d0 Properly format proxy configuration 2023-02-11 12:37:40 +01:00
Matthias
c229ba97a9 Update gateio terminology to Gate 2023-02-11 08:15:11 +01:00
Matthias
07e6932a17 Reenable longrun test mark 2023-02-11 08:14:55 +01:00
Matthias
0713fc6a6a Merge pull request #8148 from stash86/bt-metrics
Add explicit warning that supported price types gonna differ
2023-02-11 08:14:23 +01:00
Stefano Ariestasia
73992dde8d Add explicit warning that supported price types gonna differ on each exchanges 2023-02-11 11:15:31 +09:00
Matthias
42c76d9e0c Merge pull request #8147 from freqtrade/add-pair-to-env
Add pair to environment for access inside calculate_reward
2023-02-10 19:38:10 +01:00
Matthias
45e24d21d3 Bump ccxt to 2.7.78
closes #8141
2023-02-10 19:35:45 +01:00
Matthias
f440d66210 Add sample_order for gate 2023-02-10 18:12:21 +01:00
robcaulk
8873a565ee expose raw features to the environment for use in calculate_reward 2023-02-10 15:48:18 +01:00
robcaulk
154b6711b3 use function level noqa ignore 2023-02-10 15:26:17 +01:00
robcaulk
4fc0edb8b7 add pair to environment for access inside calculate_reward 2023-02-10 14:45:50 +01:00
Matthias
d47d8c135b Add windows wheel for ta-lib on python 3.11 2023-02-10 07:17:12 +01:00
Matthias
22cbc16238 Merge pull request #8120 from freqtrade/fut/stop_price_type
stoploss price type
2023-02-10 07:02:25 +01:00
Matthias
eab724fe54 Merge branch 'develop' into fut/stop_price_type 2023-02-09 20:02:59 +01:00
Matthias
8d156b2770 Bump ccxt to 2.7.66
closes  #8132
2023-02-08 20:35:24 +01:00
Matthias
3d22ad36b8 Show Config should contain stoploss-on-exchange status 2023-02-08 07:08:42 +01:00
Matthias
102c1e799c realign binance set_leverage override 2023-02-08 07:08:42 +01:00
Matthias
980ffa6bfb Add test for binance rounding leverage 2023-02-08 07:08:42 +01:00
Matthias
997df2032e Add response_log for set_leverage 2023-02-08 07:08:42 +01:00
Matthias
d19ee9c95f Update okx position mode terminology 2023-02-08 07:08:42 +01:00
Matthias
e2d81b0ce0 Skip binanceus ccxt test 2023-02-08 07:08:42 +01:00
Matthias
c15e10fe1f Improve logic for initially placed stoploss 2023-02-08 07:08:42 +01:00
Matthias
2b0e281113 Merge pull request #8136 from freqtrade/dependabot/pip/cryptography-39.0.1
Bump cryptography from 38.0.1 to 39.0.1
2023-02-08 06:33:49 +01:00
dependabot[bot]
67a2cd7086 Bump cryptography from 38.0.1 to 39.0.1
Bumps [cryptography](https://github.com/pyca/cryptography) from 38.0.1 to 39.0.1.
- [Release notes](https://github.com/pyca/cryptography/releases)
- [Changelog](https://github.com/pyca/cryptography/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/pyca/cryptography/compare/38.0.1...39.0.1)

---
updated-dependencies:
- dependency-name: cryptography
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-08 04:07:21 +00:00
Matthias
5a61e076d7 Remove unused import 2023-02-07 19:19:59 +01:00
Matthias
953be8a7f8 Split validate_order_types to 2 functions to allow selective application 2023-02-07 18:00:44 +01:00
Matthias
8c0c2496c2 Temporarily disable gate advanced stop orders 2023-02-07 07:13:57 +01:00
Matthias
e8dc3dd59a Merge pull request #8126 from freqtrade/dependabot/pip/develop/types-cachetools-5.3.0.0
Bump types-cachetools from 5.2.1 to 5.3.0.0
2023-02-07 06:21:03 +01:00
Matthias
81619fb4a0 Properly use sqlalchemy column types 2023-02-06 19:51:51 +01:00
Matthias
82dad7ab17 Merge pull request #8086 from freqtrade/feat/cancel_order
Cancel open orders through UI/telegram
2023-02-06 19:43:21 +01:00
Matthias
a6adcb485e Bump several pre-commit hooks versions 2023-02-06 19:34:30 +01:00
Matthias
be335c401d Merge pull request #8125 from freqtrade/dependabot/pip/develop/ccxt-2.7.45
Bump ccxt from 2.7.12 to 2.7.45
2023-02-06 19:24:23 +01:00
Matthias
b6eb1f9395 Bump pre-commit 2023-02-06 07:09:59 +01:00
Matthias
7f5a624cfd Merge pull request #8127 from freqtrade/dependabot/pip/develop/numpy-1.24.2
Bump numpy from 1.24.1 to 1.24.2
2023-02-06 07:08:27 +01:00
Matthias
b215329456 Merge pull request #8128 from freqtrade/dependabot/pip/develop/pymdown-extensions-9.9.2
Bump pymdown-extensions from 9.9.1 to 9.9.2
2023-02-06 07:07:47 +01:00
dependabot[bot]
c6601cbd89 Bump pymdown-extensions from 9.9.1 to 9.9.2
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 9.9.1 to 9.9.2.
- [Release notes](https://github.com/facelessuser/pymdown-extensions/releases)
- [Commits](https://github.com/facelessuser/pymdown-extensions/compare/9.9.1...9.9.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 03:01:25 +00:00
dependabot[bot]
f96cb47727 Bump numpy from 1.24.1 to 1.24.2
Bumps [numpy](https://github.com/numpy/numpy) from 1.24.1 to 1.24.2.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst)
- [Commits](https://github.com/numpy/numpy/compare/v1.24.1...v1.24.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 03:01:17 +00:00
dependabot[bot]
365522f5c8 Bump types-cachetools from 5.2.1 to 5.3.0.0
Bumps [types-cachetools](https://github.com/python/typeshed) from 5.2.1 to 5.3.0.0.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

---
updated-dependencies:
- dependency-name: types-cachetools
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 03:00:52 +00:00
dependabot[bot]
8dde7ab6b8 Bump ccxt from 2.7.12 to 2.7.45
Bumps [ccxt](https://github.com/ccxt/ccxt) from 2.7.12 to 2.7.45.
- [Release notes](https://github.com/ccxt/ccxt/releases)
- [Changelog](https://github.com/ccxt/ccxt/blob/master/exchanges.cfg)
- [Commits](https://github.com/ccxt/ccxt/compare/2.7.12...2.7.45)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-06 03:00:49 +00:00
Matthias
e964377edf Add new field to full config 2023-02-05 14:58:12 +01:00
Matthias
d904e91663 Add documentation for new setting 2023-02-05 14:55:11 +01:00
Matthias
61ba1a0dc7 Pin telegram in conda environment to <20
closes #8111
2023-02-05 14:39:20 +01:00
Matthias
48d78d8df9 Merge pull request #8116 from freqtrade/dependabot/pip/develop/technical-1.4.0
Bump technical from 1.3.0 to 1.4.0
2023-02-05 13:16:23 +01:00
Matthias
797993d0b7 Merge pull request #8118 from freqtrade/dependabot/pip/develop/isort-5.12.0
Bump isort from 5.11.4 to 5.12.0
2023-02-05 13:15:37 +01:00
Matthias
79d279b99b Merge pull request #8114 from freqtrade/dependabot/pip/develop/plotly-5.13.0
Bump plotly from 5.11.0 to 5.13.0
2023-02-05 12:43:46 +01:00
Matthias
a577d6ab36 Merge pull request #8112 from freqtrade/dependabot/pip/develop/mkdocs-material-9.0.11
Bump mkdocs-material from 9.0.8 to 9.0.11
2023-02-05 12:42:58 +01:00
Matthias
389e576b3e Merge pull request #8113 from freqtrade/dependabot/pip/develop/nbconvert-7.2.9
Bump nbconvert from 7.2.8 to 7.2.9
2023-02-05 12:42:17 +01:00
Matthias
47f47a33e3 Merge pull request #8115 from freqtrade/dependabot/pip/develop/pre-commit-3.0.4
Bump pre-commit from 2.21.0 to 3.0.4
2023-02-05 12:41:47 +01:00
Matthias
b8a527e4a0 Add gateio price type field 2023-02-05 10:46:24 +01:00
Matthias
3497de3dd5 Add more validation 2023-02-05 10:38:58 +01:00
Matthias
cf9e99b8e1 Add tests for ordertype validation 2023-02-05 10:38:58 +01:00
Matthias
2738c37845 Test stoploss validation ... 2023-02-05 10:38:58 +01:00
Matthias
c4fc811619 Add stop_price_type support (futures only!). 2023-02-05 10:38:58 +01:00
Matthias
a9241f61f9 Add Price Type Enum 2023-02-05 10:38:58 +01:00
dependabot[bot]
e38e41ab97 Bump isort from 5.11.4 to 5.12.0
Bumps [isort](https://github.com/pycqa/isort) from 5.11.4 to 5.12.0.
- [Release notes](https://github.com/pycqa/isort/releases)
- [Changelog](https://github.com/PyCQA/isort/blob/main/CHANGELOG.md)
- [Commits](https://github.com/pycqa/isort/compare/5.11.4...5.12.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-05 09:20:10 +00:00
dependabot[bot]
e3f0e66b9a Bump technical from 1.3.0 to 1.4.0
Bumps [technical](https://github.com/freqtrade/technical) from 1.3.0 to 1.4.0.
- [Release notes](https://github.com/freqtrade/technical/releases)
- [Commits](https://github.com/freqtrade/technical/compare/1.3.0...1.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-05 09:19:44 +00:00
dependabot[bot]
b80d196d56 Bump pre-commit from 2.21.0 to 3.0.4
Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 2.21.0 to 3.0.4.
- [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/v2.21.0...v3.0.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-05 09:19:39 +00:00
dependabot[bot]
c61995aad9 Bump plotly from 5.11.0 to 5.13.0
Bumps [plotly](https://github.com/plotly/plotly.py) from 5.11.0 to 5.13.0.
- [Release notes](https://github.com/plotly/plotly.py/releases)
- [Changelog](https://github.com/plotly/plotly.py/blob/master/CHANGELOG.md)
- [Commits](https://github.com/plotly/plotly.py/compare/v5.11.0...v5.13.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-05 09:19:31 +00:00
dependabot[bot]
34711eb683 Bump nbconvert from 7.2.8 to 7.2.9
Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 7.2.8 to 7.2.9.
- [Release notes](https://github.com/jupyter/nbconvert/releases)
- [Changelog](https://github.com/jupyter/nbconvert/blob/main/CHANGELOG.md)
- [Commits](https://github.com/jupyter/nbconvert/compare/v7.2.8...v7.2.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-05 09:19:25 +00:00
dependabot[bot]
5ed06cd79b Bump mkdocs-material from 9.0.8 to 9.0.11
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.0.8 to 9.0.11.
- [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.0.8...9.0.11)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-05 09:19:18 +00:00
Matthias
a7fec1f871 Merge pull request #8109 from freqtrade/add-metadata-to-feature-engineering
Pass metadata dictionary to feature_engineering_* and set_freqai_targets()
2023-02-05 09:56:21 +01:00
Matthias
801714a588 Update function signatures in all templates
add typehints to help the user's editor suggest the right things.
2023-02-04 20:04:16 +01:00
robcaulk
0dd2472385 add metadata param to docstrings 2023-02-04 16:56:36 +01:00
robcaulk
e569f6f6df add explicit metadata argument to example strat, include it with backtesting 2023-02-04 16:53:17 +01:00
robcaulk
5da60b718d pass metadata dictionary to feature_engineering_* and set_freqai_targets functions. Add doc 2023-02-04 13:47:11 +01:00
Matthias
55850a5ccd Skip orders when correlated trade was deleted.
closes #8107
2023-02-04 08:39:25 +01:00
Matthias
7991124794 Merge pull request #8102 from TheJoeSchr/develop
setup.sh: checks if git directory is dirty before bothering user with…
2023-02-03 16:56:52 +01:00
Joe Schr
02c0f91f4d fix: removes duplicated if branch 2023-02-03 16:16:30 +01:00
Joe Schr
3fd6d72984 setup.sh: fix truty/falsy return of check_git_changes() 2023-02-03 08:52:26 +01:00
Matthias
3c4ff2e037 Merge pull request #8095 from freqtrade/remove-follow-mode
remove follow mode in favor of producer consumer
2023-02-03 07:02:56 +01:00
Matthias
ef1738fbf6 Remove follow_mode from docs 2023-02-02 19:30:59 +01:00
Matthias
618eb951d3 Add ft_bot_start to notebook docs
part of #8066
2023-02-02 19:26:48 +01:00
Joe Schr
330461cf1e setup.sh: checks if git directory is dirty before bothering user with potentially scary question 2023-02-02 17:00:07 +01:00
Matthias
e95eb220c5 Merge pull request #8101 from obseries/develop
[kucoin] manage kucoin numeric password passed as environment variabl…
2023-02-02 16:58:29 +01:00
Matthias
c093934c24 Merge pull request #8099 from raphaelstar/raphaelstar-patch-2
`order.amount` -> `order.safe_amount`
2023-02-02 16:28:04 +01:00
Luca Forni
b7787a9846 [kucoin] manage kucoin numeric password passed as environment variable as a string 2023-02-02 16:15:23 +01:00
raphaelstar
b4c3e1fd58 order.amount -> order.safe_amount 2023-02-02 15:52:27 +01:00
Matthias
300e9acd37 Merge pull request #8096 from raphaelstar/raphaelstar-patch-1
Make test for `None` explicit
2023-02-02 14:53:46 +01:00
raphaelstar
36f95fb35d Make test for None explicit
Make test for `None` explicit
2023-02-02 13:29:37 +01:00
robcaulk
ccb4efbe88 remove follow mode in favor of producer consumer 2023-02-02 11:40:23 +01:00
Matthias
1d6738778b Merge pull request #8088 from Ezrahel/patch-1
Update README.md
2023-02-02 10:22:09 +01:00
Ezrahel
ba7883f549 Update README.md 2023-02-02 03:02:52 +01:00
Matthias
ceaaac6c3a Improve install sequence to install ta-lib after user interactivity 2023-02-01 18:36:48 +00:00
Matthias
21618594b2 Update setup.sh queries to not ask redundant questions 2023-02-01 17:16:11 +00:00
Matthias
8c9de445e7 Merge pull request #8089 from freqtrade/dependabot/pip/setuptools-65.5.1
Bump setuptools from 65.5.0 to 65.5.1
2023-02-01 12:32:43 +01:00
Matthias
d8583ab6e6 Bump setuptools in setup.sh 2023-02-01 11:06:30 +00:00
dependabot[bot]
7569e72f55 Bump setuptools from 65.5.0 to 65.5.1
Bumps [setuptools](https://github.com/pypa/setuptools) from 65.5.0 to 65.5.1.
- [Release notes](https://github.com/pypa/setuptools/releases)
- [Changelog](https://github.com/pypa/setuptools/blob/main/CHANGES.rst)
- [Commits](https://github.com/pypa/setuptools/compare/v65.5.0...v65.5.1)

---
updated-dependencies:
- dependency-name: setuptools
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-02-01 10:11:12 +00:00
Ezrahel
1e12e888d1 Update README.md 2023-02-01 11:06:32 +01:00
Matthias
fb742361e9 Merge pull request #8083 from leonardocustodio/patch-1
Gym aid
2023-02-01 11:05:38 +01:00
Matthias
322d4b5351 improve fix for setup.sh 2023-02-01 09:20:40 +00:00
Matthias
c1a34396d0 Merge branch 'develop' into feat/cancel_order 2023-02-01 07:06:17 +00:00
Matthias
72a98943b1 bybit: Add correct funding_fee_timeframe 2023-02-01 06:58:45 +01:00
Matthias
9bb376296d Update parse_order test 2023-01-31 20:59:55 +01:00
Matthias
839215c437 Fix Doc box error 2023-01-31 20:58:20 +01:00
Matthias
8a0fabed0e Ensure we don't overwrite valid values by invalid exchange responses 2023-01-31 20:55:11 +01:00
Matthias
680136f57d Add workaround patch for kucoin create_order returning empty
While the actual problem is caused by a ccxt change, the change itself makes sense.
once ccxt starts returning the correct status (open) for create-orders, we can remove the fix.

closes #8079
2023-01-31 20:46:34 +01:00
Matthias
448505fbfb Fix minor issue where amount could be empty in rest calls 2023-01-31 20:38:18 +01:00
Matthias
50d3b7bdef Add bybit sample order 2023-01-31 20:00:05 +01:00
Matthias
42f07e6ec2 Improve order_parse tests 2023-01-31 19:45:27 +01:00
Matthias
6012a55828 Improve test 2023-01-31 19:40:42 +01:00
Matthias
9cfbb21cd7 Improve error messages 2023-01-31 19:38:43 +01:00
Matthias
bbc663fce1 Add telegram test 2023-01-31 19:26:26 +01:00
Matthias
1c47c118d6 Add cancel-order api test 2023-01-31 19:26:21 +01:00
Matthias
daafc1c90f Update test and help 2023-01-31 18:16:59 +01:00
Matthias
bd2839fa40 Reorder documentation 2023-01-31 18:13:42 +01:00
Matthias
e291d1bb17 Document telegram /coo command 2023-01-31 18:12:18 +01:00
Matthias
1bdc0e3917 Add coo command to telegram 2023-01-31 18:09:40 +01:00
Leonardo Custodio
152aa994a6 Fix test 2023-01-31 12:46:21 -03:00
Leonardo Custodio
baf2090f9e Just change the docs 2023-01-31 12:42:39 -03:00
Leonardo Custodio
592eebe516 Add to setup 2023-01-31 12:10:41 -03:00
Leonardo Custodio
8b307357f3 Add to setup 2023-01-31 12:09:14 -03:00
Leonardo Custodio
d27d5624e0 Merge branch 'freqtrade:develop' into patch-1 2023-01-31 12:00:00 -03:00
Matthias
5073c780d8 .agg would like strings, not the sum function. 2023-01-31 11:22:04 +00:00
Matthias
2c1457fb95 Ensure limit is integer (on server) 2023-01-31 11:06:23 +00:00
Matthias
1dc3c58775 Convert missing candle count to int
closes #8082
2023-01-31 11:04:56 +00:00
Matthias
410324ac19 time-jump detection should happen on the trimmed dataframe
Fixes comment in #7615
2023-01-31 10:13:21 +00:00
Matthias
9e619ecc50 Update rest api documentation 2023-01-31 07:26:12 +01:00
Matthias
03302fa0b0 Add cancel_open_order to rest script 2023-01-31 07:24:19 +01:00
Matthias
c43e857cbc Bump API version 2023-01-31 07:09:07 +01:00
Matthias
c855e2d79c Add delete open order endpoint 2023-01-31 07:09:03 +01:00
Matthias
a704c43402 provide cancel-reason to handle_cancel_order 2023-01-31 07:08:12 +01:00
Leonardo Custodio
2b09f01293 Fixes gym issue
https://github.com/freqtrade/freqtrade/issues/8078
2023-01-30 18:52:56 -03:00
Matthias
5a7008f377 rename handle_timedout to handle_cancel_order 2023-01-30 20:02:01 +01:00
Matthias
c3ef8ebb10 Merge pull request #8059 from freqtrade/bybit
Bybit futures support 🎉
2023-01-30 18:10:46 +01:00
Matthias
b5c0daa069 Merge pull request #8028 from freqtrade/dependabot/pip/develop/sb3-contrib-1.7.0
Bump sb3-contrib from 1.6.2 to 1.7.0
2023-01-30 11:42:24 +01:00
Matthias
da0ac8190f Merge pull request #8075 from freqtrade/dependabot/pip/develop/pyarrow-11.0.0
Bump pyarrow from 10.0.1 to 11.0.0
2023-01-30 11:33:23 +01:00
Matthias
3cb9cc63b3 add pyarrow-11 rpi wheel file 2023-01-30 10:04:10 +00:00
Matthias
e77c16d510 Merge pull request #8073 from freqtrade/dependabot/pip/develop/lightgbm-3.3.5
Bump lightgbm from 3.3.4 to 3.3.5
2023-01-30 09:42:14 +01:00
Matthias
f57394c1ce Merge branch 'develop' into bybit 2023-01-30 07:23:41 +01:00
Matthias
f22f613b24 Merge pull request #8074 from freqtrade/dependabot/pip/develop/mkdocs-material-9.0.8
Bump mkdocs-material from 9.0.5 to 9.0.8
2023-01-30 07:22:46 +01:00
Matthias
2593a929d4 Bump version to 2023.2.dev 2023-01-30 07:19:35 +01:00
dependabot[bot]
411ad5641a Bump pyarrow from 10.0.1 to 11.0.0
Bumps [pyarrow](https://github.com/apache/arrow) from 10.0.1 to 11.0.0.
- [Release notes](https://github.com/apache/arrow/releases)
- [Commits](https://github.com/apache/arrow/compare/go/v10.0.1...apache-arrow-11.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-30 03:02:06 +00:00
dependabot[bot]
0dd852516a Bump mkdocs-material from 9.0.5 to 9.0.8
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.0.5 to 9.0.8.
- [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.0.5...9.0.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-30 03:01:33 +00:00
dependabot[bot]
2fea23d31a Bump lightgbm from 3.3.4 to 3.3.5
Bumps [lightgbm](https://github.com/microsoft/LightGBM) from 3.3.4 to 3.3.5.
- [Release notes](https://github.com/microsoft/LightGBM/releases)
- [Commits](https://github.com/microsoft/LightGBM/compare/v3.3.4...v3.3.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-30 03:01:12 +00:00
Matthias
f6ba0fe6ae bybit: fix broken ccxt tests 2023-01-28 18:23:23 +01:00
Matthias
7294db81e2 Bump ccxt to 2.7.7 2023-01-28 18:17:09 +01:00
Matthias
d1b069abfb bybit: Update test to align with defaultType change 2023-01-27 20:33:34 +01:00
Matthias
7029b9602c Merge branch 'develop' into bybit 2023-01-27 20:30:05 +01:00
Matthias
fa033965c8 use "swap" for bybit 2023-01-27 19:34:29 +01:00
Matthias
08ede37795 Add documentation note about stoploss on exchange 2023-01-26 19:58:58 +01:00
Matthias
8665d0866d Add test for bybit startup magic 2023-01-26 19:58:42 +01:00
Matthias
1431f7cc3e Set position mode to one-way on startup 2023-01-26 19:54:35 +01:00
Matthias
73ef1d5191 Improve exception wording on binance 2023-01-26 19:53:14 +01:00
Matthias
c12fb1a49c bybit: Some final cleanup 2023-01-24 20:12:50 +01:00
Matthias
25fa6bee74 Override get_funding_fees for bybit 2023-01-24 07:21:56 +01:00
Matthias
051c3be99e add test case for bybit 2023-01-24 07:21:56 +01:00
Matthias
3a83427f92 Add Bybit stoploss support 2023-01-24 07:21:56 +01:00
Matthias
c14553bacb Add bybit to supported Futures exchanges 2023-01-24 07:21:56 +01:00
Matthias
c2b33a0f58 Fix set-leverage function sig 2023-01-24 07:21:56 +01:00
Matthias
7a18e96042 bybit: hot-fix funding fees (temporary - must be changed) 2023-01-24 07:21:56 +01:00
Matthias
f681ce9139 Allow margin and leverage setting failures
(this is important when an exchange "fails" a request if the setting didn't change).
2023-01-24 07:21:56 +01:00
Matthias
31745a9dc2 bybit: Initial implementation liquidation calculation 2023-01-24 07:21:56 +01:00
Matthias
93ce963e9b Update test name 2023-01-24 07:21:56 +01:00
Matthias
752110a268 Add online tests for bybit 2023-01-24 07:21:56 +01:00
Matthias
d05ecd630f Update tests for new liquidation parameter 2023-01-24 07:21:56 +01:00
Matthias
34e7433844 Add leverage to dry-run liquidation price calculation 2023-01-24 07:21:56 +01:00
Matthias
a7b030fff9 Add note about bybit futures 2023-01-24 07:21:56 +01:00
Matthias
3192af8df8 Limit bybit futures markets to USDT 2023-01-24 07:21:56 +01:00
Matthias
63c732a560 Bybit futures data download 2023-01-24 07:21:56 +01:00
Matthias
75804a7f85 Bump stable-baselines3 alongside with sb3-contrib. 2023-01-16 15:53:44 +01:00
dependabot[bot]
a77fdb1594 Bump sb3-contrib from 1.6.2 to 1.7.0
Bumps [sb3-contrib](https://github.com/Stable-Baselines-Team/stable-baselines3-contrib) from 1.6.2 to 1.7.0.
- [Release notes](https://github.com/Stable-Baselines-Team/stable-baselines3-contrib/releases)
- [Commits](https://github.com/Stable-Baselines-Team/stable-baselines3-contrib/compare/v1.6.2...v1.7.0)

---
updated-dependencies:
- dependency-name: sb3-contrib
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-01-16 08:53:21 +00:00
hippocritical
feb6accc6c Merge remote-tracking branch 'origin/strategy_utils' into strategy_utils 2023-01-05 22:56:29 +01:00
hippocritical
4435c4fd0d removed prints for strategy could not be loaded
Changed logic to contain much less if conditions

currently still missing:
Webhook terminology, Telegram notification settings, Strategy/Config settings
2023-01-05 22:56:06 +01:00
hippocritical
e55638ed03 Merge branch 'freqtrade:develop' into strategy_utils 2023-01-04 23:52:35 +01:00
hippocritical
ed55296d20 removed prints for strategy could not be loaded
Changed logic to contain much less if conditions

currently still missing:
Webhook terminology, Telegram notification settings, Strategy/Config settings
2023-01-04 23:49:33 +01:00
robcaulk
3cbe51c3ca remove duplicated line 2023-01-04 13:58:25 +01:00
robcaulk
dc25668468 handle data gaps between FreqAI and DP better 2023-01-04 11:41:06 +01:00
hippocritical
71ec32ac9e removed prints for strategy could not be loaded
changed back to ast, astor is not really needed.
2023-01-02 23:35:51 +01:00
hippocritical
697fad0ac4 Merge remote-tracking branch 'origin/strategy_utils' into strategy_utils 2023-01-02 20:46:05 +01:00
hippocritical
0817e1698f requirements thinned out again
StrategyResolver.search_all_objects(enum_failed) set to False since we got no use in True
shortened update_code call
added modified_code8 test which currently still fails. (and thereby is commented out)
2023-01-02 20:45:56 +01:00
hippocritical
61d7129d7c Update freqtrade/commands/strategy_utils_commands.py
Co-authored-by: Matthias <xmatthias@outlook.com>
2023-01-02 16:51:05 +01:00
Matthias
df25dbc048 Don't require a configuration for strategy-updater 2023-01-02 08:52:18 +01:00
Matthias
a712c5d42c Improve if formatting 2023-01-02 08:52:01 +01:00
Matthias
e89609dc3a Fix crash due to invalid parameter 2023-01-02 08:51:54 +01:00
hippocritical
66f7c91357 Adding tests
added more code inside NameUpdater to grab more variables.
2023-01-01 22:03:45 +01:00
hippocritical
762dd4f024 Adding tests
added more code inside NameUpdater to grab more variables.
2023-01-01 18:57:38 +01:00
hippocritical
a51e44eea3 Adding tests 2023-01-01 12:37:15 +01:00
hippocritical
82218d01f4 sped up the function generic_visit that now skips unnecessary fields
added mentioning of skipped class names since they could not be found
2022-12-30 21:49:09 +01:00
hippocritical
a6356c2821 Merge remote-tracking branch 'origin/strategy_utils' into strategy_utils 2022-12-29 22:32:02 +01:00
hippocritical
c6f045afa9 fixing issues of the maintainer
found a bug meaning elts could contain lists of elts (now recurively gone through)

Next in line: writing tests based on StrategyUpdater.update_code
2022-12-29 22:31:33 +01:00
hippocritical
126b8dac07 Merge branch 'freqtrade:develop' into strategy_utils 2022-12-27 22:34:24 +01:00
hippocritical
70e9fa6136 implementing the strategy_updater in a first version 2022-12-27 20:43:43 +01:00
robcaulk
c9bc91c75b add shuffle_after_split option 2022-12-16 11:20:37 +01:00
195 changed files with 10788 additions and 5148 deletions

View File

@@ -16,15 +16,16 @@ on:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
repository-projects: read
jobs:
build_linux:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-18.04, ubuntu-20.04, ubuntu-22.04 ]
python-version: ["3.8", "3.9", "3.10"]
os: [ ubuntu-20.04, ubuntu-22.04 ]
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
@@ -90,14 +91,14 @@ jobs:
freqtrade create-userdir --userdir user_data
freqtrade hyperopt --datadir tests/testdata -e 6 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all
- name: Flake8
run: |
flake8
- name: Sort imports (isort)
run: |
isort --check .
- name: Run Ruff
run: |
ruff check --format=github .
- name: Mypy
run: |
mypy freqtrade scripts tests
@@ -115,7 +116,7 @@ jobs:
strategy:
matrix:
os: [ macos-latest ]
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
@@ -186,14 +187,14 @@ jobs:
freqtrade create-userdir --userdir user_data
freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all
- name: Flake8
run: |
flake8
- name: Sort imports (isort)
run: |
isort --check .
- name: Run Ruff
run: |
ruff check --format=github .
- name: Mypy
run: |
mypy freqtrade scripts
@@ -212,7 +213,7 @@ jobs:
strategy:
matrix:
os: [ windows-latest ]
python-version: ["3.8", "3.9", "3.10"]
python-version: ["3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
@@ -248,9 +249,9 @@ jobs:
freqtrade create-userdir --userdir user_data
freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all
- name: Flake8
- name: Run Ruff
run: |
flake8
ruff check --format=github .
- name: Mypy
run: |
@@ -321,7 +322,6 @@ jobs:
build_linux_online:
# Run pytest with "live" checks
runs-on: ubuntu-22.04
# permissions:
steps:
- uses: actions/checkout@v3
@@ -425,7 +425,7 @@ jobs:
python setup.py sdist bdist_wheel
- name: Publish to PyPI (Test)
uses: pypa/gh-action-pypi-publish@v1.6.4
uses: pypa/gh-action-pypi-publish@v1.8.1
if: (github.event_name == 'release')
with:
user: __token__
@@ -433,7 +433,7 @@ jobs:
repository_url: https://test.pypi.org/legacy/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@v1.6.4
uses: pypa/gh-action-pypi-publish@v1.8.1
if: (github.event_name == 'release')
with:
user: __token__
@@ -466,12 +466,13 @@ jobs:
- name: Build and test and push docker images
env:
IMAGE_NAME: freqtradeorg/freqtrade
BRANCH_NAME: ${{ steps.extract_branch.outputs.branch }}
run: |
build_helpers/publish_docker_multi.sh
deploy_arm:
permissions:
packages: write
needs: [ deploy ]
# Only run on 64bit machines
runs-on: [self-hosted, linux, ARM64]
@@ -494,8 +495,9 @@ jobs:
- name: Build and test and push docker images
env:
IMAGE_NAME: freqtradeorg/freqtrade
BRANCH_NAME: ${{ steps.extract_branch.outputs.branch }}
GHCR_USERNAME: ${{ github.actor }}
GHCR_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
build_helpers/publish_docker_arm64.sh

View File

@@ -2,33 +2,40 @@
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/pycqa/flake8
rev: "4.0.1"
rev: "6.0.0"
hooks:
- id: flake8
# stages: [push]
- repo: https://github.com/pre-commit/mirrors-mypy
rev: "v0.991"
rev: "v1.0.1"
hooks:
- id: mypy
exclude: build_helpers
additional_dependencies:
- types-cachetools==5.2.1
- types-cachetools==5.3.0.4
- types-filelock==3.2.7
- types-requests==2.28.11.8
- types-tabulate==0.9.0.0
- types-python-dateutil==2.8.19.6
- types-requests==2.28.11.15
- types-tabulate==0.9.0.1
- types-python-dateutil==2.8.19.10
- SQLAlchemy==2.0.7
# stages: [push]
- repo: https://github.com/pycqa/isort
rev: "5.10.1"
rev: "5.12.0"
hooks:
- id: isort
name: isort (python)
# stages: [push]
- repo: https://github.com/charliermarsh/ruff-pre-commit
# Ruff version.
rev: 'v0.0.255'
hooks:
- id: ruff
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v2.4.0
rev: v4.4.0
hooks:
- id: end-of-file-fixer
exclude: |

View File

@@ -45,16 +45,17 @@ pytest tests/test_<file_name>.py::test_<method_name>
### 2. Test if your code is PEP8 compliant
#### Run Flake8
#### Run Ruff
```bash
flake8 freqtrade tests scripts
ruff .
```
We receive a lot of code that fails the `flake8` checks.
We receive a lot of code that fails the `ruff` checks.
To help with that, we encourage you to install the git pre-commit
hook that will warn you when you try to commit code that fails these checks.
Guide for installing them is [here](http://flake8.pycqa.org/en/latest/user/using-hooks.html).
you can manually run pre-commit with `pre-commit run -a`.
##### Additional styles applied

View File

@@ -1,4 +1,4 @@
FROM python:3.10.7-slim-bullseye as base
FROM python:3.10.10-slim-bullseye as base
# Setup env
ENV LANG C.UTF-8

View File

@@ -40,6 +40,7 @@ Please read the [exchange specific notes](docs/exchanges.md) to learn about even
- [X] [Binance](https://www.binance.com/)
- [X] [Gate.io](https://www.gate.io/ref/6266643)
- [X] [OKX](https://okx.com/)
- [X] [Bybit](https://bybit.com/)
Please make sure to read the [exchange specific notes](docs/exchanges.md), as well as the [trading with leverage](docs/leverage.md) documentation before diving in.
@@ -164,6 +165,10 @@ first. If it hasn't been reported, please
ensure you follow the template guide so that the team can assist you as
quickly as possible.
For every [issue](https://github.com/freqtrade/freqtrade/issues/new/choose) created, kindly follow up and mark satisfaction or reminder to close issue when equilibrium ground is reached.
--Maintain github's [community policy](https://docs.github.com/en/site-policy/github-terms/github-community-code-of-conduct)--
### [Feature Requests](https://github.com/freqtrade/freqtrade/labels/enhancement)
Have you a great idea to improve the bot you want to share? Please,

Binary file not shown.

View File

@@ -8,8 +8,8 @@ if [ -n "$2" ] || [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then
tar zxvf ta-lib-0.4.0-src.tar.gz
cd ta-lib \
&& sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \
&& curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD' -o config.guess \
&& curl 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' -o config.sub \
&& curl 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.guess' -o config.guess \
&& curl 'https://raw.githubusercontent.com/gcc-mirror/gcc/master/config.sub' -o config.sub \
&& ./configure --prefix=${INSTALL_LOC}/ \
&& make
if [ $? -ne 0 ]; then

View File

@@ -14,5 +14,8 @@ if ($pyv -eq '3.9') {
if ($pyv -eq '3.10') {
pip install build_helpers\TA_Lib-0.4.25-cp310-cp310-win_amd64.whl
}
if ($pyv -eq '3.11') {
pip install build_helpers\TA_Lib-0.4.25-cp311-cp311-win_amd64.whl
}
pip install -r requirements-dev.txt
pip install -e .

View File

@@ -8,12 +8,17 @@ import yaml
pre_commit_file = Path('.pre-commit-config.yaml')
require_dev = Path('requirements-dev.txt')
require = Path('requirements.txt')
with require_dev.open('r') as rfile:
requirements = rfile.readlines()
with require.open('r') as rfile:
requirements.extend(rfile.readlines())
# Extract types only
type_reqs = [r.strip('\n') for r in requirements if r.startswith('types-')]
type_reqs = [r.strip('\n') for r in requirements if r.startswith(
'types-') or r.startswith('SQLAlchemy')]
with pre_commit_file.open('r') as file:
f = yaml.load(file, Loader=yaml.FullLoader)

View File

@@ -3,6 +3,10 @@
# Use BuildKit, otherwise building on ARM fails
export DOCKER_BUILDKIT=1
IMAGE_NAME=freqtradeorg/freqtrade
CACHE_IMAGE=freqtradeorg/freqtrade_cache
GHCR_IMAGE_NAME=ghcr.io/freqtrade/freqtrade
# Replace / with _ to create a valid tag
TAG=$(echo "${BRANCH_NAME}" | sed -e "s/\//_/g")
TAG_PLOT=${TAG}_plot
@@ -14,7 +18,6 @@ TAG_ARM=${TAG}_arm
TAG_PLOT_ARM=${TAG_PLOT}_arm
TAG_FREQAI_ARM=${TAG_FREQAI}_arm
TAG_FREQAI_RL_ARM=${TAG_FREQAI_RL}_arm
CACHE_IMAGE=freqtradeorg/freqtrade_cache
echo "Running for ${TAG}"
@@ -38,13 +41,13 @@ if [ $? -ne 0 ]; then
echo "failed building multiarch images"
return 1
fi
# Tag image for upload and next build step
docker tag freqtrade:$TAG_ARM ${CACHE_IMAGE}:$TAG_ARM
docker build --cache-from freqtrade:${TAG_ARM} --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG_ARM} -t freqtrade:${TAG_PLOT_ARM} -f docker/Dockerfile.plot .
docker build --cache-from freqtrade:${TAG_ARM} --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG_ARM} -t freqtrade:${TAG_FREQAI_ARM} -f docker/Dockerfile.freqai .
docker build --cache-from freqtrade:${TAG_ARM} --build-arg sourceimage=${CACHE_IMAGE} --build-arg sourcetag=${TAG_ARM} -t freqtrade:${TAG_FREQAI_RL_ARM} -f docker/Dockerfile.freqai_rl .
# Tag image for upload and next build step
docker tag freqtrade:$TAG_ARM ${CACHE_IMAGE}:$TAG_ARM
docker tag freqtrade:$TAG_PLOT_ARM ${CACHE_IMAGE}:$TAG_PLOT_ARM
docker tag freqtrade:$TAG_FREQAI_ARM ${CACHE_IMAGE}:$TAG_FREQAI_ARM
docker tag freqtrade:$TAG_FREQAI_RL_ARM ${CACHE_IMAGE}:$TAG_FREQAI_RL_ARM
@@ -59,7 +62,6 @@ fi
docker images
# docker push ${IMAGE_NAME}
docker push ${CACHE_IMAGE}:$TAG_PLOT_ARM
docker push ${CACHE_IMAGE}:$TAG_FREQAI_ARM
docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL_ARM
@@ -82,14 +84,30 @@ docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI}
docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM}
docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI_RL}
# copy images to ghcr.io
alias crane="docker run --rm -i -v $(pwd)/.crane:/home/nonroot/.docker/ gcr.io/go-containerregistry/crane"
mkdir .crane
chmod a+rwx .crane
echo "${GHCR_TOKEN}" | crane auth login ghcr.io -u "${GHCR_USERNAME}" --password-stdin
crane copy ${IMAGE_NAME}:${TAG_FREQAI_RL} ${GHCR_IMAGE_NAME}:${TAG_FREQAI_RL}
crane copy ${IMAGE_NAME}:${TAG_FREQAI} ${GHCR_IMAGE_NAME}:${TAG_FREQAI}
crane copy ${IMAGE_NAME}:${TAG_PLOT} ${GHCR_IMAGE_NAME}:${TAG_PLOT}
crane copy ${IMAGE_NAME}:${TAG} ${GHCR_IMAGE_NAME}:${TAG}
# Tag as latest for develop builds
if [ "${TAG}" = "develop" ]; then
echo 'Tagging image as latest'
docker manifest create ${IMAGE_NAME}:latest ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG}
docker manifest push -p ${IMAGE_NAME}:latest
crane copy ${IMAGE_NAME}:latest ${GHCR_IMAGE_NAME}:latest
fi
docker images
rm -rf .crane
# Cleanup old images from arm64 node.
docker image prune -a --force --filter "until=24h"

View File

@@ -2,6 +2,8 @@
# The below assumes a correctly setup docker buildx environment
IMAGE_NAME=freqtradeorg/freqtrade
CACHE_IMAGE=freqtradeorg/freqtrade_cache
# Replace / with _ to create a valid tag
TAG=$(echo "${BRANCH_NAME}" | sed -e "s/\//_/g")
TAG_PLOT=${TAG}_plot
@@ -11,7 +13,6 @@ TAG_PI="${TAG}_pi"
PI_PLATFORM="linux/arm/v7"
echo "Running for ${TAG}"
CACHE_IMAGE=freqtradeorg/freqtrade_cache
CACHE_TAG=${CACHE_IMAGE}:${TAG_PI}_cache
# Add commit and commit_message to docker container

View File

@@ -48,7 +48,7 @@
],
"freqai": {
"enabled": true,
"purge_old_models": true,
"purge_old_models": 2,
"train_period_days": 15,
"backtest_period_days": 7,
"live_retrain_hours": 0,

View File

@@ -60,6 +60,7 @@
"force_entry": "market",
"stoploss": "market",
"stoploss_on_exchange": false,
"stoploss_price_type": "last",
"stoploss_on_exchange_interval": 60,
"stoploss_on_exchange_limit_ratio": 0.99
},

View File

@@ -1,4 +1,4 @@
FROM python:3.9.12-slim-bullseye as base
FROM python:3.9.16-slim-bullseye as base
# Setup env
ENV LANG C.UTF-8

View File

@@ -192,7 +192,7 @@ $RepeatedMsgReduction on
### Logging to journald
This needs the `systemd` python package installed as the dependency, which is not available on Windows. Hence, the whole journald logging functionality is not available for a bot running on Windows.
This needs the `cysystemd` python package installed as dependency (`pip install cysystemd`), which is not available on Windows. Hence, the whole journald logging functionality is not available for a bot running on Windows.
To send Freqtrade log messages to `journald` system service use the `--logfile` command line option with the value in the following format:

View File

@@ -12,6 +12,9 @@ This page provides you some basic concepts on how Freqtrade works and operates.
* **Indicators**: Technical indicators (SMA, EMA, RSI, ...).
* **Limit order**: Limit orders which execute at the defined limit price or better.
* **Market order**: Guaranteed to fill, may move price depending on the order size.
* **Current Profit**: Currently pending (unrealized) profit for this trade. This is mainly used throughout the bot and UI.
* **Realized Profit**: Already realized profit. Only relevant in combination with [partial exits](strategy-callbacks.md#adjust-trade-position) - which also explains the calculation logic for this.
* **Total Profit**: Combined realized and unrealized profit. The relative number (%) is calculated against the total investment in this trade.
## Fee handling

View File

@@ -666,7 +666,7 @@ You should also make sure to read the [Exchanges](exchanges.md) section of the d
### Using proxy with Freqtrade
To use a proxy with freqtrade, export your proxy settings using the variables `"HTTP_PROXY"` and `"HTTPS_PROXY"` set to the appropriate values.
This will have the proxy settings applied to everything (telegram, coingecko, ...) except exchange requests.
This will have the proxy settings applied to everything (telegram, coingecko, ...) **except** for exchange requests.
``` bash
export HTTP_PROXY="http://addr:port"
@@ -682,11 +682,12 @@ To use a proxy for exchange connections - you will have to define the proxies as
{
"exchange": {
"ccxt_config": {
"aiohttp_proxy": "http://addr:port",
"proxies": {
"http": "http://addr:port",
"https": "http://addr:port"
},
"aiohttp_proxy": "http://addr:port",
"proxies": {
"http": "http://addr:port",
"https": "http://addr:port"
},
}
}
}
```

View File

@@ -74,3 +74,8 @@ Webhook terminology changed from "sell" to "exit", and from "buy" to "entry", re
* `webhooksell`, `webhookexit` -> `exit`
* `webhooksellfill`, `webhookexitfill` -> `exit_fill`
* `webhooksellcancel`, `webhookexitcancel` -> `exit_cancel`
## Removal of `populate_any_indicators`
version 2023.3 saw the removal of `populate_any_indicators` in favor of split methods for feature engineering and targets. Please read the [migration document](strategy_migration.md#freqai-strategy) for full details.

View File

@@ -24,7 +24,7 @@ This will spin up a local server (usually on port 8000) so you can see if everyt
To configure a development environment, you can either use the provided [DevContainer](#devcontainer-setup), or use the `setup.sh` script and answer "y" when asked "Do you want to install dependencies for dev [y/N]? ".
Alternatively (e.g. if your system is not supported by the setup.sh script), follow the manual installation process and run `pip3 install -e .[all]`.
This will install all required tools for development, including `pytest`, `flake8`, `mypy`, and `coveralls`.
This will install all required tools for development, including `pytest`, `ruff`, `mypy`, and `coveralls`.
Then install the git hook scripts by running `pre-commit install`, so your changes will be verified locally before committing.
This avoids a lot of waiting for CI already, as some basic formatting checks are done locally on your machine.
@@ -363,7 +363,7 @@ from pathlib import Path
exchange = ccxt.binance({
'apiKey': '<apikey>',
'secret': '<secret>'
'options': {'defaultType': 'future'}
'options': {'defaultType': 'swap'}
})
_ = exchange.load_markets()

View File

@@ -243,8 +243,8 @@ OKX requires a passphrase for each api key, you will therefore need to add this
OKX only provides 100 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode.
!!! Warning "Futures"
OKX Futures has the concept of "position mode" - which can be Net or long/short (hedge mode).
Freqtrade supports both modes (we recommend to use net mode) - but changing the mode mid-trading is not supported and will lead to exceptions and failures to place trades.
OKX Futures has the concept of "position mode" - which can be "Buy/Sell" or long/short (hedge mode).
Freqtrade supports both modes (we recommend to use Buy/Sell mode) - but changing the mode mid-trading is not supported and will lead to exceptions and failures to place trades.
OKX also only provides MARK candles for the past ~3 months. Backtesting futures prior to that date will therefore lead to slight deviations, as funding-fees cannot be calculated correctly without this data.
## Gate.io
@@ -255,6 +255,18 @@ OKX requires a passphrase for each api key, you will therefore need to add this
Gate.io allows the use of `POINT` to pay for fees. As this is not a tradable currency (no regular market available), automatic fee calculations will fail (and default to a fee of 0).
The configuration parameter `exchange.unknown_fee_rate` can be used to specify the exchange rate between Point and the stake currency. Obviously, changing the stake-currency will also require changes to this value.
## Bybit
Futures trading on bybit is currently supported for USDT markets, and will use isolated futures mode.
Users with unified accounts (there's no way back) can create a Sub-account which will start as "non-unified", and can therefore use isolated futures.
On startup, freqtrade will set the position mode to "One-way Mode" for the whole (sub)account. This avoids making this call over and over again (slowing down bot operations), but means that changes to this setting may result in exceptions and errors.
As bybit doesn't provide funding rate history, the dry-run calculation is used for live trades as well.
!!! 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.
## All exchanges
Should you experience constant errors with Nonce (like `InvalidNonce`), it is best to regenerate the API keys. Resetting Nonce is difficult and it's usually easier to regenerate the API keys.

View File

@@ -2,7 +2,7 @@
## Supported Markets
Freqtrade supports spot trading only.
Freqtrade supports spot trading, as well as (isolated) futures trading for some selected exchanges. Please refer to the [documentation start page](index.md#supported-futures-exchanges-experimental) for an uptodate list of supported exchanges.
### Can my bot open short positions?
@@ -248,8 +248,26 @@ The Edge module is mostly a result of brainstorming of [@mishaker](https://githu
You can find further info on expectancy, win rate, risk management and position size in the following sources:
- https://www.tradeciety.com/ultimate-math-guide-for-traders/
- http://www.vantharp.com/tharp-concepts/expectancy.asp
- https://samuraitradingacademy.com/trading-expectancy/
- https://www.learningmarkets.com/determining-expectancy-in-your-trading/
- http://www.lonestocktrader.com/make-money-trading-positive-expectancy/
- https://www.lonestocktrader.com/make-money-trading-positive-expectancy/
- https://www.babypips.com/trading/trade-expectancy-matter
## Official channels
Freqtrade is using exclusively the following official channels:
* [Freqtrade discord server](https://discord.gg/p7nuUNVfP7)
* [Freqtrade documentation (https://freqtrade.io)](https://freqtrade.io)
* [Freqtrade github organization](https://github.com/freqtrade)
Nobody affiliated with the freqtrade project will ask you about your exchange keys or anything else exposing your funds to exploitation.
Should you be asked to expose your exchange keys or send funds to some random wallet, then please don't follow these instructions.
Failing to follow these guidelines will not be responsibility of freqtrade.
## "Freqtrade token"
Freqtrade does not have a Crypto token offering.
Token offerings you find on the internet referring Freqtrade, FreqAI or freqUI must be considered to be a scam, trying to exploit freqtrade's popularity for their own, nefarious gains.

View File

@@ -9,7 +9,7 @@ FreqAI is configured through the typical [Freqtrade config file](configuration.m
```json
"freqai": {
"enabled": true,
"purge_old_models": true,
"purge_old_models": 2,
"train_period_days": 30,
"backtest_period_days": 7,
"identifier" : "unique-id",
@@ -165,10 +165,10 @@ Below are the values you can expect to include/use inside a typical strategy dat
## Setting the `startup_candle_count`
The `startup_candle_count` in the FreqAI strategy needs to be set up in the same way as in the standard Freqtrade strategy (see details [here](strategy-customization.md#strategy-startup-period)). This value is used by Freqtrade to ensure that a sufficient amount of data is provided when calling the `dataprovider`, to avoid any NaNs at the beginning of the first training. You can easily set this value by identifying the longest period (in candle units) which is passed to the indicator creation functions (e.g., Ta-Lib functions). In the presented example, `startup_candle_count` is 20 since this is the maximum value in `indicators_periods_candles`.
The `startup_candle_count` in the FreqAI strategy needs to be set up in the same way as in the standard Freqtrade strategy (see details [here](strategy-customization.md#strategy-startup-period)). This value is used by Freqtrade to ensure that a sufficient amount of data is provided when calling the `dataprovider`, to avoid any NaNs at the beginning of the first training. You can easily set this value by identifying the longest period (in candle units) which is passed to the indicator creation functions (e.g., TA-Lib functions). In the presented example, `startup_candle_count` is 20 since this is the maximum value in `indicators_periods_candles`.
!!! Note
There are instances where the Ta-Lib functions actually require more data than just the passed `period` or else the feature dataset gets populated with NaNs. Anecdotally, multiplying the `startup_candle_count` by 2 always leads to a fully NaN free training dataset. Hence, it is typically safest to multiply the expected `startup_candle_count` by 2. Look out for this log message to confirm that the data is clean:
There are instances where the TA-Lib functions actually require more data than just the passed `period` or else the feature dataset gets populated with NaNs. Anecdotally, multiplying the `startup_candle_count` by 2 always leads to a fully NaN free training dataset. Hence, it is typically safest to multiply the expected `startup_candle_count` by 2. Look out for this log message to confirm that the data is clean:
```
2022-08-31 15:14:04 - freqtrade.freqai.data_kitchen - INFO - dropped 0 training points due to NaNs in populated dataset 4319.
@@ -205,7 +205,7 @@ All of the aforementioned model libraries implement gradient boosted decision tr
* LightGBM: https://lightgbm.readthedocs.io/en/v3.3.2/#
* XGBoost: https://xgboost.readthedocs.io/en/stable/#
There are also numerous online articles describing and comparing the algorithms. Some relatively light-weight examples would be [CatBoost vs. LightGBM vs. XGBoost — Which is the best algorithm?](https://towardsdatascience.com/catboost-vs-lightgbm-vs-xgboost-c80f40662924#:~:text=In%20CatBoost%2C%20symmetric%20trees%2C%20or,the%20same%20depth%20can%20differ.) and [XGBoost, LightGBM or CatBoost — which boosting algorithm should I use?](https://medium.com/riskified-technology/xgboost-lightgbm-or-catboost-which-boosting-algorithm-should-i-use-e7fda7bb36bc). Keep in mind that the performance of each model is highly dependent on the application and so any reported metrics might not be true for your particular use of the model.
There are also numerous online articles describing and comparing the algorithms. Some relatively lightweight examples would be [CatBoost vs. LightGBM vs. XGBoost — Which is the best algorithm?](https://towardsdatascience.com/catboost-vs-lightgbm-vs-xgboost-c80f40662924#:~:text=In%20CatBoost%2C%20symmetric%20trees%2C%20or,the%20same%20depth%20can%20differ.) and [XGBoost, LightGBM or CatBoost — which boosting algorithm should I use?](https://medium.com/riskified-technology/xgboost-lightgbm-or-catboost-which-boosting-algorithm-should-i-use-e7fda7bb36bc). Keep in mind that the performance of each model is highly dependent on the application and so any reported metrics might not be true for your particular use of the model.
Apart from the models already available in FreqAI, it is also possible to customize and create your own prediction models using the `IFreqaiModel` class. You are encouraged to inherit `fit()`, `train()`, and `predict()` to customize various aspects of the training procedures. You can place custom FreqAI models in `user_data/freqaimodels` - and freqtrade will pick them up from there based on the provided `--freqaimodel` name - which has to correspond to the class name of your custom model.
Make sure to use unique names to avoid overriding built-in models.

View File

@@ -8,7 +8,7 @@ Low level feature engineering is performed in the user strategy within a set of
|---------------|-------------|
| `feature_engineering__expand_all()` | This optional function will automatically expand the defined features on the config defined `indicator_periods_candles`, `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`.
| `feature_engineering__expand_basic()` | This optional function will automatically expand the defined features on the config defined `include_timeframes`, `include_shifted_candles`, and `include_corr_pairs`. Note: this function does *not* expand across `include_periods_candles`.
| `feature_engineering_standard()` | This optional function will be called once with the dataframe of the base timeframe. This is the final function to be called, which means that the dataframe entering this function will contain all the features and columns from the base asset created by the other `feature_engineering_expand` functions. This function is a good place to do custom exotic feature extractions (e.g. tsfresh). This function is also a good place for any feature that should not be auto-expanded upon (e.g. day of the week).
| `feature_engineering_standard()` | This optional function will be called once with the dataframe of the base timeframe. This is the final function to be called, which means that the dataframe entering this function will contain all the features and columns from the base asset created by the other `feature_engineering_expand` functions. This function is a good place to do custom exotic feature extractions (e.g. tsfresh). This function is also a good place for any feature that should not be auto-expanded upon (e.g., day of the week).
| `set_freqai_targets()` | Required function to set the targets for the model. All targets must be prepended with `&` to be recognized by the FreqAI internals.
Meanwhile, high level feature engineering is handled within `"feature_parameters":{}` in the FreqAI config. Within this file, it is possible to decide large scale feature expansions on top of the `base_features` such as "including correlated pairs" or "including informative timeframes" or even "including recent candles."
@@ -16,7 +16,7 @@ Meanwhile, high level feature engineering is handled within `"feature_parameters
It is advisable to start from the template `feature_engineering_*` functions in the source provided example strategy (found in `templates/FreqaiExampleStrategy.py`) to ensure that the feature definitions are following the correct conventions. Here is an example of how to set the indicators and labels in the strategy:
```python
def feature_engineering_expand_all(self, dataframe, period, **kwargs):
def feature_engineering_expand_all(self, dataframe, period, metadata, **kwargs):
"""
*Only functional with FreqAI enabled strategies*
This function will automatically expand the defined features on the config defined
@@ -28,8 +28,13 @@ It is advisable to start from the template `feature_engineering_*` functions in
All features must be prepended with `%` to be recognized by FreqAI internals.
Access metadata such as the current pair/timeframe/period with:
`metadata["pair"]` `metadata["tf"]` `metadata["period"]`
:param df: strategy dataframe which will receive the features
:param period: period of the indicator - usage example:
:param metadata: metadata of current pair
dataframe["%-ema-period"] = ta.EMA(dataframe, timeperiod=period)
"""
@@ -62,7 +67,7 @@ It is advisable to start from the template `feature_engineering_*` functions in
return dataframe
def feature_engineering_expand_basic(self, dataframe, **kwargs):
def feature_engineering_expand_basic(self, dataframe, metadata, **kwargs):
"""
*Only functional with FreqAI enabled strategies*
This function will automatically expand the defined features on the config defined
@@ -75,9 +80,14 @@ It is advisable to start from the template `feature_engineering_*` functions in
Features defined here will *not* be automatically duplicated on user defined
`indicator_periods_candles`
Access metadata such as the current pair/timeframe with:
`metadata["pair"]` `metadata["tf"]`
All features must be prepended with `%` to be recognized by FreqAI internals.
:param df: strategy dataframe which will receive the features
:param metadata: metadata of current pair
dataframe["%-pct-change"] = dataframe["close"].pct_change()
dataframe["%-ema-200"] = ta.EMA(dataframe, timeperiod=200)
"""
@@ -86,7 +96,7 @@ It is advisable to start from the template `feature_engineering_*` functions in
dataframe["%-raw_price"] = dataframe["close"]
return dataframe
def feature_engineering_standard(self, dataframe, **kwargs):
def feature_engineering_standard(self, dataframe, metadata, **kwargs):
"""
*Only functional with FreqAI enabled strategies*
This optional function will be called once with the dataframe of the base timeframe.
@@ -98,22 +108,32 @@ It is advisable to start from the template `feature_engineering_*` functions in
This function is a good place for any feature that should not be auto-expanded upon
(e.g. day of the week).
Access metadata such as the current pair with:
`metadata["pair"]`
All features must be prepended with `%` to be recognized by FreqAI internals.
:param df: strategy dataframe which will receive the features
:param metadata: metadata of current pair
usage example: dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7
"""
dataframe["%-day_of_week"] = (dataframe["date"].dt.dayofweek + 1) / 7
dataframe["%-hour_of_day"] = (dataframe["date"].dt.hour + 1) / 25
return dataframe
def set_freqai_targets(self, dataframe, **kwargs):
def set_freqai_targets(self, dataframe, metadata, **kwargs):
"""
*Only functional with FreqAI enabled strategies*
Required function to set the targets for the model.
All targets must be prepended with `&` to be recognized by the FreqAI internals.
Access metadata such as the current pair with:
`metadata["pair"]`
:param df: strategy dataframe which will receive the targets
:param metadata: metadata of current pair
usage example: dataframe["&-target"] = dataframe["close"].shift(-1) / dataframe["close"]
"""
dataframe["&-s_close"] = (
@@ -161,6 +181,19 @@ You can ask for each of the defined features to be included also for informative
In total, the number of features the user of the presented example strat has created is: length of `include_timeframes` * no. features in `feature_engineering_expand_*()` * length of `include_corr_pairlist` * no. `include_shifted_candles` * length of `indicator_periods_candles`
$= 3 * 3 * 3 * 2 * 2 = 108$.
### Gain finer control over `feature_engineering_*` functions with `metadata`
All `feature_engineering_*` and `set_freqai_targets()` functions are passed a `metadata` dictionary which contains information about the `pair`, `tf` (timeframe), and `period` that FreqAI is automating for feature building. As such, a user can use `metadata` inside `feature_engineering_*` functions as criteria for blocking/reserving features for certain timeframes, periods, pairs etc.
```py
def feature_engineering_expand_all(self, dataframe, period, metadata, **kwargs):
if metadata["tf"] == "1h":
dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period)
```
This will block `ta.ROC()` from being added to any timeframes other than `"1h"`.
### Returning additional info from training
Important metrics can be returned to the strategy at the end of each model training by assigning them to `dk.data['extra_returns_per_train']['my_new_value'] = XYZ` inside the custom prediction model class.
@@ -201,7 +234,7 @@ This will perform PCA on the features and reduce their dimensionality so that th
## Inlier metric
The `inlier_metric` is a metric aimed at quantifying how similar a the features of a data point are to the most recent historic data points.
The `inlier_metric` is a metric aimed at quantifying how similar the features of a data point are to the most recent historical data points.
You define the lookback window by setting `inlier_metric_window` and FreqAI computes the distance between the present time point and each of the previous `inlier_metric_window` lookback points. A Weibull function is fit to each of the lookback distributions and its cumulative distribution function (CDF) is used to produce a quantile for each lookback point. The `inlier_metric` is then computed for each time point as the average of the corresponding lookback quantiles. The figure below explains the concept for an `inlier_metric_window` of 5.

View File

@@ -15,10 +15,9 @@ Mandatory parameters are marked as **Required** and have to be set in one of the
| `identifier` | **Required.** <br> A unique ID for the current model. If models are saved to disk, the `identifier` allows for reloading specific pre-trained models/data. <br> **Datatype:** String.
| `live_retrain_hours` | Frequency of retraining during dry/live runs. <br> **Datatype:** Float > 0. <br> Default: `0` (models retrain as often as possible).
| `expiration_hours` | Avoid making predictions if a model is more than `expiration_hours` old. <br> **Datatype:** Positive integer. <br> Default: `0` (models never expire).
| `purge_old_models` | Delete all unused models during live runs (not relevant to backtesting). If set to false (not default), dry/live runs will accumulate all unused models to disk. If <br> **Datatype:** Boolean. <br> Default: `True`.
| `purge_old_models` | Number of models to keep on disk (not relevant to backtesting). Default is 2, which means that dry/live runs will keep the latest 2 models on disk. Setting to 0 keeps all models. This parameter also accepts a boolean to maintain backwards compatibility. <br> **Datatype:** Integer. <br> Default: `2`.
| `save_backtest_models` | Save models to disk when running backtesting. Backtesting operates most efficiently by saving the prediction data and reusing them directly for subsequent runs (when you wish to tune entry/exit parameters). Saving backtesting models to disk also allows to use the same model files for starting a dry/live instance with the same model `identifier`. <br> **Datatype:** Boolean. <br> Default: `False` (no models are saved).
| `fit_live_predictions_candles` | Number of historical candles to use for computing target (label) statistics from prediction data, instead of from the training dataset (more information can be found [here](freqai-configuration.md#creating-a-dynamic-target-threshold)). <br> **Datatype:** Positive integer.
| `follow_mode` | Use a `follower` that will look for models associated with a specific `identifier` and load those for inferencing. A `follower` will **not** train new models. <br> **Datatype:** Boolean. <br> Default: `False`.
| `continual_learning` | Use the final state of the most recently trained model as starting point for the new model, allowing for incremental learning (more information can be found [here](freqai-running.md#continual-learning)). <br> **Datatype:** Boolean. <br> Default: `False`.
| `write_metrics_to_disk` | Collect train timings, inference timings and cpu usage in json file. <br> **Datatype:** Boolean. <br> Default: `False`
| `data_kitchen_thread_count` | <br> Designate the number of threads you want to use for data processing (outlier methods, normalization, etc.). This has no impact on the number of threads used for training. If user does not set it (default), FreqAI will use max number of threads - 2 (leaving 1 physical core available for Freqtrade bot and FreqUI) <br> **Datatype:** Positive integer.
@@ -46,13 +45,15 @@ Mandatory parameters are marked as **Required** and have to be set in one of the
| `noise_standard_deviation` | If set, FreqAI adds noise to the training features with the aim of preventing overfitting. FreqAI generates random deviates from a gaussian distribution with a standard deviation of `noise_standard_deviation` and adds them to all data points. `noise_standard_deviation` should be kept relative to the normalized space, i.e., between -1 and 1. In other words, since data in FreqAI is always normalized to be between -1 and 1, `noise_standard_deviation: 0.05` would result in 32% of the data being randomly increased/decreased by more than 2.5% (i.e., the percent of data falling within the first standard deviation). <br> **Datatype:** Integer. <br> Default: `0`.
| `outlier_protection_percentage` | Enable to prevent outlier detection methods from discarding too much data. If more than `outlier_protection_percentage` % of points are detected as outliers by the SVM or DBSCAN, FreqAI will log a warning message and ignore outlier detection, i.e., the original dataset will be kept intact. If the outlier protection is triggered, no predictions will be made based on the training dataset. <br> **Datatype:** Float. <br> Default: `30`.
| `reverse_train_test_order` | Split the feature dataset (see below) and use the latest data split for training and test on historical split of the data. This allows the model to be trained up to the most recent data point, while avoiding overfitting. However, you should be careful to understand the unorthodox nature of this parameter before employing it. <br> **Datatype:** Boolean. <br> Default: `False` (no reversal).
| `shuffle_after_split` | Split the data into train and test sets, and then shuffle both sets individually. <br> **Datatype:** Boolean. <br> Default: `False`.
| `buffer_train_data_candles` | Cut `buffer_train_data_candles` off the beginning and end of the training data *after* the indicators were populated. The main example use is when predicting maxima and minima, the argrelextrema function cannot know the maxima/minima at the edges of the timerange. To improve model accuracy, it is best to compute argrelextrema on the full timerange and then use this function to cut off the edges (buffer) by the kernel. In another case, if the targets are set to a shifted price movement, this buffer is unnecessary because the shifted candles at the end of the timerange will be NaN and FreqAI will automatically cut those off of the training dataset.<br> **Datatype:** Boolean. <br> Default: `False`.
### Data split parameters
| Parameter | Description |
|------------|-------------|
| | **Data split parameters within the `freqai.data_split_parameters` sub dictionary**
| `data_split_parameters` | Include any additional parameters available from Scikit-learn `test_train_split()`, which are shown [here](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html) (external website). <br> **Datatype:** Dictionary.
| `data_split_parameters` | Include any additional parameters available from scikit-learn `test_train_split()`, which are shown [here](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html) (external website). <br> **Datatype:** Dictionary.
| `test_size` | The fraction of data that should be used for testing instead of training. <br> **Datatype:** Positive float < 1.
| `shuffle` | Shuffle the training data points during training. Typically, to not remove the chronological order of data in time-series forecasting, this is set to `False`. <br> **Datatype:** Boolean. <br> Defaut: `False`.
@@ -83,12 +84,13 @@ Mandatory parameters are marked as **Required** and have to be set in one of the
| `add_state_info` | Tell FreqAI to include state information in the feature set for training and inferencing. The current state variables include trade duration, current profit, trade position. This is only available in dry/live runs, and is automatically switched to false for backtesting. <br> **Datatype:** bool. <br> Default: `False`.
| `net_arch` | Network architecture which is well described in [`stable_baselines3` doc](https://stable-baselines3.readthedocs.io/en/master/guide/custom_policy.html#examples). In summary: `[<shared layers>, dict(vf=[<non-shared value network layers>], pi=[<non-shared policy network layers>])]`. By default this is set to `[128, 128]`, which defines 2 shared hidden layers with 128 units each.
| `randomize_starting_position` | Randomize the starting point of each episode to avoid overfitting. <br> **Datatype:** bool. <br> Default: `False`.
| `drop_ohlc_from_features` | Do not include the normalized ohlc data in the feature set passed to the agent during training (ohlc will still be used for driving the environment in all cases) <br> **Datatype:** Boolean. <br> **Default:** `False`
### Additional parameters
| Parameter | Description |
|------------|-------------|
| | **Extraneous parameters**
| `freqai.keras` | If the selected model makes use of Keras (typical for Tensorflow-based prediction models), this flag needs to be activated so that the model save/loading follows Keras standards. <br> **Datatype:** Boolean. <br> Default: `False`.
| `freqai.keras` | If the selected model makes use of Keras (typical for TensorFlow-based prediction models), this flag needs to be activated so that the model save/loading follows Keras standards. <br> **Datatype:** Boolean. <br> Default: `False`.
| `freqai.conv_width` | The width of a convolutional neural network input tensor. This replaces the need for shifting candles (`include_shifted_candles`) by feeding in historical data points as the second dimension of the tensor. Technically, this parameter can also be used for regressors, but it only adds computational overhead and does not change the model training/prediction. <br> **Datatype:** Integer. <br> Default: `2`.
| `freqai.reduce_df_footprint` | Recast all numeric columns to float32/int32, with the objective of reducing ram/disk usage and decreasing train/inference timing. This parameter is set in the main level of the Freqtrade configuration file (not inside FreqAI). <br> **Datatype:** Boolean. <br> Default: `False`.

View File

@@ -24,7 +24,7 @@ The framework is built on stable_baselines3 (torch) and OpenAI gym for the base
### Important considerations
As explained above, the agent is "trained" in an artificial trading "environment". In our case, that environment may seem quite similar to a real Freqtrade backtesting environment, but it is *NOT*. In fact, the RL training environment is much more simplified. It does not incorporate any of the complicated strategy logic, such as callbacks like `custom_exit`, `custom_stoploss`, leverage controls, etc. The RL environment is instead a very "raw" representation of the true market, where the agent has free-will to learn the policy (read: stoploss, take profit, etc.) which is enforced by the `calculate_reward()`. Thus, it is important to consider that the agent training environment is not identical to the real world.
As explained above, the agent is "trained" in an artificial trading "environment". In our case, that environment may seem quite similar to a real Freqtrade backtesting environment, but it is *NOT*. In fact, the RL training environment is much more simplified. It does not incorporate any of the complicated strategy logic, such as callbacks like `custom_exit`, `custom_stoploss`, leverage controls, etc. The RL environment is instead a very "raw" representation of the true market, where the agent has free will to learn the policy (read: stoploss, take profit, etc.) which is enforced by the `calculate_reward()`. Thus, it is important to consider that the agent training environment is not identical to the real world.
## Running Reinforcement Learning
@@ -175,10 +175,23 @@ As you begin to modify the strategy and the prediction model, you will quickly r
pnl = self.get_unrealized_profit()
factor = 100
pair = self.pair.replace(':', '')
# you can use feature values from dataframe
# Assumes the shifted RSI indicator has been generated in the strategy.
rsi_now = self.raw_features[f"%-rsi-period-10_shift-1_{pair}_"
f"{self.config['timeframe']}"].iloc[self._current_tick]
# reward agent for entering trades
if action in (Actions.Long_enter.value, Actions.Short_enter.value) \
and self._position == Positions.Neutral:
return 25
if (action in (Actions.Long_enter.value, Actions.Short_enter.value)
and self._position == Positions.Neutral):
if rsi_now < 40:
factor = 40 / rsi_now
else:
factor = 1
return 25 * factor
# discourage agent from not entering trades
if action == Actions.Neutral.value and self._position == Positions.Neutral:
return -1
@@ -235,13 +248,13 @@ FreqAI also provides a built in episodic summary logger called `self.tensorboard
"""
def calculate_reward(self, action: int) -> float:
if not self._is_valid(action):
self.tensorboard_log("is_valid")
self.tensorboard_log("invalid")
return -2
```
!!! Note
The `self.tensorboard_log()` function is designed for tracking incremented objects only i.e. events, actions inside the training environment. If the event of interest is a float, the float can be passed as the second argument e.g. `self.tensorboard_log("float_metric1", 0.23)` would add 0.23 to `float_metric`. In this case you can also disable incrementing using `inc=False` parameter.
The `self.tensorboard_log()` function is designed for tracking incremented objects only i.e. events, actions inside the training environment. If the event of interest is a float, the float can be passed as the second argument e.g. `self.tensorboard_log("float_metric1", 0.23)`. In this case the metric values are not incremented.
### Choosing a base environment

View File

@@ -120,7 +120,7 @@ In the presented example config, the user will only allow predictions on models
Model training parameters are unique to the selected machine learning library. FreqAI allows you to set any parameter for any library using the `model_training_parameters` dictionary in the config. The example config (found in `config_examples/config_freqai.example.json`) shows some of the example parameters associated with `Catboost` and `LightGBM`, but you can add any parameters available in those libraries or any other machine learning library you choose to implement.
Data split parameters are defined in `data_split_parameters` which can be any parameters associated with Scikit-learn's `train_test_split()` function. `train_test_split()` has a parameters called `shuffle` which allows to shuffle the data or keep it unshuffled. This is particularly useful to avoid biasing training with temporally auto-correlated data. More details about these parameters can be found the [Scikit-learn website](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html) (external website).
Data split parameters are defined in `data_split_parameters` which can be any parameters associated with scikit-learn's `train_test_split()` function. `train_test_split()` has a parameters called `shuffle` which allows to shuffle the data or keep it unshuffled. This is particularly useful to avoid biasing training with temporally auto-correlated data. More details about these parameters can be found the [scikit-learn website](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html) (external website).
The FreqAI specific parameter `label_period_candles` defines the offset (number of candles into the future) used for the `labels`. In the presented [example config](freqai-configuration.md#setting-up-the-configuration-file), the user is asking for `labels` that are 24 candles in the future.
@@ -165,20 +165,3 @@ tensorboard --logdir user_data/models/unique-id
where `unique-id` is the `identifier` set in the `freqai` configuration file. This command must be run in a separate shell if you wish to view the output in your browser at 127.0.0.1:6060 (6060 is the default port used by Tensorboard).
![tensorboard](assets/tensorboard.jpg)
## Setting up a follower
You can indicate to the bot that it should not train models, but instead should look for models trained by a leader with a specific `identifier` by defining:
```json
"freqai": {
"enabled": true,
"follow_mode": true,
"identifier": "example",
"feature_parameters": {
// leader bots feature_parameters inserted here
},
}
```
In this example, the user has a leader bot with the `"identifier": "example"`. The leader bot is already running or is launched simultaneously with the follower. The follower will load models created by the leader and inference them to obtain predictions instead of training its own models. The user will also need to duplicate the `feature_parameters` parameters from from the leaders freqai configuration file into the freqai section of the followers config.

View File

@@ -4,7 +4,10 @@
## Introduction
FreqAI is a software designed to automate a variety of tasks associated with training a predictive machine learning model to generate market forecasts given a set of input signals. In general, the FreqAI aims to be a sand-box for easily deploying robust machine-learning libraries on real-time data ([details])(#freqai-position-in-open-source-machine-learning-landscape).
FreqAI is a software designed to automate a variety of tasks associated with training a predictive machine learning model to generate market forecasts given a set of input signals. In general, FreqAI aims to be a sandbox for easily deploying robust machine learning libraries on real-time data ([details](#freqai-position-in-open-source-machine-learning-landscape)).
!!! Note
FreqAI is, and always will be, a not-for-profit, open-source project. FreqAI does *not* have a crypto token, FreqAI does *not* sell signals, and FreqAI does not have a domain besides the present [freqtrade documentation](https://www.freqtrade.io/en/latest/freqai/).
Features include:
@@ -19,7 +22,7 @@ Features include:
* **Automatic data download** - Compute timeranges for data downloads and update historic data (in live deployments)
* **Cleaning of incoming data** - Handle NaNs safely before training and model inferencing
* **Dimensionality reduction** - Reduce the size of the training data via [Principal Component Analysis](freqai-feature-engineering.md#data-dimensionality-reduction-with-principal-component-analysis)
* **Deploying bot fleets** - Set one bot to train models while a fleet of [follower bots](freqai-running.md#setting-up-a-follower) inference the models and handle trades
* **Deploying bot fleets** - Set one bot to train models while a fleet of [consumers](producer-consumer.md) use signals.
## Quick start
@@ -68,13 +71,17 @@ pip install -r requirements-freqai.txt
!!! Note
Catboost will not be installed on arm devices (raspberry, Mac M1, ARM based VPS, ...), since it does not provide wheels for this platform.
!!! Note "python 3.11"
Some dependencies (Catboost, Torch) currently don't support python 3.11. Freqtrade therefore only supports python 3.10 for these models/dependencies.
Tests involving these dependencies are skipped on 3.11.
### Usage with docker
If you are using docker, a dedicated tag with FreqAI dependencies is available as `:freqai`. As such - you can replace the image line in your docker-compose file with `image: freqtradeorg/freqtrade:develop_freqai`. This image contains the regular FreqAI dependencies. Similar to native installs, Catboost will not be available on ARM based devices.
If you are using docker, a dedicated tag with FreqAI dependencies is available as `:freqai`. As such - you can replace the image line in your docker compose file with `image: freqtradeorg/freqtrade:develop_freqai`. This image contains the regular FreqAI dependencies. Similar to native installs, Catboost will not be available on ARM based devices.
### FreqAI position in open-source machine learning landscape
Forecasting chaotic time-series based systems, such as equity/cryptocurrency markets, requires a broad set of tools geared toward testing a wide range of hypotheses. Fortunately, a recent maturation of robust machine learning libraries (e.g. `scikit-learn`) has opened up a wide range of research possibilities. Scientists from a diverse range of fields can now easily prototype their studies on an abundance of established machine learning algorithms. Similarly, these user-friendly libraries enable "citzen scientists" to use their basic Python skills for data-exploration. However, leveraging these machine learning libraries on historical and live chaotic data sources can be logistically difficult and expensive. Additionally, robust data-collection, storage, and handling presents a disparate challenge. [`FreqAI`](#freqai) aims to provide a generalized and extensible open-sourced framework geared toward live deployments of adaptive modeling for market forecasting. The `FreqAI` framework is effectively a sandbox for the rich world of open-source machine learning libraries. Inside the `FreqAI` sandbox, users find they can combine a wide variety of third-party libraries to test creative hypotheses on a free live 24/7 chaotic data source - cryptocurrency exchange data.
Forecasting chaotic time-series based systems, such as equity/cryptocurrency markets, requires a broad set of tools geared toward testing a wide range of hypotheses. Fortunately, a recent maturation of robust machine learning libraries (e.g. `scikit-learn`) has opened up a wide range of research possibilities. Scientists from a diverse range of fields can now easily prototype their studies on an abundance of established machine learning algorithms. Similarly, these user-friendly libraries enable "citzen scientists" to use their basic Python skills for data exploration. However, leveraging these machine learning libraries on historical and live chaotic data sources can be logistically difficult and expensive. Additionally, robust data collection, storage, and handling presents a disparate challenge. [`FreqAI`](#freqai) aims to provide a generalized and extensible open-sourced framework geared toward live deployments of adaptive modeling for market forecasting. The `FreqAI` framework is effectively a sandbox for the rich world of open-source machine learning libraries. Inside the `FreqAI` sandbox, users find they can combine a wide variety of third-party libraries to test creative hypotheses on a free live 24/7 chaotic data source - cryptocurrency exchange data.
### Citing FreqAI

View File

@@ -52,6 +52,7 @@ Please read the [exchange specific notes](exchanges.md) to learn about eventual,
- [X] [Binance](https://www.binance.com/)
- [X] [Gate.io](https://www.gate.io/ref/6266643)
- [X] [OKX](https://okx.com/)
- [X] [Bybit](https://bybit.com/)
Please make sure to read the [exchange specific notes](exchanges.md), as well as the [trading with leverage](leverage.md) documentation before diving in.

View File

@@ -30,6 +30,12 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito
!!! Warning "Up-to-date clock"
The clock on the system running the bot must be accurate, synchronized to a NTP server frequently enough to avoid problems with communication to the exchanges.
!!! Error "Running setup.py install for gym did not run successfully."
If you get an error related with gym we suggest you to downgrade setuptools it to version 65.5.0 you can do it with the following command:
```bash
pip install setuptools==65.5.0
```
------
## Requirements
@@ -284,10 +290,8 @@ cd freqtrade
#### Freqtrade install: Conda Environment
Prepare conda-freqtrade environment, using file `environment.yml`, which exist in main freqtrade directory
```bash
conda env create -n freqtrade-conda -f environment.yml
conda create --name freqtrade python=3.10
```
!!! Note "Creating Conda Environment"
@@ -296,12 +300,9 @@ conda env create -n freqtrade-conda -f environment.yml
```bash
# choose your own packages
conda env create -n [name of the environment] [python version] [packages]
# point to file with packages
conda env create -n [name of the environment] -f [file]
```
#### Enter/exit freqtrade-conda environment
#### Enter/exit freqtrade environment
To check available environments, type
@@ -313,7 +314,7 @@ Enter installed environment
```bash
# enter conda environment
conda activate freqtrade-conda
conda activate freqtrade
# exit conda environment - don't do it now
conda deactivate
@@ -323,6 +324,7 @@ Install last python dependencies with pip
```bash
python3 -m pip install --upgrade pip
python3 -m pip install -r requirements.txt
python3 -m pip install -e .
```
@@ -330,7 +332,7 @@ Patch conda libta-lib (Linux only)
```bash
# Ensure that the environment is active!
conda activate freqtrade-conda
conda activate freqtrade
cd build_helpers
bash install_ta-lib.sh ${CONDA_PREFIX} nosudo
@@ -349,8 +351,8 @@ conda env list
# activate base environment
conda activate
# activate freqtrade-conda environment
conda activate freqtrade-conda
# activate freqtrade environment
conda activate freqtrade
#deactivate any conda environments
conda deactivate

View File

@@ -1,6 +1,6 @@
markdown==3.3.7
mkdocs==1.4.2
mkdocs-material==9.0.5
mkdocs-material==9.1.3
mdx_truly_sane_lists==1.3
pymdown-extensions==9.9.1
pymdown-extensions==9.10
jinja2==3.1.2

View File

@@ -163,7 +163,7 @@ python3 scripts/rest_client.py --config rest_config.json <command> [optional par
| `strategy <strategy>` | Get specific Strategy content. **Alpha**
| `available_pairs` | List available backtest data. **Alpha**
| `version` | Show version.
| `sysinfo` | Show informations about the system load.
| `sysinfo` | Show information about the system load.
| `health` | Show bot health (last bot loop).
!!! Warning "Alpha status"
@@ -192,6 +192,11 @@ blacklist
:param add: List of coins to add (example: "BNB/BTC")
cancel_open_order
Cancel open order for trade.
:param trade_id: Cancels open orders for this trade.
count
Return the amount of open trades.
@@ -274,7 +279,6 @@ reload_config
Reload configuration.
show_config
Returns part of the configuration, relevant for trading operations.
start
@@ -320,6 +324,7 @@ version
whitelist
Show the current whitelist.
```
### Message WebSocket

View File

@@ -24,7 +24,7 @@ These modes can be configured with these values:
```
!!! Note
Stoploss on exchange is only supported for Binance (stop-loss-limit), Huobi (stop-limit), Kraken (stop-loss-market, stop-loss-limit), Gateio (stop-limit), and Kucoin (stop-limit and stop-market) as of now.
Stoploss on exchange is only supported for Binance (stop-loss-limit), Huobi (stop-limit), Kraken (stop-loss-market, stop-loss-limit), Gate (stop-limit), and Kucoin (stop-limit and stop-market) as of now.
<ins>Do not set too low/tight stoploss value if using stop loss on exchange!</ins>
If set to low/tight then you have greater risk of missing fill on the order and stoploss will not work.
@@ -52,6 +52,18 @@ The bot cannot do these every 5 seconds (at each iteration), otherwise it would
So this parameter will tell the bot how often it should update the stoploss order. The default value is 60 (1 minute).
This same logic will reapply a stoploss order on the exchange should you cancel it accidentally.
### stoploss_price_type
!!! Warning "Only applies to futures"
`stoploss_price_type` only applies to futures markets (on exchanges where it's available).
Freqtrade will perform a validation of this setting on startup, failing to start if an invalid setting for your exchange has been selected.
Supported price types are gonna differs between each exchanges. Please check with your exchange on which price types it supports.
Stoploss on exchange on futures markets can trigger on different price types.
The naming for these prices in exchange terminology often varies, but is usually something around "last" (or "contract price" ), "mark" and "index".
Acceptable values for this setting are `"last"`, `"mark"` and `"index"` - which freqtrade will transfer automatically to the corresponding API type, and place the [stoploss on exchange](#stoploss_on_exchange-and-stoploss_on_exchange_limit_ratio) order correspondingly.
### force_exit
`force_exit` is an optional value, which defaults to the same value as `exit` and is used when sending a `/forceexit` command from Telegram or from the Rest API.

View File

@@ -316,11 +316,11 @@ class AwesomeStrategy(IStrategy):
# evaluate highest to lowest, so that highest possible stop is used
if current_profit > 0.40:
return stoploss_from_open(0.25, current_profit, is_short=trade.is_short)
return stoploss_from_open(0.25, current_profit, is_short=trade.is_short, leverage=trade.leverage)
elif current_profit > 0.25:
return stoploss_from_open(0.15, current_profit, is_short=trade.is_short)
return stoploss_from_open(0.15, current_profit, is_short=trade.is_short, leverage=trade.leverage)
elif current_profit > 0.20:
return stoploss_from_open(0.07, current_profit, is_short=trade.is_short)
return stoploss_from_open(0.07, current_profit, is_short=trade.is_short, leverage=trade.leverage)
# return maximum stoploss value, keeping current stoploss price unchanged
return 1

View File

@@ -881,7 +881,7 @@ All columns of the informative dataframe will be available on the returning data
### *stoploss_from_open()*
Stoploss values returned from `custom_stoploss` must specify a percentage relative to `current_rate`, but sometimes you may want to specify a stoploss relative to the open price instead. `stoploss_from_open()` is a helper function to calculate a stoploss value that can be returned from `custom_stoploss` which will be equivalent to the desired percentage above the open price.
Stoploss values returned from `custom_stoploss` must specify a percentage relative to `current_rate`, but sometimes you may want to specify a stoploss relative to the entry point instead. `stoploss_from_open()` is a helper function to calculate a stoploss value that can be returned from `custom_stoploss` which will be equivalent to the desired trade profit above the entry point.
??? Example "Returning a stoploss relative to the open price from the custom stoploss function"
@@ -889,6 +889,8 @@ Stoploss values returned from `custom_stoploss` must specify a percentage relati
If we want a stop price at 7% above the open price we can call `stoploss_from_open(0.07, current_profit, False)` which will return `0.1157024793`. 11.57% below $121 is $107, which is the same as 7% above $100.
This function will consider leverage - so at 10x leverage, the actual stoploss would be 0.7% above $100 (0.7% * 10x = 7%).
``` python
@@ -907,7 +909,7 @@ Stoploss values returned from `custom_stoploss` must specify a percentage relati
# once the profit has risen above 10%, keep the stoploss at 7% above the open price
if current_profit > 0.10:
return stoploss_from_open(0.07, current_profit, is_short=trade.is_short)
return stoploss_from_open(0.07, current_profit, is_short=trade.is_short, leverage=trade.leverage)
return 1
@@ -954,12 +956,14 @@ In some situations it may be confusing to deal with stops relative to current ra
## Additional data (Wallets)
The strategy provides access to the `Wallets` object. This contains the current balances on the exchange.
The strategy provides access to the `wallets` object. This contains the current balances on the exchange.
!!! Note
Wallets is not available during backtesting / hyperopt.
!!! Note "Backtesting / Hyperopt"
Wallets behaves differently depending on the function it's called.
Within `populate_*()` methods, it'll return the full wallet as configured.
Within [callbacks](strategy-callbacks.md), you'll get the wallet state corresponding to the actual simulated wallet at that point in the simulation process.
Please always check if `Wallets` is available to avoid failures during backtesting.
Please always check if `wallets` is available to avoid failures during backtesting.
``` python
if self.wallets:
@@ -1036,11 +1040,10 @@ from datetime import timedelta, datetime, timezone
# Within populate indicators (or populate_buy):
if self.config['runmode'].value in ('live', 'dry_run'):
# fetch closed trades for the last 2 days
trades = Trade.get_trades([Trade.pair == metadata['pair'],
Trade.open_date > datetime.utcnow() - timedelta(days=2),
Trade.is_open.is_(False),
]).all()
# fetch closed trades for the last 2 days
trades = Trade.get_trades_proxy(
pair=metadata['pair'], is_open=False,
open_date=datetime.now(timezone.utc) - timedelta(days=2))
# Analyze the conditions you'd like to lock the pair .... will probably be different for every strategy
sumprofit = sum(trade.close_profit for trade in trades)
if sumprofit < 0:

View File

@@ -80,6 +80,7 @@ from freqtrade.resolvers import StrategyResolver
from freqtrade.data.dataprovider import DataProvider
strategy = StrategyResolver.load_strategy(config)
strategy.dp = DataProvider(config, None, None)
strategy.ft_bot_start()
# Generate buy/sell signals using strategy
df = strategy.analyze_ticker(candles, {'pair': pair})

View File

@@ -152,7 +152,7 @@ You can create your own keyboard in `config.json`:
!!! Note "Supported Commands"
Only the following commands are allowed. Command arguments are not supported!
`/start`, `/stop`, `/status`, `/status table`, `/trades`, `/profit`, `/performance`, `/daily`, `/stats`, `/count`, `/locks`, `/balance`, `/stopentry`, `/reload_config`, `/show_config`, `/logs`, `/whitelist`, `/blacklist`, `/edge`, `/help`, `/version`
`/start`, `/stop`, `/status`, `/status table`, `/trades`, `/profit`, `/performance`, `/daily`, `/stats`, `/count`, `/locks`, `/balance`, `/stopentry`, `/reload_config`, `/show_config`, `/logs`, `/whitelist`, `/blacklist`, `/edge`, `/help`, `/version`, `/marketdir`
## Telegram commands
@@ -162,26 +162,34 @@ official commands. You can ask at any moment for help with `/help`.
| Command | Description |
|----------|-------------|
| **System commands**
| `/start` | Starts the trader
| `/stop` | Stops the trader
| `/stopbuy | /stopentry` | Stops the trader from opening new trades. Gracefully closes open trades according to their rules.
| `/reload_config` | Reloads the configuration file
| `/show_config` | Shows part of the current configuration with relevant settings to operation
| `/logs [limit]` | Show last log messages.
| `/help` | Show help message
| `/version` | Show version
| **Status** |
| `/status` | Lists all open trades
| `/status <trade_id>` | Lists one or more specific trade. Separate multiple <trade_id> with a blank space.
| `/status table` | List all open trades in a table format. Pending buy orders are marked with an asterisk (*) Pending sell orders are marked with a double asterisk (**)
| `/trades [limit]` | List all recently closed trades in a table format.
| `/delete <trade_id>` | Delete a specific trade from the Database. Tries to close open orders. Requires manual handling of this trade on the exchange.
| `/count` | Displays number of trades used and available
| `/locks` | Show currently locked pairs.
| `/unlock <pair or lock_id>` | Remove the lock for this pair (or for this lock id).
| `/profit [<n>]` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default)
| `/marketdir [long | short | even | none]` | Updates the user managed variable that represents the current market direction. If no direction is provided, the currently set direction will be displayed.
| **Modify Trade states** |
| `/forceexit <trade_id> | /fx <tradeid>` | Instantly exits the given trade (Ignoring `minimum_roi`).
| `/forceexit all | /fx all` | Instantly exits all open trades (Ignoring `minimum_roi`).
| `/fx` | alias for `/forceexit`
| `/forcelong <pair> [rate]` | Instantly buys the given pair. Rate is optional and only applies to limit orders. (`force_entry_enable` must be set to True)
| `/forceshort <pair> [rate]` | Instantly shorts the given pair. Rate is optional and only applies to limit orders. This will only work on non-spot markets. (`force_entry_enable` must be set to True)
| `/delete <trade_id>` | Delete a specific trade from the Database. Tries to close open orders. Requires manual handling of this trade on the exchange.
| `/cancel_open_order <trade_id> | /coo <trade_id>` | Cancel an open order for a trade.
| **Metrics** |
| `/profit [<n>]` | Display a summary of your profit/loss from close trades and some stats about your performance, over the last n days (all trades by default)
| `/performance` | Show performance of each finished trade grouped by pair
| `/balance` | Show account balance per currency
| `/daily <n>` | Shows profit or loss per day, over the last n days (n defaults to 7)
@@ -193,8 +201,7 @@ official commands. You can ask at any moment for help with `/help`.
| `/whitelist [sorted] [baseonly]` | Show the current whitelist. Optionally display in alphabetical order and/or with just the base currency of each pairing.
| `/blacklist [pair]` | Show the current blacklist, or adds a pair to the blacklist.
| `/edge` | Show validated pairs by Edge if it is enabled.
| `/help` | Show help message
| `/version` | Show version
## Telegram commands in action
@@ -236,7 +243,7 @@ Enter Tag is configurable via Strategy.
> **Enter Tag:** Awesome Long Signal
> **Open Rate:** `0.00007489`
> **Current Rate:** `0.00007489`
> **Current Profit:** `12.95%`
> **Unrealized Profit:** `12.95%`
> **Stoploss:** `0.00007389 (-0.02%)`
### /status table
@@ -410,3 +417,27 @@ ARDR/ETH 0.366667 0.143059 -0.01
### /version
> **Version:** `0.14.3`
### /marketdir
If a market direction is provided the command updates the user managed variable that represents the current market direction.
This variable is not set to any valid market direction on bot startup and must be set by the user. The example below is for `/marketdir long`:
```
Successfully updated marketdirection from none to long.
```
If no market direction is provided the command outputs the currently set market directions. The example below is for `/marketdir`:
```
Currently set marketdirection: even
```
You can use the market direction in your strategy via `self.market_direction`.
!!! Warning "Bot restarts"
Please note that the market direction is not persisted, and will be reset after a bot restart/reload.
!!! Danger "Backtesting"
As this value/variable is intended to be changed manually in dry/live trading.
Strategies using `market_direction` will probably not produce reliable, reproducible results (changes to this variable will not be reflected for backtesting). Use at your own risk.

View File

@@ -955,3 +955,47 @@ Print trades with id 2 and 3 as json
``` bash
freqtrade show-trades --db-url sqlite:///tradesv3.sqlite --trade-ids 2 3 --print-json
```
### Strategy-Updater
Updates listed strategies or all strategies within the strategies folder to be v3 compliant.
If the command runs without --strategy-list then all strategies inside the strategies folder will be converted.
Your original strategy will remain available in the `user_data/strategies_orig_updater/` directory.
!!! Warning "Conversion results"
Strategy updater will work on a "best effort" approach. Please do your due diligence and verify the results of the conversion.
We also recommend to run a python formatter (e.g. `black`) to format results in a sane manner.
```
usage: freqtrade strategy-updater [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
options:
-h, --help show this help message and exit
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
Provide a space-separated list of strategies to
backtest. Please note that timeframe needs to be set
either in config or via command line. When using this
together with `--export trades`, the strategy-name is
injected into the filename (so `backtest-data.json`
becomes `backtest-data-SampleStrategy.json`
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE, --log-file FILE
Log to the file specified. Special values are:
'syslog', 'journald'. See the documentation for more
details.
-V, --version show program's version number and exit
-c PATH, --config PATH
Specify configuration file (default:
`userdir/config.json` or `config.json` whichever
exists). Multiple --config options may be used. Can be
set to `-` to read config from stdin.
-d PATH, --datadir PATH, --data-dir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
```

View File

@@ -26,7 +26,7 @@ Install ta-lib according to the [ta-lib documentation](https://github.com/mrjbq7
As compiling from source on windows has heavy dependencies (requires a partial visual studio installation), there is also a repository of unofficial pre-compiled windows Wheels [here](https://www.lfd.uci.edu/~gohlke/pythonlibs/#ta-lib), which need to be downloaded and installed using `pip install TA_Lib-0.4.25-cp38-cp38-win_amd64.whl` (make sure to use the version matching your python version).
Freqtrade provides these dependencies for the latest 3 Python versions (3.8, 3.9 and 3.10) and for 64bit Windows.
Freqtrade provides these dependencies for the latest 3 Python versions (3.8, 3.9, 3.10 and 3.11) and for 64bit Windows.
Other versions must be downloaded from the above link.
``` powershell

View File

@@ -1,75 +0,0 @@
name: freqtrade
channels:
- conda-forge
# - defaults
dependencies:
# 1/4 req main
- python>=3.8,<=3.10
- numpy
- pandas
- pip
- py-find-1st
- aiohttp
- SQLAlchemy
- python-telegram-bot
- arrow
- cachetools
- requests
- urllib3
- jsonschema
- TA-Lib
- tabulate
- jinja2
- blosc
- sdnotify
- fastapi
- uvicorn
- pyjwt
- aiofiles
- psutil
- colorama
- questionary
- prompt-toolkit
- schedule
- python-dateutil
- joblib
- pyarrow
# ============================
# 2/4 req dev
- coveralls
- flake8
- mypy
- pytest
- pytest-asyncio
- pytest-cov
- pytest-mock
- isort
- nbconvert
# ============================
# 3/4 req hyperopt
- scipy
- scikit-learn
- filelock
- scikit-optimize
- progressbar2
# ============================
# 4/4 req plot
- plotly
- jupyter
- pip:
- pycoingecko
# - py_find_1st
- tables
- pytest-random-order
- ccxt
- flake8-tidy-imports
- -e .
# - python-rapidjso

View File

@@ -1,5 +1,5 @@
""" Freqtrade bot """
__version__ = '2023.1'
__version__ = '2023.3.dev'
if 'dev' in __version__:
from pathlib import Path

0
freqtrade/__main__.py Normal file → Executable file
View File

View File

@@ -22,5 +22,6 @@ from freqtrade.commands.optimize_commands import (start_backtesting, start_backt
start_edge, start_hyperopt)
from freqtrade.commands.pairlist_commands import start_test_pairlist
from freqtrade.commands.plot_commands import start_plot_dataframe, start_plot_profit
from freqtrade.commands.strategy_utils_commands import start_strategy_update
from freqtrade.commands.trade_commands import start_trading
from freqtrade.commands.webserver_commands import start_webserver

4
freqtrade/commands/analyze_commands.py Executable file → Normal file
View File

@@ -40,8 +40,8 @@ def setup_analyze_configuration(args: Dict[str, Any], method: RunMode) -> Dict[s
if (not Path(signals_file).exists()):
raise OperationalException(
(f"Cannot find latest backtest signals file: {signals_file}."
"Run backtesting with `--export signals`.")
f"Cannot find latest backtest signals file: {signals_file}."
"Run backtesting with `--export signals`."
)
return config

View File

@@ -111,10 +111,13 @@ ARGS_ANALYZE_ENTRIES_EXITS = ["exportfilename", "analysis_groups", "enter_reason
NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes",
"list-markets", "list-pairs", "list-strategies", "list-freqaimodels",
"list-data", "hyperopt-list", "hyperopt-show", "backtest-filter",
"plot-dataframe", "plot-profit", "show-trades", "trades-to-ohlcv"]
"plot-dataframe", "plot-profit", "show-trades", "trades-to-ohlcv",
"strategy-updater"]
NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-strategy"]
ARGS_STRATEGY_UTILS = ["strategy_list", "strategy_path", "recursive_strategy_search"]
class Arguments:
"""
@@ -198,8 +201,8 @@ class Arguments:
start_list_freqAI_models, start_list_markets,
start_list_strategies, start_list_timeframes,
start_new_config, start_new_strategy, start_plot_dataframe,
start_plot_profit, start_show_trades, start_test_pairlist,
start_trading, start_webserver)
start_plot_profit, start_show_trades, start_strategy_update,
start_test_pairlist, start_trading, start_webserver)
subparsers = self.parser.add_subparsers(dest='command',
# Use custom message when no subhandler is added
@@ -440,3 +443,11 @@ class Arguments:
parents=[_common_parser])
webserver_cmd.set_defaults(func=start_webserver)
self._build_args(optionlist=ARGS_WEBSERVER, parser=webserver_cmd)
# Add strategy_updater subcommand
strategy_updater_cmd = subparsers.add_parser('strategy-updater',
help='updates outdated strategy'
'files to the current version',
parents=[_common_parser])
strategy_updater_cmd.set_defaults(func=start_strategy_update)
self._build_args(optionlist=ARGS_STRATEGY_UTILS, parser=strategy_updater_cmd)

View File

@@ -108,7 +108,7 @@ def ask_user_config() -> Dict[str, Any]:
"binance",
"binanceus",
"bittrex",
"gateio",
"gate",
"huobi",
"kraken",
"kucoin",
@@ -123,7 +123,7 @@ def ask_user_config() -> Dict[str, Any]:
"message": "Do you want to trade Perpetual Swaps (perpetual futures)?",
"default": False,
"filter": lambda val: 'futures' if val else 'spot',
"when": lambda x: x["exchange_name"] in ['binance', 'gateio', 'okx'],
"when": lambda x: x["exchange_name"] in ['binance', 'gate', 'okx'],
},
{
"type": "autocomplete",

View File

@@ -5,7 +5,7 @@ from datetime import datetime, timedelta
from typing import Any, Dict, List
from freqtrade.configuration import TimeRange, setup_utils_configuration
from freqtrade.constants import DATETIME_PRINT_FORMAT
from freqtrade.constants import DATETIME_PRINT_FORMAT, Config
from freqtrade.data.converter import convert_ohlcv_format, convert_trades_format
from freqtrade.data.history import (convert_trades_to_ohlcv, refresh_backtest_ohlcv_data,
refresh_backtest_trades_data)
@@ -20,15 +20,24 @@ from freqtrade.util.binance_mig import migrate_binance_futures_data
logger = logging.getLogger(__name__)
def _data_download_sanity(config: Config) -> None:
if 'days' in config and 'timerange' in config:
raise OperationalException("--days and --timerange are mutually exclusive. "
"You can only specify one or the other.")
if 'pairs' not in config:
raise OperationalException(
"Downloading data requires a list of pairs. "
"Please check the documentation on how to configure this.")
def start_download_data(args: Dict[str, Any]) -> None:
"""
Download data (former download_backtest_data.py script)
"""
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
if 'days' in config and 'timerange' in config:
raise OperationalException("--days and --timerange are mutually exclusive. "
"You can only specify one or the other.")
_data_download_sanity(config)
timerange = TimeRange()
if 'days' in config:
time_since = (datetime.now() - timedelta(days=config['days'])).strftime("%Y%m%d")
@@ -40,11 +49,6 @@ def start_download_data(args: Dict[str, Any]) -> None:
# Remove stake-currency to skip checks which are not relevant for datadownload
config['stake_currency'] = ''
if 'pairs' not in config:
raise OperationalException(
"Downloading data requires a list of pairs. "
"Please check the documentation on how to configure this.")
pairs_not_available: List[str] = []
# Init exchange

View File

@@ -1,7 +1,7 @@
import logging
from typing import Any, Dict
from sqlalchemy import func
from sqlalchemy import func, select
from freqtrade.configuration.config_setup import setup_utils_configuration
from freqtrade.enums import RunMode
@@ -20,7 +20,7 @@ def start_convert_db(args: Dict[str, Any]) -> None:
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
init_db(config['db_url'])
session_target = Trade._session
session_target = Trade.session
init_db(config['db_url_from'])
logger.info("Starting db migration.")
@@ -36,16 +36,16 @@ def start_convert_db(args: Dict[str, Any]) -> None:
session_target.commit()
for pairlock in PairLock.query:
for pairlock in PairLock.get_all_locks():
pairlock_count += 1
make_transient(pairlock)
session_target.add(pairlock)
session_target.commit()
# Update sequences
max_trade_id = session_target.query(func.max(Trade.id)).scalar()
max_order_id = session_target.query(func.max(Order.id)).scalar()
max_pairlock_id = session_target.query(func.max(PairLock.id)).scalar()
max_trade_id = session_target.scalar(select(func.max(Trade.id)))
max_order_id = session_target.scalar(select(func.max(Order.id)))
max_pairlock_id = session_target.scalar(select(func.max(PairLock.id)))
set_sequence_ids(session_target.get_bind(),
trade_id=max_trade_id,

0
freqtrade/commands/hyperopt_commands.py Executable file → Normal file
View File

View File

@@ -0,0 +1,55 @@
import logging
import sys
import time
from pathlib import Path
from typing import Any, Dict
from freqtrade.configuration import setup_utils_configuration
from freqtrade.enums import RunMode
from freqtrade.resolvers import StrategyResolver
from freqtrade.strategy.strategyupdater import StrategyUpdater
logger = logging.getLogger(__name__)
def start_strategy_update(args: Dict[str, Any]) -> None:
"""
Start the strategy updating script
:param args: Cli args from Arguments()
:return: None
"""
if sys.version_info == (3, 8): # pragma: no cover
sys.exit("Freqtrade strategy updater requires Python version >= 3.9")
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
strategy_objs = StrategyResolver.search_all_objects(
config, enum_failed=False, recursive=config.get('recursive_strategy_search', False))
filtered_strategy_objs = []
if args['strategy_list']:
filtered_strategy_objs = [
strategy_obj for strategy_obj in strategy_objs
if strategy_obj['name'] in args['strategy_list']
]
else:
# Use all available entries.
filtered_strategy_objs = strategy_objs
processed_locations = set()
for strategy_obj in filtered_strategy_objs:
if strategy_obj['location'] not in processed_locations:
processed_locations.add(strategy_obj['location'])
start_conversion(strategy_obj, config)
def start_conversion(strategy_obj, config):
print(f"Conversion of {Path(strategy_obj['location']).name} started.")
instance_strategy_updater = StrategyUpdater()
start = time.perf_counter()
instance_strategy_updater.start(config, strategy_obj)
elapsed = time.perf_counter() - start
print(f"Conversion of {Path(strategy_obj['location']).name} took {elapsed:.1f} seconds.")

View File

@@ -1,4 +1,5 @@
import logging
import signal
from typing import Any, Dict
@@ -12,15 +13,20 @@ def start_trading(args: Dict[str, Any]) -> int:
# Import here to avoid loading worker module when it's not used
from freqtrade.worker import Worker
def term_handler(signum, frame):
# Raise KeyboardInterrupt - so we can handle it in the same way as Ctrl-C
raise KeyboardInterrupt()
# Create and run worker
worker = None
try:
signal.signal(signal.SIGTERM, term_handler)
worker = Worker(args)
worker.run()
except Exception as e:
logger.error(str(e))
logger.exception("Fatal exception!")
except KeyboardInterrupt:
except (KeyboardInterrupt):
logger.info('SIGINT received, aborting ...')
finally:
if worker:

View File

@@ -27,10 +27,7 @@ def _extend_validator(validator_class):
if 'default' in subschema:
instance.setdefault(prop, subschema['default'])
for error in validate_properties(
validator, properties, instance, schema,
):
yield error
yield from validate_properties(validator, properties, instance, schema)
return validators.extend(
validator_class, {'properties': set_defaults}

View File

@@ -32,7 +32,7 @@ def flat_vars_to_nested_dict(env_dict: Dict[str, Any], prefix: str) -> Dict[str,
:param prefix: Prefix to consider (usually FREQTRADE__)
:return: Nested dict based on available and relevant variables.
"""
no_convert = ['CHAT_ID']
no_convert = ['CHAT_ID', 'PASSWORD']
relevant_vars: Dict[str, Any] = {}
for env_var, val in sorted(env_dict.items()):

View File

@@ -58,7 +58,7 @@ def load_config_file(path: str) -> Dict[str, Any]:
"""
try:
# Read config from stdin if requested in the options
with open(path) if path != '-' else sys.stdin as file:
with Path(path).open() if path != '-' else sys.stdin as file:
config = rapidjson.load(file, parse_mode=CONFIG_PARSE_MODE)
except FileNotFoundError:
raise OperationalException(

View File

@@ -5,7 +5,7 @@ bot constants
"""
from typing import Any, Dict, List, Literal, Tuple
from freqtrade.enums import CandleType, RPCMessageType
from freqtrade.enums import CandleType, PriceType, RPCMessageType
DEFAULT_CONFIG = 'config.json'
@@ -25,6 +25,7 @@ PRICING_SIDES = ['ask', 'bid', 'same', 'other']
ORDERTYPE_POSSIBILITIES = ['limit', 'market']
_ORDERTIF_POSSIBILITIES = ['GTC', 'FOK', 'IOC', 'PO']
ORDERTIF_POSSIBILITIES = _ORDERTIF_POSSIBILITIES + [t.lower() for t in _ORDERTIF_POSSIBILITIES]
STOPLOSS_PRICE_TYPES = [p for p in PriceType]
HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss',
'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily',
'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily',
@@ -229,6 +230,7 @@ CONF_SCHEMA = {
'default': 'market'},
'stoploss': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'stoploss_on_exchange': {'type': 'boolean'},
'stoploss_price_type': {'type': 'string', 'enum': STOPLOSS_PRICE_TYPES},
'stoploss_on_exchange_interval': {'type': 'number'},
'stoploss_on_exchange_limit_ratio': {'type': 'number', 'minimum': 0.0,
'maximum': 1.0}
@@ -544,7 +546,7 @@ CONF_SCHEMA = {
"enabled": {"type": "boolean", "default": False},
"keras": {"type": "boolean", "default": False},
"write_metrics_to_disk": {"type": "boolean", "default": False},
"purge_old_models": {"type": "boolean", "default": True},
"purge_old_models": {"type": ["boolean", "number"], "default": 2},
"conv_width": {"type": "integer", "default": 1},
"train_period_days": {"type": "integer", "default": 0},
"backtest_period_days": {"type": "number", "default": 7},
@@ -566,7 +568,9 @@ CONF_SCHEMA = {
"shuffle": {"type": "boolean", "default": False},
"nu": {"type": "number", "default": 0.1}
},
}
},
"shuffle_after_split": {"type": "boolean", "default": False},
"buffer_train_data_candles": {"type": "integer", "default": 0}
},
"required": ["include_timeframes", "include_corr_pairlist", ]
},
@@ -584,6 +588,7 @@ CONF_SCHEMA = {
"rl_config": {
"type": "object",
"properties": {
"drop_ohlc_from_features": {"type": "boolean", "default": False},
"train_cycles": {"type": "integer"},
"max_trade_duration_candles": {"type": "integer"},
"add_state_info": {"type": "boolean", "default": False},
@@ -679,6 +684,7 @@ EntryExit = Literal['entry', 'exit']
BuySell = Literal['buy', 'sell']
MakerTaker = Literal['maker', 'taker']
BidAsk = Literal['bid', 'ask']
OBLiteral = Literal['asks', 'bids']
Config = Dict[str, Any]
IntOrInf = float

View File

@@ -346,7 +346,7 @@ def evaluate_result_multi(results: pd.DataFrame, timeframe: str,
return df_final[df_final['open_trades'] > max_open_trades]
def trade_list_to_dataframe(trades: List[LocalTrade]) -> pd.DataFrame:
def trade_list_to_dataframe(trades: Union[List[Trade], List[LocalTrade]]) -> pd.DataFrame:
"""
Convert list of Trade objects to pandas Dataframe
:param trades: List of trade objects
@@ -373,7 +373,7 @@ def load_trades_from_db(db_url: str, strategy: Optional[str] = None) -> pd.DataF
filters = []
if strategy:
filters.append(Trade.strategy == strategy)
trades = trade_list_to_dataframe(Trade.get_trades(filters).all())
trades = trade_list_to_dataframe(list(Trade.get_trades(filters).all()))
return trades

View File

@@ -9,7 +9,7 @@ from collections import deque
from datetime import datetime, timezone
from typing import Any, Dict, List, Optional, Tuple
from pandas import DataFrame, to_timedelta
from pandas import DataFrame, Timedelta, Timestamp, to_timedelta
from freqtrade.configuration import TimeRange
from freqtrade.constants import (FULL_DATAFRAME_THRESHOLD, Config, ListPairsWithTimeframes,
@@ -18,6 +18,7 @@ from freqtrade.data.history import load_pair_history
from freqtrade.enums import CandleType, RPCMessageType, RunMode
from freqtrade.exceptions import ExchangeError, OperationalException
from freqtrade.exchange import Exchange, timeframe_to_seconds
from freqtrade.exchange.types import OrderBook
from freqtrade.misc import append_candles_to_dataframe
from freqtrade.rpc import RPCManager
from freqtrade.util import PeriodicCache
@@ -206,9 +207,11 @@ class DataProvider:
existing_df, _ = self.__producer_pairs_df[producer_name][pair_key]
# CHECK FOR MISSING CANDLES
timeframe_delta = to_timedelta(timeframe) # Convert the timeframe to a timedelta for pandas
local_last = existing_df.iloc[-1]['date'] # We want the last date from our copy
incoming_first = dataframe.iloc[0]['date'] # We want the first date from the incoming
# Convert the timeframe to a timedelta for pandas
timeframe_delta: Timedelta = to_timedelta(timeframe)
local_last: Timestamp = existing_df.iloc[-1]['date'] # We want the last date from our copy
# We want the first date from the incoming
incoming_first: Timestamp = dataframe.iloc[0]['date']
# Remove existing candles that are newer than the incoming first candle
existing_df1 = existing_df[existing_df['date'] < incoming_first]
@@ -221,7 +224,7 @@ class DataProvider:
# we missed some candles between our data and the incoming
# so return False and candle_difference.
if candle_difference > 1:
return (False, candle_difference)
return (False, int(candle_difference))
if existing_df1.empty:
appended_df = dataframe
else:
@@ -421,10 +424,8 @@ class DataProvider:
"""
if self._exchange is None:
raise OperationalException(NO_EXCHANGE_EXCEPTION)
if helping_pairs:
self._exchange.refresh_latest_ohlcv(pairlist + helping_pairs)
else:
self._exchange.refresh_latest_ohlcv(pairlist)
final_pairs = (pairlist + helping_pairs) if helping_pairs else pairlist
self._exchange.refresh_latest_ohlcv(final_pairs)
@property
def available_pairs(self) -> ListPairsWithTimeframes:
@@ -487,7 +488,7 @@ class DataProvider:
except ExchangeError:
return {}
def orderbook(self, pair: str, maximum: int) -> Dict[str, List]:
def orderbook(self, pair: str, maximum: int) -> OrderBook:
"""
Fetch latest l2 orderbook data
Warning: Does a network request - so use with common sense.

6
freqtrade/data/entryexitanalysis.py Executable file → Normal file
View File

@@ -24,9 +24,9 @@ def _load_signal_candles(backtest_dir: Path):
scpf = Path(backtest_dir.parent / f"{backtest_dir.stem}_signals.pkl")
try:
scp = open(scpf, "rb")
signal_candles = joblib.load(scp)
logger.info(f"Loaded signal candles: {str(scpf)}")
with scpf.open("rb") as scp:
signal_candles = joblib.load(scp)
logger.info(f"Loaded signal candles: {str(scpf)}")
except Exception as e:
logger.error("Cannot load signal candles from pickled results: ", e)

View File

@@ -308,7 +308,7 @@ class IDataHandler(ABC):
timerange=timerange_startup,
candle_type=candle_type
)
if self._check_empty_df(pairdf, pair, timeframe, candle_type, warn_no_data, True):
if self._check_empty_df(pairdf, pair, timeframe, candle_type, warn_no_data):
return pairdf
else:
enddate = pairdf.iloc[-1]['date']
@@ -316,7 +316,7 @@ class IDataHandler(ABC):
if timerange_startup:
self._validate_pairdata(pair, pairdf, timeframe, candle_type, timerange_startup)
pairdf = trim_dataframe(pairdf, timerange_startup)
if self._check_empty_df(pairdf, pair, timeframe, candle_type, warn_no_data):
if self._check_empty_df(pairdf, pair, timeframe, candle_type, warn_no_data, True):
return pairdf
# incomplete candles should only be dropped if we didn't trim the end beforehand.

View File

@@ -195,7 +195,7 @@ class Edge:
def stake_amount(self, pair: str, free_capital: float,
total_capital: float, capital_in_trade: float) -> float:
stoploss = self.stoploss(pair)
stoploss = self.get_stoploss(pair)
available_capital = (total_capital + capital_in_trade) * self._capital_ratio
allowed_capital_at_risk = available_capital * self._allowed_risk
max_position_size = abs(allowed_capital_at_risk / stoploss)
@@ -214,7 +214,7 @@ class Edge:
)
return round(position_size, 15)
def stoploss(self, pair: str) -> float:
def get_stoploss(self, pair: str) -> float:
if pair in self._cached_pairs:
return self._cached_pairs[pair].stoploss
else:

View File

@@ -5,7 +5,9 @@ from freqtrade.enums.exitchecktuple import ExitCheckTuple
from freqtrade.enums.exittype import ExitType
from freqtrade.enums.hyperoptstate import HyperoptState
from freqtrade.enums.marginmode import MarginMode
from freqtrade.enums.marketstatetype import MarketDirection
from freqtrade.enums.ordertypevalue import OrderTypeValues
from freqtrade.enums.pricetype import PriceType
from freqtrade.enums.rpcmessagetype import NO_ECHO_MESSAGES, RPCMessageType, RPCRequestType
from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode
from freqtrade.enums.signaltype import SignalDirection, SignalTagType, SignalType

View File

@@ -13,6 +13,9 @@ class CandleType(str, Enum):
FUNDING_RATE = "funding_rate"
# BORROW_RATE = "borrow_rate" # * unimplemented
def __str__(self):
return f"{self.name.lower()}"
@staticmethod
def from_string(value: str) -> 'CandleType':
if not value:

View File

@@ -0,0 +1,15 @@
from enum import Enum
class MarketDirection(Enum):
"""
Enum for various market directions.
"""
LONG = "long"
SHORT = "short"
EVEN = "even"
NONE = "none"
def __str__(self):
# convert to string
return self.value

View File

@@ -0,0 +1,8 @@
from enum import Enum
class PriceType(str, Enum):
"""Enum to distinguish possible trigger prices for stoplosses"""
LAST = "last"
MARK = "mark"
INDEX = "index"

View File

@@ -4,6 +4,7 @@ from enum import Enum
class RPCMessageType(str, Enum):
STATUS = 'status'
WARNING = 'warning'
EXCEPTION = 'exception'
STARTUP = 'startup'
ENTRY = 'entry'
@@ -37,5 +38,8 @@ class RPCRequestType(str, Enum):
WHITELIST = 'whitelist'
ANALYZED_DF = 'analyzed_df'
def __str__(self):
return self.value
NO_ECHO_MESSAGES = (RPCMessageType.ANALYZED_DF, RPCMessageType.WHITELIST, RPCMessageType.NEW_CANDLE)

View File

@@ -10,6 +10,9 @@ class SignalType(Enum):
ENTER_SHORT = "enter_short"
EXIT_SHORT = "exit_short"
def __str__(self):
return f"{self.name.lower()}"
class SignalTagType(Enum):
"""
@@ -18,7 +21,13 @@ class SignalTagType(Enum):
ENTER_TAG = "enter_tag"
EXIT_TAG = "exit_tag"
def __str__(self):
return f"{self.name.lower()}"
class SignalDirection(str, Enum):
LONG = 'long'
SHORT = 'short'
def __str__(self):
return f"{self.name.lower()}"

View File

@@ -17,7 +17,7 @@ from freqtrade.exchange.exchange_utils import (amount_to_contract_precision, amo
timeframe_to_next_date, timeframe_to_prev_date,
timeframe_to_seconds, validate_exchange,
validate_exchanges)
from freqtrade.exchange.gateio import Gateio
from freqtrade.exchange.gate import Gate
from freqtrade.exchange.hitbtc import Hitbtc
from freqtrade.exchange.huobi import Huobi
from freqtrade.exchange.kraken import Kraken

View File

@@ -7,7 +7,8 @@ from typing import Dict, List, Optional, Tuple
import arrow
import ccxt
from freqtrade.enums import CandleType, MarginMode, TradingMode
from freqtrade.constants import BuySell
from freqtrade.enums import CandleType, MarginMode, PriceType, TradingMode
from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError
from freqtrade.exchange import Exchange
from freqtrade.exchange.common import retrier
@@ -23,16 +24,22 @@ class Binance(Exchange):
_ft_has: Dict = {
"stoploss_on_exchange": True,
"stoploss_order_types": {"limit": "stop_loss_limit"},
"order_time_in_force": ['GTC', 'FOK', 'IOC'],
"order_time_in_force": ["GTC", "FOK", "IOC", "PO"],
"ohlcv_candle_limit": 1000,
"trades_pagination": "id",
"trades_pagination_arg": "fromId",
"l2_limit_range": [5, 10, 20, 50, 100, 500, 1000],
"ccxt_futures_name": "swap"
}
_ft_has_futures: Dict = {
"stoploss_order_types": {"limit": "stop", "market": "stop_market"},
"order_time_in_force": ["GTC", "FOK", "IOC"],
"tickers_have_price": False,
"floor_leverage": True,
"stop_price_type_field": "workingType",
"stop_price_type_value_mapping": {
PriceType.LAST: "CONTRACT_PRICE",
PriceType.MARK: "MARK_PRICE",
},
}
_supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [
@@ -42,6 +49,26 @@ class Binance(Exchange):
(TradingMode.FUTURES, MarginMode.ISOLATED)
]
def _get_params(
self,
side: BuySell,
ordertype: str,
leverage: float,
reduceOnly: bool,
time_in_force: str = 'GTC',
) -> Dict:
params = super()._get_params(side, ordertype, leverage, reduceOnly, time_in_force)
if (
time_in_force == 'PO'
and ordertype != 'market'
and self.trading_mode == TradingMode.SPOT
# Only spot can do post only orders
):
params.pop('timeInForce')
params['postOnly'] = True
return params
def get_tickers(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Tickers:
tickers = super().get_tickers(symbols=symbols, cached=cached)
if self.trading_mode == TradingMode.FUTURES:
@@ -78,33 +105,9 @@ class Binance(Exchange):
raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError(
f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e
except ccxt.BaseError as e:
raise OperationalException(e) from e
f'Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}'
) from e
@retrier
def _set_leverage(
self,
leverage: float,
pair: Optional[str] = None,
trading_mode: Optional[TradingMode] = None
):
"""
Set's the leverage before making a trade, in order to not
have the same leverage on every trade
"""
trading_mode = trading_mode or self.trading_mode
if self._config['dry_run'] or trading_mode != TradingMode.FUTURES:
return
try:
self._api.set_leverage(symbol=pair, leverage=round(leverage))
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError(
f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e
except ccxt.BaseError as e:
raise OperationalException(e) from e
@@ -150,6 +153,7 @@ class Binance(Exchange):
is_short: bool,
amount: float,
stake_amount: float,
leverage: float,
wallet_balance: float, # Or margin balance
mm_ex_1: float = 0.0, # (Binance) Cross only
upnl_ex_1: float = 0.0, # (Binance) Cross only
@@ -159,11 +163,12 @@ class Binance(Exchange):
MARGIN: https://www.binance.com/en/support/faq/f6b010588e55413aa58b7d63ee0125ed
PERPETUAL: https://www.binance.com/en/support/faq/b3c689c1f50a44cabb3a84e663b81d93
:param exchange_name:
:param pair: Pair to calculate liquidation price for
:param open_rate: Entry price of position
:param is_short: True if the trade is a short, false otherwise
:param amount: Absolute value of position size incl. leverage (in base currency)
:param stake_amount: Stake amount - Collateral in settle currency.
:param leverage: Leverage used for this position.
:param trading_mode: SPOT, MARGIN, FUTURES, etc.
:param margin_mode: Either ISOLATED or CROSS
:param wallet_balance: Amount of margin_mode in the wallet being used to trade
@@ -212,7 +217,7 @@ class Binance(Exchange):
leverage_tiers_path = (
Path(__file__).parent / 'binance_leverage_tiers.json'
)
with open(leverage_tiers_path) as json_file:
with leverage_tiers_path.open() as json_file:
return json_load(json_file)
else:
try:

File diff suppressed because it is too large Load Diff

View File

@@ -1,9 +1,16 @@
""" Bybit exchange subclass """
import logging
from typing import Dict, List, Tuple
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from freqtrade.enums import MarginMode, TradingMode
import ccxt
from freqtrade.constants import BuySell
from freqtrade.enums import MarginMode, PriceType, TradingMode
from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError
from freqtrade.exchange import Exchange
from freqtrade.exchange.common import retrier
from freqtrade.exchange.exchange_utils import timeframe_to_msecs
logger = logging.getLogger(__name__)
@@ -20,18 +27,27 @@ class Bybit(Exchange):
"""
_ft_has: Dict = {
"ohlcv_candle_limit": 1000,
"ccxt_futures_name": "linear",
"ohlcv_candle_limit": 200,
"ohlcv_has_history": False,
}
_ft_has_futures: Dict = {
"ohlcv_has_history": True,
"mark_ohlcv_timeframe": "4h",
"funding_fee_timeframe": "8h",
"stoploss_on_exchange": True,
"stoploss_order_types": {"limit": "limit", "market": "market"},
"stop_price_type_field": "triggerBy",
"stop_price_type_value_mapping": {
PriceType.LAST: "LastPrice",
PriceType.MARK: "MarkPrice",
PriceType.INDEX: "IndexPrice",
},
}
_supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [
# TradingMode.SPOT always supported and not required in this list
# (TradingMode.FUTURES, MarginMode.CROSS),
# (TradingMode.FUTURES, MarginMode.ISOLATED)
(TradingMode.FUTURES, MarginMode.ISOLATED)
]
@property
@@ -47,3 +63,158 @@ class Bybit(Exchange):
})
config.update(super()._ccxt_config)
return config
def market_is_future(self, market: Dict[str, Any]) -> bool:
main = super().market_is_future(market)
# For ByBit, we'll only support USDT markets for now.
return (
main and market['settle'] == 'USDT'
)
@retrier
def additional_exchange_init(self) -> None:
"""
Additional exchange initialization logic.
.api will be available at this point.
Must be overridden in child methods if required.
"""
try:
if self.trading_mode == TradingMode.FUTURES and not self._config['dry_run']:
position_mode = self._api.set_position_mode(False)
self._log_exchange_response('set_position_mode', position_mode)
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError(
f'Error in additional_exchange_init due to {e.__class__.__name__}. Message: {e}'
) from e
except ccxt.BaseError as e:
raise OperationalException(e) from e
async def _fetch_funding_rate_history(
self,
pair: str,
timeframe: str,
limit: int,
since_ms: Optional[int] = None,
) -> List[List]:
"""
Fetch funding rate history
Necessary workaround until https://github.com/ccxt/ccxt/issues/15990 is fixed.
"""
params = {}
if since_ms:
until = since_ms + (timeframe_to_msecs(timeframe) * self._ft_has['ohlcv_candle_limit'])
params.update({'until': until})
# Funding rate
data = await self._api_async.fetch_funding_rate_history(
pair, since=since_ms,
params=params)
# Convert funding rate to candle pattern
data = [[x['timestamp'], x['fundingRate'], 0, 0, 0, 0] for x in data]
return data
def _lev_prep(self, pair: str, leverage: float, side: BuySell, accept_fail: bool = False):
if self.trading_mode != TradingMode.SPOT:
params = {'leverage': leverage}
self.set_margin_mode(pair, self.margin_mode, accept_fail=True, params=params)
self._set_leverage(leverage, pair, accept_fail=True)
def _get_params(
self,
side: BuySell,
ordertype: str,
leverage: float,
reduceOnly: bool,
time_in_force: str = 'GTC',
) -> Dict:
params = super()._get_params(
side=side,
ordertype=ordertype,
leverage=leverage,
reduceOnly=reduceOnly,
time_in_force=time_in_force,
)
if self.trading_mode == TradingMode.FUTURES and self.margin_mode:
params['position_idx'] = 0
return params
def dry_run_liquidation_price(
self,
pair: str,
open_rate: float, # Entry price of position
is_short: bool,
amount: float,
stake_amount: float,
leverage: float,
wallet_balance: float, # Or margin balance
mm_ex_1: float = 0.0, # (Binance) Cross only
upnl_ex_1: float = 0.0, # (Binance) Cross only
) -> Optional[float]:
"""
Important: Must be fetching data from cached values as this is used by backtesting!
PERPETUAL:
bybit:
https://www.bybithelp.com/HelpCenterKnowledge/bybitHC_Article?language=en_US&id=000001067
Long:
Liquidation Price = (
Entry Price * (1 - Initial Margin Rate + Maintenance Margin Rate)
- Extra Margin Added/ Contract)
Short:
Liquidation Price = (
Entry Price * (1 + Initial Margin Rate - Maintenance Margin Rate)
+ Extra Margin Added/ Contract)
Implementation Note: Extra margin is currently not used.
:param pair: Pair to calculate liquidation price for
:param open_rate: Entry price of position
:param is_short: True if the trade is a short, false otherwise
:param amount: Absolute value of position size incl. leverage (in base currency)
:param stake_amount: Stake amount - Collateral in settle currency.
:param leverage: Leverage used for this position.
:param trading_mode: SPOT, MARGIN, FUTURES, etc.
:param margin_mode: Either ISOLATED or CROSS
:param wallet_balance: Amount of margin_mode in the wallet being used to trade
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
"""
market = self.markets[pair]
mm_ratio, _ = self.get_maintenance_ratio_and_amt(pair, stake_amount)
if self.trading_mode == TradingMode.FUTURES and self.margin_mode == MarginMode.ISOLATED:
if market['inverse']:
raise OperationalException(
"Freqtrade does not yet support inverse contracts")
initial_margin_rate = 1 / leverage
# See docstring - ignores extra margin!
if is_short:
return open_rate * (1 + initial_margin_rate - mm_ratio)
else:
return open_rate * (1 - initial_margin_rate + mm_ratio)
else:
raise OperationalException(
"Freqtrade only supports isolated futures for leverage trading")
def get_funding_fees(
self, pair: str, amount: float, is_short: bool, open_date: datetime) -> float:
"""
Fetch funding fees, either from the exchange (live) or calculates them
based on funding rate/mark price history
:param pair: The quote/base pair of the trade
:param is_short: trade direction
:param amount: Trade amount
:param open_date: Open date of the trade
:return: funding fee since open_date
:raises: ExchangeError if something goes wrong.
"""
# Bybit does not provide "applied" funding fees per position.
if self.trading_mode == TradingMode.FUTURES:
return self._fetch_and_calculate_funding_fees(
pair, amount, is_short, open_date)
return 0.0

View File

@@ -46,13 +46,13 @@ MAP_EXCHANGE_CHILDCLASS = {
'binanceje': 'binance',
'binanceusdm': 'binance',
'okex': 'okx',
'gate': 'gateio',
'gateio': 'gate',
}
SUPPORTED_EXCHANGES = [
'binance',
'bittrex',
'gateio',
'gate',
'huobi',
'kraken',
'okx',

View File

@@ -7,6 +7,7 @@ import inspect
import logging
from copy import deepcopy
from datetime import datetime, timedelta, timezone
from math import floor
from threading import Lock
from typing import Any, Coroutine, Dict, List, Literal, Optional, Tuple, Union
@@ -20,9 +21,10 @@ from pandas import DataFrame, concat
from freqtrade.constants import (DEFAULT_AMOUNT_RESERVE_PERCENT, NON_OPEN_EXCHANGE_STATES, BidAsk,
BuySell, Config, EntryExit, ListPairsWithTimeframes, MakerTaker,
PairWithTimeframe)
OBLiteral, PairWithTimeframe)
from freqtrade.data.converter import clean_ohlcv_dataframe, ohlcv_to_dataframe, trades_dict_to_list
from freqtrade.enums import OPTIMIZE_MODES, CandleType, MarginMode, TradingMode
from freqtrade.enums.pricetype import PriceType
from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFundsError,
InvalidOrderException, OperationalException, PricingError,
RetryableOrderError, TemporaryError)
@@ -35,7 +37,7 @@ from freqtrade.exchange.exchange_utils import (CcxtModuleType, amount_to_contrac
price_to_precision, timeframe_to_minutes,
timeframe_to_msecs, timeframe_to_next_date,
timeframe_to_prev_date, timeframe_to_seconds)
from freqtrade.exchange.types import OHLCVResponse, Ticker, Tickers
from freqtrade.exchange.types import OHLCVResponse, OrderBook, Ticker, Tickers
from freqtrade.misc import (chunks, deep_merge_dicts, file_dump_json, file_load_json,
safe_value_fallback2)
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
@@ -58,7 +60,6 @@ class Exchange:
_ft_has_default: Dict = {
"stoploss_on_exchange": False,
"order_time_in_force": ["GTC"],
"time_in_force_parameter": "timeInForce",
"ohlcv_params": {},
"ohlcv_candle_limit": 500,
"ohlcv_has_history": True, # Some exchanges (Kraken) don't provide history via ohlcv
@@ -67,6 +68,7 @@ class Exchange:
# Check https://github.com/ccxt/ccxt/issues/10767 for removal of ohlcv_volume_currency
"ohlcv_volume_currency": "base", # "base" or "quote"
"tickers_have_quoteVolume": True,
"tickers_have_bid_ask": True, # bid / ask empty for fetch_tickers
"tickers_have_price": True,
"trades_pagination": "time", # Possible are "time" or "id"
"trades_pagination_arg": "since",
@@ -599,12 +601,27 @@ class Exchange:
if not self.exchange_has('createMarketOrder'):
raise OperationalException(
f'Exchange {self.name} does not support market orders.')
self.validate_stop_ordertypes(order_types)
def validate_stop_ordertypes(self, order_types: Dict) -> None:
"""
Validate stoploss order types
"""
if (order_types.get("stoploss_on_exchange")
and not self._ft_has.get("stoploss_on_exchange", False)):
raise OperationalException(
f'On exchange stoploss is not supported for {self.name}.'
)
if self.trading_mode == TradingMode.FUTURES:
price_mapping = self._ft_has.get('stop_price_type_value_mapping', {}).keys()
if (
order_types.get("stoploss_on_exchange", False) is True
and 'stoploss_price_type' in order_types
and order_types['stoploss_price_type'] not in price_mapping
):
raise OperationalException(
f'On exchange stoploss price type is not supported for {self.name}.'
)
def validate_pricing(self, pricing: Dict) -> None:
if pricing.get('use_order_book', False) and not self.exchange_has('fetchL2OrderBook'):
@@ -833,7 +850,7 @@ class Exchange:
'remaining': _amount,
'datetime': arrow.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
'timestamp': arrow.utcnow().int_timestamp * 1000,
'status': "closed" if ordertype == "market" and not stop_loss else "open",
'status': "open",
'fee': None,
'info': {},
'leverage': leverage
@@ -843,20 +860,33 @@ class Exchange:
dry_order["stopPrice"] = dry_order["price"]
# Workaround to avoid filling stoploss orders immediately
dry_order["ft_order_type"] = "stoploss"
orderbook: Optional[OrderBook] = None
if self.exchange_has('fetchL2OrderBook'):
orderbook = self.fetch_l2_order_book(pair, 20)
if ordertype == "limit" and orderbook:
# Allow a 3% price difference
allowed_diff = 0.03
if self._dry_is_price_crossed(pair, side, rate, orderbook, allowed_diff):
logger.info(
f"Converted order {pair} to market order due to price {rate} crossing spread "
f"by more than {allowed_diff:.2%}.")
dry_order["type"] = "market"
if dry_order["type"] == "market" and not dry_order.get("ft_order_type"):
# Update market order pricing
average = self.get_dry_market_fill_price(pair, side, amount, rate)
average = self.get_dry_market_fill_price(pair, side, amount, rate, orderbook)
dry_order.update({
'average': average,
'filled': _amount,
'remaining': 0.0,
'status': "closed",
'cost': (dry_order['amount'] * average) / leverage
})
# market orders will always incurr taker fees
dry_order = self.add_dry_order_fee(pair, dry_order, 'taker')
dry_order = self.check_dry_limit_order_filled(dry_order, immediate=True)
dry_order = self.check_dry_limit_order_filled(
dry_order, immediate=True, orderbook=orderbook)
self._dry_run_open_orders[dry_order["id"]] = dry_order
# Copy order and close it - so the returned order is open unless it's a market order
@@ -878,20 +908,22 @@ class Exchange:
})
return dry_order
def get_dry_market_fill_price(self, pair: str, side: str, amount: float, rate: float) -> float:
def get_dry_market_fill_price(self, pair: str, side: str, amount: float, rate: float,
orderbook: Optional[OrderBook]) -> float:
"""
Get the market order fill price based on orderbook interpolation
"""
if self.exchange_has('fetchL2OrderBook'):
ob = self.fetch_l2_order_book(pair, 20)
ob_type = 'asks' if side == 'buy' else 'bids'
if not orderbook:
orderbook = self.fetch_l2_order_book(pair, 20)
ob_type: OBLiteral = 'asks' if side == 'buy' else 'bids'
slippage = 0.05
max_slippage_val = rate * ((1 + slippage) if side == 'buy' else (1 - slippage))
remaining_amount = amount
filled_amount = 0.0
book_entry_price = 0.0
for book_entry in ob[ob_type]:
for book_entry in orderbook[ob_type]:
book_entry_price = book_entry[0]
book_entry_coin_volume = book_entry[1]
if remaining_amount > 0:
@@ -919,20 +951,20 @@ class Exchange:
return rate
def _is_dry_limit_order_filled(self, pair: str, side: str, limit: float) -> bool:
def _dry_is_price_crossed(self, pair: str, side: str, limit: float,
orderbook: Optional[OrderBook] = None, offset: float = 0.0) -> bool:
if not self.exchange_has('fetchL2OrderBook'):
return True
ob = self.fetch_l2_order_book(pair, 1)
if not orderbook:
orderbook = self.fetch_l2_order_book(pair, 1)
try:
if side == 'buy':
price = ob['asks'][0][0]
logger.debug(f"{pair} checking dry buy-order: price={price}, limit={limit}")
if limit >= price:
price = orderbook['asks'][0][0]
if limit * (1 - offset) >= price:
return True
else:
price = ob['bids'][0][0]
logger.debug(f"{pair} checking dry sell-order: price={price}, limit={limit}")
if limit <= price:
price = orderbook['bids'][0][0]
if limit * (1 + offset) <= price:
return True
except IndexError:
# Ignore empty orderbooks when filling - can be filled with the next iteration.
@@ -940,7 +972,8 @@ class Exchange:
return False
def check_dry_limit_order_filled(
self, order: Dict[str, Any], immediate: bool = False) -> Dict[str, Any]:
self, order: Dict[str, Any], immediate: bool = False,
orderbook: Optional[OrderBook] = None) -> Dict[str, Any]:
"""
Check dry-run limit order fill and update fee (if it filled).
"""
@@ -948,7 +981,7 @@ class Exchange:
and order['type'] in ["limit"]
and not order.get('ft_order_type')):
pair = order['symbol']
if self._is_dry_limit_order_filled(pair, order['side'], order['price']):
if self._dry_is_price_crossed(pair, order['side'], order['price'], orderbook):
order.update({
'status': 'closed',
'filled': order['amount'],
@@ -985,10 +1018,10 @@ class Exchange:
# Order handling
def _lev_prep(self, pair: str, leverage: float, side: BuySell):
def _lev_prep(self, pair: str, leverage: float, side: BuySell, accept_fail: bool = False):
if self.trading_mode != TradingMode.SPOT:
self.set_margin_mode(pair, self.margin_mode)
self._set_leverage(leverage, pair)
self.set_margin_mode(pair, self.margin_mode, accept_fail)
self._set_leverage(leverage, pair, accept_fail)
def _get_params(
self,
@@ -1000,8 +1033,7 @@ class Exchange:
) -> Dict:
params = self._params.copy()
if time_in_force != 'GTC' and ordertype != 'market':
param = self._ft_has.get('time_in_force_parameter', '')
params.update({param: time_in_force.upper()})
params.update({'timeInForce': time_in_force.upper()})
if reduceOnly:
params.update({'reduceOnly': True})
return params
@@ -1053,7 +1085,7 @@ class Exchange:
f'Tried to {side} amount {amount} at rate {rate}.'
f'Message: {e}') from e
except ccxt.InvalidOrder as e:
raise ExchangeError(
raise InvalidOrderException(
f'Could not create {ordertype} {side} order on market {pair}. '
f'Tried to {side} amount {amount} at rate {rate}. '
f'Message: {e}') from e
@@ -1103,8 +1135,15 @@ class Exchange:
"sell" else (stop_price >= limit_rate))
# Ensure rate is less than stop price
if bad_stop_price:
raise OperationalException(
'In stoploss limit order, stop price should be more than limit price')
# This can for example happen if the stop / liquidation price is set to 0
# Which is possible if a market-order closes right away.
# The InvalidOrderException will bubble up to exit_positions, where it will be
# handled gracefully.
raise InvalidOrderException(
"In stoploss limit order, stop price should be more than limit price. "
f"Stop price: {stop_price}, Limit price: {limit_rate}, "
f"Limit Price pct: {limit_price_pct}"
)
return limit_rate
def _get_stop_params(self, side: BuySell, ordertype: str, stop_price: float) -> Dict:
@@ -1114,8 +1153,8 @@ class Exchange:
return params
@retrier(retries=0)
def stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict,
side: BuySell, leverage: float) -> Dict:
def create_stoploss(self, pair: str, amount: float, stop_price: float, order_types: Dict,
side: BuySell, leverage: float) -> Dict:
"""
creates a stoploss order.
requires `_ft_has['stoploss_order_types']` to be set as a dict mapping limit and market
@@ -1160,10 +1199,14 @@ class Exchange:
stop_price=stop_price_norm)
if self.trading_mode == TradingMode.FUTURES:
params['reduceOnly'] = True
if 'stoploss_price_type' in order_types and 'stop_price_type_field' in self._ft_has:
price_type = self._ft_has['stop_price_type_value_mapping'][
order_types.get('stoploss_price_type', PriceType.LAST)]
params[self._ft_has['stop_price_type_field']] = price_type
amount = self.amount_to_precision(pair, self._amount_to_contracts(pair, amount))
self._lev_prep(pair, leverage, side)
self._lev_prep(pair, leverage, side, accept_fail=True)
order = self._api.create_order(symbol=pair, type=ordertype, side=side,
amount=amount, price=limit_rate, params=params)
self._log_exchange_response('create_stoploss_order', order)
@@ -1490,7 +1533,7 @@ class Exchange:
return result
@retrier
def fetch_l2_order_book(self, pair: str, limit: int = 100) -> dict:
def fetch_l2_order_book(self, pair: str, limit: int = 100) -> OrderBook:
"""
Get L2 order book from exchange.
Can be limited to a certain amount (if supported).
@@ -1533,7 +1576,7 @@ class Exchange:
def get_rate(self, pair: str, refresh: bool,
side: EntryExit, is_short: bool,
order_book: Optional[dict] = None, ticker: Optional[Ticker] = None) -> float:
order_book: Optional[OrderBook] = None, ticker: Optional[Ticker] = None) -> float:
"""
Calculates bid/ask target
bid rate - between current ask price and last price
@@ -1571,7 +1614,8 @@ class Exchange:
logger.debug('order_book %s', order_book)
# top 1 = index 0
try:
rate = order_book[f"{price_side}s"][order_book_top - 1][0]
obside: OBLiteral = 'bids' if price_side == 'bid' else 'asks'
rate = order_book[obside][order_book_top - 1][0]
except (IndexError, KeyError) as e:
logger.warning(
f"{pair} - {name} Price at location {order_book_top} from orderbook "
@@ -1923,7 +1967,8 @@ class Exchange:
cache: bool, drop_incomplete: bool) -> DataFrame:
# keeping last candle time as last refreshed time of the pair
if ticks and cache:
self._pairs_last_refresh_time[(pair, timeframe, c_type)] = ticks[-1][0] // 1000
idx = -2 if drop_incomplete and len(ticks) > 1 else -1
self._pairs_last_refresh_time[(pair, timeframe, c_type)] = ticks[idx][0] // 1000
# keeping parsed dataframe in cache
ohlcv_df = ohlcv_to_dataframe(ticks, timeframe, pair=pair, fill_missing=True,
drop_incomplete=drop_incomplete)
@@ -1977,9 +2022,9 @@ class Exchange:
continue
# Deconstruct tuple (has 5 elements)
pair, timeframe, c_type, ticks, drop_hint = res
drop_incomplete = drop_hint if drop_incomplete is None else drop_incomplete
drop_incomplete_ = drop_hint if drop_incomplete is None else drop_incomplete
ohlcv_df = self._process_ohlcv_df(
pair, timeframe, c_type, ticks, cache, drop_incomplete)
pair, timeframe, c_type, ticks, cache, drop_incomplete_)
results_df[(pair, timeframe, c_type)] = ohlcv_df
@@ -1996,7 +2041,9 @@ class Exchange:
# Timeframe in seconds
interval_in_sec = timeframe_to_seconds(timeframe)
plr = self._pairs_last_refresh_time.get((pair, timeframe, candle_type), 0) + interval_in_sec
return plr < arrow.utcnow().int_timestamp
# current,active candle open date
now = int(timeframe_to_prev_date(timeframe).timestamp())
return plr < now
@retrier_async
async def _async_get_candle_history(
@@ -2484,7 +2531,7 @@ class Exchange:
self,
leverage: float,
pair: Optional[str] = None,
trading_mode: Optional[TradingMode] = None
accept_fail: bool = False,
):
"""
Set's the leverage before making a trade, in order to not
@@ -2493,12 +2540,18 @@ class Exchange:
if self._config['dry_run'] or not self.exchange_has("setLeverage"):
# Some exchanges only support one margin_mode type
return
if self._ft_has.get('floor_leverage', False) is True:
# Rounding for binance ...
leverage = floor(leverage)
try:
res = self._api.set_leverage(symbol=pair, leverage=leverage)
self._log_exchange_response('set_leverage', res)
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.BadRequest, ccxt.InsufficientFunds) as e:
if not accept_fail:
raise TemporaryError(
f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError(
f'Could not set leverage due to {e.__class__.__name__}. Message: {e}') from e
@@ -2520,7 +2573,8 @@ class Exchange:
return open_date.minute > 0 or open_date.second > 0
@retrier
def set_margin_mode(self, pair: str, margin_mode: MarginMode, params: dict = {}):
def set_margin_mode(self, pair: str, margin_mode: MarginMode, accept_fail: bool = False,
params: dict = {}):
"""
Set's the margin mode on the exchange to cross or isolated for a specific pair
:param pair: base/quote currency pair (e.g. "ADA/USDT")
@@ -2534,6 +2588,10 @@ class Exchange:
self._log_exchange_response('set_margin_mode', res)
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except ccxt.BadRequest as e:
if not accept_fail:
raise TemporaryError(
f'Could not set margin mode due to {e.__class__.__name__}. Message: {e}') from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
raise TemporaryError(
f'Could not set margin mode due to {e.__class__.__name__}. Message: {e}') from e
@@ -2687,6 +2745,7 @@ class Exchange:
is_short: bool,
amount: float, # Absolute value of position size
stake_amount: float,
leverage: float,
wallet_balance: float,
mm_ex_1: float = 0.0, # (Binance) Cross only
upnl_ex_1: float = 0.0, # (Binance) Cross only
@@ -2700,14 +2759,15 @@ class Exchange:
raise OperationalException(
f"{self.name} does not support {self.margin_mode} {self.trading_mode}")
isolated_liq = None
liquidation_price = None
if self._config['dry_run'] or not self.exchange_has("fetchPositions"):
isolated_liq = self.dry_run_liquidation_price(
liquidation_price = self.dry_run_liquidation_price(
pair=pair,
open_rate=open_rate,
is_short=is_short,
amount=amount,
leverage=leverage,
stake_amount=stake_amount,
wallet_balance=wallet_balance,
mm_ex_1=mm_ex_1,
@@ -2717,16 +2777,16 @@ class Exchange:
positions = self.fetch_positions(pair)
if len(positions) > 0:
pos = positions[0]
isolated_liq = pos['liquidationPrice']
liquidation_price = pos['liquidationPrice']
if isolated_liq:
buffer_amount = abs(open_rate - isolated_liq) * self.liquidation_buffer
isolated_liq = (
isolated_liq - buffer_amount
if liquidation_price is not None:
buffer_amount = abs(open_rate - liquidation_price) * self.liquidation_buffer
liquidation_price_buffer = (
liquidation_price - buffer_amount
if is_short else
isolated_liq + buffer_amount
liquidation_price + buffer_amount
)
return isolated_liq
return max(liquidation_price_buffer, 0.0)
else:
return None
@@ -2737,6 +2797,7 @@ class Exchange:
is_short: bool,
amount: float,
stake_amount: float,
leverage: float,
wallet_balance: float, # Or margin balance
mm_ex_1: float = 0.0, # (Binance) Cross only
upnl_ex_1: float = 0.0, # (Binance) Cross only
@@ -2744,7 +2805,7 @@ class Exchange:
"""
Important: Must be fetching data from cached values as this is used by backtesting!
PERPETUAL:
gateio: https://www.gate.io/help/futures/futures/27724/liquidation-price-bankruptcy-price
gate: https://www.gate.io/help/futures/futures/27724/liquidation-price-bankruptcy-price
> Liquidation Price = (Entry Price ± Margin / Contract Multiplier / Size) /
[ 1 ± (Maintenance Margin Ratio + Taker Rate)]
Wherein, "+" or "-" depends on whether the contract goes long or short:
@@ -2758,13 +2819,14 @@ class Exchange:
:param is_short: True if the trade is a short, false otherwise
:param amount: Absolute value of position size incl. leverage (in base currency)
:param stake_amount: Stake amount - Collateral in settle currency.
:param leverage: Leverage used for this position.
:param trading_mode: SPOT, MARGIN, FUTURES, etc.
:param margin_mode: Either ISOLATED or CROSS
:param wallet_balance: Amount of margin_mode in the wallet being used to trade
Cross-Margin Mode: crossWalletBalance
Isolated-Margin Mode: isolatedWalletBalance
# * Not required by Gateio or OKX
# * Not required by Gate or OKX
:param mm_ex_1:
:param upnl_ex_1:
"""

View File

@@ -4,7 +4,7 @@ from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from freqtrade.constants import BuySell
from freqtrade.enums import MarginMode, TradingMode
from freqtrade.enums import MarginMode, PriceType, TradingMode
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import Exchange
from freqtrade.misc import safe_value_fallback2
@@ -13,7 +13,7 @@ from freqtrade.misc import safe_value_fallback2
logger = logging.getLogger(__name__)
class Gateio(Exchange):
class Gate(Exchange):
"""
Gate.io exchange class. Contains adjustments needed for Freqtrade to work
with this exchange.
@@ -32,8 +32,15 @@ class Gateio(Exchange):
_ft_has_futures: Dict = {
"needs_trading_fees": True,
"tickers_have_bid_ask": False,
"fee_cost_in_contracts": False, # Set explicitly to false for clarity
"order_props_in_contracts": ['amount', 'filled', 'remaining'],
"stop_price_type_field": "price_type",
"stop_price_type_value_mapping": {
PriceType.LAST: 0,
PriceType.MARK: 1,
PriceType.INDEX: 2,
},
}
_supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [
@@ -49,6 +56,7 @@ class Gateio(Exchange):
if any(v == 'market' for k, v in order_types.items()):
raise OperationalException(
f'Exchange {self.name} does not support market orders.')
super().validate_stop_ordertypes(order_types)
def _get_params(
self,
@@ -67,8 +75,7 @@ class Gateio(Exchange):
)
if ordertype == 'market' and self.trading_mode == TradingMode.FUTURES:
params['type'] = 'market'
param = self._ft_has.get('time_in_force_parameter', '')
params.update({param: 'IOC'})
params.update({'timeInForce': 'IOC'})
return params
def get_trades_for_order(self, order_id: str, pair: str, since: datetime,
@@ -77,7 +84,7 @@ class Gateio(Exchange):
if self.trading_mode == TradingMode.FUTURES:
# Futures usually don't contain fees in the response.
# As such, futures orders on gateio will not contain a fee, which causes
# As such, futures orders on gate will not contain a fee, which causes
# a repeated "update fee" cycle and wrong calculations.
# Therefore we patch the response with fees if it's not available.
# An alternative also contianing fees would be

View File

@@ -19,5 +19,4 @@ class Hitbtc(Exchange):
_ft_has: Dict = {
"ohlcv_candle_limit": 1000,
"ohlcv_params": {"sort": "DESC"}
}

View File

@@ -97,8 +97,8 @@ class Kraken(Exchange):
))
@retrier(retries=0)
def stoploss(self, pair: str, amount: float, stop_price: float,
order_types: Dict, side: BuySell, leverage: float) -> Dict:
def create_stoploss(self, pair: str, amount: float, stop_price: float,
order_types: Dict, side: BuySell, leverage: float) -> Dict:
"""
Creates a stoploss market order.
Stoploss market orders is the only stoploss type supported by kraken.
@@ -158,7 +158,7 @@ class Kraken(Exchange):
self,
leverage: float,
pair: Optional[str] = None,
trading_mode: Optional[TradingMode] = None
accept_fail: bool = False,
):
"""
Kraken set's the leverage as an option in the order object, so we need to

View File

@@ -36,3 +36,35 @@ class Kucoin(Exchange):
'stop': 'loss'
})
return params
def create_order(
self,
*,
pair: str,
ordertype: str,
side: BuySell,
amount: float,
rate: float,
leverage: float,
reduceOnly: bool = False,
time_in_force: str = 'GTC',
) -> Dict:
res = super().create_order(
pair=pair,
ordertype=ordertype,
side=side,
amount=amount,
rate=rate,
leverage=leverage,
reduceOnly=reduceOnly,
time_in_force=time_in_force,
)
# Kucoin returns only the order-id.
# ccxt returns status = 'closed' at the moment - which is information ccxt invented.
# Since we rely on status heavily, we must set it to 'open' here.
# ref: https://github.com/ccxt/ccxt/pull/16674, (https://github.com/ccxt/ccxt/pull/16553)
if not self._config['dry_run']:
res['type'] = ordertype
res['status'] = 'open'
return res

View File

@@ -1,13 +1,16 @@
import logging
from typing import Dict, List, Optional, Tuple
from typing import Any, Dict, List, Optional, Tuple
import ccxt
from freqtrade.constants import BuySell
from freqtrade.enums import CandleType, MarginMode, TradingMode
from freqtrade.exceptions import DDosProtection, OperationalException, TemporaryError
from freqtrade.enums.pricetype import PriceType
from freqtrade.exceptions import (DDosProtection, OperationalException, RetryableOrderError,
TemporaryError)
from freqtrade.exchange import Exchange, date_minus_candles
from freqtrade.exchange.common import retrier
from freqtrade.misc import safe_value_fallback2
logger = logging.getLogger(__name__)
@@ -23,10 +26,18 @@ class Okx(Exchange):
"ohlcv_candle_limit": 100, # Warning, special case with data prior to X months
"mark_ohlcv_timeframe": "4h",
"funding_fee_timeframe": "8h",
"stoploss_order_types": {"limit": "limit"},
"stoploss_on_exchange": True,
}
_ft_has_futures: Dict = {
"tickers_have_quoteVolume": False,
"fee_cost_in_contracts": True,
"stop_price_type_field": "slTriggerPxType",
"stop_price_type_value_mapping": {
PriceType.LAST: "last",
PriceType.MARK: "index",
PriceType.INDEX: "mark",
},
}
_supported_trading_mode_margin_pairs: List[Tuple[TradingMode, MarginMode]] = [
@@ -114,17 +125,18 @@ class Okx(Exchange):
return params
@retrier
def _lev_prep(self, pair: str, leverage: float, side: BuySell):
def _lev_prep(self, pair: str, leverage: float, side: BuySell, accept_fail: bool = False):
if self.trading_mode != TradingMode.SPOT and self.margin_mode is not None:
try:
# TODO-lev: Test me properly (check mgnMode passed)
self._api.set_leverage(
res = self._api.set_leverage(
leverage=leverage,
symbol=pair,
params={
"mgnMode": self.margin_mode.value,
"posSide": self._get_posSide(side, False),
})
self._log_exchange_response('set_leverage', res)
except ccxt.DDoSProtection as e:
raise DDosProtection(e) from e
except (ccxt.NetworkError, ccxt.ExchangeError) as e:
@@ -148,3 +160,78 @@ class Okx(Exchange):
pair_tiers = self._leverage_tiers[pair]
return pair_tiers[-1]['maxNotional'] / leverage
def _get_stop_params(self, side: BuySell, ordertype: str, stop_price: float) -> Dict:
params = self._params.copy()
# Verify if stopPrice works for your exchange!
params.update({'stopLossPrice': stop_price})
if self.trading_mode == TradingMode.FUTURES and self.margin_mode:
params['tdMode'] = self.margin_mode.value
params['posSide'] = self._get_posSide(side, True)
return params
def stoploss_adjust(self, stop_loss: float, order: Dict, side: str) -> bool:
"""
OKX uses non-default stoploss price naming.
"""
if not self._ft_has.get('stoploss_on_exchange'):
raise OperationalException(f"stoploss is not implemented for {self.name}.")
return (
order.get('stopLossPrice', None) is None
or ((side == "sell" and stop_loss > float(order['stopLossPrice'])) or
(side == "buy" and stop_loss < float(order['stopLossPrice'])))
)
def fetch_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict:
if self._config['dry_run']:
return self.fetch_dry_run_order(order_id)
try:
params1 = {'stop': True}
order_reg = self._api.fetch_order(order_id, pair, params=params1)
self._log_exchange_response('fetch_stoploss_order', order_reg)
return order_reg
except ccxt.OrderNotFound:
pass
params2 = {'stop': True, 'ordType': 'conditional'}
for method in (self._api.fetch_open_orders, self._api.fetch_closed_orders,
self._api.fetch_canceled_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]
if (order['status'] == 'closed'
and (real_order_id := order.get('info', {}).get('ordId')) is not None):
# Once a order triggered, we fetch the regular followup order.
order_reg = self.fetch_order(real_order_id, pair)
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['type'] = 'stoploss'
return order
except ccxt.BaseError:
pass
raise RetryableOrderError(
f'StoplossOrder not found (pair: {pair} id: {order_id}).')
def get_order_id_conditional(self, order: Dict[str, Any]) -> str:
if order['type'] == 'stop':
return safe_value_fallback2(order, order, 'id_stop', 'id')
return order['id']
def cancel_stoploss_order(self, order_id: str, pair: str, params: Dict = {}) -> Dict:
params1 = {'stop': True}
# 'ordType': 'conditional'
#
return self.cancel_order(
order_id=order_id,
pair=pair,
params=params1,
)

View File

@@ -15,6 +15,15 @@ class Ticker(TypedDict):
# Several more - only listing required.
class OrderBook(TypedDict):
symbol: str
bids: List[Tuple[float, float]]
asks: List[Tuple[float, float]]
timestamp: Optional[int]
datetime: Optional[str]
nonce: Optional[int]
Tickers = Dict[str, Ticker]
# pair, timeframe, candleType, OHLCV, drop last?,

View File

@@ -47,7 +47,7 @@ class Base3ActionRLEnv(BaseEnvironment):
self._update_unrealized_total_profit()
step_reward = self.calculate_reward(action)
self.total_reward += step_reward
self.tensorboard_log(self.actions._member_names_[action])
self.tensorboard_log(self.actions._member_names_[action], category="actions")
trade_type = None
if self.is_tradesignal(action):

View File

@@ -48,7 +48,7 @@ class Base4ActionRLEnv(BaseEnvironment):
self._update_unrealized_total_profit()
step_reward = self.calculate_reward(action)
self.total_reward += step_reward
self.tensorboard_log(self.actions._member_names_[action])
self.tensorboard_log(self.actions._member_names_[action], category="actions")
trade_type = None
if self.is_tradesignal(action):

View File

@@ -49,7 +49,7 @@ class Base5ActionRLEnv(BaseEnvironment):
self._update_unrealized_total_profit()
step_reward = self.calculate_reward(action)
self.total_reward += step_reward
self.tensorboard_log(self.actions._member_names_[action])
self.tensorboard_log(self.actions._member_names_[action], category="actions")
trade_type = None
if self.is_tradesignal(action):

View File

@@ -45,7 +45,8 @@ class BaseEnvironment(gym.Env):
def __init__(self, df: DataFrame = DataFrame(), prices: DataFrame = DataFrame(),
reward_kwargs: dict = {}, window_size=10, starting_point=True,
id: str = 'baseenv-1', seed: int = 1, config: dict = {}, live: bool = False,
fee: float = 0.0015, can_short: bool = False):
fee: float = 0.0015, can_short: bool = False, pair: str = "",
df_raw: DataFrame = DataFrame()):
"""
Initializes the training/eval environment.
:param df: dataframe of features
@@ -60,12 +61,14 @@ class BaseEnvironment(gym.Env):
:param fee: The fee to use for environmental interactions.
:param can_short: Whether or not the environment can short
"""
self.config = config
self.rl_config = config['freqai']['rl_config']
self.add_state_info = self.rl_config.get('add_state_info', False)
self.id = id
self.max_drawdown = 1 - self.rl_config.get('max_training_drawdown_pct', 0.8)
self.compound_trades = config['stake_amount'] == 'unlimited'
self.config: dict = config
self.rl_config: dict = config['freqai']['rl_config']
self.add_state_info: bool = self.rl_config.get('add_state_info', False)
self.id: str = id
self.max_drawdown: float = 1 - self.rl_config.get('max_training_drawdown_pct', 0.8)
self.compound_trades: bool = config['stake_amount'] == 'unlimited'
self.pair: str = pair
self.raw_features: DataFrame = df_raw
if self.config.get('fee', None) is not None:
self.fee = self.config['fee']
else:
@@ -74,8 +77,8 @@ class BaseEnvironment(gym.Env):
# set here to default 5Ac, but all children envs can override this
self.actions: Type[Enum] = BaseActions
self.tensorboard_metrics: dict = {}
self.can_short = can_short
self.live = live
self.can_short: bool = can_short
self.live: bool = live
if not self.live and self.add_state_info:
self.add_state_info = False
logger.warning("add_state_info is not available in backtesting. Deactivating.")
@@ -93,13 +96,12 @@ class BaseEnvironment(gym.Env):
:param reward_kwargs: extra config settings assigned by user in `rl_config`
:param starting_point: start at edge of window or not
"""
self.df = df
self.signal_features = self.df
self.prices = prices
self.window_size = window_size
self.starting_point = starting_point
self.rr = reward_kwargs["rr"]
self.profit_aim = reward_kwargs["profit_aim"]
self.signal_features: DataFrame = df
self.prices: DataFrame = prices
self.window_size: int = window_size
self.starting_point: bool = starting_point
self.rr: float = reward_kwargs["rr"]
self.profit_aim: float = reward_kwargs["profit_aim"]
# # spaces
if self.add_state_info:
@@ -135,7 +137,8 @@ class BaseEnvironment(gym.Env):
self.np_random, seed = seeding.np_random(seed)
return [seed]
def tensorboard_log(self, metric: str, value: Union[int, float] = 1, inc: bool = True):
def tensorboard_log(self, metric: str, value: Optional[Union[int, float]] = None,
inc: Optional[bool] = None, category: str = "custom"):
"""
Function builds the tensorboard_metrics dictionary
to be parsed by the TensorboardCallback. This
@@ -147,17 +150,24 @@ class BaseEnvironment(gym.Env):
def calculate_reward(self, action: int) -> float:
if not self._is_valid(action):
self.tensorboard_log("is_valid")
self.tensorboard_log("invalid")
return -2
:param metric: metric to be tracked and incremented
:param value: value to increment `metric` by
:param inc: sets whether the `value` is incremented or not
:param value: `metric` value
:param inc: (deprecated) sets whether the `value` is incremented or not
:param category: `metric` category
"""
if not inc or metric not in self.tensorboard_metrics:
self.tensorboard_metrics[metric] = value
increment = True if value is None else False
value = 1 if increment else value
if category not in self.tensorboard_metrics:
self.tensorboard_metrics[category] = {}
if not increment or metric not in self.tensorboard_metrics[category]:
self.tensorboard_metrics[category][metric] = value
else:
self.tensorboard_metrics[metric] += value
self.tensorboard_metrics[category][metric] += value
def reset_tensorboard_log(self):
self.tensorboard_metrics = {}

View File

@@ -1,3 +1,4 @@
import copy
import importlib
import logging
from abc import abstractmethod
@@ -50,6 +51,7 @@ class BaseReinforcementLearningModel(IFreqaiModel):
self.eval_callback: Optional[EvalCallback] = None
self.model_type = self.freqai_info['rl_config']['model_type']
self.rl_config = self.freqai_info['rl_config']
self.df_raw: DataFrame = DataFrame()
self.continual_learning = self.freqai_info.get('continual_learning', False)
if self.model_type in SB3_MODELS:
import_str = 'stable_baselines3'
@@ -107,10 +109,12 @@ class BaseReinforcementLearningModel(IFreqaiModel):
data_dictionary: Dict[str, Any] = dk.make_train_test_datasets(
features_filtered, labels_filtered)
self.df_raw = copy.deepcopy(data_dictionary["train_features"])
dk.fit_labels() # FIXME useless for now, but just satiating append methods
# normalize all data based on train_dataset only
prices_train, prices_test = self.build_ohlc_price_dataframes(dk.data_dictionary, pair, dk)
data_dictionary = dk.normalize_data(data_dictionary)
# data cleaning/analysis
@@ -143,14 +147,10 @@ class BaseReinforcementLearningModel(IFreqaiModel):
train_df = data_dictionary["train_features"]
test_df = data_dictionary["test_features"]
env_info = self.pack_env_dict()
env_info = self.pack_env_dict(dk.pair)
self.train_env = self.MyRLEnv(df=train_df,
prices=prices_train,
**env_info)
self.eval_env = Monitor(self.MyRLEnv(df=test_df,
prices=prices_test,
**env_info))
self.train_env = self.MyRLEnv(df=train_df, prices=prices_train, **env_info)
self.eval_env = Monitor(self.MyRLEnv(df=test_df, prices=prices_test, **env_info))
self.eval_callback = EvalCallback(self.eval_env, deterministic=True,
render=False, eval_freq=len(train_df),
best_model_save_path=str(dk.data_path))
@@ -158,7 +158,7 @@ class BaseReinforcementLearningModel(IFreqaiModel):
actions = self.train_env.get_actions()
self.tensorboard_callback = TensorboardCallback(verbose=1, actions=actions)
def pack_env_dict(self) -> Dict[str, Any]:
def pack_env_dict(self, pair: str) -> Dict[str, Any]:
"""
Create dictionary of environment arguments
"""
@@ -166,7 +166,9 @@ class BaseReinforcementLearningModel(IFreqaiModel):
"reward_kwargs": self.reward_params,
"config": self.config,
"live": self.live,
"can_short": self.can_short}
"can_short": self.can_short,
"pair": pair,
"df_raw": self.df_raw}
if self.data_provider:
env_info["fee"] = self.data_provider._exchange \
.get_fee(symbol=self.data_provider.current_whitelist()[0]) # type: ignore
@@ -233,6 +235,9 @@ class BaseReinforcementLearningModel(IFreqaiModel):
filtered_dataframe, _ = dk.filter_features(
unfiltered_df, dk.training_features_list, training_filter=False
)
filtered_dataframe = self.drop_ohlc_from_df(filtered_dataframe, dk)
filtered_dataframe = dk.normalize_data_from_metadata(filtered_dataframe)
dk.data_dictionary["prediction_features"] = filtered_dataframe
@@ -280,7 +285,6 @@ class BaseReinforcementLearningModel(IFreqaiModel):
train_df = data_dictionary["train_features"]
test_df = data_dictionary["test_features"]
# %-raw_volume_gen_shift-2_ETH/USDT_1h
# price data for model training and evaluation
tf = self.config['timeframe']
rename_dict = {'%-raw_open': 'open', '%-raw_low': 'low',
@@ -313,8 +317,24 @@ class BaseReinforcementLearningModel(IFreqaiModel):
prices_test.rename(columns=rename_dict, inplace=True)
prices_test.reset_index(drop=True)
train_df = self.drop_ohlc_from_df(train_df, dk)
test_df = self.drop_ohlc_from_df(test_df, dk)
return prices_train, prices_test
def drop_ohlc_from_df(self, df: DataFrame, dk: FreqaiDataKitchen):
"""
Given a dataframe, drop the ohlc data
"""
drop_list = ['%-raw_open', '%-raw_low', '%-raw_high', '%-raw_close']
if self.rl_config["drop_ohlc_from_features"]:
df.drop(drop_list, axis=1, inplace=True)
feature_list = dk.training_features_list
dk.training_features_list = [e for e in feature_list if e not in drop_list]
return df
def load_model_from_disk(self, dk: FreqaiDataKitchen) -> Any:
"""
Can be used by user if they are trying to limit_ram_usage *and*
@@ -347,7 +367,7 @@ class BaseReinforcementLearningModel(IFreqaiModel):
sets a custom reward based on profit and trade duration.
"""
def calculate_reward(self, action: int) -> float:
def calculate_reward(self, action: int) -> float: # noqa: C901
"""
An example reward function. This is the one function that users will likely
wish to inject their own creativity into.
@@ -363,10 +383,19 @@ class BaseReinforcementLearningModel(IFreqaiModel):
pnl = self.get_unrealized_profit()
factor = 100.
# you can use feature values from dataframe
rsi_now = self.raw_features[f"%-rsi-period-10_shift-1_{self.pair}_"
f"{self.config['timeframe']}"].iloc[self._current_tick]
# reward agent for entering trades
if (action in (Actions.Long_enter.value, Actions.Short_enter.value)
and self._position == Positions.Neutral):
return 25
if rsi_now < 40:
factor = 40 / rsi_now
else:
factor = 1
return 25 * factor
# discourage agent from not entering trades
if action == Actions.Neutral.value and self._position == Positions.Neutral:
return -1

View File

@@ -13,7 +13,7 @@ class TensorboardCallback(BaseCallback):
episodic summary reports.
"""
def __init__(self, verbose=1, actions: Type[Enum] = BaseActions):
super(TensorboardCallback, self).__init__(verbose)
super().__init__(verbose)
self.model: Any = None
self.logger = None # type: Any
self.training_env: BaseEnvironment = None # type: ignore
@@ -46,14 +46,12 @@ class TensorboardCallback(BaseCallback):
local_info = self.locals["infos"][0]
tensorboard_metrics = self.training_env.get_attr("tensorboard_metrics")[0]
for info in local_info:
if info not in ["episode", "terminal_observation"]:
self.logger.record(f"_info/{info}", local_info[info])
for metric in local_info:
if metric not in ["episode", "terminal_observation"]:
self.logger.record(f"info/{metric}", local_info[metric])
for info in tensorboard_metrics:
if info in [action.name for action in self.actions]:
self.logger.record(f"_actions/{info}", tensorboard_metrics[info])
else:
self.logger.record(f"_custom/{info}", tensorboard_metrics[info])
for category in tensorboard_metrics:
for metric in tensorboard_metrics[category]:
self.logger.record(f"{category}/{metric}", tensorboard_metrics[category][metric])
return True

View File

@@ -59,7 +59,7 @@ class FreqaiDataDrawer:
Juha Nykänen @suikula, Wagner Costa @wagnercosta, Johan Vlugt @Jooopieeert
"""
def __init__(self, full_path: Path, config: Config, follow_mode: bool = False):
def __init__(self, full_path: Path, config: Config):
self.config = config
self.freqai_info = config.get("freqai", {})
@@ -72,21 +72,13 @@ class FreqaiDataDrawer:
self.model_return_values: Dict[str, DataFrame] = {}
self.historic_data: Dict[str, Dict[str, DataFrame]] = {}
self.historic_predictions: Dict[str, DataFrame] = {}
self.follower_dict: Dict[str, pair_info] = {}
self.full_path = full_path
self.follower_name: str = self.config.get("bot_name", "follower1")
self.follower_dict_path = Path(
self.full_path / f"follower_dictionary-{self.follower_name}.json"
)
self.historic_predictions_path = Path(self.full_path / "historic_predictions.pkl")
self.historic_predictions_bkp_path = Path(
self.full_path / "historic_predictions.backup.pkl")
self.historic_predictions_folder = Path(self.full_path / "historic_predictions")
self.historic_predictions_bkp_folder = Path(self.full_path / "historic_predictions_backup")
self.pair_dictionary_path = Path(self.full_path / "pair_dictionary.json")
self.global_metadata_path = Path(self.full_path / "global_metadata.json")
self.metric_tracker_path = Path(self.full_path / "metric_tracker.json")
self.follow_mode = follow_mode
if follow_mode:
self.create_follower_dict()
self.load_drawer_from_disk()
self.load_historic_predictions_from_disk()
self.metric_tracker: Dict[str, Dict[str, Dict[str, list]]] = {}
@@ -134,7 +126,7 @@ class FreqaiDataDrawer:
"""
exists = self.global_metadata_path.is_file()
if exists:
with open(self.global_metadata_path, "r") as fp:
with self.global_metadata_path.open("r") as fp:
metatada_dict = rapidjson.load(fp, number_mode=rapidjson.NM_NATIVE)
return metatada_dict
return {}
@@ -147,15 +139,10 @@ class FreqaiDataDrawer:
"""
exists = self.pair_dictionary_path.is_file()
if exists:
with open(self.pair_dictionary_path, "r") as fp:
with self.pair_dictionary_path.open("r") as fp:
self.pair_dict = rapidjson.load(fp, number_mode=rapidjson.NM_NATIVE)
elif not self.follow_mode:
logger.info("Could not find existing datadrawer, starting from scratch")
else:
logger.warning(
f"Follower could not find pair_dictionary at {self.full_path} "
"sending null values back to strategy"
)
logger.info("Could not find existing datadrawer, starting from scratch")
def load_metric_tracker_from_disk(self):
"""
@@ -165,7 +152,7 @@ class FreqaiDataDrawer:
if self.freqai_info.get('write_metrics_to_disk', False):
exists = self.metric_tracker_path.is_file()
if exists:
with open(self.metric_tracker_path, "r") as fp:
with self.metric_tracker_path.open("r") as fp:
self.metric_tracker = rapidjson.load(fp, number_mode=rapidjson.NM_NATIVE)
logger.info("Loading existing metric tracker from disk.")
else:
@@ -176,11 +163,12 @@ class FreqaiDataDrawer:
Locate and load a previously saved historic predictions.
:return: bool - whether or not the drawer was located
"""
exists = self.historic_predictions_path.is_file()
exists = self.historic_predictions_folder.exists()
convert = self.historic_predictions_path.is_file()
if exists:
try:
with open(self.historic_predictions_path, "rb") as fp:
self.historic_predictions = cloudpickle.load(fp)
self.load_historic_predictions_from_folder()
logger.info(
f"Found existing historic predictions at {self.full_path}, but beware "
"that statistics may be inaccurate if the bot has been offline for "
@@ -188,13 +176,19 @@ class FreqaiDataDrawer:
)
except EOFError:
logger.warning(
'Historical prediction file was corrupted. Trying to load backup file.')
with open(self.historic_predictions_bkp_path, "rb") as fp:
self.historic_predictions = cloudpickle.load(fp)
logger.warning('FreqAI successfully loaded the backup historical predictions file.')
'Historical prediction files were corrupted. Trying to load backup files.')
self.load_historic_predictions_from_folder()
logger.warning('FreqAI successfully loaded the backup '
'historical predictions files.')
elif not exists and convert:
logger.info("Converting your historic predictions pkl to parquet"
"to improve performance.")
with Path.open(self.historic_predictions_path, "rb") as fp:
self.historic_predictions = cloudpickle.load(fp)
self.save_historic_predictions_to_disk()
exists = True
elif not self.follow_mode:
logger.info("Could not find existing historic_predictions, starting from scratch")
else:
logger.warning(
f"Follower could not find historic predictions at {self.full_path} "
@@ -203,73 +197,66 @@ class FreqaiDataDrawer:
return exists
def load_historic_predictions_from_folder(self):
"""
Try to build the historic_predictions dictionary from parquet
files in the historic_predictions_folder
"""
for file_path in self.historic_predictions_folder.glob("*.parquet"):
key = file_path.stem
key.replace("_", "/")
self.historic_predictions[key] = pd.read_parquet(file_path)
return
def save_historic_predictions_to_disk(self):
"""
Save historic predictions pickle to disk
"""
with open(self.historic_predictions_path, "wb") as fp:
cloudpickle.dump(self.historic_predictions, fp, protocol=cloudpickle.DEFAULT_PROTOCOL)
self.historic_predictions_folder.mkdir(parents=True, exist_ok=True)
for key, value in self.historic_predictions.items():
key = key.replace("/", "_")
# pytest.set_trace()
filename = Path(self.historic_predictions_folder / f"{key}.parquet")
value.to_parquet(filename)
# create a backup
shutil.copy(self.historic_predictions_path, self.historic_predictions_bkp_path)
shutil.copytree(self.historic_predictions_folder,
self.historic_predictions_bkp_folder, dirs_exist_ok=True)
def save_metric_tracker_to_disk(self):
"""
Save metric tracker of all pair metrics collected.
"""
with self.save_lock:
with open(self.metric_tracker_path, 'w') as fp:
with self.metric_tracker_path.open('w') as fp:
rapidjson.dump(self.metric_tracker, fp, default=self.np_encoder,
number_mode=rapidjson.NM_NATIVE)
def save_drawer_to_disk(self):
def save_drawer_to_disk(self) -> None:
"""
Save data drawer full of all pair model metadata in present model folder.
"""
with self.save_lock:
with open(self.pair_dictionary_path, 'w') as fp:
with self.pair_dictionary_path.open('w') as fp:
rapidjson.dump(self.pair_dict, fp, default=self.np_encoder,
number_mode=rapidjson.NM_NATIVE)
def save_follower_dict_to_disk(self):
"""
Save follower dictionary to disk (used by strategy for persistent prediction targets)
"""
with open(self.follower_dict_path, "w") as fp:
rapidjson.dump(self.follower_dict, fp, default=self.np_encoder,
number_mode=rapidjson.NM_NATIVE)
def save_global_metadata_to_disk(self, metadata: Dict[str, Any]):
"""
Save global metadata json to disk
"""
with self.save_lock:
with open(self.global_metadata_path, 'w') as fp:
with self.global_metadata_path.open('w') as fp:
rapidjson.dump(metadata, fp, default=self.np_encoder,
number_mode=rapidjson.NM_NATIVE)
def create_follower_dict(self):
"""
Create or dictionary for each follower to maintain unique persistent prediction targets
"""
whitelist_pairs = self.config.get("exchange", {}).get("pair_whitelist")
exists = self.follower_dict_path.is_file()
if exists:
logger.info("Found an existing follower dictionary")
for pair in whitelist_pairs:
self.follower_dict[pair] = {}
self.save_follower_dict_to_disk()
def np_encoder(self, object):
if isinstance(object, np.generic):
return object.item()
def get_pair_dict_info(self, pair: str) -> Tuple[str, int, bool]:
def get_pair_dict_info(self, pair: str) -> Tuple[str, int]:
"""
Locate and load existing model metadata from persistent storage. If not located,
create a new one and append the current pair to it and prepare it for its first
@@ -278,32 +265,19 @@ class FreqaiDataDrawer:
:return:
model_filename: str = unique filename used for loading persistent objects from disk
trained_timestamp: int = the last time the coin was trained
return_null_array: bool = Follower could not find pair metadata
"""
pair_dict = self.pair_dict.get(pair)
data_path_set = self.pair_dict.get(pair, self.empty_pair_dict).get("data_path", "")
return_null_array = False
if pair_dict:
model_filename = pair_dict["model_filename"]
trained_timestamp = pair_dict["trained_timestamp"]
elif not self.follow_mode:
else:
self.pair_dict[pair] = self.empty_pair_dict.copy()
model_filename = ""
trained_timestamp = 0
if not data_path_set and self.follow_mode:
logger.warning(
f"Follower could not find current pair {pair} in "
f"pair_dictionary at path {self.full_path}, sending null values "
"back to strategy."
)
trained_timestamp = 0
model_filename = ''
return_null_array = True
return model_filename, trained_timestamp, return_null_array
return model_filename, trained_timestamp
def set_pair_dict_info(self, metadata: dict) -> None:
pair_in_dict = self.pair_dict.get(metadata["pair"])
@@ -311,7 +285,6 @@ class FreqaiDataDrawer:
return
else:
self.pair_dict[metadata["pair"]] = self.empty_pair_dict.copy()
return
def set_initial_return_values(self, pair: str, pred_df: DataFrame) -> None:
@@ -423,6 +396,12 @@ class FreqaiDataDrawer:
def purge_old_models(self) -> None:
num_keep = self.freqai_info["purge_old_models"]
if not num_keep:
return
elif type(num_keep) == bool:
num_keep = 2
model_folders = [x for x in self.full_path.iterdir() if x.is_dir()]
pattern = re.compile(r"sub-train-(\w+)_(\d{10})")
@@ -445,11 +424,11 @@ class FreqaiDataDrawer:
delete_dict[coin]["timestamps"][int(timestamp)] = dir
for coin in delete_dict:
if delete_dict[coin]["num_folders"] > 2:
if delete_dict[coin]["num_folders"] > num_keep:
sorted_dict = collections.OrderedDict(
sorted(delete_dict[coin]["timestamps"].items())
)
num_delete = len(sorted_dict) - 2
num_delete = len(sorted_dict) - num_keep
deleted = 0
for k, v in sorted_dict.items():
if deleted >= num_delete:
@@ -458,12 +437,6 @@ class FreqaiDataDrawer:
shutil.rmtree(v)
deleted += 1
def update_follower_metadata(self):
# follower needs to load from disk to get any changes made by leader to pair_dict
self.load_drawer_from_disk()
if self.config.get("freqai", {}).get("purge_old_models", False):
self.purge_old_models()
def save_metadata(self, dk: FreqaiDataKitchen) -> None:
"""
Saves only metadata for backtesting studies if user prefers
@@ -481,7 +454,7 @@ class FreqaiDataDrawer:
dk.data["training_features_list"] = list(dk.data_dictionary["train_features"].columns)
dk.data["label_list"] = dk.label_list
with open(save_path / f"{dk.model_filename}_metadata.json", "w") as fp:
with (save_path / f"{dk.model_filename}_metadata.json").open("w") as fp:
rapidjson.dump(dk.data, fp, default=self.np_encoder, number_mode=rapidjson.NM_NATIVE)
return
@@ -514,7 +487,7 @@ class FreqaiDataDrawer:
dk.data["training_features_list"] = dk.training_features_list
dk.data["label_list"] = dk.label_list
# store the metadata
with open(save_path / f"{dk.model_filename}_metadata.json", "w") as fp:
with (save_path / f"{dk.model_filename}_metadata.json").open("w") as fp:
rapidjson.dump(dk.data, fp, default=self.np_encoder, number_mode=rapidjson.NM_NATIVE)
# save the train data to file so we can check preds for area of applicability later
@@ -528,7 +501,7 @@ class FreqaiDataDrawer:
if self.freqai_info["feature_parameters"].get("principal_component_analysis"):
cloudpickle.dump(
dk.pca, open(dk.data_path / f"{dk.model_filename}_pca_object.pkl", "wb")
dk.pca, (dk.data_path / f"{dk.model_filename}_pca_object.pkl").open("wb")
)
self.model_dictionary[coin] = model
@@ -548,7 +521,7 @@ class FreqaiDataDrawer:
Load only metadata into datakitchen to increase performance during
presaved backtesting (prediction file loading).
"""
with open(dk.data_path / f"{dk.model_filename}_metadata.json", "r") as fp:
with (dk.data_path / f"{dk.model_filename}_metadata.json").open("r") as fp:
dk.data = rapidjson.load(fp, number_mode=rapidjson.NM_NATIVE)
dk.training_features_list = dk.data["training_features_list"]
dk.label_list = dk.data["label_list"]
@@ -571,7 +544,7 @@ class FreqaiDataDrawer:
dk.data = self.meta_data_dictionary[coin]["meta_data"]
dk.data_dictionary["train_features"] = self.meta_data_dictionary[coin]["train_df"]
else:
with open(dk.data_path / f"{dk.model_filename}_metadata.json", "r") as fp:
with (dk.data_path / f"{dk.model_filename}_metadata.json").open("r") as fp:
dk.data = rapidjson.load(fp, number_mode=rapidjson.NM_NATIVE)
dk.data_dictionary["train_features"] = pd.read_pickle(
@@ -609,7 +582,7 @@ class FreqaiDataDrawer:
if self.config["freqai"]["feature_parameters"]["principal_component_analysis"]:
dk.pca = cloudpickle.load(
open(dk.data_path / f"{dk.model_filename}_pca_object.pkl", "rb")
(dk.data_path / f"{dk.model_filename}_pca_object.pkl").open("rb")
)
return model
@@ -627,12 +600,12 @@ class FreqaiDataDrawer:
for pair in dk.all_pairs:
for tf in feat_params.get("include_timeframes"):
hist_df = history_data[pair][tf]
# check if newest candle is already appended
df_dp = strategy.dp.get_pair_dataframe(pair, tf)
if len(df_dp.index) == 0:
continue
if str(history_data[pair][tf].iloc[-1]["date"]) == str(
if str(hist_df.iloc[-1]["date"]) == str(
df_dp.iloc[-1:]["date"].iloc[-1]
):
continue
@@ -640,21 +613,30 @@ class FreqaiDataDrawer:
try:
index = (
df_dp.loc[
df_dp["date"] == history_data[pair][tf].iloc[-1]["date"]
df_dp["date"] == hist_df.iloc[-1]["date"]
].index[0]
+ 1
)
except IndexError:
logger.warning(
f"Unable to update pair history for {pair}. "
"If this does not resolve itself after 1 additional candle, "
"please report the error to #freqai discord channel"
)
return
if hist_df.iloc[-1]['date'] < df_dp['date'].iloc[0]:
raise OperationalException("In memory historical data is older than "
f"oldest DataProvider candle for {pair} on "
f"timeframe {tf}")
else:
index = -1
logger.warning(
f"No common dates in historical data and dataprovider for {pair}. "
f"Appending latest dataprovider candle to historical data "
"but please be aware that there is likely a gap in the historical "
"data. \n"
f"Historical data ends at {hist_df.iloc[-1]['date']} "
f"while dataprovider starts at {df_dp['date'].iloc[0]} and"
f"ends at {df_dp['date'].iloc[0]}."
)
history_data[pair][tf] = pd.concat(
[
history_data[pair][tf],
hist_df,
df_dp.iloc[index:],
],
ignore_index=True,
@@ -723,7 +705,7 @@ class FreqaiDataDrawer:
Returns timerange information based on historic predictions file
:return: timerange calculated from saved live data
"""
if not self.historic_predictions_path.is_file():
if not self.historic_predictions_folder.exists():
raise OperationalException(
'Historic predictions not found. Historic predictions data is required '
'to run backtest with the freqai-backtest-live-models option '

View File

@@ -1,6 +1,7 @@
import copy
import inspect
import logging
import random
import shutil
from datetime import datetime, timezone
from math import cos, sin
@@ -170,6 +171,19 @@ class FreqaiDataKitchen:
train_labels = labels
train_weights = weights
if feat_dict["shuffle_after_split"]:
rint1 = random.randint(0, 100)
rint2 = random.randint(0, 100)
train_features = train_features.sample(
frac=1, random_state=rint1).reset_index(drop=True)
train_labels = train_labels.sample(frac=1, random_state=rint1).reset_index(drop=True)
train_weights = pd.DataFrame(train_weights).sample(
frac=1, random_state=rint1).reset_index(drop=True).to_numpy()[:, 0]
test_features = test_features.sample(frac=1, random_state=rint2).reset_index(drop=True)
test_labels = test_labels.sample(frac=1, random_state=rint2).reset_index(drop=True)
test_weights = pd.DataFrame(test_weights).sample(
frac=1, random_state=rint2).reset_index(drop=True).to_numpy()[:, 0]
# Simplest way to reverse the order of training and test data:
if self.freqai_config['feature_parameters'].get('reverse_train_test_order', False):
return self.build_data_dictionary(
@@ -237,7 +251,7 @@ class FreqaiDataKitchen:
(drop_index == 0) & (drop_index_labels == 0)
]
logger.info(
f"dropped {len(unfiltered_df) - len(filtered_df)} training points"
f"{self.pair}: dropped {len(unfiltered_df) - len(filtered_df)} training points"
f" due to NaNs in populated dataset {len(unfiltered_df)}."
)
if (1 - len(filtered_df) / len(unfiltered_df)) > 0.1 and self.live:
@@ -661,7 +675,7 @@ class FreqaiDataKitchen:
]
logger.info(
f"SVM tossed {len(y_pred) - kept_points.sum()}"
f"{self.pair}: SVM tossed {len(y_pred) - kept_points.sum()}"
f" test points from {len(y_pred)} total points."
)
@@ -935,7 +949,7 @@ class FreqaiDataKitchen:
if (len(do_predict) - do_predict.sum()) > 0:
logger.info(
f"DI tossed {len(do_predict) - do_predict.sum()} predictions for "
f"{self.pair}: DI tossed {len(do_predict) - do_predict.sum()} predictions for "
"being too far from training data."
)
@@ -1247,17 +1261,19 @@ class FreqaiDataKitchen:
tfs: List[str] = self.freqai_config["feature_parameters"].get("include_timeframes")
for tf in tfs:
metadata = {"pair": pair, "tf": tf}
informative_df = self.get_pair_data_for_features(
pair, tf, strategy, corr_dataframes, base_dataframes, is_corr_pairs)
informative_copy = informative_df.copy()
for t in self.freqai_config["feature_parameters"]["indicator_periods_candles"]:
df_features = strategy.feature_engineering_expand_all(
informative_copy.copy(), t)
informative_copy.copy(), t, metadata=metadata)
suffix = f"{t}"
informative_df = self.merge_features(informative_df, df_features, tf, tf, suffix)
generic_df = strategy.feature_engineering_expand_basic(informative_copy.copy())
generic_df = strategy.feature_engineering_expand_basic(
informative_copy.copy(), metadata=metadata)
suffix = "gen"
informative_df = self.merge_features(informative_df, generic_df, tf, tf, suffix)
@@ -1299,123 +1315,54 @@ class FreqaiDataKitchen:
dataframe: DataFrame = dataframe containing populated indicators
"""
# this is a hack to check if the user is using the populate_any_indicators function
# check if the user is using the deprecated populate_any_indicators function
new_version = inspect.getsource(strategy.populate_any_indicators) == (
inspect.getsource(IStrategy.populate_any_indicators))
if new_version:
tfs: List[str] = self.freqai_config["feature_parameters"].get("include_timeframes")
pairs: List[str] = self.freqai_config["feature_parameters"].get(
"include_corr_pairlist", [])
if not new_version:
raise OperationalException(
"You are using the `populate_any_indicators()` function"
" which was deprecated on March 1, 2023. Please refer "
"to the strategy migration guide to use the new "
"feature_engineering_* methods: \n"
"https://www.freqtrade.io/en/stable/strategy_migration/#freqai-strategy \n"
"And the feature_engineering_* documentation: \n"
"https://www.freqtrade.io/en/latest/freqai-feature-engineering/"
)
for tf in tfs:
if tf not in base_dataframes:
base_dataframes[tf] = pd.DataFrame()
for p in pairs:
if p not in corr_dataframes:
corr_dataframes[p] = {}
if tf not in corr_dataframes[p]:
corr_dataframes[p][tf] = pd.DataFrame()
if not prediction_dataframe.empty:
dataframe = prediction_dataframe.copy()
else:
dataframe = base_dataframes[self.config["timeframe"]].copy()
corr_pairs: List[str] = self.freqai_config["feature_parameters"].get(
"include_corr_pairlist", [])
dataframe = self.populate_features(dataframe.copy(), pair, strategy,
corr_dataframes, base_dataframes)
dataframe = strategy.feature_engineering_standard(dataframe.copy())
# ensure corr pairs are always last
for corr_pair in corr_pairs:
if pair == corr_pair:
continue # dont repeat anything from whitelist
if corr_pairs and do_corr_pairs:
dataframe = self.populate_features(dataframe.copy(), corr_pair, strategy,
corr_dataframes, base_dataframes, True)
dataframe = strategy.set_freqai_targets(dataframe.copy())
self.get_unique_classes_from_labels(dataframe)
dataframe = self.remove_special_chars_from_feature_names(dataframe)
if self.config.get('reduce_df_footprint', False):
dataframe = reduce_dataframe_footprint(dataframe)
return dataframe
else:
# the user is using the populate_any_indicators functions which is deprecated
df = self.use_strategy_to_populate_indicators_old_version(
strategy, corr_dataframes, base_dataframes, pair,
prediction_dataframe, do_corr_pairs)
return df
def use_strategy_to_populate_indicators_old_version(
self,
strategy: IStrategy,
corr_dataframes: dict = {},
base_dataframes: dict = {},
pair: str = "",
prediction_dataframe: DataFrame = pd.DataFrame(),
do_corr_pairs: bool = True,
) -> DataFrame:
"""
Use the user defined strategy for populating indicators during retrain
:param strategy: IStrategy = user defined strategy object
:param corr_dataframes: dict = dict containing the df pair dataframes
(for user defined timeframes)
:param base_dataframes: dict = dict containing the current pair dataframes
(for user defined timeframes)
:param metadata: dict = strategy furnished pair metadata
:return:
dataframe: DataFrame = dataframe containing populated indicators
"""
# for prediction dataframe creation, we let dataprovider handle everything in the strategy
# so we create empty dictionaries, which allows us to pass None to
# `populate_any_indicators()`. Signaling we want the dp to give us the live dataframe.
tfs: List[str] = self.freqai_config["feature_parameters"].get("include_timeframes")
pairs: List[str] = self.freqai_config["feature_parameters"].get("include_corr_pairlist", [])
pairs: List[str] = self.freqai_config["feature_parameters"].get(
"include_corr_pairlist", [])
for tf in tfs:
if tf not in base_dataframes:
base_dataframes[tf] = pd.DataFrame()
for p in pairs:
if p not in corr_dataframes:
corr_dataframes[p] = {}
if tf not in corr_dataframes[p]:
corr_dataframes[p][tf] = pd.DataFrame()
if not prediction_dataframe.empty:
dataframe = prediction_dataframe.copy()
for tf in tfs:
base_dataframes[tf] = None
for p in pairs:
if p not in corr_dataframes:
corr_dataframes[p] = {}
corr_dataframes[p][tf] = None
else:
dataframe = base_dataframes[self.config["timeframe"]].copy()
sgi = False
for tf in tfs:
if tf == tfs[-1]:
sgi = True # doing this last allows user to use all tf raw prices in labels
dataframe = strategy.populate_any_indicators(
pair,
dataframe.copy(),
tf,
informative=base_dataframes[tf],
set_generalized_indicators=sgi
)
corr_pairs: List[str] = self.freqai_config["feature_parameters"].get(
"include_corr_pairlist", [])
dataframe = self.populate_features(dataframe.copy(), pair, strategy,
corr_dataframes, base_dataframes)
metadata = {"pair": pair}
dataframe = strategy.feature_engineering_standard(dataframe.copy(), metadata=metadata)
# ensure corr pairs are always last
for corr_pair in pairs:
for corr_pair in corr_pairs:
if pair == corr_pair:
continue # dont repeat anything from whitelist
for tf in tfs:
if pairs and do_corr_pairs:
dataframe = strategy.populate_any_indicators(
corr_pair,
dataframe.copy(),
tf,
informative=corr_dataframes[corr_pair][tf]
)
if corr_pairs and do_corr_pairs:
dataframe = self.populate_features(dataframe.copy(), corr_pair, strategy,
corr_dataframes, base_dataframes, True)
dataframe = strategy.set_freqai_targets(dataframe.copy(), metadata=metadata)
self.get_unique_classes_from_labels(dataframe)
@@ -1546,3 +1493,25 @@ class FreqaiDataKitchen:
dataframe.columns = dataframe.columns.str.replace(c, "")
return dataframe
def buffer_timerange(self, timerange: TimeRange):
"""
Buffer the start and end of the timerange. This is used *after* the indicators
are populated.
The main example use is when predicting maxima and minima, the argrelextrema
function cannot know the maxima/minima at the edges of the timerange. To improve
model accuracy, it is best to compute argrelextrema on the full timerange
and then use this function to cut off the edges (buffer) by the kernel.
In another case, if the targets are set to a shifted price movement, this
buffer is unnecessary because the shifted candles at the end of the timerange
will be NaN and FreqAI will automatically cut those off of the training
dataset.
"""
buffer = self.freqai_config["feature_parameters"]["buffer_train_data_candles"]
if buffer:
timerange.stopts -= buffer * timeframe_to_seconds(self.config["timeframe"])
timerange.startts += buffer * timeframe_to_seconds(self.config["timeframe"])
return timerange

View File

@@ -1,4 +1,3 @@
import inspect
import logging
import threading
import time
@@ -66,12 +65,11 @@ class IFreqaiModel(ABC):
self.retrain = False
self.first = True
self.set_full_path()
self.follow_mode: bool = self.freqai_info.get("follow_mode", False)
self.save_backtest_models: bool = self.freqai_info.get("save_backtest_models", True)
if self.save_backtest_models:
logger.info('Backtesting module configured to save all models.')
self.dd = FreqaiDataDrawer(Path(self.full_path), self.config, self.follow_mode)
self.dd = FreqaiDataDrawer(Path(self.full_path), self.config)
# set current candle to arbitrary historical date
self.current_candle: datetime = datetime.fromtimestamp(637887600, tz=timezone.utc)
self.dd.current_candle = self.current_candle
@@ -106,8 +104,7 @@ class IFreqaiModel(ABC):
self.data_provider: Optional[DataProvider] = None
self.max_system_threads = max(int(psutil.cpu_count() * 2 - 2), 1)
self.can_short = True # overridden in start() with strategy.can_short
self.warned_deprecated_populate_any_indicators = False
self.model: Any = None
record_params(config, self.full_path)
@@ -139,9 +136,6 @@ class IFreqaiModel(ABC):
self.data_provider = strategy.dp
self.can_short = strategy.can_short
# check if the strategy has deprecated populate_any_indicators function
self.check_deprecated_populate_any_indicators(strategy)
if self.live:
self.inference_timer('start')
self.dk = FreqaiDataKitchen(self.config, self.live, metadata["pair"])
@@ -153,7 +147,7 @@ class IFreqaiModel(ABC):
# (backtest window, i.e. window immediately following the training window).
# FreqAI slides the window and sequentially builds the backtesting results before returning
# the concatenated results for the full backtesting period back to the strategy.
elif not self.follow_mode:
else:
self.dk = FreqaiDataKitchen(self.config, self.live, metadata["pair"])
if not self.config.get("freqai_backtest_live_models", False):
logger.info(f"Training {len(self.dk.training_timeranges)} timeranges")
@@ -228,7 +222,7 @@ class IFreqaiModel(ABC):
logger.warning(f'{pair} not in current whitelist, removing from train queue.')
continue
(_, trained_timestamp, _) = self.dd.get_pair_dict_info(pair)
(_, trained_timestamp) = self.dd.get_pair_dict_info(pair)
dk = FreqaiDataKitchen(self.config, self.live, pair)
(
@@ -286,7 +280,7 @@ class IFreqaiModel(ABC):
# following tr_train. Both of these windows slide through the
# entire backtest
for tr_train, tr_backtest in zip(dk.training_timeranges, dk.backtesting_timeranges):
(_, _, _) = self.dd.get_pair_dict_info(pair)
(_, _) = self.dd.get_pair_dict_info(pair)
train_it += 1
total_trains = len(dk.backtesting_timeranges)
self.training_timerange = tr_train
@@ -325,9 +319,13 @@ class IFreqaiModel(ABC):
populate_indicators = False
dataframe_base_train = dataframe.loc[dataframe["date"] < tr_train.stopdt, :]
dataframe_base_train = strategy.set_freqai_targets(dataframe_base_train)
dataframe_base_train = strategy.set_freqai_targets(
dataframe_base_train, metadata=metadata)
dataframe_base_backtest = dataframe.loc[dataframe["date"] < tr_backtest.stopdt, :]
dataframe_base_backtest = strategy.set_freqai_targets(dataframe_base_backtest)
dataframe_base_backtest = strategy.set_freqai_targets(
dataframe_base_backtest, metadata=metadata)
tr_train = dk.buffer_timerange(tr_train)
dataframe_train = dk.slice_dataframe(tr_train, dataframe_base_train)
dataframe_backtest = dk.slice_dataframe(tr_backtest, dataframe_base_backtest)
@@ -341,13 +339,14 @@ class IFreqaiModel(ABC):
except Exception as msg:
logger.warning(
f"Training {pair} raised exception {msg.__class__.__name__}. "
f"Message: {msg}, skipping.")
f"Message: {msg}, skipping.", exc_info=True)
self.model = None
self.dd.pair_dict[pair]["trained_timestamp"] = int(
tr_train.stopts)
if self.plot_features:
if self.plot_features and self.model is not None:
plot_feature_importance(self.model, pair, dk, self.plot_features)
if self.save_backtest_models:
if self.save_backtest_models and self.model is not None:
logger.info('Saving backtest model to disk.')
self.dd.save_data(self.model, pair, dk)
else:
@@ -379,18 +378,9 @@ class IFreqaiModel(ABC):
:returns:
dk: FreqaiDataKitchen = Data management/analysis tool associated to present pair only
"""
# update follower
if self.follow_mode:
self.dd.update_follower_metadata()
# get the model metadata associated with the current pair
(_, trained_timestamp, return_null_array) = self.dd.get_pair_dict_info(metadata["pair"])
# if the metadata doesn't exist, the follower returns null arrays to strategy
if self.follow_mode and return_null_array:
logger.info("Returning null array from follower to strategy")
self.dd.return_null_values_to_strategy(dataframe, dk)
return dk
(_, trained_timestamp) = self.dd.get_pair_dict_info(metadata["pair"])
# append the historic data once per round
if self.dd.historic_data:
@@ -398,27 +388,18 @@ class IFreqaiModel(ABC):
logger.debug(f'Updating historic data on pair {metadata["pair"]}')
self.track_current_candle()
if not self.follow_mode:
(_, new_trained_timerange, data_load_timerange) = dk.check_if_new_training_required(
trained_timestamp
)
dk.set_paths(metadata["pair"], new_trained_timerange.stopts)
(_, new_trained_timerange, data_load_timerange) = dk.check_if_new_training_required(
trained_timestamp
)
dk.set_paths(metadata["pair"], new_trained_timerange.stopts)
# load candle history into memory if it is not yet.
if not self.dd.historic_data:
self.dd.load_all_pair_histories(data_load_timerange, dk)
# load candle history into memory if it is not yet.
if not self.dd.historic_data:
self.dd.load_all_pair_histories(data_load_timerange, dk)
if not self.scanning:
self.scanning = True
self.start_scanning(strategy)
elif self.follow_mode:
dk.set_paths(metadata["pair"], trained_timestamp)
logger.info(
"FreqAI instance set to follow_mode, finding existing pair "
f"using { self.identifier }"
)
if not self.scanning:
self.scanning = True
self.start_scanning(strategy)
# load the model and associated data into the data kitchen
self.model = self.dd.load_data(metadata["pair"], dk)
@@ -506,7 +487,7 @@ class IFreqaiModel(ABC):
"strategy is furnishing the same features as the pretrained"
"model. In case of --strategy-list, please be aware that FreqAI "
"requires all strategies to maintain identical "
"populate_any_indicator() functions"
"feature_engineering_* functions"
)
def data_cleaning_train(self, dk: FreqaiDataKitchen) -> None:
@@ -580,7 +561,13 @@ class IFreqaiModel(ABC):
:return:
:boolean: whether the model file exists or not.
"""
path_to_modelfile = Path(dk.data_path / f"{dk.model_filename}_model.joblib")
if self.dd.model_type == 'joblib':
file_type = ".joblib"
elif self.dd.model_type == 'keras':
file_type = ".h5"
elif 'stable_baselines' in self.dd.model_type or 'sb3_contrib' == self.dd.model_type:
file_type = ".zip"
path_to_modelfile = Path(dk.data_path / f"{dk.model_filename}_model{file_type}")
file_exists = path_to_modelfile.is_file()
if file_exists:
logger.info("Found model at %s", dk.data_path / dk.model_filename)
@@ -612,7 +599,7 @@ class IFreqaiModel(ABC):
:param strategy: IStrategy = user defined strategy object
:param dk: FreqaiDataKitchen = non-persistent data container for current coin/loop
:param data_load_timerange: TimeRange = the amount of data to be loaded
for populate_any_indicators
for populating indicators
(larger than new_trained_timerange so that
new_trained_timerange does not contain any NaNs)
"""
@@ -625,6 +612,8 @@ class IFreqaiModel(ABC):
strategy, corr_dataframes, base_dataframes, pair
)
new_trained_timerange = dk.buffer_timerange(new_trained_timerange)
unfiltered_dataframe = dk.slice_dataframe(new_trained_timerange, unfiltered_dataframe)
# find the features indicated by strategy and store in datakitchen
@@ -640,8 +629,7 @@ class IFreqaiModel(ABC):
if self.plot_features:
plot_feature_importance(model, pair, dk, self.plot_features)
if self.freqai_info.get("purge_old_models", False):
self.dd.purge_old_models()
self.dd.purge_old_models()
def set_initial_historic_predictions(
self, pred_df: DataFrame, dk: FreqaiDataKitchen, pair: str, strat_df: DataFrame
@@ -817,7 +805,7 @@ class IFreqaiModel(ABC):
logger.warning("Couldn't cache corr_pair dataframes for improved performance. "
"Consider ensuring that the full coin/stake, e.g. XYZ/USD, "
"is included in the column names when you are creating features "
"in `populate_any_indicators()`.")
"in `feature_engineering_*` functions.")
self.get_corr_dataframes = not bool(self.corr_dataframes)
elif self.corr_dataframes:
dataframe = dk.attach_corr_pair_columns(
@@ -944,26 +932,6 @@ class IFreqaiModel(ABC):
dk.return_dataframe, saved_dataframe, how='left', left_on='date', right_on="date_pred")
return dk
def check_deprecated_populate_any_indicators(self, strategy: IStrategy):
"""
Check and warn if the deprecated populate_any_indicators function is used.
:param strategy: strategy object
"""
if not self.warned_deprecated_populate_any_indicators:
self.warned_deprecated_populate_any_indicators = True
old_version = inspect.getsource(strategy.populate_any_indicators) != (
inspect.getsource(IStrategy.populate_any_indicators))
if old_version:
logger.warning("DEPRECATION WARNING: "
"You are using the deprecated populate_any_indicators function. "
"This function will raise an error on March 1 2023. "
"Please update your strategy by using "
"the new feature_engineering functions. See \n"
"https://www.freqtrade.io/en/latest/freqai-feature-engineering/"
"for details.")
# Following methods which are overridden by user made prediction models.
# See freqai/prediction_models/CatboostPredictionModel.py for an example.

View File

@@ -100,7 +100,7 @@ class ReinforcementLearner(BaseReinforcementLearningModel):
"""
# first, penalize if the action is not valid
if not self._is_valid(action):
self.tensorboard_log("is_valid")
self.tensorboard_log("invalid", category="actions")
return -2
pnl = self.get_unrealized_profit()

View File

@@ -34,7 +34,12 @@ class ReinforcementLearner_multiproc(ReinforcementLearner):
train_df = data_dictionary["train_features"]
test_df = data_dictionary["test_features"]
env_info = self.pack_env_dict()
if self.train_env:
self.train_env.close()
if self.eval_env:
self.eval_env.close()
env_info = self.pack_env_dict(dk.pair)
env_id = "train_env"
self.train_env = SubprocVecEnv([make_env(self.MyRLEnv, env_id, i, 1,

View File

@@ -211,7 +211,7 @@ def record_params(config: Dict[str, Any], full_path: Path) -> None:
"pairs": config.get('exchange', {}).get('pair_whitelist')
}
with open(params_record_path, "w") as handle:
with params_record_path.open("w") as handle:
rapidjson.dump(
run_params,
handle,

View File

@@ -127,19 +127,19 @@ class FreqtradeBot(LoggingMixin):
for minutes in [0, 15, 30, 45]:
t = str(time(time_slot, minutes, 2))
self._schedule.every().day.at(t).do(update)
self.last_process = datetime(1970, 1, 1, tzinfo=timezone.utc)
self.last_process: Optional[datetime] = None
self.strategy.ft_bot_start()
# Initialize protections AFTER bot start - otherwise parameters are not loaded.
self.protections = ProtectionManager(self.config, self.strategy.protections)
def notify_status(self, msg: str) -> None:
def notify_status(self, msg: str, msg_type=RPCMessageType.STATUS) -> None:
"""
Public method for users of this class (worker, etc.) to send notifications
via RPC about changes in the bot status.
"""
self.rpc.send_msg({
'type': RPCMessageType.STATUS,
'type': msg_type,
'status': msg
})
@@ -344,7 +344,15 @@ class FreqtradeBot(LoggingMixin):
try:
fo = self.exchange.fetch_order_or_stoploss_order(order.order_id, order.ft_pair,
order.ft_order_side == 'stoploss')
if not order.trade:
# This should not happen, but it does if trades were deleted manually.
# This can only incur on sqlite, which doesn't enforce foreign constraints.
logger.warning(
f"Order {order.order_id} has no trade attached. "
"This may suggest a database corruption. "
f"The expected trade ID is {order.ft_trade_id}. Ignoring this order."
)
continue
self.update_trade_state(order.trade, order.order_id, fo,
stoploss_order=(order.ft_order_side == 'stoploss'))
@@ -355,7 +363,7 @@ class FreqtradeBot(LoggingMixin):
"Order is older than 5 days. Assuming order was fully cancelled.")
fo = order.to_ccxt_object()
fo['status'] = 'canceled'
self.handle_timedout_order(fo, order.trade)
self.handle_cancel_order(fo, order.trade, constants.CANCEL_REASON['TIMEOUT'])
except ExchangeError as e:
@@ -578,7 +586,7 @@ class FreqtradeBot(LoggingMixin):
min_entry_stake = self.exchange.get_min_pair_stake_amount(trade.pair,
current_entry_rate,
self.strategy.stoploss)
0.0)
min_exit_stake = self.exchange.get_min_pair_stake_amount(trade.pair,
current_exit_rate,
self.strategy.stoploss)
@@ -586,7 +594,7 @@ class FreqtradeBot(LoggingMixin):
stake_available = self.wallets.get_available_stake_amount()
logger.debug(f"Calling adjust_trade_position for pair {trade.pair}")
stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position,
default_retval=None)(
default_retval=None, supress_error=True)(
trade=trade,
current_time=datetime.now(timezone.utc), current_rate=current_entry_rate,
current_profit=current_entry_profit, min_stake=min_entry_stake,
@@ -625,7 +633,7 @@ class FreqtradeBot(LoggingMixin):
return
remaining = (trade.amount - amount) * current_exit_rate
if remaining < min_exit_stake:
if min_exit_stake and remaining < min_exit_stake:
logger.info(f"Remaining amount of {remaining} would be smaller "
f"than the minimum of {min_exit_stake}.")
return
@@ -692,7 +700,8 @@ class FreqtradeBot(LoggingMixin):
pos_adjust = trade is not None
enter_limit_requested, stake_amount, leverage = self.get_valid_enter_price_and_stake(
pair, price, stake_amount, trade_side, enter_tag, trade, order_adjust, leverage_)
pair, price, stake_amount, trade_side, enter_tag, trade, order_adjust, leverage_,
pos_adjust)
if not stake_amount:
return False
@@ -750,13 +759,15 @@ class FreqtradeBot(LoggingMixin):
self.exchange.name, order['filled'], order['amount'],
order['remaining']
)
amount = safe_value_fallback(order, 'filled', 'amount')
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
amount = safe_value_fallback(order, 'filled', 'amount', amount)
enter_limit_filled_price = safe_value_fallback(
order, 'average', 'price', enter_limit_filled_price)
# in case of FOK the order may be filled immediately and fully
elif order_status == 'closed':
amount = safe_value_fallback(order, 'filled', 'amount')
enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
amount = safe_value_fallback(order, 'filled', 'amount', amount)
enter_limit_filled_price = safe_value_fallback(
order, 'average', 'price', enter_limit_requested)
# Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
@@ -799,6 +810,9 @@ class FreqtradeBot(LoggingMixin):
precision_mode=self.exchange.precisionMode,
contract_size=self.exchange.get_contract_size(pair),
)
stoploss = self.strategy.stoploss if not self.edge else self.edge.get_stoploss(pair)
trade.adjust_stop_loss(trade.open_rate, stoploss, initial=True)
else:
# This is additional buy, we reset fee_open_currency so timeout checking can work
trade.is_open = True
@@ -808,7 +822,7 @@ class FreqtradeBot(LoggingMixin):
trade.orders.append(order_obj)
trade.recalc_trade_from_orders()
Trade.query.session.add(trade)
Trade.session.add(trade)
Trade.commit()
# Updating wallets
@@ -831,7 +845,7 @@ class FreqtradeBot(LoggingMixin):
def cancel_stoploss_on_exchange(self, trade: Trade) -> Trade:
# First cancelling stoploss on exchange ...
if self.strategy.order_types.get('stoploss_on_exchange') and trade.stoploss_order_id:
if trade.stoploss_order_id:
try:
logger.info(f"Canceling stoploss on exchange for {trade}")
co = self.exchange.cancel_stoploss_order_with_result(
@@ -850,7 +864,12 @@ class FreqtradeBot(LoggingMixin):
trade: Optional[Trade],
order_adjust: bool,
leverage_: Optional[float],
pos_adjust: bool,
) -> Tuple[float, float, float]:
"""
Validate and eventually adjust (within limits) limit, amount and leverage
:return: Tuple with (price, amount, leverage)
"""
if price:
enter_limit_requested = price
@@ -896,7 +915,9 @@ class FreqtradeBot(LoggingMixin):
# We do however also need min-stake to determine leverage, therefore this is ignored as
# edge-case for now.
min_stake_amount = self.exchange.get_min_pair_stake_amount(
pair, enter_limit_requested, self.strategy.stoploss, leverage)
pair, enter_limit_requested,
self.strategy.stoploss if not pos_adjust else 0.0,
leverage)
max_stake_amount = self.exchange.get_max_pair_stake_amount(
pair, enter_limit_requested, leverage)
@@ -1003,12 +1024,16 @@ class FreqtradeBot(LoggingMixin):
trades_closed = 0
for trade in trades:
try:
try:
if (self.strategy.order_types.get('stoploss_on_exchange') and
self.handle_stoploss_on_exchange(trade)):
trades_closed += 1
Trade.commit()
continue
if (self.strategy.order_types.get('stoploss_on_exchange') and
self.handle_stoploss_on_exchange(trade)):
trades_closed += 1
Trade.commit()
continue
except InvalidOrderException as exception:
logger.warning(
f'Unable to handle stoploss on exchange for {trade.pair}: {exception}')
# Check if we can sell our current pair
if trade.open_order_id is None and trade.is_open and self.handle_trade(trade):
trades_closed += 1
@@ -1068,7 +1093,7 @@ class FreqtradeBot(LoggingMixin):
datetime.now(timezone.utc),
enter=enter,
exit_=exit_,
force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0
force_stoploss=self.edge.get_stoploss(trade.pair) if self.edge else 0
)
for should_exit in exits:
if should_exit.exit_flag:
@@ -1088,7 +1113,7 @@ class FreqtradeBot(LoggingMixin):
:return: True if the order succeeded, and False in case of problems.
"""
try:
stoploss_order = self.exchange.stoploss(
stoploss_order = self.exchange.create_stoploss(
pair=trade.pair,
amount=trade.amount,
stop_price=stop_price,
@@ -1112,8 +1137,7 @@ class FreqtradeBot(LoggingMixin):
trade.stoploss_order_id = None
logger.error(f'Unable to place a stoploss order on exchange. {e}')
logger.warning('Exiting the trade forcefully')
self.execute_trade_exit(trade, stop_price, exit_check=ExitCheckTuple(
exit_type=ExitType.EMERGENCY_EXIT))
self.emergency_exit(trade, stop_price)
except ExchangeError:
trade.stoploss_order_id = None
@@ -1160,15 +1184,13 @@ class FreqtradeBot(LoggingMixin):
# If enter order is fulfilled but there is no stoploss, we add a stoploss on exchange
if not stoploss_order:
stoploss = (
self.edge.stoploss(pair=trade.pair)
if self.edge else
trade.stop_loss_pct / trade.leverage
)
if trade.is_short:
stop_price = trade.open_rate * (1 - stoploss)
else:
stop_price = trade.open_rate * (1 + stoploss)
stop_price = trade.stoploss_or_liquidation
if self.edge:
stoploss = self.edge.get_stoploss(pair=trade.pair)
stop_price = (
trade.open_rate * (1 - stoploss) if trade.is_short
else trade.open_rate * (1 + stoploss)
)
if self.create_stoploss_order(trade=trade, stop_price=stop_price):
# The above will return False if the placement failed and the trade was force-sold.
@@ -1253,11 +1275,11 @@ class FreqtradeBot(LoggingMixin):
if not_closed:
if fully_cancelled or (order_obj and self.strategy.ft_check_timed_out(
trade, order_obj, datetime.now(timezone.utc))):
self.handle_timedout_order(order, trade)
self.handle_cancel_order(order, trade, constants.CANCEL_REASON['TIMEOUT'])
else:
self.replace_order(order, order_obj, trade)
def handle_timedout_order(self, order: Dict, trade: Trade) -> None:
def handle_cancel_order(self, order: Dict, trade: Trade, reason: str) -> None:
"""
Check if current analyzed order timed out and cancel if necessary.
:param order: Order dict grabbed with exchange.fetch_order()
@@ -1265,22 +1287,24 @@ class FreqtradeBot(LoggingMixin):
:return: None
"""
if order['side'] == trade.entry_side:
self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT'])
self.handle_cancel_enter(trade, order, reason)
else:
canceled = self.handle_cancel_exit(
trade, order, constants.CANCEL_REASON['TIMEOUT'])
canceled = self.handle_cancel_exit(trade, order, reason)
canceled_count = trade.get_exit_order_count()
max_timeouts = self.config.get('unfilledtimeout', {}).get('exit_timeout_count', 0)
if canceled and max_timeouts > 0 and canceled_count >= max_timeouts:
logger.warning(f'Emergency exiting trade {trade}, as the exit order '
f'timed out {max_timeouts} times.')
try:
self.execute_trade_exit(
trade, order['price'],
exit_check=ExitCheckTuple(exit_type=ExitType.EMERGENCY_EXIT))
except DependencyException as exception:
logger.warning(
f'Unable to emergency sell trade {trade.pair}: {exception}')
self.emergency_exit(trade, order['price'])
def emergency_exit(self, trade: Trade, price: float) -> None:
try:
self.execute_trade_exit(
trade, price,
exit_check=ExitCheckTuple(exit_type=ExitType.EMERGENCY_EXIT))
except DependencyException as exception:
logger.warning(
f'Unable to emergency exit trade {trade.pair}: {exception}')
def replace_order(self, order: Dict, order_obj: Optional[Order], trade: Trade) -> None:
"""
@@ -1307,7 +1331,7 @@ class FreqtradeBot(LoggingMixin):
default_retval=order_obj.price)(
trade=trade, order=order_obj, pair=trade.pair,
current_time=datetime.now(timezone.utc), proposed_rate=proposed_rate,
current_order_rate=order_obj.price, entry_tag=trade.enter_tag,
current_order_rate=order_obj.safe_price, entry_tag=trade.enter_tag,
side=trade.entry_side)
replacing = True
@@ -1323,7 +1347,8 @@ class FreqtradeBot(LoggingMixin):
# place new order only if new price is supplied
self.execute_entry(
pair=trade.pair,
stake_amount=(order_obj.remaining * order_obj.price / trade.leverage),
stake_amount=(
order_obj.safe_remaining * order_obj.safe_price / trade.leverage),
price=adjusted_entry_price,
trade=trade,
is_short=trade.is_short,
@@ -1337,6 +1362,8 @@ class FreqtradeBot(LoggingMixin):
"""
for trade in Trade.get_open_order_trades():
if not trade.open_order_id:
continue
try:
order = self.exchange.fetch_order(trade.open_order_id, trade.pair)
except (ExchangeError):
@@ -1361,6 +1388,9 @@ class FreqtradeBot(LoggingMixin):
"""
was_trade_fully_canceled = False
side = trade.entry_side.capitalize()
if not trade.open_order_id:
logger.warning(f"No open order for {trade}.")
return False
# Cancelled orders may have the status of 'canceled' or 'closed'
if order['status'] not in constants.NON_OPEN_EXCHANGE_STATES:
@@ -1447,34 +1477,32 @@ class FreqtradeBot(LoggingMixin):
return False
try:
co = self.exchange.cancel_order_with_result(trade.open_order_id, trade.pair,
trade.amount)
order = self.exchange.cancel_order_with_result(order['id'], trade.pair,
trade.amount)
except InvalidOrderException:
logger.exception(
f"Could not cancel {trade.exit_side} order {trade.open_order_id}")
return False
trade.close_rate = None
trade.close_rate_requested = None
trade.close_profit = None
trade.close_profit_abs = None
# Set exit_reason for fill message
exit_reason_prev = trade.exit_reason
trade.exit_reason = trade.exit_reason + f", {reason}" if trade.exit_reason else reason
self.update_trade_state(trade, trade.open_order_id, co)
# Order might be filled above in odd timing issues.
if co.get('status') in ('canceled', 'cancelled'):
if order.get('status') in ('canceled', 'cancelled'):
trade.exit_reason = None
trade.open_order_id = None
else:
trade.exit_reason = exit_reason_prev
logger.info(f'{trade.exit_side.capitalize()} order {reason} for {trade}.')
cancelled = True
else:
reason = constants.CANCEL_REASON['CANCELLED_ON_EXCHANGE']
logger.info(f'{trade.exit_side.capitalize()} order {reason} for {trade}.')
self.update_trade_state(trade, trade.open_order_id, order)
trade.open_order_id = None
trade.exit_reason = None
self.update_trade_state(trade, trade.open_order_id, order)
logger.info(f'{trade.exit_side.capitalize()} order {reason} for {trade}.')
trade.open_order_id = None
trade.close_rate = None
trade.close_rate_requested = None
self._notify_exit_cancel(
trade,
@@ -1626,13 +1654,13 @@ class FreqtradeBot(LoggingMixin):
# second condition is for mypy only; order will always be passed during sub trade
if sub_trade and order is not None:
amount = order.safe_filled if fill else order.amount
amount = order.safe_filled if fill else order.safe_amount
order_rate: float = order.safe_price
profit = trade.calc_profit(rate=order_rate, amount=amount, open_rate=trade.open_rate)
profit_ratio = trade.calc_profit_ratio(order_rate, amount, trade.open_rate)
else:
order_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
order_rate = trade.safe_close_rate
profit = trade.calc_profit(rate=order_rate) + (0.0 if fill else trade.realized_profit)
profit_ratio = trade.calc_profit_ratio(order_rate)
amount = trade.amount
@@ -1687,7 +1715,7 @@ class FreqtradeBot(LoggingMixin):
raise DependencyException(
f"Order_obj not found for {order_id}. This should not have happened.")
profit_rate = trade.close_rate if trade.close_rate else trade.close_rate_requested
profit_rate: float = trade.safe_close_rate
profit_trade = trade.calc_profit(rate=profit_rate)
current_rate = self.exchange.get_rate(
trade.pair, side='exit', is_short=trade.is_short, refresh=False)
@@ -1730,7 +1758,8 @@ class FreqtradeBot(LoggingMixin):
#
def update_trade_state(
self, trade: Trade, order_id: str, action_order: Optional[Dict[str, Any]] = None,
self, trade: Trade, order_id: Optional[str],
action_order: Optional[Dict[str, Any]] = None,
stoploss_order: bool = False, send_msg: bool = True) -> bool:
"""
Checks trades with open orders and updates the amount if necessary
@@ -1789,6 +1818,7 @@ class FreqtradeBot(LoggingMixin):
is_short=trade.is_short,
amount=trade.amount,
stake_amount=trade.stake_amount,
leverage=trade.leverage,
wallet_balance=trade.stake_amount,
))

View File

@@ -1,2 +1 @@
# flake8: noqa: F401
from freqtrade.leverage.interest import interest
from freqtrade.leverage.interest import interest # noqa: F401

View File

@@ -103,9 +103,9 @@ def setup_logging(config: Config) -> None:
logging.root.addHandler(handler_sl)
elif s[0] == 'journald': # pragma: no cover
try:
from systemd.journal import JournaldLogHandler
from cysystemd.journal import JournaldLogHandler
except ImportError:
raise OperationalException("You need the systemd python package be installed in "
raise OperationalException("You need the cysystemd python package be installed in "
"order to use logging to journald.")
handler_jd = get_existing_handlers(JournaldLogHandler)
if handler_jd:

View File

@@ -6,8 +6,7 @@ import logging
import re
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Iterator, List, Mapping, Optional, Union
from typing.io import IO
from typing import Any, Dict, Iterator, List, Mapping, Optional, TextIO, Union
from urllib.parse import urlparse
import orjson
@@ -81,7 +80,7 @@ def file_dump_json(filename: Path, data: Any, is_zip: bool = False, log: bool =
else:
if log:
logger.info(f'dumping json to "{filename}"')
with open(filename, 'w') as fp:
with filename.open('w') as fp:
rapidjson.dump(data, fp, default=str, number_mode=rapidjson.NM_NATIVE)
logger.debug(f'done json to "{filename}"')
@@ -98,12 +97,12 @@ def file_dump_joblib(filename: Path, data: Any, log: bool = True) -> None:
if log:
logger.info(f'dumping joblib to "{filename}"')
with open(filename, 'wb') as fp:
with filename.open('wb') as fp:
joblib.dump(data, fp)
logger.debug(f'done joblib dump to "{filename}"')
def json_load(datafile: IO) -> Any:
def json_load(datafile: Union[gzip.GzipFile, TextIO]) -> Any:
"""
load data with rapidjson
Use this to have a consistent experience,
@@ -112,7 +111,7 @@ def json_load(datafile: IO) -> Any:
return rapidjson.load(datafile, number_mode=rapidjson.NM_NATIVE)
def file_load_json(file):
def file_load_json(file: Path):
if file.suffix != ".gz":
gzipfile = file.with_suffix(file.suffix + '.gz')
@@ -125,7 +124,7 @@ def file_load_json(file):
pairdata = json_load(datafile)
elif file.is_file():
logger.debug(f"Loading historical data from file {file}")
with open(file) as datafile:
with file.open() as datafile:
pairdata = json_load(datafile)
else:
return None

View File

@@ -1,2 +1 @@
# flake8: noqa: F401
from freqtrade.mixins.logging_mixin import LoggingMixin
from freqtrade.mixins.logging_mixin import LoggingMixin # noqa: F401

View File

@@ -29,7 +29,7 @@ def get_strategy_run_id(strategy) -> str:
# Include _ft_params_from_file - so changing parameter files cause cache eviction
digest.update(rapidjson.dumps(
strategy._ft_params_from_file, default=str, number_mode=rapidjson.NM_NAN).encode('utf-8'))
with open(strategy.__file__, 'rb') as fp:
with Path(strategy.__file__).open('rb') as fp:
digest.update(fp.read())
return digest.hexdigest().lower()

View File

@@ -93,7 +93,7 @@ class Backtesting:
if self.config.get('strategy_list'):
if self.config.get('freqai', {}).get('enabled', False):
logger.warning("Using --strategy-list with FreqAI REQUIRES all strategies "
"to have identical populate_any_indicators.")
"to have identical feature_engineering_* functions.")
for strat in list(self.config['strategy_list']):
stratconf = deepcopy(self.config)
stratconf['strategy'] = strat
@@ -440,11 +440,8 @@ class Backtesting:
side_1 * abs(self.strategy.trailing_stop_positive / leverage)))
else:
# Worst case: price ticks tiny bit above open and dives down.
stop_rate = row[OPEN_IDX] * (1 - side_1 * abs(trade.stop_loss_pct / leverage))
if is_short:
assert stop_rate > row[LOW_IDX]
else:
assert stop_rate < row[HIGH_IDX]
stop_rate = row[OPEN_IDX] * (1 - side_1 * abs(
(trade.stop_loss_pct or 0.0) / leverage))
# Limit lower-end to candle low to avoid exits below the low.
# This still remains "worst case" - but "worst realistic case".
@@ -472,7 +469,7 @@ class Backtesting:
# - (Expected abs profit - open_rate - open_fee) / (fee_close -1)
roi_rate = trade.open_rate * roi / leverage
open_fee_rate = side_1 * trade.open_rate * (1 + side_1 * trade.fee_open)
close_rate = -(roi_rate + open_fee_rate) / (trade.fee_close - side_1 * 1)
close_rate = -(roi_rate + open_fee_rate) / ((trade.fee_close or 0.0) - side_1 * 1)
if is_short:
is_new_roi = row[OPEN_IDX] < close_rate
else:
@@ -525,7 +522,7 @@ class Backtesting:
max_stake = self.exchange.get_max_pair_stake_amount(trade.pair, current_rate)
stake_available = self.wallets.get_available_stake_amount()
stake_amount = strategy_safe_wrapper(self.strategy.adjust_trade_position,
default_retval=None)(
default_retval=None, supress_error=True)(
trade=trade, # type: ignore[arg-type]
current_time=current_date, current_rate=current_rate,
current_profit=current_profit, min_stake=min_stake,
@@ -563,7 +560,7 @@ class Backtesting:
pos_trade = self._get_exit_for_signal(trade, row, exit_, amount)
if pos_trade is not None:
order = pos_trade.orders[-1]
if self._get_order_filled(order.price, row):
if self._get_order_filled(order.ft_price, row):
order.close_bt_order(current_date, trade)
trade.recalc_trade_from_orders()
self.wallets.update()
@@ -664,6 +661,7 @@ class Backtesting:
side=trade.exit_side,
order_type=order_type,
status="open",
ft_price=close_rate,
price=close_rate,
average=close_rate,
amount=amount,
@@ -747,7 +745,7 @@ class Backtesting:
leverage = min(max(leverage, 1.0), max_leverage)
min_stake_amount = self.exchange.get_min_pair_stake_amount(
pair, propose_rate, -0.05, leverage=leverage) or 0
pair, propose_rate, -0.05 if not pos_adjust else 0.0, leverage=leverage) or 0
max_stake_amount = self.exchange.get_max_pair_stake_amount(
pair, propose_rate, leverage=leverage)
stake_available = self.wallets.get_available_stake_amount()
@@ -868,6 +866,7 @@ class Backtesting:
open_rate=propose_rate,
amount=amount,
stake_amount=trade.stake_amount,
leverage=trade.leverage,
wallet_balance=trade.stake_amount,
is_short=is_short,
))
@@ -886,6 +885,7 @@ class Backtesting:
order_date=current_time,
order_filled_date=current_time,
order_update_date=current_time,
ft_price=propose_rate,
price=propose_rate,
average=propose_rate,
amount=amount,
@@ -894,7 +894,7 @@ class Backtesting:
cost=stake_amount + trade.fee_open,
)
trade.orders.append(order)
if pos_adjust and self._get_order_filled(order.price, row):
if pos_adjust and self._get_order_filled(order.ft_price, row):
order.close_bt_order(current_time, trade)
else:
trade.open_order_id = str(self.order_id_counter)
@@ -1007,15 +1007,15 @@ class Backtesting:
# only check on new candles for open entry orders
if order.side == trade.entry_side and current_time > order.order_date_utc:
requested_rate = strategy_safe_wrapper(self.strategy.adjust_entry_price,
default_retval=order.price)(
default_retval=order.ft_price)(
trade=trade, # type: ignore[arg-type]
order=order, pair=trade.pair, current_time=current_time,
proposed_rate=row[OPEN_IDX], current_order_rate=order.price,
proposed_rate=row[OPEN_IDX], current_order_rate=order.ft_price,
entry_tag=trade.enter_tag, side=trade.trade_direction
) # default value is current order price
# cancel existing order whenever a new rate is requested (or None)
if requested_rate == order.price:
if requested_rate == order.ft_price:
# assumption: there can't be multiple open entry orders at any given time
return False
else:
@@ -1027,7 +1027,8 @@ class Backtesting:
if requested_rate:
self._enter_trade(pair=trade.pair, row=row, trade=trade,
requested_rate=requested_rate,
requested_stake=(order.remaining * order.price / trade.leverage),
requested_stake=(
order.safe_remaining * order.ft_price / trade.leverage),
direction='short' if trade.is_short else 'long')
self.replaced_entry_orders += 1
else:
@@ -1094,7 +1095,7 @@ class Backtesting:
for trade in list(LocalTrade.bt_trades_open_pp[pair]):
# 3. Process entry orders.
order = trade.select_order(trade.entry_side, is_open=True)
if order and self._get_order_filled(order.price, row):
if order and self._get_order_filled(order.ft_price, row):
order.close_bt_order(current_time, trade)
trade.open_order_id = None
self.wallets.update()
@@ -1105,7 +1106,7 @@ class Backtesting:
# 5. Process exit orders.
order = trade.select_order(trade.exit_side, is_open=True)
if order and self._get_order_filled(order.price, row):
if order and self._get_order_filled(order.ft_price, row):
order.close_bt_order(current_time, trade)
trade.open_order_id = None
sub_trade = order.safe_amount_after_fee != trade.amount
@@ -1114,7 +1115,7 @@ class Backtesting:
trade.recalc_trade_from_orders()
else:
trade.close_date = current_time
trade.close(order.price, show_msg=False)
trade.close(order.ft_price, show_msg=False)
# logger.debug(f"{pair} - Backtesting exit {trade}")
LocalTrade.close_bt_trade(trade)

View File

@@ -44,7 +44,7 @@ class SharpeHyperOptLossDaily(IHyperOptLoss):
sum_daily = (
results.resample(resample_freq, on='close_date').agg(
{"profit_ratio_after_slippage": sum}).reindex(t_index).fillna(0)
{"profit_ratio_after_slippage": 'sum'}).reindex(t_index).fillna(0)
)
total_profit = sum_daily["profit_ratio_after_slippage"] - risk_free_rate

View File

@@ -46,7 +46,7 @@ class SortinoHyperOptLossDaily(IHyperOptLoss):
sum_daily = (
results.resample(resample_freq, on='close_date').agg(
{"profit_ratio_after_slippage": sum}).reindex(t_index).fillna(0)
{"profit_ratio_after_slippage": 'sum'}).reindex(t_index).fillna(0)
)
total_profit = sum_daily["profit_ratio_after_slippage"] - minimum_acceptable_return

5
freqtrade/optimize/hyperopt_tools.py Executable file → Normal file
View File

@@ -1,4 +1,3 @@
import io
import logging
from copy import deepcopy
from datetime import datetime, timezone
@@ -464,8 +463,8 @@ class HyperoptTools():
return
try:
io.open(csv_file, 'w+').close()
except IOError:
Path(csv_file).open('w+').close()
except OSError:
logger.error(f"Failed to create CSV file: {csv_file}")
return

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