Compare commits

...

894 Commits

Author SHA1 Message Date
Matthias
b530600718 Merge pull request #6134 from freqtrade/new_release
New release 2021.12
2021-12-29 17:00:19 +01:00
Matthias
043218cc7e Version bump to 2021.12 2021-12-29 16:18:14 +01:00
Matthias
c3e9ef27f6 Merge branch 'stable' into new_release 2021-12-29 16:17:56 +01:00
Matthias
24807515c1 Fix random test failure 2021-12-28 09:04:14 +01:00
Matthias
5a546855e6 Import TTLCache from cachetools
Importing from cachetools.ttl is deprecated, and will be removed in 5.0
2021-12-27 19:30:17 +01:00
Matthias
df53873dab Merge pull request #6119 from freqtrade/dependabot/pip/develop/scikit-learn-1.0.2
Bump scikit-learn from 1.0.1 to 1.0.2
2021-12-27 16:48:48 +01:00
Matthias
1b739acc08 Merge pull request #6118 from freqtrade/dependabot/pip/develop/sqlalchemy-1.4.29
Bump sqlalchemy from 1.4.28 to 1.4.29
2021-12-27 10:03:06 +01:00
dependabot[bot]
3804a17775 Bump scikit-learn from 1.0.1 to 1.0.2
Bumps [scikit-learn](https://github.com/scikit-learn/scikit-learn) from 1.0.1 to 1.0.2.
- [Release notes](https://github.com/scikit-learn/scikit-learn/releases)
- [Commits](https://github.com/scikit-learn/scikit-learn/compare/1.0.1...1.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-27 08:45:22 +00:00
Matthias
c8253790b6 Merge pull request #6125 from freqtrade/dependabot/pip/develop/filelock-3.4.2
Bump filelock from 3.4.0 to 3.4.2
2021-12-27 09:44:48 +01:00
Matthias
a215e29d2a Merge pull request #6117 from freqtrade/dependabot/pip/develop/ccxt-1.65.25
Bump ccxt from 1.64.44 to 1.65.25
2021-12-27 09:42:40 +01:00
Matthias
d58ed0e242 Merge pull request #6122 from freqtrade/dependabot/pip/develop/types-python-dateutil-2.8.4
Bump types-python-dateutil from 2.8.3 to 2.8.4
2021-12-27 08:45:01 +01:00
Matthias
2ab8f467dd Merge pull request #6121 from freqtrade/dependabot/pip/develop/jsonschema-4.3.2
Bump jsonschema from 4.3.1 to 4.3.2
2021-12-27 08:44:11 +01:00
Matthias
c1ec368c0c Merge pull request #6123 from freqtrade/dependabot/pip/develop/mypy-0.930
Bump mypy from 0.920 to 0.930
2021-12-27 08:43:54 +01:00
Matthias
29fff65598 Merge pull request #6120 from freqtrade/dependabot/pip/develop/plotly-5.5.0
Bump plotly from 5.4.0 to 5.5.0
2021-12-27 08:43:36 +01:00
dependabot[bot]
3cba405b2e Bump filelock from 3.4.0 to 3.4.2
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.4.0 to 3.4.2.
- [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.4.0...3.4.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-27 03:54:13 +00:00
dependabot[bot]
24d16d7dab Bump mypy from 0.920 to 0.930
Bumps [mypy](https://github.com/python/mypy) from 0.920 to 0.930.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v0.920...v0.930)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-27 03:54:06 +00:00
dependabot[bot]
2e84b8f0d5 Bump types-python-dateutil from 2.8.3 to 2.8.4
Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.3 to 2.8.4.
- [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>
2021-12-27 03:54:03 +00:00
dependabot[bot]
470ef7c160 Bump jsonschema from 4.3.1 to 4.3.2
Bumps [jsonschema](https://github.com/Julian/jsonschema) from 4.3.1 to 4.3.2.
- [Release notes](https://github.com/Julian/jsonschema/releases)
- [Changelog](https://github.com/Julian/jsonschema/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/Julian/jsonschema/compare/v4.3.1...v4.3.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-27 03:53:58 +00:00
dependabot[bot]
1093f22b80 Bump plotly from 5.4.0 to 5.5.0
Bumps [plotly](https://github.com/plotly/plotly.py) from 5.4.0 to 5.5.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.4.0...v5.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-27 03:53:54 +00:00
dependabot[bot]
e085058621 Bump sqlalchemy from 1.4.28 to 1.4.29
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.28 to 1.4.29.
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES)
- [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>
2021-12-27 03:53:47 +00:00
dependabot[bot]
81b383fe5c Bump ccxt from 1.64.44 to 1.65.25
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.64.44 to 1.65.25.
- [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/1.64.44...1.65.25)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-27 03:53:41 +00:00
Matthias
2917cc1f2e Bitpanda's "fetch_my_trades" requires "to" argument
closes #4938
2021-12-25 14:28:22 +01:00
Matthias
6fdad8c6bd Prevent exception, ensure deletion occurs 2021-12-25 14:03:44 +01:00
Matthias
356b2d3d91 Reestablish backward compatibility 2021-12-25 13:47:28 +01:00
Matthias
b1feb69ca9 Use Pathlib to delete testfile 2021-12-25 10:30:59 +01:00
Matthias
49aa34c6f3 Merge pull request #6112 from xataxxx/develop
Fix test not running when user_data contains historical data.
2021-12-25 10:11:15 +01:00
Reigo Reinmets
d11a8928d4 Fix test not running when user_data contains historical data. 2021-12-25 10:39:27 +02:00
Matthias
58663180e0 Merge pull request #6107 from freqtrade/remove_slack
Update CI to notify on discord only
2021-12-23 21:50:49 +01:00
Matthias
98f6d2d722 Update CI to notify on discord only 2021-12-23 21:27:30 +01:00
Matthias
110e48c541 Remove travis config file
Travisci seems to no longer offer a free plan for open source
repositories, and other repositories report the need to get in touch
with support again and again.

This complication is not necessary with github actions, which covers our
CI needs well.
2021-12-23 20:38:07 +01:00
Matthias
61dbb6206f Slightly reduce verbosity when reload_conf is issued
part of #6095
2021-12-23 20:33:13 +01:00
Matthias
9a9cc31d83 Update docs regarding multiarch builds 2021-12-23 17:01:44 +01:00
Matthias
f88b6af26f Merge pull request #6070 from cdimauro/suppress_logs
Suppress additional logs for pairs in blacklist
2021-12-21 21:07:15 +01:00
Matthias
e5aaef6440 Fix CI failure 2021-12-21 19:20:09 +01:00
cdimauro
6ba8b17fdd Use LoggingMixin.log_once to remove/reduce logs on pairlists 2021-12-21 09:11:57 +01:00
Matthias
40036bc710 Force dry-run for webserver backtest mode
closes #6094
2021-12-20 19:41:33 +01:00
Matthias
afad9be53f Merge pull request #6093 from freqtrade/dependabot/pip/develop/cryptography-36.0.1
Bump cryptography from 36.0.0 to 36.0.1
2021-12-20 09:01:25 +01:00
Matthias
6fe09b6dee Merge pull request #6090 from freqtrade/dependabot/pip/develop/mypy-0.920
Bump mypy from 0.910 to 0.920
2021-12-20 07:16:21 +01:00
dependabot[bot]
21da01f777 Bump cryptography from 36.0.0 to 36.0.1
Bumps [cryptography](https://github.com/pyca/cryptography) from 36.0.0 to 36.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/36.0.0...36.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-20 05:39:04 +00:00
Matthias
260c627e99 Merge pull request #6091 from freqtrade/dependabot/pip/develop/time-machine-2.5.0
Bump time-machine from 2.4.1 to 2.5.0
2021-12-20 06:38:46 +01:00
Matthias
d47167c9c4 Merge pull request #6087 from freqtrade/dependabot/pip/develop/numpy-1.21.5
Bump numpy from 1.21.4 to 1.21.5
2021-12-20 06:38:25 +01:00
dependabot[bot]
b6f8765d3b Bump mypy from 0.910 to 0.920
Bumps [mypy](https://github.com/python/mypy) from 0.910 to 0.920.
- [Release notes](https://github.com/python/mypy/releases)
- [Commits](https://github.com/python/mypy/compare/v0.910...v0.920)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-20 05:38:03 +00:00
Matthias
5b608c9005 Merge pull request #6088 from freqtrade/dependabot/pip/develop/ccxt-1.64.44
Bump ccxt from 1.63.65 to 1.64.44
2021-12-20 06:37:59 +01:00
Matthias
cfad873ea7 Merge pull request #6092 from freqtrade/dependabot/pip/develop/jsonschema-4.3.1
Bump jsonschema from 4.2.1 to 4.3.1
2021-12-20 06:37:41 +01:00
Matthias
480eb55721 Merge pull request #6086 from freqtrade/dependabot/pip/develop/mkdocs-material-8.1.3
Bump mkdocs-material from 8.1.0 to 8.1.3
2021-12-20 06:37:23 +01:00
Matthias
e754cc09fc Merge pull request #6089 from freqtrade/dependabot/pip/develop/types-requests-2.26.2
Bump types-requests from 2.26.1 to 2.26.2
2021-12-20 06:36:46 +01:00
dependabot[bot]
cde35509db Bump jsonschema from 4.2.1 to 4.3.1
Bumps [jsonschema](https://github.com/Julian/jsonschema) from 4.2.1 to 4.3.1.
- [Release notes](https://github.com/Julian/jsonschema/releases)
- [Changelog](https://github.com/Julian/jsonschema/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/Julian/jsonschema/compare/v4.2.1...v4.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-20 03:01:52 +00:00
dependabot[bot]
5a3a5e98d6 Bump time-machine from 2.4.1 to 2.5.0
Bumps [time-machine](https://github.com/adamchainz/time-machine) from 2.4.1 to 2.5.0.
- [Release notes](https://github.com/adamchainz/time-machine/releases)
- [Changelog](https://github.com/adamchainz/time-machine/blob/main/HISTORY.rst)
- [Commits](https://github.com/adamchainz/time-machine/compare/2.4.1...2.5.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-20 03:01:47 +00:00
dependabot[bot]
44ac002cf0 Bump types-requests from 2.26.1 to 2.26.2
Bumps [types-requests](https://github.com/python/typeshed) from 2.26.1 to 2.26.2.
- [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>
2021-12-20 03:01:41 +00:00
dependabot[bot]
56d96d6cff Bump ccxt from 1.63.65 to 1.64.44
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.63.65 to 1.64.44.
- [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/1.63.65...1.64.44)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-20 03:01:40 +00:00
dependabot[bot]
36632b48c7 Bump numpy from 1.21.4 to 1.21.5
Bumps [numpy](https://github.com/numpy/numpy) from 1.21.4 to 1.21.5.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst.txt)
- [Commits](https://github.com/numpy/numpy/compare/v1.21.4...v1.21.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-20 03:01:34 +00:00
dependabot[bot]
1b3aaffef4 Bump mkdocs-material from 8.1.0 to 8.1.3
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.1.0 to 8.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/8.1.0...8.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>
2021-12-20 03:01:26 +00:00
Matthias
1cbc4da72b Merge pull request #6082 from Rikj000/docs/hyperopt-import-any
📝 Docs - Added `Any` import
2021-12-19 07:54:49 +01:00
Rik Helsen
58c3d69d14 📝 Docs - Added Any import 2021-12-18 23:29:55 +01:00
Matthias
ea38b58081 Add base_currency to allowed webhook fields
closes #6075
2021-12-16 20:18:01 +01:00
Matthias
b2fc3e814e Merge pull request #6055 from freqtrade/blacklist_delete
Add Blacklist delete
2021-12-16 13:41:18 +01:00
Matthias
39f0a17e62 Fix formatting 2021-12-16 07:11:35 +01:00
Matthias
f9aa36f291 Don't hard-fail when executing emergency sell fails
closes #6068
2021-12-15 19:37:35 +01:00
Matthias
b80b5ed1ad Improve uri_logging test
part of #6069
2021-12-15 19:25:30 +01:00
cdimauro
9d8646072c Add test case for checking removal of logs for pains in blacklist 2021-12-14 06:23:40 +01:00
Matthias
dda302eea2 Merge pull request #6026 from freqtrade/dependabot/pip/develop/ta-lib-0.4.22
Bump ta-lib from 0.4.21 to 0.4.22
2021-12-13 19:44:46 +01:00
Matthias
793d090561 Improve log message wording for rejected stake amounts
closes #6064
2021-12-13 19:29:07 +01:00
Matthias
95949bd466 Update windows wheels to ta-lib 0.4.22 2021-12-13 19:05:35 +01:00
Matthias
1d0af074ac Merge pull request #6061 from freqtrade/dependabot/pip/develop/ccxt-1.63.65
Bump ccxt from 1.63.55 to 1.63.65
2021-12-13 06:51:17 +01:00
Matthias
f2d55a91cd Merge pull request #6063 from freqtrade/dependabot/pip/develop/fastapi-0.70.1
Bump fastapi from 0.70.0 to 0.70.1
2021-12-13 06:51:05 +01:00
Matthias
5371458c99 Merge pull request #6062 from freqtrade/dependabot/pip/develop/pandas-1.3.5
Bump pandas from 1.3.4 to 1.3.5
2021-12-13 06:50:32 +01:00
dependabot[bot]
884a04c7fe Bump fastapi from 0.70.0 to 0.70.1
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.70.0 to 0.70.1.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.70.0...0.70.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-13 03:01:49 +00:00
dependabot[bot]
172b9383c0 Bump pandas from 1.3.4 to 1.3.5
Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.3.4 to 1.3.5.
- [Release notes](https://github.com/pandas-dev/pandas/releases)
- [Changelog](https://github.com/pandas-dev/pandas/blob/master/RELEASE.md)
- [Commits](https://github.com/pandas-dev/pandas/compare/v1.3.4...v1.3.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-13 03:01:44 +00:00
dependabot[bot]
ec4a24649c Bump ccxt from 1.63.55 to 1.63.65
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.63.55 to 1.63.65.
- [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/1.63.55...1.63.65)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-13 03:01:38 +00:00
Matthias
3398469e55 Update PerformanceFilter to have min_profit as ratio again.
closes #6056
2021-12-12 13:21:36 +01:00
cdimauro
8dd3128ed4 Add type annotation to new logs suppression code 2021-12-12 12:32:09 +01:00
cdimauro
5b998aeca7 Remove unused import
Remove the import from copy, since deepcopy() isn't used anymore
(list.copy() is used instead).
2021-12-12 10:21:54 +01:00
cdimauro
878e16545d Suppress additional logs for pairs in blacklist
Every time that there's freqtrade "ticks", pairs in the blacklist are
checked and a warning message is displayed.
So, the logs are continuously flooded with the same warnings.

For example:
2021-07-26 06:24:45 freqtrade.plugins.pairlistmanager: WARNING -
Pair XTZUP/USDT in your blacklist. Removing it from whitelist...
2021-07-26 06:24:45 freqtrade.plugins.pairlistmanager: WARNING -
Pair SUSHIUP/USDT in your blacklist. Removing it from whitelist...
2021-07-26 06:24:45 freqtrade.plugins.pairlistmanager: WARNING -
Pair XTZDOWN/USDT in your blacklist. Removing it from whitelist...
2021-07-26 06:24:50 freqtrade.plugins.pairlistmanager: WARNING -
Pair XTZUP/USDT in your blacklist. Removing it from whitelist...
2021-07-26 06:24:50 freqtrade.plugins.pairlistmanager: WARNING -
Pair SUSHIUP/USDT in your blacklist. Removing it from whitelist...
2021-07-26 06:24:50 freqtrade.plugins.pairlistmanager: WARNING -
Pair XTZDOWN/USDT in your blacklist. Removing it from whitelist...

This patch shows the warning only the first time, by keeping track
of which pairs in the blacklist were already logged.
2021-12-12 10:20:08 +01:00
Matthias
c12f2378db Merge pull request #6045 from freqtrade/trade_fee_fallback_value
Add unknown_fee_rate parameter
2021-12-11 20:00:01 +01:00
Matthias
1a4b403792 Merge pull request #6047 from freqtrade/dependabot/pip/develop/uvicorn-0.16.0
Bump uvicorn from 0.15.0 to 0.16.0
2021-12-11 19:50:18 +01:00
Matthias
b90c5e56fb Fix webserver schema bug when running in webserver mode 2021-12-11 19:46:35 +01:00
Matthias
8fdef2900e Increment API version to let clients know this is now available 2021-12-11 19:41:30 +01:00
Matthias
2918032dac Merge pull request #6046 from freqtrade/dependabot/pip/develop/python-telegram-bot-13.9
Bump python-telegram-bot from 13.8.1 to 13.9
2021-12-11 19:41:14 +01:00
Matthias
06bd8a1540 Merge pull request #6052 from freqtrade/dependabot/github_actions/develop/peter-evans/dockerhub-description-2.4.3
Bump peter-evans/dockerhub-description from 2.1.0 to 2.4.3
2021-12-11 17:26:43 +01:00
dependabot[bot]
58cd91bd80 Bump python-telegram-bot from 13.8.1 to 13.9
Bumps [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) from 13.8.1 to 13.9.
- [Release notes](https://github.com/python-telegram-bot/python-telegram-bot/releases)
- [Changelog](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/CHANGES.rst)
- [Commits](https://github.com/python-telegram-bot/python-telegram-bot/compare/v13.8.1...v13.9)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-11 16:00:35 +00:00
Matthias
dbe97bcdb1 Merge pull request #6053 from freqtrade/dependabot/github_actions/develop/crazy-max/ghaction-docker-buildx-3.3.1
Bump crazy-max/ghaction-docker-buildx from 1 to 3.3.1
2021-12-11 16:59:56 +01:00
Matthias
843eec63f0 Merge pull request #6051 from freqtrade/dependabot/pip/develop/sqlalchemy-1.4.28
Bump sqlalchemy from 1.4.27 to 1.4.28
2021-12-11 16:59:42 +01:00
Matthias
0df8786af6 Merge pull request #6048 from freqtrade/dependabot/pip/develop/prompt-toolkit-3.0.24
Bump prompt-toolkit from 3.0.23 to 3.0.24
2021-12-11 16:35:07 +01:00
Matthias
b4ed90788b Merge pull request #6050 from freqtrade/dependabot/pip/develop/ccxt-1.63.55
Bump ccxt from 1.63.1 to 1.63.55
2021-12-11 16:34:36 +01:00
Matthias
c871e51dcc Merge pull request #6049 from freqtrade/dependabot/pip/develop/mkdocs-material-8.1.0
Bump mkdocs-material from 8.0.4 to 8.1.0
2021-12-11 16:34:28 +01:00
Matthias
857f4ec125 Remove exception-handlers which catch exceptions that are never raised 2021-12-11 16:20:09 +01:00
dependabot[bot]
783ee633aa Bump crazy-max/ghaction-docker-buildx from 1 to 3.3.1
Bumps [crazy-max/ghaction-docker-buildx](https://github.com/crazy-max/ghaction-docker-buildx) from 1 to 3.3.1.
- [Release notes](https://github.com/crazy-max/ghaction-docker-buildx/releases)
- [Changelog](https://github.com/crazy-max/ghaction-docker-buildx/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crazy-max/ghaction-docker-buildx/compare/v1...v3.3.1)

---
updated-dependencies:
- dependency-name: crazy-max/ghaction-docker-buildx
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-11 15:13:10 +00:00
dependabot[bot]
fb134c67a9 Bump peter-evans/dockerhub-description from 2.1.0 to 2.4.3
Bumps [peter-evans/dockerhub-description](https://github.com/peter-evans/dockerhub-description) from 2.1.0 to 2.4.3.
- [Release notes](https://github.com/peter-evans/dockerhub-description/releases)
- [Commits](https://github.com/peter-evans/dockerhub-description/compare/v2.1.0...v2.4.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-11 15:13:08 +00:00
Matthias
849ca1ec06 Dependabot - use correct branch 2021-12-11 16:12:36 +01:00
Matthias
8da79d0ab2 Add blacklist-control to telegram 2021-12-11 16:12:24 +01:00
dependabot[bot]
aaf5f4ce39 Bump sqlalchemy from 1.4.27 to 1.4.28
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.27 to 1.4.28.
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES)
- [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>
2021-12-11 14:55:27 +00:00
dependabot[bot]
ae92bf56bf Bump ccxt from 1.63.1 to 1.63.55
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.63.1 to 1.63.55.
- [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/1.63.1...1.63.55)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-11 14:55:21 +00:00
dependabot[bot]
f47cfbd2a9 Bump mkdocs-material from 8.0.4 to 8.1.0
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.0.4 to 8.1.0.
- [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/8.0.4...8.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-11 14:55:13 +00:00
dependabot[bot]
c9c683f2b0 Bump prompt-toolkit from 3.0.23 to 3.0.24
Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.23 to 3.0.24.
- [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.23...3.0.24)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-11 14:55:09 +00:00
dependabot[bot]
81cafd090d Bump uvicorn from 0.15.0 to 0.16.0
Bumps [uvicorn](https://github.com/encode/uvicorn) from 0.15.0 to 0.16.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.15.0...0.16.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-11 14:55:05 +00:00
Matthias
671b9903d7 Add github-actions dependabot 2021-12-11 15:54:09 +01:00
Matthias
cc96db76f0 Add possibility to delete pairs from the pairlist via api 2021-12-11 15:53:44 +01:00
Matthias
e729fad99c Add unknown_fee_rate parameter 2021-12-11 15:26:08 +01:00
Matthias
e9c3f0cbbd Add note about python3.10 not being supported
closes #6041
2021-12-11 10:01:55 +01:00
Matthias
be6b1f6f83 Import from enums, not submodules 2021-12-09 06:18:21 +01:00
Matthias
b79f2f2981 Merge pull request #6035 from freqtrade/revert-6034-dependabot/docker/python-3.10.1-slim-bullseye
Revert "Bump python from 3.9.9-slim-bullseye to 3.10.1-slim-bullseye"
2021-12-09 06:18:11 +01:00
Matthias
facb5b3991 Revert "Bump python from 3.9.9-slim-bullseye to 3.10.1-slim-bullseye" 2021-12-09 06:17:56 +01:00
Matthias
79a87649b9 Merge pull request #6034 from freqtrade/dependabot/docker/python-3.10.1-slim-bullseye
Bump python from 3.9.9-slim-bullseye to 3.10.1-slim-bullseye
2021-12-09 06:15:16 +01:00
dependabot[bot]
7848e17a49 Bump python from 3.9.9-slim-bullseye to 3.10.1-slim-bullseye
Bumps python from 3.9.9-slim-bullseye to 3.10.1-slim-bullseye.

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-09 03:01:59 +00:00
Matthias
decaa24f81 Merge pull request #6028 from freqtrade/dependabot/pip/develop/mkdocs-material-8.0.4
Bump mkdocs-material from 8.0.1 to 8.0.4
2021-12-06 07:03:50 +01:00
Matthias
f9529c1fb6 Merge pull request #6027 from freqtrade/dependabot/pip/develop/ccxt-1.63.1
Bump ccxt from 1.62.42 to 1.63.1
2021-12-06 06:22:58 +01:00
dependabot[bot]
3dda0ef2ef Bump mkdocs-material from 8.0.1 to 8.0.4
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 8.0.1 to 8.0.4.
- [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/8.0.1...8.0.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-06 03:01:35 +00:00
dependabot[bot]
50a6eaea22 Bump ccxt from 1.62.42 to 1.63.1
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.62.42 to 1.63.1.
- [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/1.62.42...1.63.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-06 03:01:30 +00:00
dependabot[bot]
61211a1194 Bump ta-lib from 0.4.21 to 0.4.22
Bumps [ta-lib](https://github.com/mrjbq7/ta-lib) from 0.4.21 to 0.4.22.
- [Release notes](https://github.com/mrjbq7/ta-lib/releases)
- [Changelog](https://github.com/mrjbq7/ta-lib/blob/master/CHANGELOG)
- [Commits](https://github.com/mrjbq7/ta-lib/compare/TA_Lib-0.4.21...TA_Lib-0.4.22)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-12-06 03:01:18 +00:00
Matthias
fbd64d757d Improve doc wording 2021-12-05 09:26:44 +01:00
Matthias
4278c5a24a add note about arm64 installation
closes #6025
2021-12-05 09:24:40 +01:00
Matthias
243e59cabb Merge pull request #5929 from dvdmchl/develop
Telegram and log prints strategy version.
2021-12-04 15:16:42 +01:00
Matthias
210202a797 Merge pull request #5756 from GluTbl/patch-1
add custom entry/exit price support to backtesting
2021-12-04 15:16:15 +01:00
Matthias
c981cc335d Remove wrong comment 2021-12-04 14:51:55 +01:00
Matthias
d0467b30ba Add strategy_version to API response 2021-12-04 14:49:45 +01:00
Matthias
e3190cf8a8 Update documentation 2021-12-04 14:44:03 +01:00
Matthias
848a2d5383 Merge branch 'develop' into pr/dvdmchl/5929 2021-12-04 14:40:15 +01:00
Matthias
2080bf0952 Fix some formatting errors, add test for strategy version 2021-12-04 14:40:05 +01:00
Matthias
68ac8008ec Call custom_exit_price only for sell_signal and custom_sell 2021-12-04 14:14:22 +01:00
Matthias
84ad176287 Improve documentation wording 2021-12-04 13:33:38 +01:00
Matthias
86910b58dc Bracket entry/exit prices to low/high of the candle 2021-12-03 17:44:53 +01:00
Matthias
d1209fe415 Merge branch 'develop' into pr/GluTbl/5756 2021-12-03 17:37:44 +01:00
Matthias
d09a30cc67 OrderTypeValues should be in enums 2021-12-03 15:34:28 +01:00
Matthias
ad5c8f601c Simplify datahandler classes by exploiting commonalities 2021-12-02 20:19:22 +01:00
Matthias
d3ad4fb52e Don't crash dry-run if orderbook side is empty
closes #6018
2021-12-02 19:17:47 +01:00
Matthias
294c98ed5e Document exchange.uid
part of #6016
2021-12-02 06:55:08 +01:00
Matthias
c1fed8a077 Merge pull request #6014 from freqtrade/double_notifications
Double notifications
2021-12-02 06:39:18 +01:00
Matthias
0375a08302 use to_hdf instead of HDFStore 2021-12-01 20:32:23 +01:00
Matthias
5ce1eeecf5 Reorder messages to be sent in correct order
buy first, then buy fill,
sell first, then sell fill.
2021-12-01 19:57:24 +01:00
Matthias
c22f381dfe Fix Schema issue
closes #6010
2021-11-30 20:46:47 +01:00
Matthias
542963c7a6 Reduce code complexity by combining buy and buy_fill methods 2021-11-30 19:45:20 +01:00
Matthias
f0abe218a2 Batch ohlcv requests to not overwelm ccxt's async throttler
closes #6003
2021-11-30 07:10:12 +01:00
Matthias
231b1e2f57 Improve Async error message content 2021-11-30 07:10:12 +01:00
Matthias
de7e1e6bf7 Merge pull request #5980 from incrementby1/ShuffleFilterDetectLiveMode
Shuffle filter use seed only in backtesting mode
2021-11-30 06:37:35 +01:00
incrementby1
85b1f6f6b3 Update pairlists.md 2021-11-29 20:44:51 +01:00
incrementby1
60eca8b1f1 revert to random object 2021-11-29 20:35:43 +01:00
Matthias
06d8217e62 Merge pull request #5983 from PostmanSpat/webhook-raw-retry
Added raw config and retry config to webhook
2021-11-29 20:30:06 +01:00
Matthias
dfb148f8d7 Fix formatting 2021-11-29 19:54:54 +01:00
Matthias
f8cb3d2901 Restore openAPI functioning 2021-11-29 19:52:40 +01:00
Matthias
bd8348451e Merge pull request #5999 from freqtrade/dependabot/pip/develop/mkdocs-material-8.0.1
Bump mkdocs-material from 7.3.6 to 8.0.1
2021-11-29 19:50:59 +01:00
Matthias
0f15340269 Merge pull request #5995 from freqtrade/dependabot/pip/develop/aiofiles-0.8.0
Bump aiofiles from 0.7.0 to 0.8.0
2021-11-29 19:32:45 +01:00
Matthias
2e51477455 Update mkdocs file to 8.0 2021-11-29 19:32:16 +01:00
Spat
018407852a Added missing webhook config params to constants 2021-11-29 18:17:59 +11:00
Matthias
56b4457a9c Merge pull request #5996 from freqtrade/dependabot/pip/develop/time-machine-2.4.1
Bump time-machine from 2.4.0 to 2.4.1
2021-11-29 08:07:30 +01:00
Matthias
2db064d8f7 Merge pull request #6000 from stash86/fix-docs
Add few sentences to make clear about backtest + pairlist handlers
2021-11-29 07:09:36 +01:00
Matthias
f0bf9b51dc Merge pull request #5992 from freqtrade/dependabot/pip/develop/ccxt-1.62.42
Bump ccxt from 1.61.92 to 1.62.42
2021-11-29 07:08:46 +01:00
dependabot[bot]
57e55eb938 Bump time-machine from 2.4.0 to 2.4.1
Bumps [time-machine](https://github.com/adamchainz/time-machine) from 2.4.0 to 2.4.1.
- [Release notes](https://github.com/adamchainz/time-machine/releases)
- [Changelog](https://github.com/adamchainz/time-machine/blob/main/HISTORY.rst)
- [Commits](https://github.com/adamchainz/time-machine/compare/2.4.0...2.4.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-29 06:00:32 +00:00
Matthias
5ee5600cb9 Merge pull request #5993 from freqtrade/dependabot/pip/develop/scipy-1.7.3
Bump scipy from 1.7.2 to 1.7.3
2021-11-29 06:59:51 +01:00
Matthias
828ab874c1 Merge pull request #5991 from freqtrade/dependabot/pip/develop/prompt-toolkit-3.0.23
Bump prompt-toolkit from 3.0.22 to 3.0.23
2021-11-29 06:59:30 +01:00
Matthias
90892e5a89 Merge pull request #5997 from freqtrade/dependabot/pip/develop/types-python-dateutil-2.8.3
Bump types-python-dateutil from 2.8.2 to 2.8.3
2021-11-29 06:59:14 +01:00
Matthias
180df0514f Merge pull request #5998 from freqtrade/dependabot/pip/develop/types-requests-2.26.1
Bump types-requests from 2.26.0 to 2.26.1
2021-11-29 06:58:55 +01:00
Matthias
731208936f Merge pull request #5994 from freqtrade/dependabot/pip/develop/types-cachetools-4.2.6
Bump types-cachetools from 4.2.5 to 4.2.6
2021-11-29 06:58:41 +01:00
Stefano Ariestasia
3b4051488f Merge branch 'fix-docs' of https://github.com/stash86/freqtrade into fix-docs 2021-11-29 14:32:37 +09:00
Stefano Ariestasia
c126d2530a Add few sentences on docs
- Add warning that PrecisionFilter can't be used on backtest that use multiple strategies
- Add note that not all pairlist handlers can be used on backtest
2021-11-29 14:32:33 +09:00
dependabot[bot]
24997fb36f Bump mkdocs-material from 7.3.6 to 8.0.1
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.3.6 to 8.0.1.
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG)
- [Upgrade guide](https://github.com/squidfunk/mkdocs-material/blob/master/docs/upgrade.md)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/7.3.6...8.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-29 03:01:50 +00:00
dependabot[bot]
b81d768eb3 Bump types-requests from 2.26.0 to 2.26.1
Bumps [types-requests](https://github.com/python/typeshed) from 2.26.0 to 2.26.1.
- [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>
2021-11-29 03:01:45 +00:00
dependabot[bot]
39c3175b69 Bump types-python-dateutil from 2.8.2 to 2.8.3
Bumps [types-python-dateutil](https://github.com/python/typeshed) from 2.8.2 to 2.8.3.
- [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>
2021-11-29 03:01:43 +00:00
dependabot[bot]
b0b2fdba70 Bump aiofiles from 0.7.0 to 0.8.0
Bumps [aiofiles](https://github.com/Tinche/aiofiles) from 0.7.0 to 0.8.0.
- [Release notes](https://github.com/Tinche/aiofiles/releases)
- [Commits](https://github.com/Tinche/aiofiles/compare/v0.7.0...v0.8.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-29 03:01:38 +00:00
dependabot[bot]
c2a7b1930b Bump types-cachetools from 4.2.5 to 4.2.6
Bumps [types-cachetools](https://github.com/python/typeshed) from 4.2.5 to 4.2.6.
- [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>
2021-11-29 03:01:36 +00:00
dependabot[bot]
589c9f55e0 Bump scipy from 1.7.2 to 1.7.3
Bumps [scipy](https://github.com/scipy/scipy) from 1.7.2 to 1.7.3.
- [Release notes](https://github.com/scipy/scipy/releases)
- [Commits](https://github.com/scipy/scipy/compare/v1.7.2...v1.7.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-29 03:01:33 +00:00
dependabot[bot]
e9e8023d73 Bump ccxt from 1.61.92 to 1.62.42
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.61.92 to 1.62.42.
- [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/1.61.92...1.62.42)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-29 03:01:27 +00:00
dependabot[bot]
df09fe5df6 Bump prompt-toolkit from 3.0.22 to 3.0.23
Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.22 to 3.0.23.
- [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.22...3.0.23)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-29 03:01:20 +00:00
Spat
29180a1d2b Moved retry config to constants 2021-11-29 10:48:35 +11:00
Spat
0fa5bf54cd Changed comment 2021-11-29 10:30:41 +11:00
Matthias
cf5ff9257d Add plotconfig as property documentation and sample 2021-11-28 19:39:43 +01:00
incrementby1
c7d10e2c7e delete unneeded comment 2021-11-28 19:05:02 +01:00
Matthias
2414c0bd9f Merge pull request #5982 from stash86/fix-docs
add weekly and monthly to valid keys
2021-11-28 08:28:13 +01:00
Spat
fb6ae174b9 Added raw config and retry config to webhook 2021-11-28 11:42:57 +11:00
Stefano Ariestasia
fd9bf2adb0 add weekly and monthly to valid keys 2021-11-28 08:23:02 +09:00
Matthias
6429205d39 Improve Notebook documentation to include Dataprovider
fix #5975
2021-11-27 19:53:37 +01:00
Matthias
2b3e7eeb21 Use Enum values within bot code 2021-11-27 19:41:36 +01:00
Matthias
409a801763 Fix caching problem in refresh_ohlcv
closes #5978
2021-11-27 19:31:39 +01:00
incrementby1
b90303c9a3 Update ShuffleFilter.py
random.Random() is deprecated since 3.9
2021-11-27 18:26:30 +01:00
Matthias
4179a1a797 Merge pull request #5977 from freqtrade/new_release
New release 2021.11
2021-11-27 17:01:56 +01:00
Matthias
cb95b362ec Merge pull request #5976 from freqtrade/forcebuy
allow force options with ordertype
2021-11-27 17:01:18 +01:00
incrementby1
62d248d182 Merge pull request #2 from incrementby1/ShuffleFilterDetectLiveModes
Update pairlists.md
2021-11-27 16:30:46 +01:00
incrementby1
2f0f576fce Update pairlists.md
ShuffleFilter will automatically detect runmodes and apply the `seed` only for backtesting modes - if ad `seed` value is set.
2021-11-27 16:28:41 +01:00
incrementby1
8c52ba3360 ShuffleFilterDetectLiveMode
# Apply seed in backtesting mode to get comparable results,
        # but not in live modes to get a non-repeating order of pairs during live modes.
2021-11-27 16:21:23 +01:00
Matthias
7e1eedd7df Version bump to 2021.11 2021-11-27 09:55:00 +01:00
Matthias
eab4bdd274 Merge branch 'stable' into new_release 2021-11-27 09:54:51 +01:00
Matthias
a9cdb428d0 Version bump to 2021.10 2021-11-27 09:53:34 +01:00
Matthias
3f10430eb5 Version bump to 2021.9 2021-11-27 09:53:34 +01:00
Matthias
a629777890 Improve test coverage in telegram module 2021-11-27 09:53:05 +01:00
Matthias
6ca6f62509 Remove duplicate code in optimize_reports 2021-11-27 09:39:10 +01:00
Matthias
bc52b3db56 Properly handle None values via API 2021-11-27 09:26:14 +01:00
Matthias
80ed5283b2 Add forcesell market/limit distinction 2021-11-27 09:10:18 +01:00
Matthias
450293878f Merge pull request #5964 from stash86/fix-docs
Add more words on VolumePairlist backtest error message
2021-11-26 07:48:24 +01:00
Matthias
897788de17 Reformulate exception to be "nicer" 2021-11-26 07:02:50 +01:00
Matthias
f4bc30c927 Update docs to include "vpn/ssh" section 2021-11-26 06:23:29 +01:00
Stefano Ariestasia
5307d2bf3b Trimming the sentence 2021-11-25 17:04:04 +09:00
Stefano Ariestasia
c23d90e2b8 Update test_backtesting.py 2021-11-25 16:56:56 +09:00
Stefano Ariestasia
0c629fc951 Update test_backtesting.py 2021-11-25 16:03:29 +09:00
Stefano Ariestasia
0d1e84cf55 Add more words
Because apparently, we get at least 1 question about this everyday in Discord
2021-11-25 16:00:10 +09:00
Matthias
338fe333a9 Allow forcebuy to specify order_type 2021-11-24 20:20:58 +01:00
Matthias
65906d330f Improve tests for pair_to_filename 2021-11-23 20:07:54 +01:00
Matthias
e8feac3674 Improve tests for pair_to_filename 2021-11-23 20:02:07 +01:00
Matthias
342862a5f3 Merge pull request #5952 from freqtrade/armhf_39
Update ARMHF image to 3.9
2021-11-23 15:37:40 +01:00
Matthias
c23ca35d23 Update ARMHF image to 3.9 2021-11-23 14:04:39 +01:00
Matthias
b8cefd687e Add api_version to botresponse 2021-11-23 07:08:55 +01:00
Matthias
0d082f7b17 Merge pull request #5950 from flozzone/patch-1
fix typo in Volatility filter description.
2021-11-22 20:17:54 +01:00
flozzone
c245a2a897 fix typo in Volatility filter description. 2021-11-22 20:10:26 +01:00
Matthias
2c805e53ee Merge pull request #5945 from ACMCMC/patch-1
Changed the wording of the documentation to be clearer
2021-11-22 19:28:45 +01:00
Matthias
259b95074f Merge pull request #5936 from rokups/rk/decorator-fix
Use market data to get base and quote currencies in @informative() decorator
2021-11-22 19:14:35 +01:00
Aldán Creo
43dab3ee60 Changed the wording of the documentation to be clearer
The sentence I've changed was continued on a different paragraph before, even though they were connected ideas. I have changed it so that they are part of the same paragraph now.
2021-11-22 19:08:06 +01:00
Rokas Kupstys
78a00f2518 Use market data to get base and quote currencies in @informative() decorator. 2021-11-22 09:27:45 +02:00
Matthias
280a0ec17e Merge pull request #5944 from freqtrade/dependabot/pip/develop/ccxt-1.61.92
Bump ccxt from 1.61.24 to 1.61.92
2021-11-22 07:15:53 +01:00
Matthias
64e34f382e Sell-fill should include open-rate 2021-11-22 07:13:22 +01:00
Matthias
ecf2ac3c21 Bump aiohttp to 3.8.1 2021-11-22 06:51:06 +01:00
dependabot[bot]
80946cd9d6 Bump ccxt from 1.61.24 to 1.61.92
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.61.24 to 1.61.92.
- [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/1.61.24...1.61.92)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-22 05:47:48 +00:00
Matthias
965ab3848c Merge pull request #5943 from freqtrade/dependabot/pip/develop/plotly-5.4.0
Bump plotly from 5.3.1 to 5.4.0
2021-11-22 06:46:52 +01:00
Matthias
6f93f96f18 Merge pull request #5941 from freqtrade/dependabot/pip/develop/cryptography-36.0.0
Bump cryptography from 35.0.0 to 36.0.0
2021-11-22 06:46:29 +01:00
Matthias
9f1fdc9931 Merge pull request #5942 from freqtrade/dependabot/pip/develop/types-cachetools-4.2.5
Bump types-cachetools from 4.2.4 to 4.2.5
2021-11-22 06:45:09 +01:00
Matthias
e0f21a5e35 Merge pull request #5939 from freqtrade/dependabot/pip/develop/filelock-3.4.0
Bump filelock from 3.3.2 to 3.4.0
2021-11-22 06:44:03 +01:00
dependabot[bot]
0ef99206b0 Bump plotly from 5.3.1 to 5.4.0
Bumps [plotly](https://github.com/plotly/plotly.py) from 5.3.1 to 5.4.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.3.1...v5.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-22 03:01:56 +00:00
dependabot[bot]
247f855ba9 Bump types-cachetools from 4.2.4 to 4.2.5
Bumps [types-cachetools](https://github.com/python/typeshed) from 4.2.4 to 4.2.5.
- [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>
2021-11-22 03:01:52 +00:00
dependabot[bot]
fdc6ca1bd8 Bump cryptography from 35.0.0 to 36.0.0
Bumps [cryptography](https://github.com/pyca/cryptography) from 35.0.0 to 36.0.0.
- [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/35.0.0...36.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-22 03:01:48 +00:00
dependabot[bot]
ab93e13682 Bump filelock from 3.3.2 to 3.4.0
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.3.2 to 3.4.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.3.2...3.4.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-22 03:01:36 +00:00
Dardon
d4fd13bf50 Telegram and log prints strategy version. 2021-11-20 16:26:07 +00:00
Matthias
c0cc3f5f97 Small doc improvements to callback documentation 2021-11-20 16:15:03 +01:00
Matthias
b36fe8fe0f Simplify strategy documentation 2021-11-20 11:48:11 +01:00
Matthias
0bae1471bd Extract callbacks into a separate site 2021-11-20 11:44:56 +01:00
Matthias
ef67a2adfc Improve callback documentation 2021-11-20 11:39:24 +01:00
Matthias
d8ee72554f Improve callback documentation 2021-11-20 11:39:24 +01:00
Matthias
f8f7d81fc2 Update strategy template to use parameters 2021-11-20 11:39:21 +01:00
Matthias
a239e5f725 Add segment on colliding signals 2021-11-20 11:35:48 +01:00
Matthias
06c81b5234 Merge pull request #5919 from mablue/patch-6
indentation problem :)
2021-11-18 11:58:36 +01:00
Masoud Azizi
0b6060dd11 indentation problem :) 2021-11-18 13:28:17 +03:30
Matthias
5fb0f53539 Add curl to install description 2021-11-17 19:36:38 +01:00
Matthias
60cf52aa34 Remove unused test code 2021-11-15 07:10:58 +01:00
Matthias
4d45eb0644 Merge pull request #5896 from freqtrade/dependabot/pip/develop/python-telegram-bot-13.8.1
Bump python-telegram-bot from 13.7 to 13.8.1
2021-11-15 07:01:36 +01:00
Matthias
056f8c72a1 Merge pull request #5895 from freqtrade/dependabot/pip/develop/ccxt-1.61.24
Bump ccxt from 1.60.68 to 1.61.24
2021-11-15 07:01:15 +01:00
Matthias
6a79a04350 Merge pull request #5901 from freqtrade/dependabot/pip/develop/jinja2-3.0.3
Bump jinja2 from 3.0.2 to 3.0.3
2021-11-15 06:28:00 +01:00
dependabot[bot]
d477ccab19 Bump ccxt from 1.60.68 to 1.61.24
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.60.68 to 1.61.24.
- [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/1.60.68...1.61.24)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 05:27:50 +00:00
dependabot[bot]
e3bb102dc0 Bump python-telegram-bot from 13.7 to 13.8.1
Bumps [python-telegram-bot](https://github.com/python-telegram-bot/python-telegram-bot) from 13.7 to 13.8.1.
- [Release notes](https://github.com/python-telegram-bot/python-telegram-bot/releases)
- [Changelog](https://github.com/python-telegram-bot/python-telegram-bot/blob/master/CHANGES.rst)
- [Commits](https://github.com/python-telegram-bot/python-telegram-bot/compare/v13.7...v13.8.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 05:27:49 +00:00
Matthias
5df5a6f13b Merge pull request #5898 from freqtrade/dependabot/pip/develop/coveralls-3.3.1
Bump coveralls from 3.3.0 to 3.3.1
2021-11-15 06:27:39 +01:00
Matthias
f4fd4ecdb9 Merge pull request #5899 from freqtrade/dependabot/pip/develop/isort-5.10.1
Bump isort from 5.10.0 to 5.10.1
2021-11-15 06:27:20 +01:00
Matthias
c8191c4412 Merge pull request #5893 from freqtrade/dependabot/pip/develop/types-requests-2.26.0
Bump types-requests from 2.25.11 to 2.26.0
2021-11-15 06:26:50 +01:00
Matthias
46de615b50 Merge pull request #5894 from freqtrade/dependabot/pip/develop/pymdown-extensions-9.1
Bump pymdown-extensions from 9.0 to 9.1
2021-11-15 06:26:31 +01:00
Matthias
003e17bbb2 Merge pull request #5902 from freqtrade/dependabot/pip/develop/nbconvert-6.3.0
Bump nbconvert from 6.2.0 to 6.3.0
2021-11-15 06:26:13 +01:00
Matthias
b1618afef3 Merge pull request #5897 from freqtrade/dependabot/pip/develop/sqlalchemy-1.4.27
Bump sqlalchemy from 1.4.26 to 1.4.27
2021-11-15 06:25:55 +01:00
dependabot[bot]
7bd384c7fb Bump nbconvert from 6.2.0 to 6.3.0
Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 6.2.0 to 6.3.0.
- [Release notes](https://github.com/jupyter/nbconvert/releases)
- [Commits](https://github.com/jupyter/nbconvert/compare/6.2.0...6.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 03:01:45 +00:00
dependabot[bot]
876b59f477 Bump jinja2 from 3.0.2 to 3.0.3
Bumps [jinja2](https://github.com/pallets/jinja) from 3.0.2 to 3.0.3.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.0.2...3.0.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 03:01:42 +00:00
dependabot[bot]
8ec5f72be4 Bump isort from 5.10.0 to 5.10.1
Bumps [isort](https://github.com/pycqa/isort) from 5.10.0 to 5.10.1.
- [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.10.0...5.10.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 03:01:30 +00:00
dependabot[bot]
178e3ac6af Bump coveralls from 3.3.0 to 3.3.1
Bumps [coveralls](https://github.com/TheKevJames/coveralls-python) from 3.3.0 to 3.3.1.
- [Release notes](https://github.com/TheKevJames/coveralls-python/releases)
- [Changelog](https://github.com/TheKevJames/coveralls-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TheKevJames/coveralls-python/compare/3.3.0...3.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 03:01:27 +00:00
dependabot[bot]
2a1c61fb30 Bump sqlalchemy from 1.4.26 to 1.4.27
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.26 to 1.4.27.
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES)
- [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>
2021-11-15 03:01:22 +00:00
dependabot[bot]
c046790727 Bump pymdown-extensions from 9.0 to 9.1
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 9.0 to 9.1.
- [Release notes](https://github.com/facelessuser/pymdown-extensions/releases)
- [Commits](https://github.com/facelessuser/pymdown-extensions/compare/9.0...9.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 03:01:04 +00:00
dependabot[bot]
43120e03f9 Bump types-requests from 2.25.11 to 2.26.0
Bumps [types-requests](https://github.com/python/typeshed) from 2.25.11 to 2.26.0.
- [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-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-15 03:01:00 +00:00
Matthias
4d1d8de9b7 Split /stats messages
closes #5869
2021-11-14 10:20:04 +01:00
Matthias
1dc98cc4d5 Break line 2021-11-14 10:12:19 +01:00
Matthias
c70fdea886 Merge pull request #5847 from stash86/kucoin-api
Hardcoded temp fix for Kucoin API issue
2021-11-14 10:11:02 +01:00
Matthias
5b9cbaf277 Use Close value for trade signal calculation 2021-11-14 09:50:04 +01:00
Matthias
33f00d23b9 Merge pull request #5885 from ethanopp/develop
Include more details in _FILL telegram notifications
2021-11-14 09:37:58 +01:00
Stefano Ariestasia
632c1bc0aa Add static workaround for kucoin 429000 issue
closes #5700
2021-11-14 09:31:38 +01:00
Matthias
7c11619924 avoid using replace in messages 2021-11-14 09:19:21 +01:00
ethan
c4c1b301cd buy notification code consolidation 2021-11-13 15:46:00 -05:00
ethan
0bc9384451 more notification code consolidation 2021-11-13 14:52:59 -05:00
ethan
7412b7ba51 buy/sell fill notification code consolidation 2021-11-13 10:23:47 -05:00
ethan
a177e58dc4 Remove "currency" generating from splitting pair str 2021-11-13 08:49:02 -05:00
Matthias
37d461c6c2 Improve strategy dataframe documentation 2021-11-13 11:48:31 +01:00
Matthias
0e70d23bef Add documentation for exit_tags 2021-11-13 09:13:32 +01:00
Matthias
0e2b5ef6d4 Simplify custom strategy file wording 2021-11-13 09:03:58 +01:00
Matthias
df27499e19 Improve /help output from telegram 2021-11-13 08:46:06 +01:00
ethan
32e3376296 Update buy/sell fill telegram notifications 2021-11-12 21:49:07 -05:00
ethan
a237667bc9 Update buy/sell fill telegram notifications 2021-11-12 16:18:04 -05:00
Matthias
4d1ce51207 Merge pull request #5879 from freqtrade/improve_pct_formatting
Improve pct formatting
2021-11-11 19:30:55 +01:00
Matthias
39bb34cdb3 Fix test loading bug 2021-11-11 16:34:40 +01:00
Matthias
e0fd880c11 Improve some more pct formattings 2021-11-11 16:12:23 +01:00
Matthias
4eb9038358 Some more fixes to % formatting 2021-11-11 15:06:16 +01:00
Matthias
1b271d0840 Improve % outputs to not use explicit "pct" entries 2021-11-11 12:58:38 +01:00
Matthias
ce2aa1dc69 Small formatting upgrades 2021-11-11 12:06:18 +01:00
Matthias
f8d30abd79 Handle order returns that contain trades directly
binance market orders - and potentially other exchanges
2021-11-10 19:43:36 +01:00
Matthias
f7b2c0c5d7 Remove unneeded assignment from tests 2021-11-10 19:16:37 +01:00
Matthias
e7d1630c92 Add space 2021-11-10 16:51:31 +01:00
Matthias
d3d17f9f8b Only allow min-stake adjustments of up to 30%
fix #5856
2021-11-10 06:57:22 +01:00
Matthias
23a566b478 validate_stake_amount should not be a private method 2021-11-10 06:38:24 +01:00
Matthias
c9d974d210 Clarify performancefilter docs
closes #5870
2021-11-09 19:52:05 +01:00
Matthias
e8b4d44881 Add warning about telegram group usage 2021-11-09 15:16:51 +01:00
Matthias
b676868ce6 Merge pull request #5868 from mapreal19/patch-1
docs: removes duplicated "without" in pairlists.md
2021-11-09 14:18:16 +01:00
Mario Pérez Alarcón
6f0a98229f docs: removes duplicated "without" in pairlists.md 2021-11-09 12:27:38 +00:00
Matthias
6267678ca9 Use doublequotes for docstrings 2021-11-09 10:40:01 +00:00
Matthias
f9e5a25b36 Add docstring style to Contributing 2021-11-09 07:48:25 +00:00
Matthias
2bfec7d549 Add small test-case confirming trade object copy 2021-11-08 20:14:32 +01:00
Matthias
ae0e72a945 Provide strategy with copied objects
avoids accidental modification of crucial elements in a trade object
part of #5828
2021-11-08 19:59:29 +01:00
Matthias
e4cca63163 Align sell_reason assignment location
trade mode sets it after "exit confirmation" - so should backtesting
detected in #5828
2021-11-08 19:32:13 +01:00
Matthias
f2be820f73 Merge pull request #5855 from freqtrade/multi_ohlcv_calls
Provide more historic data in trade mode
2021-11-08 19:30:40 +01:00
Matthias
63f4221f70 Fix broken documentation link 2021-11-08 11:29:10 +01:00
Matthias
84261237a0 Improve doc wording 2021-11-08 08:09:33 +01:00
Matthias
bb2b8efef1 Merge pull request #5859 from freqtrade/dependabot/pip/develop/isort-5.10.0
Bump isort from 5.9.3 to 5.10.0
2021-11-08 08:07:40 +01:00
dependabot[bot]
3ce898e4a9 Bump isort from 5.9.3 to 5.10.0
Bumps [isort](https://github.com/pycqa/isort) from 5.9.3 to 5.10.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.9.3...5.10.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 05:29:09 +00:00
Matthias
bbd7c6e4fc Merge pull request #5862 from freqtrade/dependabot/pip/develop/ccxt-1.60.68
Bump ccxt from 1.60.11 to 1.60.68
2021-11-08 06:24:50 +01:00
Matthias
d003a2b7a3 Merge pull request #5863 from freqtrade/dependabot/pip/develop/numpy-1.21.4
Bump numpy from 1.21.3 to 1.21.4
2021-11-08 06:24:23 +01:00
Matthias
2b88b3b749 Merge pull request #5864 from freqtrade/dependabot/pip/develop/scipy-1.7.2
Bump scipy from 1.7.1 to 1.7.2
2021-11-08 06:23:51 +01:00
Matthias
d80dda9caa Merge pull request #5858 from freqtrade/dependabot/pip/develop/prompt-toolkit-3.0.22
Bump prompt-toolkit from 3.0.21 to 3.0.22
2021-11-08 06:23:35 +01:00
Matthias
3cfce605de Merge pull request #5860 from freqtrade/dependabot/pip/develop/jsonschema-4.2.1
Bump jsonschema from 4.1.2 to 4.2.1
2021-11-08 06:23:18 +01:00
Matthias
fdc6053633 Merge pull request #5861 from freqtrade/dependabot/pip/develop/coveralls-3.3.0
Bump coveralls from 3.2.0 to 3.3.0
2021-11-08 06:22:51 +01:00
dependabot[bot]
b39794f8d2 Bump scipy from 1.7.1 to 1.7.2
Bumps [scipy](https://github.com/scipy/scipy) from 1.7.1 to 1.7.2.
- [Release notes](https://github.com/scipy/scipy/releases)
- [Commits](https://github.com/scipy/scipy/compare/v1.7.1...v1.7.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 03:01:38 +00:00
dependabot[bot]
ab06584a3e Bump numpy from 1.21.3 to 1.21.4
Bumps [numpy](https://github.com/numpy/numpy) from 1.21.3 to 1.21.4.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst.txt)
- [Commits](https://github.com/numpy/numpy/compare/v1.21.3...v1.21.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 03:01:32 +00:00
dependabot[bot]
a2c12f15f1 Bump ccxt from 1.60.11 to 1.60.68
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.60.11 to 1.60.68.
- [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/1.60.11...1.60.68)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 03:01:25 +00:00
dependabot[bot]
d0199b6014 Bump coveralls from 3.2.0 to 3.3.0
Bumps [coveralls](https://github.com/TheKevJames/coveralls-python) from 3.2.0 to 3.3.0.
- [Release notes](https://github.com/TheKevJames/coveralls-python/releases)
- [Changelog](https://github.com/TheKevJames/coveralls-python/blob/master/CHANGELOG.md)
- [Commits](https://github.com/TheKevJames/coveralls-python/compare/3.2.0...3.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 03:01:19 +00:00
dependabot[bot]
dbc863bcdf Bump jsonschema from 4.1.2 to 4.2.1
Bumps [jsonschema](https://github.com/Julian/jsonschema) from 4.1.2 to 4.2.1.
- [Release notes](https://github.com/Julian/jsonschema/releases)
- [Changelog](https://github.com/Julian/jsonschema/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/Julian/jsonschema/compare/v4.1.2...v4.2.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 03:01:14 +00:00
dependabot[bot]
c54cf63bae Bump prompt-toolkit from 3.0.21 to 3.0.22
Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.21 to 3.0.22.
- [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.21...3.0.22)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-08 03:01:06 +00:00
Matthias
c11e1a84e4 Fix wrong logging
detected in #5856
2021-11-07 15:41:04 +01:00
Matthias
de4bc7204d Update documentation to clarify new behaviour 2021-11-07 15:36:43 +01:00
Matthias
a08dd17bc1 Use startup_candle-count to determine call count 2021-11-07 13:10:40 +01:00
Matthias
9fa64c2647 Allow multiple calls to get more candles in live-run 2021-11-07 11:31:59 +01:00
Matthias
fb6ba62158 Add default to "is_new_pair" 2021-11-07 11:08:30 +01:00
Matthias
1dd6872b80 Merge pull request #5843 from Theagainmen/patch-2
Update warning message open trades
2021-11-07 11:07:16 +01:00
Matthias
4595c1e73c Slightly reformat to simplify new change 2021-11-07 10:55:11 +01:00
Matthias
25fcab0794 Enhance /show_config endpoint 2021-11-06 16:20:18 +01:00
Matthias
fef7da03b2 Merge pull request #5850 from freqtrade/timeout_forcesell
multiple exit-timeouts can trigger emergencysell
2021-11-06 16:20:06 +01:00
Matthias
66220d6f9f Merge pull request #5846 from Merinorus/5527-show_average_profit_in_overwiew
Add /weekly and /monthly to Telegram (#5527)
2021-11-06 15:43:34 +01:00
Matthias
4f5c5b6982 Clarify timeout documentation 2021-11-06 15:29:05 +01:00
Antoine Merino
d0e192e20f Fix naive timezone for /daily command 2021-11-06 13:14:15 +01:00
Matthias
f7dc47b1c8 Add test for exit_timeout_count 2021-11-06 13:10:41 +01:00
Antoine Merino
d5acd979dc Move dev-only requirement 2021-11-06 13:10:22 +01:00
Antoine Merino
3c33b48fd5 Fix naive timezones 2021-11-06 13:09:15 +01:00
Matthias
7a907a7636 Add Emergencyselling after X timeouts have been reached 2021-11-06 11:48:49 +01:00
Antoine Merino
da4344d216 Remove line breaks
Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-05 22:52:04 +01:00
Antoine Merino
8eabdd659f Fix missing CallbackQueryHandler
Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-05 22:51:35 +01:00
Antoine Merino
77f3dabd15 Merge remote-tracking branch 'origin/5527-show_average_profit_in_overwiew' into 5527-show_average_profit_in_overwiew
# Conflicts:
#	freqtrade/rpc/rpc.py
#	requirements.txt
#	tests/rpc/test_rpc_telegram.py
2021-11-05 22:37:42 +01:00
Antoine Merino
70253258f0 Test /monthly & clean
Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-05 22:33:06 +01:00
Antoine Merino
87634f0409 /weekly and /monthly documentation
Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-05 21:07:29 +01:00
Antoine Merino
459ff9692d Add /weekly and /monthly to Telegram RPC
/weekly now list weeks starting from monday instead of rolling weeks.
/monthly now list months starting from the 1st.

Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-05 21:07:28 +01:00
Antoine Merino
5f40158c0b WIP Add /weekly and /monthly to Telegram RPC
Related to "Show average profit in overview" (#5527)

Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-05 21:07:19 +01:00
Antoine Merino
a8651b0dcd /weekly and /monthly documentation
Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-05 20:44:01 +01:00
Antoine Merino
15616d75ad Add /weekly and /monthly to Telegram RPC
/weekly now list weeks starting from monday instead of rolling weeks.
/monthly now list months starting from the 1st.

Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-05 20:24:40 +01:00
Matthias
d99eaccb5a Fix exception when using okex
closes #5842
2021-11-05 19:47:13 +01:00
Matthias
ae3b53014d Add failing test for OKEX failure
part of #5842
2021-11-05 19:44:02 +01:00
Matthias
60a5ded532 Don't convert telegram chat_id
closes #5840
2021-11-05 19:27:54 +01:00
Theagainmen
2115a3ed12 Update warning message open trades
This shouldn't confuse user when just reloading their bot.
2021-11-05 18:49:10 +01:00
Antoine Merino
ffc2de8d33 WIP Add /weekly and /monthly to Telegram RPC
Related to "Show average profit in overview" (#5527)

Signed-off-by: Antoine Merino <antoine.merino.dev@gmail.com>
2021-11-04 23:02:13 +01:00
Matthias
781f8a059c Merge pull request #5835 from freqtrade/okex_support
Add official Okex support
2021-11-04 20:03:19 +01:00
Matthias
26e5418519 Merge pull request #5834 from raph92/patch-4
Update optimize_reports
2021-11-04 16:56:21 +01:00
raphael
ae2343db93 Update optimize_reports
Update show_backtest_reults() to preserve backwards compatibility by fixing KeyError: 'results_per_buy_tag' for older hyperopt result files.
2021-11-04 10:25:13 -04:00
Matthias
eb280798d8 Merge pull request #5832 from samgermain/setup
setup.sh - Redhat
2021-11-04 15:23:48 +01:00
Sam Germain
10e839c17e Update setup.sh
python versions 3.7 to 3.9
2021-11-04 07:26:17 -06:00
Sam Germain
5b9a168ca9 removed build-essential from redhat install 2021-11-04 00:44:58 -06:00
Matthias
17ecfda2e8 Merge pull request #5710 from theluxaz/freqtrade-development
Added SELL_TAG for trading, backtesting and telegram
2021-11-04 07:13:06 +01:00
Matthias
c061b576a9 OKEX Notes 2021-11-04 06:22:31 +01:00
Matthias
431b96de98 Merge branch 'develop' into pr/theluxaz/5710 2021-11-03 19:43:36 +01:00
Matthias
048db4f509 Enhance "new exchange" documentation 2021-11-03 19:27:17 +01:00
Matthias
437e5f0645 Fix officially supported exchange list 2021-11-03 19:20:39 +01:00
Matthias
6fb0866350 Add OKEX to list of officially supported exchanges 2021-11-03 19:19:27 +01:00
Matthias
a1e8878030 Merge pull request #5826 from Theagainmen/patch-1
[docs] Update RateLimit value [small]
2021-11-03 17:06:01 +01:00
Theagainmen
ce597d12d9 Update exchanges.md
Fix 3100ms to 3.1s in docs, instead of the 0.2s
2021-11-03 15:04:45 +01:00
Matthias
f60d101076 Some finetuning for OKEX 2021-11-03 07:12:42 +01:00
Matthias
1fefb132e0 Improve wording in documentation 2021-11-02 20:26:38 +01:00
Matthias
161a3fac15 Run exchange-enabled tests against okex 2021-11-02 20:08:56 +01:00
Matthias
e78df59e30 Configure candle length for OKEX 2021-11-02 19:49:53 +01:00
Theagainmen
f365e68706 [docs] Update RateLimit value [small]
## Summary
Fix very small mistake in docs, that might confuse people. Let me know if this is the correct value now, there is still another 3100 in there, which I think makes sense there and is correct.

## Quick changelog
Changed the `rateLimit` 3100 value to 200, to match the 200ms and thus 0.2s delay.
2021-11-01 23:07:16 +01:00
Matthias
7ae9b90174 Further clarify backtesting trailing stop logic
part of #5816
2021-11-01 20:12:34 +01:00
Matthias
3056be3a1d document prerequisites for exchange listing 2021-11-01 20:04:52 +01:00
Matthias
74e8b28991 Improve FAQ with outdated history message
closes #5819
2021-11-01 13:54:12 +01:00
Matthias
a16328f372 Don't force timeframe in config in config generator 2021-11-01 13:44:26 +01:00
Matthias
6623dfe7da Improve CORS documentation 2021-11-01 11:07:06 +01:00
Matthias
4249fcefba Merge pull request #5150 from cryptomeisternox/backtesting-filter
Adding command for Filtering and print trades
2021-11-01 09:43:49 +01:00
Matthias
6934f37d16 Merge pull request #5822 from freqtrade/dependabot/pip/develop/mkdocs-material-7.3.6
Bump mkdocs-material from 7.3.4 to 7.3.6
2021-11-01 08:26:10 +01:00
Matthias
27dce9eeea Merge pull request #5820 from freqtrade/dependabot/pip/develop/filelock-3.3.2
Bump filelock from 3.3.1 to 3.3.2
2021-11-01 07:55:09 +01:00
Matthias
e34c62074b Merge pull request #5824 from freqtrade/dependabot/pip/develop/scikit-learn-1.0.1
Bump scikit-learn from 1.0 to 1.0.1
2021-11-01 07:54:53 +01:00
Matthias
2b1373966f Merge pull request #5821 from freqtrade/dependabot/pip/develop/ccxt-1.59.77
Bump ccxt from 1.59.2 to 1.59.77
2021-11-01 07:53:39 +01:00
dependabot[bot]
46d4418e85 Bump scikit-learn from 1.0 to 1.0.1
Bumps [scikit-learn](https://github.com/scikit-learn/scikit-learn) from 1.0 to 1.0.1.
- [Release notes](https://github.com/scikit-learn/scikit-learn/releases)
- [Commits](https://github.com/scikit-learn/scikit-learn/compare/1.0...1.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-01 03:01:23 +00:00
dependabot[bot]
45f7093e52 Bump mkdocs-material from 7.3.4 to 7.3.6
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.3.4 to 7.3.6.
- [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/7.3.4...7.3.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-01 03:01:14 +00:00
dependabot[bot]
e2041ddb70 Bump ccxt from 1.59.2 to 1.59.77
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.59.2 to 1.59.77.
- [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/1.59.2...1.59.77)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-01 03:01:10 +00:00
dependabot[bot]
3d59289b09 Bump filelock from 3.3.1 to 3.3.2
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.3.1 to 3.3.2.
- [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.3.1...3.3.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-11-01 03:01:03 +00:00
Matthias
6b90b4a144 Test "get-signal" 2021-10-31 10:53:30 +01:00
Matthias
dffe76f109 Don't double-loop to generate profits 2021-10-31 10:49:56 +01:00
Matthias
c15f73aa1f Rename command to backtesting-show 2021-10-31 10:13:11 +01:00
Matthias
20904f1ca4 Add tests for new command 2021-10-30 19:43:42 +02:00
Matthias
72ecb45d86 Add test for backtest_show logic 2021-10-30 16:53:48 +02:00
Matthias
650d6c276a Add documentation 2021-10-30 16:40:03 +02:00
Matthias
e8f85aed6b Merge pull request #5818 from freqtrade/fix/5816
Fix/5816
2021-10-30 16:36:46 +02:00
Matthias
d60001e886 Stoploss cannot be below candle low
fix #5816
2021-10-30 16:14:13 +02:00
Matthias
459a2239ce Fix candle ranges in backtesting test 2021-10-30 16:13:04 +02:00
Matthias
6cf140f8fb FIx testcases 2021-10-30 16:07:10 +02:00
Matthias
851062ca46 Rename backtest-filter to backtest_show 2021-10-30 10:53:18 +02:00
Matthias
f472709438 Add option to show sorted pairlist
Allows easy copy/pasting of the pairlist to a configuration
2021-10-30 10:50:40 +02:00
Matthias
0f3809345a Remove backtest-path parameter 2021-10-30 10:28:12 +02:00
Matthias
6f1e719216 Merge branch 'develop' into pr/cryptomeisternox/5150 2021-10-30 10:26:05 +02:00
Matthias
c34b8a95d7 Merge pull request #5798 from incrementby1/personal-branch
Add function to unlock PairLocks by reason
2021-10-30 10:15:21 +02:00
Matthias
c579fcfc19 Add tests and documentation for unlock_reason 2021-10-30 09:51:09 +02:00
Matthias
201fe108bc Merge pull request #5607 from TreborNamor/develop
a new hyperopt loss created that uses calmar ratio
2021-10-29 09:20:44 +02:00
Matthias
240923341b Reformat telegram test 2021-10-29 07:05:02 +02:00
Matthias
5cdae2ce3f Remove CalmarDaily hyperopt loss 2021-10-29 06:53:40 +02:00
incrementby1
e9d71f26b3 small changes 2021-10-29 00:03:20 +02:00
incrementby1
658006e7ee removed wrong use of map and filter function 2021-10-28 23:29:26 +02:00
Matthias
dadf015c23 Merge pull request #5805 from freqtrade/new_release
New release 2021.10
2021-10-28 20:49:51 +02:00
theluxaz
560802c326 Added tests for the new rpc/telegram functions 2021-10-28 21:39:42 +03:00
incrementby1
02e69e1667 Changes to unlock_reason:
- introducing filter
	- replaced get_all_locks with a query for speed
	. removed logging in backtesting mode for speed
	. replaced for-loop with map-function for speed

Changes to models.py:
	- changed string representation of Pairlock to also contain reason and active-state
2021-10-28 15:16:07 +02:00
Matthias
335412a3a8 Improve wording of FAQ entry 2021-10-28 07:59:28 +02:00
Matthias
f280397fd7 Add FAQ section about Fees
closes #5807
2021-10-28 07:51:32 +02:00
Matthias
98ed7edb11 Version bump to 2021.10 2021-10-28 06:21:40 +02:00
Matthias
8dd7d134f2 Merge branch 'stable' into new_release 2021-10-28 06:20:33 +02:00
incrementby1
dc605e29aa removed empty lines for flake8 2021-10-27 21:04:08 +02:00
Matthias
92130837a9 Improve and clarify informative pairs documentation 2021-10-27 19:58:29 +02:00
Matthias
892a1ca60c Merge pull request #5804 from JackBananas/patch-1
Update data-download.md
2021-10-27 19:32:37 +02:00
JackBananas
e2b64a750f Update data-download.md
Minor change due to a misleading sentence
2021-10-27 17:14:26 +02:00
incrementby1
2e7d08612e Merge branch 'personal-branch' of https://github.com/incrementby1/freqtrade into personal-branch 2021-10-27 16:03:05 +02:00
incrementby1
2eb33707c9 Undo changes 2021-10-27 15:58:41 +02:00
incrementby1
a50bde10de Merge https://github.com/freqtrade/freqtrade into personal-branch 2021-10-27 15:52:10 +02:00
incrementby1
91b9e5ce68 Delete StackingDemo.py 2021-10-27 12:43:00 +02:00
incrementby1
c1b5dcd756 Delete freqtradebot.py 2021-10-27 12:42:18 +02:00
incrementby1
6b17094c6f Delete configuration.py 2021-10-27 12:41:49 +02:00
incrementby1
51c925f9f3 Delete StackingConfig.json 2021-10-27 12:40:26 +02:00
Matthias
f80d3d48e4 Add default to minimal_roi to avoid failures
closes #5796
2021-10-27 06:33:49 +02:00
theluxaz
21ab83163d Quick import/clarity fix 2021-10-27 01:35:47 +03:00
theluxaz
e4e75d4861 Added test data for buy_tag/sell_reason testing 2021-10-27 01:29:19 +03:00
incrementby1
9c6cbc025a Update StackingDemo.py 2021-10-26 00:34:01 +02:00
incrementby1
9f6e4c6c0e uncomment 2021-10-26 00:31:17 +02:00
incrementby1
ae06899694 removed commenting 2021-10-26 00:29:11 +02:00
incrementby1
c3f3bdaa2a Add "allow_position_stacking" value to config, which allows rebuys of a pair
Add function unlock_reason(str: pair) which removes all PairLocks with reason
Provide demo strategy that allows buying the same pair multiple times
2021-10-26 00:04:40 +02:00
theluxaz
b51f946ee0 Fixed models and rpc performance functions, added skeletons for tests. 2021-10-25 23:43:22 +03:00
Matthias
20a61e03da Merge pull request #5786 from SimonEbner/clean_up_file_handles
Clean up file handles
2021-10-25 19:49:07 +02:00
Sam Germain
d1e2a53267 Added centOS support to setup.sh script 2021-10-25 03:20:41 -06:00
Sam Germain
7ff16997e9 Wrote echo block method for setup script 2021-10-25 03:19:49 -06:00
Robert Roman
88b96d5d1b Update hyperopt_loss_calmar.py 2021-10-25 00:45:10 -05:00
Matthias
029ddd23c1 Merge pull request #5791 from freqtrade/dependabot/pip/develop/numpy-1.21.3
Bump numpy from 1.21.2 to 1.21.3
2021-10-25 07:20:06 +02:00
Matthias
262f186a37 . 2021-10-25 07:19:55 +02:00
Matthias
33d75e9963 Merge pull request #5790 from freqtrade/dependabot/pip/develop/arrow-1.2.1
Bump arrow from 1.2.0 to 1.2.1
2021-10-25 07:07:50 +02:00
Matthias
cea251c83c Clarify documentation for /forcebuy
closes #5783
2021-10-25 06:46:02 +02:00
dependabot[bot]
4e88bd07fa Bump numpy from 1.21.2 to 1.21.3
Bumps [numpy](https://github.com/numpy/numpy) from 1.21.2 to 1.21.3.
- [Release notes](https://github.com/numpy/numpy/releases)
- [Changelog](https://github.com/numpy/numpy/blob/main/doc/HOWTO_RELEASE.rst.txt)
- [Commits](https://github.com/numpy/numpy/compare/v1.21.2...v1.21.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-25 04:40:30 +00:00
dependabot[bot]
538d9e8b37 Bump arrow from 1.2.0 to 1.2.1
Bumps [arrow](https://github.com/arrow-py/arrow) from 1.2.0 to 1.2.1.
- [Release notes](https://github.com/arrow-py/arrow/releases)
- [Changelog](https://github.com/arrow-py/arrow/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/arrow-py/arrow/compare/1.2.0...1.2.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-25 04:40:24 +00:00
Matthias
478013a306 Merge pull request #5792 from freqtrade/dependabot/pip/develop/ccxt-1.59.2
Bump ccxt from 1.58.47 to 1.59.2
2021-10-25 06:39:25 +02:00
Matthias
0e72a901cc Merge pull request #5789 from freqtrade/dependabot/pip/develop/sqlalchemy-1.4.26
Bump sqlalchemy from 1.4.25 to 1.4.26
2021-10-25 06:39:01 +02:00
Matthias
2979679db4 Merge pull request #5793 from freqtrade/dependabot/pip/develop/jsonschema-4.1.2
Bump jsonschema from 4.1.0 to 4.1.2
2021-10-25 06:38:33 +02:00
Matthias
1a40e02ace Merge pull request #5788 from freqtrade/dependabot/pip/develop/prompt-toolkit-3.0.21
Bump prompt-toolkit from 3.0.20 to 3.0.21
2021-10-25 06:38:15 +02:00
dependabot[bot]
826d4eb2f4 Bump jsonschema from 4.1.0 to 4.1.2
Bumps [jsonschema](https://github.com/Julian/jsonschema) from 4.1.0 to 4.1.2.
- [Release notes](https://github.com/Julian/jsonschema/releases)
- [Changelog](https://github.com/Julian/jsonschema/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/Julian/jsonschema/compare/v4.1.0...v4.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-25 03:01:33 +00:00
dependabot[bot]
3d90305f8e Bump ccxt from 1.58.47 to 1.59.2
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.58.47 to 1.59.2.
- [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/1.58.47...1.59.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-25 03:01:29 +00:00
dependabot[bot]
b50b38f049 Bump sqlalchemy from 1.4.25 to 1.4.26
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.25 to 1.4.26.
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/main/CHANGES)
- [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>
2021-10-25 03:01:10 +00:00
dependabot[bot]
520c5687aa Bump prompt-toolkit from 3.0.20 to 3.0.21
Bumps [prompt-toolkit](https://github.com/prompt-toolkit/python-prompt-toolkit) from 3.0.20 to 3.0.21.
- [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/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-25 03:01:05 +00:00
Simon Ebner
f7926083ca Clean up unclosed file handles
Close all file handles that are left dangling to avoid warnings such as

```
ResourceWarning: unclosed file <_io.TextIOWrapper
name='...' mode='r' encoding='UTF-8'> params = json_load(filename.open('r'))
```
2021-10-24 23:15:05 +02:00
Matthias
4539170424 Merge pull request #5776 from SimonEbner/performance_decimalspace
Improve performance of decimalspace.py
2021-10-24 19:27:24 +02:00
Simon Ebner
df033d92ef Improve performance of decimalspace.py
decimalspace.py is heavily used in the hyperoptimization. The following
benchmark code runs an optimization which is taken from optimizing a
real strategy (wtc).
The optimized version takes on my machine approx. 11/12s compared to the
original 32s. Results are equivalent in both cases.

```
import freqtrade.optimize.space
import numpy as np
import skopt
import timeit

def init():
    Decimal = freqtrade.optimize.space.decimalspace.SKDecimal
    Integer = skopt.space.space.Integer
    dimensions = [Decimal(low=-1.0,
        high=1.0,
        decimals=4,
        prior='uniform',
        transform='identity')] * 20

    return skopt.Optimizer(
        dimensions,
        base_estimator="ET",
        acq_optimizer="auto",
        n_initial_points=5,
        acq_optimizer_kwargs={'n_jobs': 96},
        random_state=0,
        model_queue_size=10,
    )

def test():
    opt = init()
    actual = opt.ask(n_points=2)
    expected = [[
        0.7515, -0.4723, -0.6941, -0.7988, 0.0448, 0.8605, -0.108, 0.5399,
        0.763, -0.2948, 0.8345, -0.7683, 0.7077, -0.2478, -0.333, 0.8575,
        0.6108, 0.4514, 0.5982, 0.3506
    ], [
        0.5563, 0.7386, -0.6407, 0.9073, -0.5211, -0.8167, -0.3771,
        -0.0318, 0.2861, 0.1176, 0.0943, -0.6077, -0.9317, -0.5372,
        -0.4934, -0.3637, -0.8035, -0.8627, -0.5399, 0.6036
    ]]

    absdiff = np.max(np.abs(np.asarray(expected) - np.asarray(actual)))
    assert absdiff < 1e-5

def time():
    opt = init()
    print('dt', timeit.timeit("opt.ask(n_points=20)", globals=locals()))

if __name__ == "__main__":
    test()
    time()
```
2021-10-24 18:14:24 +02:00
Matthias
22dd2ca003 Fix mypy type errors 2021-10-24 15:18:29 +02:00
Matthias
17432b2823 Improve some stylings 2021-10-24 09:15:05 +02:00
Matthias
5f309627ea Update tests for Calmar ratio 2021-10-24 09:01:13 +02:00
Matthias
dffb4c5d53 Merge branch 'develop' into pr/TreborNamor/5607 2021-10-24 08:55:10 +02:00
Matthias
b4bedc22d7 Merge pull request #5777 from SimonEbner/pathlib_stem
Use pathlib.stem instead of str(x).ends_with
2021-10-23 19:29:18 +02:00
Simon Ebner
fde10f5395 Use pathlib.stem instead of str(x).ends_with 2021-10-23 12:26:07 +02:00
Matthias
78724e304e Merge branch 'develop' into pr/theluxaz/5710 2021-10-21 17:46:39 +02:00
theluxaz
0e085298e9 Fixed test failures. 2021-10-21 17:25:38 +03:00
Matthias
96f99699e0 Merge pull request #4606 from rextea/add_days_breakdown_to_backtesting_summary
Add days breakdown table to backtesting
2021-10-21 13:56:30 +02:00
Matthias
053fb076e4 Add documentation for breakdown command 2021-10-21 10:57:23 +02:00
Matthias
e458c9867a Styling fixes 2021-10-21 07:45:15 +02:00
Matthias
7b5346b984 Add test for breakdown-stats 2021-10-21 07:11:39 +02:00
Matthias
fa028c2134 Support day/week/month breakdowns 2021-10-21 06:58:40 +02:00
Matthias
7197f4ce77 Don't show daily % profit (it's wrong) 2021-10-20 20:01:31 +02:00
Matthias
de5497c766 backtest_days cannot be below 1 2021-10-20 19:39:37 +02:00
Matthias
1267374c8a Small fixes to tests 2021-10-20 19:21:38 +02:00
theluxaz
905f3a1a50 Removed exit_tag from Trade objects. 2021-10-20 17:58:50 +03:00
Matthias
5454460227 Revert initial_points to 30
closes #5760
2021-10-20 07:46:15 +02:00
theluxaz
1fdc4425dd Changed exit_tag to be represented as sell_reason 2021-10-20 01:26:15 +03:00
Matthias
55b0216180 Allow StaticPairlist in non-first position
closes #5754
2021-10-19 19:48:56 +02:00
Matthias
42a4dfed28 Reallow bitstamp
revert #1984, related to #1983
2021-10-19 19:12:35 +02:00
GluTbl
00406ea7d5 Update backtesting.py
Support for custom entry-prices and exit-prices during backtesting.
2021-10-19 17:15:45 +05:30
Matthias
2995f9a347 Merge pull request #5726 from daniila/patch-1
How to run multiple instances with docker
2021-10-19 11:43:12 +02:00
theluxaz
5ecdd1d112 Merge branch 'develop' into freqtrade-development 2021-10-19 00:00:15 +03:00
theluxaz
69a59cdf37 Fixed flake 8, changed sell_tag to exit_tag and fixed telegram functions 2021-10-18 23:56:41 +03:00
daniila
f863f4fdfc Update advanced-setup.md
A note on having to use different database files, ports and telegram configs for each bot.
2021-10-18 23:49:59 +03:00
daniila
5d2e374099 Update docs/advanced-setup.md
Co-authored-by: Matthias <xmatthias@outlook.com>
2021-10-18 23:38:45 +03:00
daniila
f9b1667478 Update docs/advanced-setup.md
Co-authored-by: Matthias <xmatthias@outlook.com>
2021-10-18 23:36:47 +03:00
Matthias
0da5ef16e6 Remove unnecessary dependency 2021-10-18 19:16:56 +02:00
Matthias
ddba4e32d7 Fully remove flake8-type-annotations 2021-10-18 16:04:24 +02:00
Matthias
52bd761111 Merge pull request #5749 from freqtrade/dependabot/pip/develop/types-filelock-3.2.1
Bump types-filelock from 3.2.0 to 3.2.1
2021-10-18 09:51:45 +02:00
Matthias
711897cffa Merge pull request #5737 from freqtrade/dependabot/pip/develop/pytest-asyncio-0.16.0
Bump pytest-asyncio from 0.15.1 to 0.16.0
2021-10-18 09:51:15 +02:00
Matthias
1c6fc068c6 Merge pull request #5741 from freqtrade/dependabot/pip/develop/pandas-1.3.4
Bump pandas from 1.3.3 to 1.3.4
2021-10-18 09:30:25 +02:00
Matthias
925df4dfec Merge pull request #5743 from freqtrade/dependabot/pip/develop/mkdocs-material-7.3.4
Bump mkdocs-material from 7.3.2 to 7.3.4
2021-10-18 09:29:59 +02:00
dependabot[bot]
8a7ea65531 Bump types-filelock from 3.2.0 to 3.2.1
Bumps [types-filelock](https://github.com/python/typeshed) from 3.2.0 to 3.2.1.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 07:06:05 +00:00
Matthias
0ef20a5b04 Merge pull request #5744 from freqtrade/dependabot/pip/develop/types-tabulate-0.8.3
Bump types-tabulate from 0.8.2 to 0.8.3
2021-10-18 09:05:06 +02:00
dependabot[bot]
3af55cc8c7 Bump pandas from 1.3.3 to 1.3.4
Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.3.3 to 1.3.4.
- [Release notes](https://github.com/pandas-dev/pandas/releases)
- [Changelog](https://github.com/pandas-dev/pandas/blob/master/RELEASE.md)
- [Commits](https://github.com/pandas-dev/pandas/compare/v1.3.3...v1.3.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 06:58:47 +00:00
Matthias
0d7be62e62 Merge pull request #5752 from freqtrade/dependabot/pip/develop/ccxt-1.58.47
Bump ccxt from 1.57.94 to 1.58.47
2021-10-18 08:57:52 +02:00
dependabot[bot]
75e6a2d276 Bump mkdocs-material from 7.3.2 to 7.3.4
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.3.2 to 7.3.4.
- [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/7.3.2...7.3.4)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 06:47:32 +00:00
Matthias
e00a71a3db Merge pull request #5751 from freqtrade/dependabot/pip/develop/mkdocs-1.2.3
Bump mkdocs from 1.2.2 to 1.2.3
2021-10-18 08:46:39 +02:00
Matthias
ef70ea3997 Merge pull request #5748 from freqtrade/dependabot/pip/develop/progressbar2-3.55.0
Bump progressbar2 from 3.53.3 to 3.55.0
2021-10-18 08:40:55 +02:00
dependabot[bot]
618f0ffe68 Bump types-tabulate from 0.8.2 to 0.8.3
Bumps [types-tabulate](https://github.com/python/typeshed) from 0.8.2 to 0.8.3.
- [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>
2021-10-18 06:38:42 +00:00
Matthias
5320ddc382 Merge pull request #5746 from freqtrade/dependabot/pip/develop/types-cachetools-4.2.4
Bump types-cachetools from 4.2.2 to 4.2.4
2021-10-18 08:37:56 +02:00
dependabot[bot]
44e6e13429 Bump ccxt from 1.57.94 to 1.58.47
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.57.94 to 1.58.47.
- [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/1.57.94...1.58.47)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 06:16:09 +00:00
dependabot[bot]
4b02749019 Bump mkdocs from 1.2.2 to 1.2.3
Bumps [mkdocs](https://github.com/mkdocs/mkdocs) from 1.2.2 to 1.2.3.
- [Release notes](https://github.com/mkdocs/mkdocs/releases)
- [Commits](https://github.com/mkdocs/mkdocs/compare/1.2.2...1.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 06:15:52 +00:00
Matthias
ff3bfa3d52 Merge pull request #5747 from freqtrade/dependabot/pip/develop/python-rapidjson-1.5
Bump python-rapidjson from 1.4 to 1.5
2021-10-18 08:15:01 +02:00
Matthias
dccce4855e Merge pull request #5740 from freqtrade/dependabot/pip/develop/pyjwt-2.3.0
Bump pyjwt from 2.2.0 to 2.3.0
2021-10-18 07:40:20 +02:00
Matthias
733d254644 Merge pull request #5742 from freqtrade/dependabot/pip/develop/wrapt-1.13.2
Bump wrapt from 1.13.1 to 1.13.2
2021-10-18 07:39:54 +02:00
dependabot[bot]
82684f5de9 Bump progressbar2 from 3.53.3 to 3.55.0
Bumps [progressbar2](https://github.com/WoLpH/python-progressbar) from 3.53.3 to 3.55.0.
- [Release notes](https://github.com/WoLpH/python-progressbar/releases)
- [Changelog](https://github.com/WoLpH/python-progressbar/blob/develop/CHANGES.rst)
- [Commits](https://github.com/WoLpH/python-progressbar/compare/v3.53.3...v3.55.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 05:19:03 +00:00
Matthias
bddbb474aa Merge pull request #5739 from freqtrade/dependabot/pip/develop/filelock-3.3.1
Bump filelock from 3.3.0 to 3.3.1
2021-10-18 07:18:58 +02:00
dependabot[bot]
69c98c4141 Bump python-rapidjson from 1.4 to 1.5
Bumps [python-rapidjson](https://github.com/python-rapidjson/python-rapidjson) from 1.4 to 1.5.
- [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.4...v1.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 05:18:47 +00:00
dependabot[bot]
035380d8a4 Bump types-cachetools from 4.2.2 to 4.2.4
Bumps [types-cachetools](https://github.com/python/typeshed) from 4.2.2 to 4.2.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>
2021-10-18 05:18:42 +00:00
Matthias
e6bbfaefe5 Merge pull request #5736 from freqtrade/dependabot/pip/develop/types-requests-2.25.11
Bump types-requests from 2.25.9 to 2.25.11
2021-10-18 07:18:30 +02:00
Matthias
c58126e9c5 Merge pull request #5738 from freqtrade/dependabot/pip/develop/flake8-4.0.1
Bump flake8 from 4.0.0 to 4.0.1
2021-10-18 07:18:06 +02:00
dependabot[bot]
d7756efe8b Bump wrapt from 1.13.1 to 1.13.2
Bumps [wrapt](https://github.com/GrahamDumpleton/wrapt) from 1.13.1 to 1.13.2.
- [Release notes](https://github.com/GrahamDumpleton/wrapt/releases)
- [Changelog](https://github.com/GrahamDumpleton/wrapt/blob/develop/docs/changes.rst)
- [Commits](https://github.com/GrahamDumpleton/wrapt/compare/1.13.1...1.13.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 03:01:28 +00:00
dependabot[bot]
b60371822f Bump pyjwt from 2.2.0 to 2.3.0
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.2.0 to 2.3.0.
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jpadilla/pyjwt/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 03:01:19 +00:00
dependabot[bot]
e7a2672f07 Bump filelock from 3.3.0 to 3.3.1
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.3.0 to 3.3.1.
- [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.3.0...3.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 03:01:17 +00:00
dependabot[bot]
9b0171ef37 Bump flake8 from 4.0.0 to 4.0.1
Bumps [flake8](https://github.com/pycqa/flake8) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/pycqa/flake8/releases)
- [Commits](https://github.com/pycqa/flake8/compare/4.0.0...4.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-18 03:01:14 +00:00
dependabot[bot]
12a041b466 Bump pytest-asyncio from 0.15.1 to 0.16.0
Bumps [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) from 0.15.1 to 0.16.0.
- [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases)
- [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.15.1...v0.16.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>
2021-10-18 03:01:10 +00:00
dependabot[bot]
6be40cb7c3 Bump types-requests from 2.25.9 to 2.25.11
Bumps [types-requests](https://github.com/python/typeshed) from 2.25.9 to 2.25.11.
- [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>
2021-10-18 03:01:07 +00:00
Matthias
00fc38a5dc Update setup.sh to correctly exit if ta-lib fails
part of #5734
2021-10-17 19:24:09 +02:00
Matthias
e09ec6e6b3 Merge pull request #5733 from freqtrade/download_all
Download all
2021-10-17 16:50:41 +02:00
Matthias
7d8cd736b8 Support days-breakdown also for hyperopt results 2021-10-17 16:49:39 +02:00
Matthias
47bba331c1 Merge branch 'develop' into pr/rextea/4606 2021-10-17 16:29:31 +02:00
Matthias
28483a7952 Fix doc-link in developer docs 2021-10-17 16:10:15 +02:00
Matthias
d4d57f0002 Document expansion of --pairs, add download-inactive 2021-10-17 16:09:56 +02:00
Matthias
9bb2dd1851 Merge pull request #5694 from freqtrade/dependabot/pip/develop/fastapi-0.70.0
Bump fastapi from 0.68.1 to 0.70.0
2021-10-17 15:01:28 +02:00
Matthias
e23eb99abf Disable ability to use lookahead-biased vwap
closes #5782
2021-10-17 11:23:58 +02:00
Matthias
abd5c4f278 Convert additional test to USDT 2021-10-17 10:39:53 +02:00
Matthias
fb2c8f7621 Rollback after each request
This closes the transaction and avoids "sticking" transactions.
2021-10-17 10:30:06 +02:00
Matthias
29ad90f1e3 Merge pull request #5727 from Rikj000/docs/fix-mkdocs-darktheme-toggle
📝 `mkdocs.yml` - Fixed darktheme toggle
2021-10-17 08:37:34 +02:00
Rik Helsen
f61dc6d95a 📝 mkdocs.yml - Fixed darktheme toggle 2021-10-17 00:14:09 +02:00
daniila
5a9983086a How to run multiple instances with docker
Basic guide on how to run multiple instances using docker.
2021-10-17 00:24:00 +03:00
dependabot[bot]
89ca8abea9 Bump fastapi from 0.68.1 to 0.70.0
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.68.1 to 0.70.0.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.68.1...0.70.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-16 19:31:12 +02:00
Matthias
b1ee56a5ce Merge pull request #5724 from freqtrade/fix/5719
Make sure transactions are reset
2021-10-16 19:30:40 +02:00
Matthias
5ba1d66be7 Make sure transactions are reset
closes #5719
2021-10-16 17:57:51 +02:00
Matthias
dcefb3eb9c Fix delete_Trade api test 2021-10-16 16:48:35 +02:00
Matthias
7f1080368b Commit mock-trades to avoid errors in tests 2021-10-16 16:48:19 +02:00
Matthias
de5657a91b Fix test failing when UI is installed 2021-10-16 16:47:28 +02:00
Matthias
f120e0d256 Merge pull request #5716 from freqtrade/setupsh_fix
Don't build ta-lib in parallel, this causes failures
2021-10-15 10:31:32 +02:00
Matthias
fe9f597eab Don't build ta-lib in parallel, this causes failures 2021-10-15 10:11:25 +02:00
Matthias
794862a35a Merge pull request #5670 from sergeykhliustin/develop
Added min_profit param to PerformanceFilter
2021-10-14 19:57:36 +02:00
Matthias
c02a538187 Add documentation and log to PerformanceFilter 2021-10-14 19:36:34 +02:00
Matthias
0e7d903a6f Merge pull request #5644 from slyons/develop
Add ability to ignore unparameterized spaces
2021-10-14 08:07:07 +02:00
Matthias
fe8374f2a4 Test for non-failing missing hyperopt space 2021-10-14 07:06:51 +02:00
theluxaz
0bb7ea10ab Fixed minor header for backtesting 2021-10-14 01:34:30 +03:00
theluxaz
ed39b8dab0 fixed profit total calculation 2021-10-14 01:18:16 +03:00
theluxaz
8b2c14a6fa Readme fix 2021-10-14 01:15:43 +03:00
theluxaz
d341d85079 Refixed some files for the pull request 2021-10-14 01:13:28 +03:00
theluxaz
96cab22a8c Fixed some bugs for live sell_tags. 2021-10-14 01:03:15 +03:00
Matthias
3279ea568c Add new parameter to hyperopt docs 2021-10-13 19:57:42 +02:00
Matthias
aed919a05f Simplify "no-space-configured" error handling by moving it to hyperopt_auto 2021-10-13 19:54:35 +02:00
theluxaz
7067c43ff4 Merge branch 'main' of https://github.com/theluxaz/freqtrade into main 2021-10-13 02:20:30 +03:00
theluxaz
0f670189eb quick typo fix 2021-10-13 02:14:07 +03:00
theluxaz
3ee9674bb7 Update README.md 2021-10-13 02:07:45 +03:00
theluxaz
af74850e79 Update README.md 2021-10-13 02:07:23 +03:00
theluxaz
b151cf032b Merge branch 'develop' of https://github.com/theluxaz/freqtrade into main
# Conflicts:
#	freqtrade/freqtradebot.py
#	freqtrade/optimize/backtesting.py
2021-10-13 02:01:26 +03:00
theluxaz
02243b1a2b minifix 2021-10-13 01:34:29 +03:00
theluxaz
80b71790bc Added some bigfixes for sell_tag 2021-10-13 01:22:53 +03:00
theluxaz
c9edf3bf4a Updated the gitignore 2021-10-13 00:09:30 +03:00
theluxaz
b898f86364 Added sell_tag and buy/sell telegram performance functions 2021-10-13 00:02:28 +03:00
Matthias
0926beaf73 Merge pull request #5632 from freqtrade/dependabot/pip/develop/scikit-learn-1.0
Bump scikit-learn from 0.24.2 to 1.0
2021-10-12 20:04:29 +02:00
Matthias
8798ae5677 Version bump also scikit-optimize 2021-10-12 19:06:23 +02:00
Matthias
59ed11358f Merge pull request #5708 from freqtrade/ui_version_specify
Add version argument to freqUI installer
2021-10-12 07:16:34 +02:00
Matthias
ce9debe9fd Add version argument to freqUI installer 2021-10-12 06:44:07 +02:00
Matthias
7e958589b3 Merge pull request #5701 from freqtrade/dependabot/pip/develop/flake8-4.0.0
Bump flake8 from 3.9.2 to 4.0.0
2021-10-11 20:34:40 +02:00
Matthias
396bc9b2e3 Version bump flake8-tidy-imports to 4.5.0 2021-10-11 20:00:53 +02:00
Matthias
7b1e81689a Merge pull request #5704 from freqtrade/dependabot/pip/develop/mkdocs-material-7.3.2
Bump mkdocs-material from 7.3.1 to 7.3.2
2021-10-11 10:06:18 +02:00
Matthias
1649c00cb7 Merge pull request #5706 from freqtrade/dependabot/pip/develop/ccxt-1.57.94
Bump ccxt from 1.57.38 to 1.57.94
2021-10-11 10:05:53 +02:00
dependabot[bot]
fa00b52c47 Bump scikit-learn from 0.24.2 to 1.0
Bumps [scikit-learn](https://github.com/scikit-learn/scikit-learn) from 0.24.2 to 1.0.
- [Release notes](https://github.com/scikit-learn/scikit-learn/releases)
- [Commits](https://github.com/scikit-learn/scikit-learn/compare/0.24.2...1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 07:41:16 +00:00
Matthias
7d629d45c3 Merge pull request #5705 from freqtrade/dependabot/pip/develop/joblib-1.1.0
Bump joblib from 1.0.1 to 1.1.0
2021-10-11 09:40:27 +02:00
Matthias
f5a0e78c1b Merge pull request #5692 from freqtrade/dependabot/pip/develop/jsonschema-4.1.0
Bump jsonschema from 4.0.1 to 4.1.0
2021-10-11 09:39:24 +02:00
dependabot[bot]
802599bdc9 Bump ccxt from 1.57.38 to 1.57.94
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.57.38 to 1.57.94.
- [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/1.57.38...1.57.94)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 06:15:32 +00:00
dependabot[bot]
29371b2f28 Bump joblib from 1.0.1 to 1.1.0
Bumps [joblib](https://github.com/joblib/joblib) from 1.0.1 to 1.1.0.
- [Release notes](https://github.com/joblib/joblib/releases)
- [Changelog](https://github.com/joblib/joblib/blob/master/CHANGES.rst)
- [Commits](https://github.com/joblib/joblib/compare/1.0.1...1.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 06:15:03 +00:00
Matthias
c4e967c003 Merge pull request #5696 from freqtrade/dependabot/pip/develop/jinja2-3.0.2
Bump jinja2 from 3.0.1 to 3.0.2
2021-10-11 08:14:59 +02:00
Matthias
8b2bad3366 Merge pull request #5698 from freqtrade/dependabot/pip/develop/arrow-1.2.0
Bump arrow from 1.1.1 to 1.2.0
2021-10-11 08:14:24 +02:00
Matthias
acc2760512 Merge pull request #5703 from freqtrade/dependabot/pip/develop/pyjwt-2.2.0
Bump pyjwt from 2.1.0 to 2.2.0
2021-10-11 08:13:32 +02:00
dependabot[bot]
90ea3d4440 Bump mkdocs-material from 7.3.1 to 7.3.2
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.3.1 to 7.3.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/7.3.1...7.3.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>
2021-10-11 05:18:24 +00:00
Matthias
9cb20241d9 Merge pull request #5697 from freqtrade/dependabot/pip/develop/cryptography-35.0.0
Bump cryptography from 3.4.8 to 35.0.0
2021-10-11 07:17:20 +02:00
dependabot[bot]
4921a4caec Bump jinja2 from 3.0.1 to 3.0.2
Bumps [jinja2](https://github.com/pallets/jinja) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/pallets/jinja/releases)
- [Changelog](https://github.com/pallets/jinja/blob/main/CHANGES.rst)
- [Commits](https://github.com/pallets/jinja/compare/3.0.1...3.0.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 05:14:19 +00:00
dependabot[bot]
32174f8f90 Bump pyjwt from 2.1.0 to 2.2.0
Bumps [pyjwt](https://github.com/jpadilla/pyjwt) from 2.1.0 to 2.2.0.
- [Release notes](https://github.com/jpadilla/pyjwt/releases)
- [Changelog](https://github.com/jpadilla/pyjwt/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/jpadilla/pyjwt/compare/2.1.0...2.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 05:14:08 +00:00
Matthias
01e7b08aa9 Merge pull request #5695 from freqtrade/dependabot/pip/develop/blosc-1.10.6
Bump blosc from 1.10.4 to 1.10.6
2021-10-11 07:13:07 +02:00
dependabot[bot]
afc086f33c Bump arrow from 1.1.1 to 1.2.0
Bumps [arrow](https://github.com/arrow-py/arrow) from 1.1.1 to 1.2.0.
- [Release notes](https://github.com/arrow-py/arrow/releases)
- [Changelog](https://github.com/arrow-py/arrow/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/arrow-py/arrow/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 05:05:30 +00:00
dependabot[bot]
e467491dbe Bump jsonschema from 4.0.1 to 4.1.0
Bumps [jsonschema](https://github.com/Julian/jsonschema) from 4.0.1 to 4.1.0.
- [Release notes](https://github.com/Julian/jsonschema/releases)
- [Changelog](https://github.com/Julian/jsonschema/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/Julian/jsonschema/compare/v4.0.1...v4.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 05:05:23 +00:00
dependabot[bot]
3fdc62d29c Bump flake8 from 3.9.2 to 4.0.0
Bumps [flake8](https://github.com/pycqa/flake8) from 3.9.2 to 4.0.0.
- [Release notes](https://github.com/pycqa/flake8/releases)
- [Commits](https://github.com/pycqa/flake8/compare/3.9.2...4.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 05:05:14 +00:00
Matthias
a51084f7a7 Merge pull request #5693 from freqtrade/dependabot/pip/develop/wrapt-1.13.1
Bump wrapt from 1.12.1 to 1.13.1
2021-10-11 07:04:35 +02:00
dependabot[bot]
5fb0401dca Bump cryptography from 3.4.8 to 35.0.0
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.4.8 to 35.0.0.
- [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/3.4.8...35.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 03:01:39 +00:00
dependabot[bot]
7323ffa25a Bump blosc from 1.10.4 to 1.10.6
Bumps [blosc](https://github.com/blosc/python-blosc) from 1.10.4 to 1.10.6.
- [Release notes](https://github.com/blosc/python-blosc/releases)
- [Changelog](https://github.com/Blosc/python-blosc/blob/master/RELEASE_NOTES.rst)
- [Commits](https://github.com/blosc/python-blosc/compare/v1.10.4...v1.10.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 03:01:31 +00:00
dependabot[bot]
57095d7167 Bump wrapt from 1.12.1 to 1.13.1
Bumps [wrapt](https://github.com/GrahamDumpleton/wrapt) from 1.12.1 to 1.13.1.
- [Release notes](https://github.com/GrahamDumpleton/wrapt/releases)
- [Changelog](https://github.com/GrahamDumpleton/wrapt/blob/develop/docs/changes.rst)
- [Commits](https://github.com/GrahamDumpleton/wrapt/compare/1.12.1...1.13.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-11 03:01:22 +00:00
Matthias
50439ac441 Merge pull request #5674 from jonny07/patch-4
Update docker_quickstart.md
2021-10-09 15:49:34 +02:00
Matthias
1a3b41ed97 Rephrase and simplify UI access section in docker quickstart 2021-10-09 15:35:39 +02:00
Matthias
fa9484a06b Merge branch 'develop' into pr/jonny07/5674 2021-10-09 15:29:24 +02:00
Matthias
cae8ff5949 Merge pull request #5623 from froggleston/rest_sysinfo
Add CPU,RAM sysinfo support to the REST API to help with bot system m…
2021-10-09 15:17:21 +02:00
Matthias
4d61e3866c Merge pull request #5684 from SmartManoj/patch-1
pypi installation
2021-10-09 10:49:39 +02:00
Matthias
2c68342140 Move pypi installation to documentation 2021-10-09 10:37:33 +02:00
Matthias
91ceaef02f Merge pull request #5678 from sidml/develop
Hyperopt loss function using max drawdown
2021-10-09 10:26:40 +02:00
Matthias
7b1c888665 Add FAQ entry for incomplete candles
closes #5687
2021-10-09 08:39:32 +02:00
sid
30bc96cf3f simplify expression 2021-10-09 06:36:23 +05:30
Matthias
11ec1d9b06 Revert previous commit 2021-10-08 20:22:07 +02:00
Matthias
482f4418c6 Clarify "required candle" message 2021-10-08 14:36:52 +02:00
மனோஜ்குமார் பழனிச்சாமி
1327c21d01 Update README.md 2021-10-07 19:12:09 +05:30
Robert Davey
f07eeddda0 Update api_schemas.py
Fix api schema for cpu_pct float List.
2021-10-07 12:04:42 +01:00
Matthias
a1be6124f2 Don't set bid_last_balance if None in tests
part of #5681
2021-10-07 07:15:09 +02:00
Matthias
45b7a0c837 Add Test and docs for MaxDrawDownHyperOptLoss 2021-10-07 07:12:45 +02:00
Matthias
29863ad2bf Fix error when ask_last_balance is not set
closes #5181
2021-10-07 06:51:29 +02:00
sid
46c320513a use profit_abs 2021-10-07 08:07:07 +05:30
sid
93e4cf4006 Merge remote-tracking branch 'upstream/develop' into develop 2021-10-07 08:04:40 +05:30
Matthias
526bdaa2dc Recommend using 0.0.0.0 as listen address for docker 2021-10-06 20:14:59 +02:00
Matthias
65d4df938d Improve docker port api 2021-10-06 20:09:08 +02:00
Matthias
992cef56e6 Add test for sysinfo endpoint 2021-10-06 19:36:51 +02:00
Matthias
57ef25789e Fix style errors 2021-10-06 19:36:41 +02:00
sid
6ba46b38bd fix formatting 2021-10-06 13:46:05 +05:30
sid
c0d01dbc26 add max_drawdown loss 2021-10-06 13:24:27 +05:30
jonny07
949d616082 Update docker_quickstart.md
Got help in the discord chat to get the UI running, I think most people will need this...
2021-10-05 21:33:15 +02:00
froggleston
0db5c07314 Fix issues with sysinfo rpc/API code, add SysInfo api_schema 2021-10-05 00:10:39 +01:00
Matthias
92f8f231af Remove ratelimit from kucoin template 2021-10-04 20:22:41 +02:00
Matthias
7f4baab420 Remove explicit rateLimits, improve docs 2021-10-04 20:14:22 +02:00
Matthias
60e28a30f4 Merge pull request #5664 from freqtrade/dependabot/pip/develop/ccxt-1.57.38
Bump ccxt from 1.57.3 to 1.57.38
2021-10-04 19:29:28 +02:00
Matthias
f15922a168 Fix custom_stoploss in strategy template
closes #5658
2021-10-04 19:11:35 +02:00
Sergey Khliustin
07750518c3 Added min_profit param to PerformanceFilter 2021-10-04 18:49:57 +03:00
Matthias
26d2b5b81f Merge pull request #5666 from freqtrade/dependabot/pip/develop/pytest-cov-3.0.0
Bump pytest-cov from 2.12.1 to 3.0.0
2021-10-04 07:21:20 +02:00
Matthias
ae46b516e6 Merge pull request #5665 from freqtrade/dependabot/pip/develop/mkdocs-material-7.3.1
Bump mkdocs-material from 7.3.0 to 7.3.1
2021-10-04 07:17:44 +02:00
Matthias
222a15922e Merge pull request #5667 from freqtrade/dependabot/pip/develop/types-cachetools-4.2.2
Bump types-cachetools from 4.2.0 to 4.2.2
2021-10-04 07:02:20 +02:00
dependabot[bot]
f41fd4e88d Bump mkdocs-material from 7.3.0 to 7.3.1
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.3.0 to 7.3.1.
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/7.3.0...7.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 04:40:24 +00:00
Matthias
5e195bdc0f Merge pull request #5661 from freqtrade/dependabot/pip/develop/pymdown-extensions-9.0
Bump pymdown-extensions from 8.2 to 9.0
2021-10-04 06:39:43 +02:00
dependabot[bot]
949f4fbbbf Bump types-cachetools from 4.2.0 to 4.2.2
Bumps [types-cachetools](https://github.com/python/typeshed) from 4.2.0 to 4.2.2.
- [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>
2021-10-04 04:36:11 +00:00
Matthias
8f4b598ee2 Merge pull request #5663 from freqtrade/dependabot/pip/develop/jsonschema-4.0.1
Bump jsonschema from 3.2.0 to 4.0.1
2021-10-04 06:35:34 +02:00
Matthias
9491564148 Merge pull request #5662 from freqtrade/dependabot/pip/develop/types-filelock-3.2.0
Bump types-filelock from 0.1.5 to 3.2.0
2021-10-04 06:34:58 +02:00
Matthias
2a4fb992c3 Merge pull request #5659 from freqtrade/dependabot/pip/develop/filelock-3.3.0
Bump filelock from 3.0.12 to 3.3.0
2021-10-04 06:34:31 +02:00
dependabot[bot]
2b41066ab7 Bump pytest-cov from 2.12.1 to 3.0.0
Bumps [pytest-cov](https://github.com/pytest-dev/pytest-cov) from 2.12.1 to 3.0.0.
- [Release notes](https://github.com/pytest-dev/pytest-cov/releases)
- [Changelog](https://github.com/pytest-dev/pytest-cov/blob/master/CHANGELOG.rst)
- [Commits](https://github.com/pytest-dev/pytest-cov/compare/v2.12.1...v3.0.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 03:01:29 +00:00
dependabot[bot]
0071d002b6 Bump ccxt from 1.57.3 to 1.57.38
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.57.3 to 1.57.38.
- [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/1.57.3...1.57.38)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 03:01:22 +00:00
dependabot[bot]
35c4a0a188 Bump jsonschema from 3.2.0 to 4.0.1
Bumps [jsonschema](https://github.com/Julian/jsonschema) from 3.2.0 to 4.0.1.
- [Release notes](https://github.com/Julian/jsonschema/releases)
- [Changelog](https://github.com/Julian/jsonschema/blob/main/CHANGELOG.rst)
- [Commits](https://github.com/Julian/jsonschema/compare/v3.2.0...v4.0.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 03:01:17 +00:00
dependabot[bot]
ff45d52d49 Bump types-filelock from 0.1.5 to 3.2.0
Bumps [types-filelock](https://github.com/python/typeshed) from 0.1.5 to 3.2.0.
- [Release notes](https://github.com/python/typeshed/releases)
- [Commits](https://github.com/python/typeshed/commits)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 03:01:14 +00:00
dependabot[bot]
d220c55d40 Bump pymdown-extensions from 8.2 to 9.0
Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 8.2 to 9.0.
- [Release notes](https://github.com/facelessuser/pymdown-extensions/releases)
- [Commits](https://github.com/facelessuser/pymdown-extensions/compare/8.2...9.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 03:01:11 +00:00
dependabot[bot]
0d9beaa3f3 Bump filelock from 3.0.12 to 3.3.0
Bumps [filelock](https://github.com/tox-dev/py-filelock) from 3.0.12 to 3.3.0.
- [Release notes](https://github.com/tox-dev/py-filelock/releases)
- [Commits](https://github.com/tox-dev/py-filelock/compare/v3.0.12...3.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 03:01:04 +00:00
Matthias
1c63d01cec Prevent using market-orders on gateio
GateIo does not support market orders on spot markets
2021-10-03 14:14:16 +02:00
Matthias
f5e5203388 Use "round" to 12 digits for TickSize mode
Avoids float rounding problems, fix #5652
2021-10-03 09:49:55 +02:00
Matthias
e73f5ab480 Add test confirming #5652 2021-10-03 09:49:55 +02:00
Matthias
ad6ca3773d Merge pull request #5592 from samgermain/test-freqtradebot-usdt
Test freqtradebot usdt
2021-10-03 09:41:08 +02:00
Matthias
126c291988 Improve docs
closes #5654
2021-10-03 09:32:53 +02:00
Matthias
9e77a739fa Change usdt stake_amount to 60$ 2021-10-03 09:22:50 +02:00
Sam Germain
058c7b3e99 Fixed odd test_execute_entry where the filled coins were higher than the amount 2021-10-02 20:43:32 -06:00
Sam Germain
908dee961d Changed test values in test_sell_profit_only to usdt like values 2021-10-02 20:37:05 -06:00
Sam Germain
93679db7c4 Removed ... TODOs 2021-10-02 20:33:46 -06:00
Sam Germain
057a187231 Removed uneccessary TODOs 2021-10-02 20:32:51 -06:00
Matthias
3b5cc5f015 Improve dates used for hyperopt tests 2021-10-02 15:37:01 +02:00
Matthias
77388eb423 Improve generate_test_data to make it easier to use 2021-10-02 15:23:48 +02:00
Matthias
66e19f5775 Merge pull request #5651 from freqtrade/simplify_loss_Tests
Combine most hyperopt-loss tests to one
2021-10-02 14:44:46 +02:00
Matthias
5fdeca812d Combine most hyperopt-loss tests to one 2021-10-02 14:30:24 +02:00
Matthias
022839b728 remove unnecessary test 2021-10-02 13:17:10 +02:00
Matthias
e5e1e49f53 Remove some unused test parameters 2021-10-02 13:01:33 +02:00
Sam Germain
96d09b5615 Fixed breaking rpc tests 2021-10-02 01:44:30 -06:00
Sam Germain
6f8e66117b flake8 isort 2021-10-02 01:44:30 -06:00
Sam Germain
107fa911a5 Fixed test_tsl_on_exchange_compatible_with_edge 2021-10-02 01:44:30 -06:00
Rokas Kupstys
c820db4c60 Fix couple more usdt tests which failed due to ticker prices causing roi being hit, but tests did not expect that to happen. 2021-10-02 01:44:30 -06:00
Rokas Kupstys
8961370269 Fix failing test due to not updated expected values. 2021-10-02 01:44:30 -06:00
Rokas Kupstys
2ee87f8c66 Fix failing USDT tests due to not enough open markets. 2021-10-02 01:44:30 -06:00
Sam Germain
43339f1660 A lot of the usdt freqtradebot tests pass now 2021-10-02 01:44:30 -06:00
Sam Germain
ba5d78f005 swapped default_conf for default_conf_usdt and ticker for ticker_usdt 2021-10-02 01:44:30 -06:00
Sam Germain
7eebb6bb2d updated test_create_trade to use default_conf_usdt 2021-10-02 01:44:30 -06:00
Sam Germain
755cc9cda1 Updated test_check_available_stake_amount to use default_conf_usdt 2021-10-02 01:44:30 -06:00
Sam Germain
26fdad8468 Removed edge_conf_usdt 2021-10-02 01:44:30 -06:00
Sam Germain
d0e0d0ee01 Removed init_persistence_usdt 2021-10-02 01:44:30 -06:00
Sam Germain
5ce09c7519 updated test_reupdate_enter_order_fees to usdt 2021-10-02 01:44:30 -06:00
Sam Germain
ffa9a3ac7d changed default_conf_usdt stake_amount to 10 2021-10-02 01:44:30 -06:00
Sam Germain
6fdcf8cd73 created default_conf_usdt and init_persistence_usdt so that these tests pass: test_handle_stoploss_on_exchange_trailing, test_handle_stoploss_on_exchange_custom_stop, test_update_trade_state_withorderdict 2021-10-02 01:44:30 -06:00
Sam Germain
d1e3d48075 changed test_update_trade_state_withorderdict to usdt 2021-10-02 01:44:30 -06:00
Sam Germain
8d7f75c4de Fixed a bunch of freqtradebot tests 2021-10-02 01:44:30 -06:00
Sam Germain
dadd134200 changes some tests to use usdt values 2021-10-02 01:44:30 -06:00
Matthias
f69cb39a17 Fix missing comma in kucoin template
closes #5646
2021-10-01 19:26:51 +02:00
Matthias
bd7d9c0d33 Merge pull request #5648 from froggleston/patch-1
Fix pair_candles to point to correct API call
2021-10-01 19:25:22 +02:00
Robert Davey
15df5fd9c5 Fix pair_candles to point to correct API call
pair_candles pointed to available_pairs RPC call instead of pair_candles
2021-10-01 13:49:16 +01:00
Matthias
99e3450d30 Merge pull request #5642 from freqtrade/add_trade_conversion_command
Add trade conversion command
2021-10-01 06:38:42 +02:00
Scott Lyons
df45f467c6 Adding ability to ignore unparameterized spaces 2021-09-30 01:11:02 -07:00
Scott Lyons
95227376b6 Adding IUS to optimize args 2021-09-30 00:53:46 -07:00
Scott Lyons
08fcd1a0d4 Adding ignore space errors to Hyperopt CLI 2021-09-30 00:46:56 -07:00
Scott Lyons
5dd1088d8d Adding ignore unparameterized spaces flag 2021-09-30 00:44:26 -07:00
Matthias
5f23af5802 Rename update_open_trades to clarify it's only called at startup 2021-09-30 07:24:16 +02:00
Matthias
bd27993e79 Add documentation segment about indicator libraries 2021-09-30 06:42:42 +02:00
Matthias
178db516bf Add documentation for trade-to-ohlcv 2021-09-29 20:00:14 +02:00
Matthias
248c61bb26 Add test for trades-to-ohlcv 2021-09-29 19:39:29 +02:00
Matthias
fc511aac44 don't use %default when no default is defined 2021-09-29 19:21:54 +02:00
Matthias
656526c007 Add trades-to-ohlcv command to simplify adding new timeframes 2021-09-29 16:50:05 +02:00
Matthias
51c6eb2014 Merge pull request #5640 from rokups/rk/tests-static-market
markets_static fixture
2021-09-29 16:20:18 +02:00
Rokas Kupstys
e025576d8c Introduce markets_static fixture serving an immutable list of markets. Adapt pairlist/markets tests to use this new fixture.
This allows freely modifying markets in get_markets() without a need of updating pairlist/markets tests.
2021-09-29 10:15:05 +03:00
Matthias
a0ee490957 Merge pull request #5636 from freqtrade/new_release
New release 2021.9
2021-09-28 19:21:42 +02:00
Robert Roman
ca973c05d1 Merge branch 'freqtrade:develop' into develop 2021-09-28 10:16:36 -05:00
Matthias
5938514e5d Version bump to 2021.9 2021-09-28 07:03:26 +02:00
Matthias
d73f5f75fc Merge branch 'stable' into new_release 2021-09-28 07:02:24 +02:00
Robert Roman
626a40252d resolved mypy error
error: Signature of "hyperopt_loss_function" incompatible with supertype "IHyperOptLoss"
2021-09-27 17:33:29 -05:00
Robert Roman
c3414c3b78 resolved mypy error
error: Signature of "hyperopt_loss_function" incompatible with supertype "IHyperOptLoss"
2021-09-27 17:32:49 -05:00
Matthias
5726886b06 Reduce backtest-noise from "pandas slice" warning 2021-09-27 20:52:19 +02:00
Robert Roman
67e9626da1 fixed isort issue 2021-09-27 12:16:57 -05:00
Robert Roman
a1566fe5d7 updated to latest constant.py file 2021-09-27 11:47:03 -05:00
Robert Roman
bc86cb3280 updated to correct hyperopt.md file 2021-09-27 11:41:38 -05:00
Robert Roman
193b22475d Merge branch 'freqtrade:develop' into develop 2021-09-27 11:35:34 -05:00
Matthias
3fbf716f85 Fix "sticking" timerange in webserver mode 2021-09-27 17:52:00 +02:00
Matthias
6a033bd01e Merge pull request #5633 from freqtrade/dependabot/pip/develop/nbconvert-6.2.0
Bump nbconvert from 6.1.0 to 6.2.0
2021-09-27 12:20:02 +02:00
Matthias
5b7a1f8642 Validate config also in webserver mode 2021-09-27 07:12:40 +02:00
Matthias
37a1cd5d38 Merge pull request #5631 from freqtrade/dependabot/pip/develop/ccxt-1.57.3
Bump ccxt from 1.56.86 to 1.57.3
2021-09-27 07:02:18 +02:00
dependabot[bot]
78096c9eff Bump nbconvert from 6.1.0 to 6.2.0
Bumps [nbconvert](https://github.com/jupyter/nbconvert) from 6.1.0 to 6.2.0.
- [Release notes](https://github.com/jupyter/nbconvert/releases)
- [Commits](https://github.com/jupyter/nbconvert/compare/6.1.0...6.2.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-27 04:32:26 +00:00
Matthias
29c6f182f6 Merge pull request #5630 from freqtrade/dependabot/pip/develop/types-requests-2.25.9
Bump types-requests from 2.25.8 to 2.25.9
2021-09-27 06:31:29 +02:00
dependabot[bot]
9059502303 Bump ccxt from 1.56.86 to 1.57.3
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.56.86 to 1.57.3.
- [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/1.56.86...1.57.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-27 03:01:27 +00:00
dependabot[bot]
08b1f04ed5 Bump types-requests from 2.25.8 to 2.25.9
Bumps [types-requests](https://github.com/python/typeshed) from 2.25.8 to 2.25.9.
- [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>
2021-09-27 03:01:18 +00:00
Robert Roman
bdca3e2343 Merge branch 'freqtrade:develop' into develop 2021-09-26 15:37:09 -05:00
Matthias
ec445776e9 Merge pull request #5601 from ferrants/parameterize-tests
parameterize some tests
2021-09-26 19:07:47 +02:00
Matthias
6319c104fe Fix unreliable backtest-result when using webserver mode 2021-09-26 15:07:48 +02:00
Robert Roman
a77ca22026 Merge branch 'freqtrade:develop' into develop 2021-09-26 02:57:02 -05:00
Robert Roman
e1036d6f58 Added Calmar Ratio Daily to hyperopt.md file 2021-09-25 16:40:02 -05:00
Robert Roman
89b7dfda0e Added Calmar Ratio Daily 2021-09-25 16:34:41 -05:00
Robert Roman
24baad7884 Add Calmar Ratio Daily
This hyper opt loss calculates the daily Calmar ratio.
2021-09-25 16:28:36 -05:00
froggleston
097da448e2 Add CPU,RAM sysinfo support to the REST API to help with bot system monitoring 2021-09-25 15:48:42 +01:00
Matthias
f4f204d849 Update test to use cost dict 2021-09-24 20:17:38 +02:00
Matthias
4c268847d4 Add pandas-ta to setup.py 2021-09-24 19:32:30 +02:00
Matthias
4d72632524 Merge pull request #5618 from freqtrade/dependabot/pip/develop/progressbar2-3.53.3
Bump progressbar2 from 3.53.2 to 3.53.3
2021-09-24 19:26:59 +02:00
Matthias
b59906b117 Update minimum for tradable_balance_ratio to 0.0 2021-09-24 19:24:33 +02:00
Matthias
2431c9f195 Merge pull request #5615 from freqtrade/dependabot/pip/develop/ccxt-1.56.86
Bump ccxt from 1.56.30 to 1.56.86
2021-09-24 13:19:00 +02:00
Matthias
9657028633 Merge pull request #5614 from freqtrade/dependabot/pip/develop/mkdocs-material-7.3.0
Bump mkdocs-material from 7.2.6 to 7.3.0
2021-09-24 10:19:03 +02:00
Matthias
c61b2a83c1 Merge pull request #5617 from freqtrade/dependabot/pip/develop/urllib3-1.26.7
Bump urllib3 from 1.26.6 to 1.26.7
2021-09-24 09:45:30 +02:00
dependabot[bot]
72a1e27fc6 Bump ccxt from 1.56.30 to 1.56.86
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.56.30 to 1.56.86.
- [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/1.56.30...1.56.86)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-24 07:31:20 +00:00
Matthias
a217d84e0f Merge pull request #5616 from freqtrade/dependabot/pip/develop/sqlalchemy-1.4.25
Bump sqlalchemy from 1.4.23 to 1.4.25
2021-09-24 09:30:33 +02:00
Matthias
5da218e383 Merge pull request #5613 from freqtrade/dependabot/pip/develop/types-requests-2.25.8
Bump types-requests from 2.25.6 to 2.25.8
2021-09-24 08:42:26 +02:00
Matthias
954c468191 Add pandas-ta to requirements 2021-09-24 07:12:38 +02:00
dependabot[bot]
0353f070f9 Bump progressbar2 from 3.53.2 to 3.53.3
Bumps [progressbar2](https://github.com/WoLpH/python-progressbar) from 3.53.2 to 3.53.3.
- [Release notes](https://github.com/WoLpH/python-progressbar/releases)
- [Changelog](https://github.com/WoLpH/python-progressbar/blob/develop/CHANGES.rst)
- [Commits](https://github.com/WoLpH/python-progressbar/compare/v3.53.2...v3.53.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-24 05:06:24 +00:00
dependabot[bot]
90d5af9a35 Bump urllib3 from 1.26.6 to 1.26.7
Bumps [urllib3](https://github.com/urllib3/urllib3) from 1.26.6 to 1.26.7.
- [Release notes](https://github.com/urllib3/urllib3/releases)
- [Changelog](https://github.com/urllib3/urllib3/blob/1.26.7/CHANGES.rst)
- [Commits](https://github.com/urllib3/urllib3/compare/1.26.6...1.26.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-24 05:06:20 +00:00
dependabot[bot]
766ef90b56 Bump sqlalchemy from 1.4.23 to 1.4.25
Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.4.23 to 1.4.25.
- [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases)
- [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/master/CHANGES)
- [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>
2021-09-24 05:06:16 +00:00
dependabot[bot]
e85dc63263 Bump mkdocs-material from 7.2.6 to 7.3.0
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.2.6 to 7.3.0.
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/7.2.6...7.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-24 05:06:01 +00:00
dependabot[bot]
422d560189 Bump types-requests from 2.25.6 to 2.25.8
Bumps [types-requests](https://github.com/python/typeshed) from 2.25.6 to 2.25.8.
- [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>
2021-09-24 05:05:55 +00:00
Robert Roman
ca20e17d40 added CalmarHyperOpt to hyperopt.md
i added CalmarHyperOpt to hyperopt.md and gave a brief description inside the docs
2021-09-23 21:48:08 -05:00
Robert Roman
b2ac039d5c added CalmarHyperOptLoss to HYPEROPT_LOSS_BUILTIN
I added CalmarHyperOptLoss to HYPEROPT_LOSS_BUILTIN variable inside constants.py file
2021-09-23 21:46:07 -05:00
Robert Roman
0f29cbc882 added CalmarHyperOptLoss
I added CalmarHyperOptLoss to HYPEROPT_LOSS_BUILTIN variable inside constants.py file
2021-09-23 21:37:28 -05:00
Robert Roman
3b99c84b0a resolved the total profit issue
I resolved the total profit issue and locally ran flak8 and isort
2021-09-23 21:31:33 -05:00
Matthias
9a6d8977de Merge pull request #5605 from peterwilli/fix-sell-cancel-webhook-error
fixed webhook "unsupported format string passed to NoneType." error
2021-09-23 20:17:35 +02:00
Matthias
ff9c8fe234 Merge pull request #5496 from LoveIsGrief/docs/performance-warning
Docs: Mention Performance Warning for strategies
2021-09-23 20:16:58 +02:00
Peter Willemsen
692e91a26d changed close date from datetime.utcnow() to datetime.now(timezone.utc) 2021-09-23 10:28:15 +02:00
Matthias
d7903f012f Move PerformanceWarning to advanced section
rewrite to use strategy parameters instead of plain range
2021-09-23 07:25:11 +02:00
Matthias
fcca637107 Merge pull request #5599 from freqtrade/notify_trigger_prot
Notify trigger protections
2021-09-23 07:17:26 +02:00
matt ferrante
2bf49445b7 add parameterized names 2021-09-22 16:11:27 -06:00
matt ferrante
30cc69c880 set all to eth for multi test 2021-09-22 11:28:42 -06:00
matt ferrante
8cfb6ddd51 fix long line 2021-09-22 10:48:13 -06:00
matt ferrante
f768bdea50 cleanup based on feedback 2021-09-22 10:32:30 -06:00
Robert Roman
c6b684603c removed trade_count inside if statement
i removed trade_count inside if statement. Even though it helps overfitting, It is not useful when running hyperopt on small datasets.
2021-09-22 09:21:43 -05:00
Robert Roman
b946f8e7f1 I sorted imports with isort 2021-09-22 09:18:17 -05:00
Robert Roman
3834bb86ff updated line 42
I removed the minus sign on max drawdown.
2021-09-21 20:25:17 -05:00
Robert Roman
3845d55186 a new hyperopt loss created that uses calmar ratio
This is a new hyperopt loss file that uses the Calmar Ratio.

Calmar Ratio = average annual rate of return / maximum drawdown
2021-09-21 20:04:23 -05:00
Sam Germain
553c868d7f combined test_order_book_depth_of_market and test_order_book_depth_of_market_high_delta 2021-09-21 16:40:24 -06:00
Peter Willemsen
b0de4d333e fixed webhook error 2021-09-21 23:20:40 +02:00
matt ferrante
707d0ef795 remove trades_for_order3 2021-09-21 12:16:10 -06:00
matt ferrante
277828bf0e parameterize some tests 2021-09-21 07:56:16 -06:00
Matthias
6fc770d97d Add warning about running with docker on windows 2021-09-21 15:12:35 +02:00
Matthias
4237acf5b6 Merge pull request #5598 from SeriousM/patch-1
Add docker troubleshooting information for win10/wsl
2021-09-21 14:54:31 +02:00
Bernhard Millauer
abddb0db66 Fix header indention
Co-authored-by: Matthias <xmatthias@outlook.com>
2021-09-21 10:13:19 +02:00
Matthias
3ce05c0d54 Add "sane" defaults to protection triggers 2021-09-20 20:16:58 +02:00
Matthias
fd23ab3d64 improve formatting, add tests 2021-09-20 19:50:56 +02:00
Matthias
dd0db7ee5d Split protection-notification into global and per-pair 2021-09-20 19:23:40 +02:00
Matthias
a0fb43c6ca Add pairlock-notification 2021-09-20 19:12:59 +02:00
Bernhard Millauer
c91a9a92f2 Add troubleshooting information
The time in wsl docker container shifts over time. Added information how to fix this issue.
2021-09-20 14:22:24 +02:00
Matthias
1da091dea3 ProtectionManager should return the lock just created 2021-09-19 19:41:19 +02:00
Matthias
879bf47b32 Refactor telegram.py to simplify send_msg 2021-09-19 19:25:36 +02:00
Matthias
c46ef637c3 Merge pull request #5593 from samgermain/parametrized-test-freqtradebot
Parametrized test freqtradebot
2021-09-19 13:40:13 +02:00
Matthias
ec03531771 Improve naming of variables 2021-09-19 13:29:09 +02:00
Matthias
ab88217186 Improve /balance output to include starting balance and percentual change
closes #5503
2021-09-19 13:17:34 +02:00
Sam Germain
cee4ed541b parametrized test_update_trade_state_withorderdict 2021-09-18 19:46:46 -06:00
Sam Germain
ec9dbc550e parametrized test_create_trade_minimal_amount 2021-09-18 19:19:53 -06:00
Matthias
c1895a0fc2 Remove warning related to legacy hyperopt 2021-09-18 15:30:33 +02:00
Matthias
73f044d1e2 Merge pull request #5281 from rokups/rk/helpers
A decorator for easy creation of informative pairs
2021-09-18 15:30:20 +02:00
Rokas Kupstys
eab7f8f694 [SQUASH] Doh. 2021-09-18 15:44:21 +03:00
Rokas Kupstys
713e7819f7 [SQUASH] Remove mypy import. 2021-09-18 15:27:58 +03:00
Sam Germain
518a59ad41 parametrized test_edge_overrides_stoploss 2021-09-18 03:20:00 -06:00
Sam Germain
42a2fdc1c5 parametrized test_order_dict 2021-09-18 03:01:08 -06:00
Sam Germain
216f75bbb9 parametrized test_sell_profit_only , test__safe_exit_amount, test_order_book_bid_strategy1 2021-09-18 02:53:34 -06:00
Rokas Kupstys
e4ca42faec [SQUASH] Update stoploss_from_absolute to behave more like stoploss_from_open and add a test for it. 2021-09-18 10:48:53 +03:00
Rokas Kupstys
7e6aa9390a [SQUASH] Unconditionally include quote currency when asset is explicitly specified. Added docs suggesting to use string formatting to make strategy independent of configured stake currency. 2021-09-18 10:48:53 +03:00
Rokas Kupstys
e88c4701bb [SQUASH] Address PR comments. 2021-09-18 10:48:53 +03:00
Matthias
bb6ae682fc Small simplifications 2021-09-18 10:48:53 +03:00
Rokas Kupstys
5dc78a0c66 [SQUASH] Get rid of _initialize() and fix informatives for dynamic pairlists. 2021-09-18 10:48:53 +03:00
Rokas Kupstys
f81df19b93 [TMP] Make tests not fail for now. 2021-09-18 10:48:53 +03:00
Rokas Kupstys
dfa61b7ad2 [SQUASH] Fix informatives for each pair not being created because dataprovider was not available.
Fix not being able to have informative dataframe of a pair in whitelist.
2021-09-18 10:48:53 +03:00
Rokas Kupstys
f2a1d9d2fc [SQUASH] Address PR comments. 2021-09-18 10:48:18 +03:00
Rokas Kupstys
1fdb656334 Add a decorator which can be used to declare populate_indicators() functions for informative pairs. 2021-09-18 10:48:18 +03:00
Rokas Kupstys
d84ef34740 A helper to calculate stoploss value from absolute price. 2021-09-18 10:48:18 +03:00
Matthias
11f08b0053 Merge pull request #5582 from sergeykhliustin/develop
Added days parameter to PerformanceFilter
2021-09-18 09:24:14 +02:00
Matthias
56fb25c5e5 Add test for PerformanceFilter lookback 2021-09-18 09:10:37 +02:00
Matthias
564e0b9a1a Switch performanceFilter to use Minutes lookback resolution
closes #5060
2021-09-18 09:10:25 +02:00
Matthias
12c12d42df Add documentation for days parameter in PerformanceFilter 2021-09-18 08:30:44 +02:00
Matthias
853c3a4433 Merge pull request #5587 from raph92/patch-3
Update prepare_trials_columns() return type
2021-09-18 08:08:18 +02:00
Sergey Khliustin
d7395e873b Removed unused OperationalException 2021-09-17 22:05:57 +03:00
raphael
4b2c1a9b8e Remove trailing whitespace 2021-09-17 14:39:15 -04:00
raphael
e715f2a253 Update formatting
Line 302 was too long
2021-09-17 14:23:26 -04:00
raphael
9525a5b96c Add type to "trials" parameter 2021-09-17 14:10:37 -04:00
Matthias
9c50d0c250 Merge pull request #5589 from Ottavio97/develop
Include Raspberry Pi armv6 (0, 0W,...)
2021-09-17 19:54:35 +02:00
Matthias
6d1604d6fa Merge pull request #5588 from raph92/patch-4
Update HyperoptTools.export_csv_file usage
2021-09-17 19:14:47 +02:00
Ottavio Miele
fb6beb90e8 Include Raspberry Pi armv6 (0, 0W,...) 2021-09-17 18:03:54 +02:00
raphael
124e97f3b9 Remove ununsed variables from export_csv_file 2021-09-17 11:57:36 -04:00
raphael
5fc993231a Update HyperoptTools.export_csv_file usage 2021-09-17 11:51:55 -04:00
raphael
3a98fb72a4 Update prepare_trials_columns() return type
Was returning str, updated to pd.DataFrame
2021-09-17 11:42:33 -04:00
sergeykhliustin
982deeedf0 Update freqtrade/persistence/models.py
Co-authored-by: Matthias <xmatthias@outlook.com>
2021-09-17 18:23:13 +03:00
Sergey Khliustin
54ef36a497 Updates after review to PerformanceFilter days param 2021-09-17 13:45:44 +03:00
Matthias
4ce1375bf3 Merge pull request #5580 from freqtrade/hyperopt_diff_base_estimators
Hyperopt set diff base estimators
2021-09-17 10:32:47 +02:00
Sergey Khliustin
457e738b4a Added days parameter to PerformanceFilter 2021-09-16 14:48:02 +03:00
Matthias
994c3c3a4c Add some errorhandling for custom estimator 2021-09-16 07:13:25 +02:00
Matthias
c0811ae896 Add possibility to override estimator from within hyperopt 2021-09-15 21:36:53 +02:00
Matthias
90ad178932 Remove verbosity of edge 2021-09-15 21:04:25 +02:00
Matthias
57ea0c322f Rename indicator_space to buy_indicator_space 2021-09-15 20:20:31 +02:00
Matthias
f7bae81d96 Dataframe should be copied after populate_indicator
Without that, PerformanceWarnings can appear throughout hyperopt which
are unnecessary and missleading for users

closes #5408
2021-09-15 19:56:12 +02:00
Matthias
e4ec5679a1 Merge pull request #5574 from freqtrade/agefilter_cache
Agefilter cache
2021-09-15 06:33:36 +02:00
Matthias
4e2b1764b8 ccxt_compat_tests must run with dry-run=False 2021-09-14 20:24:44 +02:00
Matthias
315ea1e116 Merge pull request #5566 from freqtrade/remove_hyperopt
Remove legacy hyperopt
2021-09-14 19:20:58 +02:00
Matthias
35eda8c8c7 Improve agefilter test 2021-09-14 07:07:20 +02:00
Matthias
3ce5197e8d Add Tests for AgeFilter caching
closes #5552
2021-09-14 06:45:26 +02:00
Matthias
c9ba52d732 Expire cached pairs in age-filter once per day 2021-09-14 06:30:18 +02:00
Matthias
e8e8ef4872 Merge pull request #5572 from freqtrade/dependabot/pip/develop/ccxt-1.56.30
Bump ccxt from 1.55.83 to 1.56.30
2021-09-13 20:43:10 +02:00
Matthias
a12c3ecc9b Remove credentials whenever dry-run is set from within the exchange 2021-09-13 20:27:32 +02:00
Matthias
8afb3c4b70 Move AgeFilter cache to instance level 2021-09-13 19:33:28 +02:00
Matthias
3cdd06f562 Add PeriodicCache 2021-09-13 19:32:51 +02:00
dependabot[bot]
b13bd87625 Bump ccxt from 1.55.83 to 1.56.30
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.55.83 to 1.56.30.
- [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/1.55.83...1.56.30)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-13 04:31:52 +00:00
Matthias
51643ed56c Merge pull request #5571 from freqtrade/dependabot/pip/develop/progressbar2-3.53.2
Bump progressbar2 from 3.53.1 to 3.53.2
2021-09-13 06:31:00 +02:00
Matthias
22e0728ac2 Merge pull request #5569 from freqtrade/dependabot/pip/develop/pandas-1.3.3
Bump pandas from 1.3.2 to 1.3.3
2021-09-13 06:30:37 +02:00
dependabot[bot]
81039fce28 Bump progressbar2 from 3.53.1 to 3.53.2
Bumps [progressbar2](https://github.com/WoLpH/python-progressbar) from 3.53.1 to 3.53.2.
- [Release notes](https://github.com/WoLpH/python-progressbar/releases)
- [Changelog](https://github.com/WoLpH/python-progressbar/blob/develop/CHANGES.rst)
- [Commits](https://github.com/WoLpH/python-progressbar/compare/v3.53.1...v3.53.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-13 03:01:24 +00:00
dependabot[bot]
d8f48cf0e3 Bump pandas from 1.3.2 to 1.3.3
Bumps [pandas](https://github.com/pandas-dev/pandas) from 1.3.2 to 1.3.3.
- [Release notes](https://github.com/pandas-dev/pandas/releases)
- [Changelog](https://github.com/pandas-dev/pandas/blob/master/RELEASE.md)
- [Commits](https://github.com/pandas-dev/pandas/compare/v1.3.2...v1.3.3)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-13 03:01:14 +00:00
Matthias
236dc48000 Update CI to use new hyperopt interface 2021-09-12 08:18:17 +02:00
Matthias
0017b3438e Remove list-hyperopts 2021-09-12 08:18:17 +02:00
Matthias
3675df8344 Update documentation regarding Legacy Hyperopt 2021-09-12 08:18:17 +02:00
Matthias
fd6bf591f8 Update some tests to remove explicit hyperopt interface 2021-09-12 08:18:13 +02:00
Matthias
dad4a49e81 Remove legacy hyperopt interface from hyperopt.py 2021-09-12 08:18:13 +02:00
Matthias
ebb0b8aa3f Remove new-hyperopt command 2021-09-12 08:18:13 +02:00
Matthias
432c3df17e Add documentation for Bittex/Gemini with VolumePairlist
closes #5565
2021-09-12 08:04:22 +02:00
Matthias
50479d0b44 Merge pull request #5560 from freqtrade/fix/5548_1mdl
Don't blindly create coroutines, but fire them off in batches
2021-09-11 08:33:43 +02:00
Matthias
a5f90a409c Small updates to async_history_fetch 2021-09-11 08:18:32 +02:00
Matthias
4c4604f837 Add explicit test for get_historic_ohlcv 2021-09-10 19:47:56 +02:00
Matthias
8c9159f596 Improve comments 2021-09-10 19:46:38 +02:00
Matthias
a19c33ba54 Don't blindly create coroutines, but fire them off in batches 2021-09-10 19:37:07 +02:00
Matthias
7251a3ab19 Merge pull request #5544 from freqtrade/new_pair_download
New pair download improvement
2021-09-10 19:36:45 +02:00
Matthias
982534ddc7 Add gate.io to list of supported exchanges 2021-09-10 19:32:20 +02:00
Matthias
5844f5a7fa Merge pull request #5546 from samgermain/clear-caplog-freqtradebot
freqtradebot-tests-caplog-clears
2021-09-09 21:18:54 +02:00
Sam Germain
366247dff3 removed caplog.clears at end of functions in test_freqtradebot 2021-09-09 02:17:41 -06:00
Matthias
fb376153a2 Merge pull request #5549 from samgermain/name-changes
Name changes
2021-09-09 07:40:39 +02:00
Sam Germain
b2f289e404 Fixed freqtradebot failing tests 2021-09-08 02:16:25 -06:00
Sam Germain
a1c9a4d619 freqtradebot local name changes 2021-09-08 02:09:36 -06:00
Sam Germain
362dc20406 notify_buy -> notify_enter, notify_sell -> notify_exit 2021-09-08 02:06:01 -06:00
Sam Germain
e1f846f22f sell_lock -> exit_lock 2021-09-08 02:04:31 -06:00
Sam Germain
e0092a85e9 handle_cancel_buy/sell -> handle_cancel_enter/exit 2021-09-08 02:04:20 -06:00
Sam Germain
be93c75e44 reupdate_buy_order_fees -> reupdate_enter_order_fees 2021-09-08 02:03:40 -06:00
Sam Germain
aac05029e1 safe_sell_amount -> safe_exit_amount 2021-09-08 02:03:24 -06:00
Sam Germain
93fcaac19f Merge branch 'develop' into clear-caplog-freqtradebot 2021-09-07 21:55:00 -06:00
Sam Germain
79ca6135a2 added caplog clears to freqtradebot tests 2021-09-07 21:53:38 -06:00
Matthias
2d66987ac7 Add test for "pair-startdate" detection 2021-09-07 20:27:49 +02:00
Matthias
8c83c258a5 Move "first-pair_getting" to binance subclass 2021-09-07 19:32:32 +02:00
Matthias
71ff214adf Support "initial_call" for download-data of new pairs 2021-09-07 07:14:40 +02:00
Matthias
880474594e have ftuser use /bin/bash in dockerfile 2021-09-07 06:51:31 +02:00
Matthias
10d0987f49 Fix docs for custom hyperopt space 2021-09-06 19:55:04 +02:00
Matthias
6bd495a32a Fix 0Exception error
happens when wrong stake-currency is selected and /profit
is called
2021-09-06 19:55:04 +02:00
Matthias
fb78caf801 Merge pull request #5538 from EnzovdWetering/patch-1
Update edge.md
2021-09-06 19:22:38 +02:00
EnzovdWetering
a04875eb55 Update edge.md
Typo fix
2021-09-06 17:53:44 +02:00
Matthias
3f0032498e Merge pull request #5537 from freqtrade/dependabot/pip/develop/mkdocs-material-7.2.6
Bump mkdocs-material from 7.2.5 to 7.2.6
2021-09-06 06:44:16 +02:00
Matthias
76a59bf2b6 Merge pull request #5536 from freqtrade/dependabot/pip/develop/ccxt-1.55.83
Bump ccxt from 1.55.56 to 1.55.83
2021-09-06 06:43:47 +02:00
Matthias
8347219990 Merge pull request #5534 from freqtrade/dependabot/pip/develop/pytest-6.2.5
Bump pytest from 6.2.4 to 6.2.5
2021-09-06 06:43:25 +02:00
Matthias
64ec1b6f8c Merge pull request #5535 from freqtrade/dependabot/pip/develop/plotly-5.3.1
Bump plotly from 5.3.0 to 5.3.1
2021-09-06 06:43:08 +02:00
dependabot[bot]
765e72715b Bump mkdocs-material from 7.2.5 to 7.2.6
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.2.5 to 7.2.6.
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/7.2.5...7.2.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-06 03:01:28 +00:00
dependabot[bot]
44f8d7abf2 Bump ccxt from 1.55.56 to 1.55.83
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.55.56 to 1.55.83.
- [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/1.55.56...1.55.83)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-06 03:01:23 +00:00
dependabot[bot]
771193cbe4 Bump plotly from 5.3.0 to 5.3.1
Bumps [plotly](https://github.com/plotly/plotly.py) from 5.3.0 to 5.3.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.3.0...v5.3.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-06 03:01:19 +00:00
dependabot[bot]
4daa4b9e63 Bump pytest from 6.2.4 to 6.2.5
Bumps [pytest](https://github.com/pytest-dev/pytest) from 6.2.4 to 6.2.5.
- [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/6.2.4...6.2.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-06 03:01:10 +00:00
Matthias
01b5fe9f97 Merge pull request #5532 from lazydroid/patch-2
case insensitive blacklist
2021-09-05 19:53:39 +02:00
lenik terenin
1d24d3d5ee case insensitive blacklist
Allow "btc/usdt" pairs in blacklist to match to "BTC/USDT" pairs that come from the exchange.
2021-09-05 22:41:58 +09:00
Matthias
c519ecf8df Exclude more untestable sections from coverage 2021-09-05 15:40:21 +02:00
Matthias
a8f28ffb11 Increase test coverage 2021-09-05 15:34:57 +02:00
Matthias
ea5c7e7ed6 Merge pull request #5531 from freqtrade/exclude_coverage
Exclude some parts from coverage that can't really be tested
2021-09-05 10:01:07 +02:00
Matthias
2173ff0133 Update PR template to not link to issues in changelog 2021-09-05 09:16:19 +02:00
Matthias
4e049f65f2 Exclude some parts from coverage that can't really be tested 2021-09-05 09:14:44 +02:00
Matthias
63f2494936 Merge pull request #5530 from freqtrade/fix_uvicorn
Fix uvicorn not working properly on windows
2021-09-04 08:22:11 +02:00
Matthias
35267de88a Merge pull request #5529 from Rikj000/setup/use-build-helpers-install-ta-lib-script
 `setup.sh` - Use `build_helpers/install_ta-lib.sh` for TA-Lib insta…
2021-09-04 08:15:19 +02:00
Rik Helsen
eb0362c29e ️ ️install_ta-lib.sh - Run ldconfig after make install 2021-09-03 23:52:40 +02:00
Matthias
493fb35073 Fix uvicorn not working properly on windows 2021-09-03 22:05:40 +02:00
Matthias
91779ee0cc Merge pull request #5524 from freqtrade/kucoin_tif
Improve generated configuration templates, support kucoin TIF
2021-09-03 19:46:58 +02:00
Rikj000
103a8e827e setup.sh - Use build_helpers/install_ta-lib.sh for TA-Lib installation 2021-09-03 16:37:36 +02:00
Matthias
2f92838c39 Properly close parenteses in exchange doc 2021-09-03 16:19:27 +02:00
Matthias
b4130dfabb Use volumePairlist instead of staticPairlist in generated config 2021-09-03 09:23:26 +02:00
Matthias
c489e6825c Simplify binance blacklist 2021-09-03 09:18:15 +02:00
Matthias
68f13173bc Update new-config templates to use USDT by default 2021-09-03 08:59:43 +02:00
Matthias
e64ccd8fc1 Add new_config section for kucoin 2021-09-03 08:57:53 +02:00
Matthias
19ad165483 Add time_in_force for kucoin 2021-09-03 08:48:53 +02:00
Matthias
93c1dff71b Allow adding new additional headers 2021-09-02 21:02:45 +02:00
Matthias
f59ba92920 Merge pull request #5413 from freqtrade/feat/backtest_detail
Add backtest-detail to allow intra-candle backtests
2021-09-01 19:48:12 +02:00
Matthias
ab5e63cbdd Merge pull request #5520 from freqtrade/dependabot/docker/python-3.9.7-slim-buster
Bump python from 3.9.6-slim-buster to 3.9.7-slim-buster
2021-09-01 13:40:54 +02:00
Matthias
b65a15d8b4 Merge pull request #5501 from pan-long/hdf5-path
Export HDF5 and CBLOSC paths.
2021-09-01 07:06:28 +02:00
dependabot[bot]
87fa49d529 Bump python from 3.9.6-slim-buster to 3.9.7-slim-buster
Bumps python from 3.9.6-slim-buster to 3.9.7-slim-buster.

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-01 03:01:49 +00:00
Matthias
b0c4f079c2 Merge branch 'develop' into feat/backtest_detail 2021-08-31 20:16:42 +02:00
Matthias
1cbe303434 Add documentation for --detail-timeframe 2021-08-31 19:58:08 +02:00
Matthias
525aa234dc Merge pull request #5516 from yehya-dev/patch-1
Update bot-basics.md
2021-08-31 16:58:01 +02:00
Matthias
da5f8c87ae Add stake_currency to strategy interface
allows type-completion in editors
2021-08-31 07:18:57 +02:00
Yehya
4cc1f2b4a4 Update bot-basics.md
Term usage mistake (The first in the pair is the base and second is the quote)
2021-08-31 10:48:09 +05:30
Matthias
ab9a4375cc Merge pull request #5504 from pan-long/unlimited-quote
Surround "unlimited" by double quotes in build config.
2021-08-30 20:33:21 +02:00
Matthias
2a0c95a2e7 Update freqtrade/commands/build_config_commands.py 2021-08-30 20:00:52 +02:00
Matthias
b25a161e22 Merge pull request #5507 from freqtrade/dependabot/pip/develop/plotly-5.3.0
Bump plotly from 5.2.1 to 5.3.0
2021-08-30 06:42:01 +02:00
Matthias
7f13eec5d3 Merge pull request #5510 from freqtrade/dependabot/pip/develop/mkdocs-material-7.2.5
Bump mkdocs-material from 7.2.4 to 7.2.5
2021-08-30 06:34:03 +02:00
Matthias
bf1e78fcc8 Merge pull request #5509 from freqtrade/dependabot/pip/develop/fastapi-0.68.1
Bump fastapi from 0.68.0 to 0.68.1
2021-08-30 06:33:39 +02:00
Matthias
89d7e36d64 Merge pull request #5506 from freqtrade/dependabot/pip/develop/cryptography-3.4.8
Bump cryptography from 3.4.7 to 3.4.8
2021-08-30 06:32:58 +02:00
Matthias
6682d44f05 Merge pull request #5508 from freqtrade/dependabot/pip/develop/ccxt-1.55.56
Bump ccxt from 1.55.28 to 1.55.56
2021-08-30 06:32:33 +02:00
dependabot[bot]
45c6f90691 Bump mkdocs-material from 7.2.4 to 7.2.5
Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 7.2.4 to 7.2.5.
- [Release notes](https://github.com/squidfunk/mkdocs-material/releases)
- [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/docs/changelog.md)
- [Commits](https://github.com/squidfunk/mkdocs-material/compare/7.2.4...7.2.5)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-30 03:01:24 +00:00
dependabot[bot]
9e0ab9c2ca Bump fastapi from 0.68.0 to 0.68.1
Bumps [fastapi](https://github.com/tiangolo/fastapi) from 0.68.0 to 0.68.1.
- [Release notes](https://github.com/tiangolo/fastapi/releases)
- [Commits](https://github.com/tiangolo/fastapi/compare/0.68.0...0.68.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-30 03:01:19 +00:00
dependabot[bot]
26451e8c01 Bump ccxt from 1.55.28 to 1.55.56
Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.55.28 to 1.55.56.
- [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/1.55.28...1.55.56)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-30 03:01:14 +00:00
dependabot[bot]
d0504c47ef Bump plotly from 5.2.1 to 5.3.0
Bumps [plotly](https://github.com/plotly/plotly.py) from 5.2.1 to 5.3.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.2.1...v5.3.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-30 03:01:09 +00:00
dependabot[bot]
c64ebeb6e2 Bump cryptography from 3.4.7 to 3.4.8
Bumps [cryptography](https://github.com/pyca/cryptography) from 3.4.7 to 3.4.8.
- [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/3.4.7...3.4.8)

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

Signed-off-by: dependabot[bot] <support@github.com>
2021-08-30 03:01:05 +00:00
LoveIsGrief
c17595b314 Docs: Mention Performance Warning for strategies
Related to #5408
2021-08-29 20:00:59 +02:00
Pan Long
20878290a0 Surround "unlimited" by double quotes in build config. 2021-08-30 01:02:48 +08:00
Pan Long
c14d8ea827 Export HDF5 and CBLOSC paths.
This is needed if homebrew isn't installed in the standard path, say,
/usr/local/.
2021-08-29 16:34:01 +08:00
Matthias
a6b4b8bfd9 Merge pull request #5500 from freqtrade/clarify_exchange_error
Clarify exception on load when markets could not be loaded
2021-08-29 09:42:17 +02:00
Matthias
1895230afe Clarify exception on load when markets could not be loaded
closes #5498
2021-08-29 09:18:46 +02:00
Matthias
89581ad25c Fix typo in protections hyperopt doc
closes #5499
2021-08-29 08:24:31 +02:00
Matthias
0a52d7c24f Merge pull request #5495 from LoveIsGrief/docs/minor-fixes
Docs: Minor grammar fixes
2021-08-28 20:09:24 +02:00
LoveIsGrief
f79b30e886 Docs: Minor fixes 2021-08-28 18:51:43 +02:00
Matthias
19b3e8a8c5 Merge pull request #5493 from pan-long/develop
Remove extra comma after the last element in binance pair_blacklist.
2021-08-28 16:20:26 +02:00
Pan Long
482e65453f Remove extra comma after the last element in binance pair_blacklist. 2021-08-28 21:57:54 +08:00
Matthias
ac0dada962 Update Version to develop again 2021-08-28 10:43:49 +02:00
Matthias
c6f38bc2f3 Merge pull request #5487 from freqtrade/new_release
New release 2021.8
2021-08-28 10:38:48 +02:00
Matthias
fa4ec9f83e Add explicit test for get_sell_trade_entry 2021-08-15 14:52:24 +02:00
Matthias
3406b889b6 First test 2021-08-14 17:06:28 +02:00
Matthias
8405ccc15e Seperate detail data loading from regular backest-data loading 2021-08-14 16:33:01 +02:00
Matthias
88172fab82 Allow "detailed" backtesting timeframe to look into the candle 2021-08-14 16:04:23 +02:00
Cryptomeister Nox
85979c3176 * Adding command for Filtering
* Read latest Backtest file and print trades
2021-06-17 20:35:02 +02:00
rextea
76a02ff70a fix indentations 2021-03-26 18:49:17 +03:00
rextea
2bed41da5d Add days breakdown table to backtesting 2021-03-26 18:40:50 +03:00
215 changed files with 8389 additions and 5437 deletions

View File

@@ -9,7 +9,7 @@ assignees: ''
<!-- <!--
Have you searched for similar issues before posting it? Have you searched for similar issues before posting it?
If you have discovered a bug in the bot, please [search our issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue). If you have discovered a bug in the bot, please [search the issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue).
If it hasn't been reported, please create a new issue. If it hasn't been reported, please create a new issue.
Please do not use bug reports to request new features. Please do not use bug reports to request new features.

View File

@@ -22,4 +22,4 @@ Please do not use the question template to report bugs or to request new feature
## Your question ## Your question
*Ask the question you have not been able to find an answer in our [Documentation](https://www.freqtrade.io/en/latest/)* *Ask the question you have not been able to find an answer in the [Documentation](https://www.freqtrade.io/en/latest/)*

View File

@@ -2,14 +2,16 @@ Thank you for sending your pull request. But first, have you included
unit tests, and is your code PEP8 conformant? [More details](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md) unit tests, and is your code PEP8 conformant? [More details](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
## Summary ## Summary
Explain in one sentence the goal of this PR Explain in one sentence the goal of this PR
Solve the issue: #___ Solve the issue: #___
## Quick changelog ## Quick changelog
- <change log #1> - <change log 1>
- <change log #2> - <change log 1>
## What's new? ## What's new?
*Explain in details what this PR solve or improve. You can include visuals.* *Explain in details what this PR solve or improve. You can include visuals.*

View File

@@ -5,9 +5,17 @@ updates:
schedule: schedule:
interval: daily interval: daily
open-pull-requests-limit: 10 open-pull-requests-limit: 10
- package-ecosystem: pip - package-ecosystem: pip
directory: "/" directory: "/"
schedule: schedule:
interval: weekly interval: weekly
open-pull-requests-limit: 10 open-pull-requests-limit: 10
target-branch: develop target-branch: develop
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
target-branch: develop

View File

@@ -87,7 +87,7 @@ jobs:
run: | run: |
cp config_examples/config_bittrex.example.json config.json cp config_examples/config_bittrex.example.json config.json
freqtrade create-userdir --userdir user_data freqtrade create-userdir --userdir user_data
freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt SampleHyperOpt --hyperopt-loss SharpeHyperOptLossDaily --print-all freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all
- name: Flake8 - name: Flake8
run: | run: |
@@ -101,16 +101,13 @@ jobs:
run: | run: |
mypy freqtrade scripts mypy freqtrade scripts
- name: Slack Notification - name: Discord notification
uses: lazy-actions/slatify@v3.0.0 uses: rjstone/discord-webhook-notify@v1
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
with: with:
type: ${{ job.status }} severity: error
job_name: '*Freqtrade CI ${{ matrix.os }}*' details: Freqtrade CI failed on ${{ matrix.os }}
mention: 'here' webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
mention_if: 'failure'
channel: '#notifications'
url: ${{ secrets.SLACK_WEBHOOK }}
build_macos: build_macos:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@@ -180,7 +177,7 @@ jobs:
run: | run: |
cp config_examples/config_bittrex.example.json config.json cp config_examples/config_bittrex.example.json config.json
freqtrade create-userdir --userdir user_data freqtrade create-userdir --userdir user_data
freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt SampleHyperOpt --hyperopt-loss SharpeHyperOptLossDaily --print-all freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all
- name: Flake8 - name: Flake8
run: | run: |
@@ -194,17 +191,13 @@ jobs:
run: | run: |
mypy freqtrade scripts mypy freqtrade scripts
- name: Slack Notification - name: Discord notification
uses: lazy-actions/slatify@v3.0.0 uses: rjstone/discord-webhook-notify@v1
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
with: with:
type: ${{ job.status }} severity: error
job_name: '*Freqtrade CI ${{ matrix.os }}*' details: Test Succeeded!
mention: 'here' webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
mention_if: 'failure'
channel: '#notifications'
url: ${{ secrets.SLACK_WEBHOOK }}
build_windows: build_windows:
@@ -247,7 +240,7 @@ jobs:
run: | run: |
cp config_examples/config_bittrex.example.json config.json cp config_examples/config_bittrex.example.json config.json
freqtrade create-userdir --userdir user_data freqtrade create-userdir --userdir user_data
freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt SampleHyperOpt --hyperopt-loss SharpeHyperOptLossDaily --print-all freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all
- name: Flake8 - name: Flake8
run: | run: |
@@ -257,16 +250,13 @@ jobs:
run: | run: |
mypy freqtrade scripts mypy freqtrade scripts
- name: Slack Notification - name: Discord notification
uses: lazy-actions/slatify@v3.0.0 uses: rjstone/discord-webhook-notify@v1
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
with: with:
type: ${{ job.status }} severity: error
job_name: '*Freqtrade CI windows*' details: Test Failed
mention: 'here' webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
mention_if: 'failure'
channel: '#notifications'
url: ${{ secrets.SLACK_WEBHOOK }}
docs_check: docs_check:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@@ -288,14 +278,13 @@ jobs:
pip install mkdocs pip install mkdocs
mkdocs build mkdocs build
- name: Slack Notification - name: Discord notification
uses: lazy-actions/slatify@v3.0.0 uses: rjstone/discord-webhook-notify@v1
if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) if: failure() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
with: with:
type: ${{ job.status }} severity: error
job_name: '*Freqtrade Docs*' details: Freqtrade doc test failed!
channel: '#notifications' webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
url: ${{ secrets.SLACK_WEBHOOK }}
cleanup-prior-runs: cleanup-prior-runs:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@@ -306,7 +295,7 @@ jobs:
env: env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
# Notify on slack only once - when CI completes (and after deploy) in case it's successfull # Notify only once - when CI completes (and after deploy) in case it's successfull
notify-complete: notify-complete:
needs: [ build_linux, build_macos, build_windows, docs_check ] needs: [ build_linux, build_macos, build_windows, docs_check ]
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
@@ -320,14 +309,13 @@ jobs:
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Slack Notification - name: Discord notification
uses: lazy-actions/slatify@v3.0.0 uses: rjstone/discord-webhook-notify@v1
if: always() && steps.check.outputs.has-permission && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) if: always() && steps.check.outputs.has-permission && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
with: with:
type: ${{ job.status }} severity: info
job_name: '*Freqtrade CI*' details: Test Completed!
channel: '#notifications' webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
url: ${{ secrets.SLACK_WEBHOOK }}
deploy: deploy:
needs: [ build_linux, build_macos, build_windows, docs_check ] needs: [ build_linux, build_macos, build_windows, docs_check ]
@@ -385,7 +373,7 @@ jobs:
- name: Set up Docker Buildx - name: Set up Docker Buildx
id: buildx id: buildx
uses: crazy-max/ghaction-docker-buildx@v1 uses: crazy-max/ghaction-docker-buildx@v3.3.1
with: with:
buildx-version: latest buildx-version: latest
qemu-version: latest qemu-version: latest
@@ -400,17 +388,13 @@ jobs:
run: | run: |
build_helpers/publish_docker_multi.sh build_helpers/publish_docker_multi.sh
- name: Discord notification
- name: Slack Notification uses: rjstone/discord-webhook-notify@v1
uses: lazy-actions/slatify@v3.0.0
if: always() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false) if: always() && ( github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false)
with: with:
type: ${{ job.status }} severity: info
job_name: '*Freqtrade CI Deploy*' details: Deploy Succeeded!
mention: 'here' webhookUrl: ${{ secrets.DISCORD_WEBHOOK }}
mention_if: 'failure'
channel: '#notifications'
url: ${{ secrets.SLACK_WEBHOOK }}
deploy_arm: deploy_arm:

View File

@@ -10,7 +10,7 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: Docker Hub Description - name: Docker Hub Description
uses: peter-evans/dockerhub-description@v2.1.0 uses: peter-evans/dockerhub-description@v2.4.3
env: env:
DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USERNAME }} DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USERNAME }}
DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} DOCKERHUB_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}

View File

@@ -1,55 +0,0 @@
os:
- linux
dist: bionic
language: python
python:
- 3.8
services:
- docker
env:
global:
- IMAGE_NAME=freqtradeorg/freqtrade
install:
- cd build_helpers && ./install_ta-lib.sh ${HOME}/dependencies; cd ..
- export LD_LIBRARY_PATH=${HOME}/dependencies/lib:$LD_LIBRARY_PATH
- export TA_LIBRARY_PATH=${HOME}/dependencies/lib
- export TA_INCLUDE_PATH=${HOME}/dependencies/include
- pip install -r requirements-dev.txt
- pip install -e .
jobs:
include:
- stage: tests
script:
- pytest --random-order --cov=freqtrade --cov-config=.coveragerc
# Allow failure for coveralls
# - coveralls || true
name: pytest
- script:
- cp config_examples/config_bittrex.example.json config.json
- freqtrade create-userdir --userdir user_data
- freqtrade backtesting --datadir tests/testdata --strategy SampleStrategy
name: backtest
- script:
- cp config_examples/config_bittrex.example.json config.json
- freqtrade create-userdir --userdir user_data
- freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt SampleHyperOpt --hyperopt-loss SharpeHyperOptLossDaily
name: hyperopt
- script: flake8
name: flake8
- script:
# Test Documentation boxes -
# !!! <TYPE>: is not allowed!
# !!! <TYPE> "title" - Title needs to be quoted!
- grep -Er '^!{3}\s\S+:|^!{3}\s\S+\s[^"]' docs/*; test $? -ne 0
name: doc syntax
- script: mypy freqtrade scripts
name: mypy
notifications:
slack:
secure: bKLXmOrx8e2aPZl7W8DA5BdPAXWGpI5UzST33oc1G/thegXcDVmHBTJrBs4sZak6bgAclQQrdZIsRd2eFYzHLalJEaw6pk7hoAw8SvLnZO0ZurWboz7qg2+aZZXfK4eKl/VUe4sM9M4e/qxjkK+yWG7Marg69c4v1ypF7ezUi1fPYILYw8u0paaiX0N5UX8XNlXy+PBlga2MxDjUY70MuajSZhPsY2pDUvYnMY1D/7XN3cFW0g+3O8zXjF0IF4q1Z/1ASQe+eYjKwPQacE+O8KDD+ZJYoTOFBAPllrtpO1jnOPFjNGf3JIbVMZw4bFjIL0mSQaiSUaUErbU3sFZ5Or79rF93XZ81V7uEZ55vD8KMfR2CB1cQJcZcj0v50BxLo0InkFqa0Y8Nra3sbpV4fV5Oe8pDmomPJrNFJnX6ULQhQ1gTCe0M5beKgVms5SITEpt4/Y0CmLUr6iHDT0CUiyMIRWAXdIgbGh1jfaWOMksybeRevlgDsIsNBjXmYI1Sw2ZZR2Eo2u4R6zyfyjOMLwYJ3vgq9IrACv2w5nmf0+oguMWHf6iWi2hiOqhlAN1W74+3HsYQcqnuM3LGOmuCnPprV1oGBqkPXjIFGpy21gNx4vHfO1noLUyJnMnlu2L7SSuN1CdLsnjJ1hVjpJjPfqB4nn8g12x87TqM1bOm+3Q=
cache:
pip: True
directories:
- $HOME/dependencies

View File

@@ -56,6 +56,13 @@ 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. 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). Guide for installing them is [here](http://flake8.pycqa.org/en/latest/user/using-hooks.html).
##### Additional styles applied
* Have docstrings on all public methods
* Use double-quotes for docstrings
* Multiline docstrings should be indented to the level of the first quote
* Doc-strings should follow the reST format (`:param xxx: ...`, `:return: ...`, `:raises KeyError: ... `)
### 3. Test if all type-hints are correct ### 3. Test if all type-hints are correct
#### Run mypy #### Run mypy

View File

@@ -1,4 +1,4 @@
FROM python:3.9.6-slim-buster as base FROM python:3.9.9-slim-bullseye as base
# Setup env # Setup env
ENV LANG C.UTF-8 ENV LANG C.UTF-8
@@ -13,7 +13,7 @@ RUN mkdir /freqtrade \
&& apt-get update \ && apt-get update \
&& apt-get -y install sudo libatlas3-base curl sqlite3 libhdf5-serial-dev \ && apt-get -y install sudo libatlas3-base curl sqlite3 libhdf5-serial-dev \
&& apt-get clean \ && apt-get clean \
&& useradd -u 1000 -G sudo -U -m ftuser \ && useradd -u 1000 -G sudo -U -m -s /bin/bash ftuser \
&& chown ftuser:ftuser /freqtrade \ && chown ftuser:ftuser /freqtrade \
# Allow sudoers # Allow sudoers
&& echo "ftuser ALL=(ALL) NOPASSWD: /bin/chown" >> /etc/sudoers && echo "ftuser ALL=(ALL) NOPASSWD: /bin/chown" >> /etc/sudoers

View File

@@ -28,8 +28,10 @@ Please read the [exchange specific notes](docs/exchanges.md) to learn about even
- [X] [Binance](https://www.binance.com/) ([*Note for binance users](docs/exchanges.md#binance-blacklist)) - [X] [Binance](https://www.binance.com/) ([*Note for binance users](docs/exchanges.md#binance-blacklist))
- [X] [Bittrex](https://bittrex.com/) - [X] [Bittrex](https://bittrex.com/)
- [X] [Kraken](https://kraken.com/)
- [X] [FTX](https://ftx.com) - [X] [FTX](https://ftx.com)
- [X] [Gate.io](https://www.gate.io/ref/6266643)
- [X] [Kraken](https://kraken.com/)
- [X] [OKEX](https://www.okex.com/)
- [ ] [potentially many others](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ - [ ] [potentially many others](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_
### Community tested ### Community tested
@@ -43,7 +45,7 @@ Exchanges confirmed working by the community:
We invite you to read the bot documentation to ensure you understand how the bot is working. We invite you to read the bot documentation to ensure you understand how the bot is working.
Please find the complete documentation on our [website](https://www.freqtrade.io). Please find the complete documentation on the [freqtrade website](https://www.freqtrade.io).
## Features ## Features
@@ -52,7 +54,7 @@ Please find the complete documentation on our [website](https://www.freqtrade.io
- [x] **Dry-run**: Run the bot without paying money. - [x] **Dry-run**: Run the bot without paying money.
- [x] **Backtesting**: Run a simulation of your buy/sell strategy. - [x] **Backtesting**: Run a simulation of your buy/sell strategy.
- [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data. - [x] **Strategy Optimization by machine learning**: Use machine learning to optimize your buy/sell strategy parameters with real exchange data.
- [x] **Edge position sizing** Calculate your win rate, risk reward ratio, the best stoploss and adjust your position size before taking a position for each specific market. [Learn more](https://www.freqtrade.io/en/latest/edge/). - [x] **Edge position sizing** Calculate your win rate, risk reward ratio, the best stoploss and adjust your position size before taking a position for each specific market. [Learn more](https://www.freqtrade.io/en/stable/edge/).
- [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade or use dynamic whitelists. - [x] **Whitelist crypto-currencies**: Select which crypto-currency you want to trade or use dynamic whitelists.
- [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid. - [x] **Blacklist crypto-currencies**: Select which crypto-currency you want to avoid.
- [x] **Manageable via Telegram**: Manage the bot with Telegram. - [x] **Manageable via Telegram**: Manage the bot with Telegram.
@@ -70,7 +72,7 @@ cd freqtrade
./setup.sh --install ./setup.sh --install
``` ```
For any other type of installation please refer to [Installation doc](https://www.freqtrade.io/en/latest/installation/). For any other type of installation please refer to [Installation doc](https://www.freqtrade.io/en/stable/installation/).
## Basic Usage ## Basic Usage
@@ -78,22 +80,22 @@ For any other type of installation please refer to [Installation doc](https://ww
``` ```
usage: freqtrade [-h] [-V] usage: freqtrade [-h] [-V]
{trade,create-userdir,new-config,new-hyperopt,new-strategy,download-data,convert-data,convert-trade-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,plot-dataframe,plot-profit} {trade,create-userdir,new-config,new-strategy,download-data,convert-data,convert-trade-data,list-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,install-ui,plot-dataframe,plot-profit,webserver}
... ...
Free, open source crypto trading bot Free, open source crypto trading bot
positional arguments: positional arguments:
{trade,create-userdir,new-config,new-hyperopt,new-strategy,download-data,convert-data,convert-trade-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,plot-dataframe,plot-profit} {trade,create-userdir,new-config,new-strategy,download-data,convert-data,convert-trade-data,list-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,install-ui,plot-dataframe,plot-profit,webserver}
trade Trade module. trade Trade module.
create-userdir Create user-data directory. create-userdir Create user-data directory.
new-config Create new config new-config Create new config
new-hyperopt Create new hyperopt
new-strategy Create new strategy new-strategy Create new strategy
download-data Download backtesting data. download-data Download backtesting data.
convert-data Convert candle (OHLCV) data from one format to convert-data Convert candle (OHLCV) data from one format to
another. another.
convert-trade-data Convert trade data from one format to another. convert-trade-data Convert trade data from one format to another.
list-data List downloaded data.
backtesting Backtesting module. backtesting Backtesting module.
edge Edge module. edge Edge module.
hyperopt Hyperopt module. hyperopt Hyperopt module.
@@ -107,8 +109,10 @@ positional arguments:
list-timeframes Print available timeframes for the exchange. list-timeframes Print available timeframes for the exchange.
show-trades Show trades. show-trades Show trades.
test-pairlist Test your pairlist configuration. test-pairlist Test your pairlist configuration.
install-ui Install FreqUI
plot-dataframe Plot candles with indicators. plot-dataframe Plot candles with indicators.
plot-profit Generate plot showing profits. plot-profit Generate plot showing profits.
webserver Webserver module.
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
@@ -118,7 +122,7 @@ optional arguments:
### Telegram RPC commands ### Telegram RPC commands
Telegram is not mandatory. However, this is a great way to control your bot. More details and the full command list on our [documentation](https://www.freqtrade.io/en/latest/telegram-usage/) Telegram is not mandatory. However, this is a great way to control your bot. More details and the full command list on the [documentation](https://www.freqtrade.io/en/latest/telegram-usage/)
- `/start`: Starts the trader. - `/start`: Starts the trader.
- `/stop`: Stops the trader. - `/stop`: Stops the trader.
@@ -149,10 +153,10 @@ For any questions not covered by the documentation or for further information ab
### [Bugs / Issues](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue) ### [Bugs / Issues](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue)
If you discover a bug in the bot, please If you discover a bug in the bot, please
[search our issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue) [search the issue tracker](https://github.com/freqtrade/freqtrade/issues?q=is%3Aissue)
first. If it hasn't been reported, please first. If it hasn't been reported, please
[create a new issue](https://github.com/freqtrade/freqtrade/issues/new/choose) and [create a new issue](https://github.com/freqtrade/freqtrade/issues/new/choose) and
ensure you follow the template guide so that our team can assist you as ensure you follow the template guide so that the team can assist you as
quickly as possible. quickly as possible.
### [Feature Requests](https://github.com/freqtrade/freqtrade/labels/enhancement) ### [Feature Requests](https://github.com/freqtrade/freqtrade/labels/enhancement)
@@ -166,13 +170,13 @@ in the bug reports.
### [Pull Requests](https://github.com/freqtrade/freqtrade/pulls) ### [Pull Requests](https://github.com/freqtrade/freqtrade/pulls)
Feel like our bot is missing a feature? We welcome your pull requests! Feel like the bot is missing a feature? We welcome your pull requests!
Please read our Please read the
[Contributing document](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md) [Contributing document](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md)
to understand the requirements before sending your pull-requests. to understand the requirements before sending your pull-requests.
Coding is not a necessity to contribute - maybe start with improving our documentation? Coding is not a necessity to contribute - maybe start with improving the documentation?
Issues labeled [good first issue](https://github.com/freqtrade/freqtrade/labels/good%20first%20issue) can be good first contributions, and will help get you familiar with the codebase. Issues labeled [good first issue](https://github.com/freqtrade/freqtrade/labels/good%20first%20issue) can be good first contributions, and will help get you familiar with the codebase.
**Note** before starting any major new feature work, *please open an issue describing what you are planning to do* or talk to us on [discord](https://discord.gg/p7nuUNVfP7) (please use the #dev channel for this). This will ensure that interested parties can give valuable feedback on the feature, and let others know that you are working on it. **Note** before starting any major new feature work, *please open an issue describing what you are planning to do* or talk to us on [discord](https://discord.gg/p7nuUNVfP7) (please use the #dev channel for this). This will ensure that interested parties can give valuable feedback on the feature, and let others know that you are working on it.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -11,10 +11,18 @@ if [ ! -f "${INSTALL_LOC}/lib/libta_lib.a" ]; then
&& 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.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 'http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD' -o config.sub \
&& ./configure --prefix=${INSTALL_LOC}/ \ && ./configure --prefix=${INSTALL_LOC}/ \
&& make -j$(nproc) \ && make
&& which sudo && sudo make install || make install \ if [ $? -ne 0 ]; then
&& cd .. echo "Failed building ta-lib."
cd .. && rm -rf ./ta-lib/
exit 1
fi
which sudo && sudo make install || make install
if [ -x "$(command -v apt-get)" ]; then
echo "Updating library path using ldconfig"
sudo ldconfig
fi
cd .. && rm -rf ./ta-lib/
else else
echo "TA-lib already installed, skipping installation" echo "TA-lib already installed, skipping installation"
fi fi
# && sed -i.bak "s|0.00000001|0.000000000000000001 |g" src/ta_func/ta_utility.h \

View File

@@ -6,13 +6,13 @@ python -m pip install --upgrade pip
$pyv = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" $pyv = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"
if ($pyv -eq '3.7') { if ($pyv -eq '3.7') {
pip install build_helpers\TA_Lib-0.4.21-cp37-cp37m-win_amd64.whl pip install build_helpers\TA_Lib-0.4.22-cp37-cp37m-win_amd64.whl
} }
if ($pyv -eq '3.8') { if ($pyv -eq '3.8') {
pip install build_helpers\TA_Lib-0.4.21-cp38-cp38-win_amd64.whl pip install build_helpers\TA_Lib-0.4.22-cp38-cp38-win_amd64.whl
} }
if ($pyv -eq '3.9') { if ($pyv -eq '3.9') {
pip install build_helpers\TA_Lib-0.4.21-cp39-cp39-win_amd64.whl pip install build_helpers\TA_Lib-0.4.22-cp39-cp39-win_amd64.whl
} }
pip install -r requirements-dev.txt pip install -r requirements-dev.txt

View File

@@ -28,10 +28,8 @@
"name": "binance", "name": "binance",
"key": "your_exchange_key", "key": "your_exchange_key",
"secret": "your_exchange_secret", "secret": "your_exchange_secret",
"ccxt_config": {"enableRateLimit": true}, "ccxt_config": {},
"ccxt_async_config": { "ccxt_async_config": {
"enableRateLimit": true,
"rateLimit": 200
}, },
"pair_whitelist": [ "pair_whitelist": [
"ALGO/BTC", "ALGO/BTC",

View File

@@ -28,11 +28,8 @@
"name": "ftx", "name": "ftx",
"key": "your_exchange_key", "key": "your_exchange_key",
"secret": "your_exchange_secret", "secret": "your_exchange_secret",
"ccxt_config": {"enableRateLimit": true}, "ccxt_config": {},
"ccxt_async_config": { "ccxt_async_config": {},
"enableRateLimit": true,
"rateLimit": 50
},
"pair_whitelist": [ "pair_whitelist": [
"BTC/USD", "BTC/USD",
"ETH/USD", "ETH/USD",

View File

@@ -28,6 +28,7 @@
"unfilledtimeout": { "unfilledtimeout": {
"buy": 10, "buy": 10,
"sell": 30, "sell": 30,
"exit_timeout_count": 0,
"unit": "minutes" "unit": "minutes"
}, },
"bid_strategy": { "bid_strategy": {
@@ -84,12 +85,8 @@
"key": "your_exchange_key", "key": "your_exchange_key",
"secret": "your_exchange_secret", "secret": "your_exchange_secret",
"password": "", "password": "",
"ccxt_config": {"enableRateLimit": true}, "ccxt_config": {},
"ccxt_async_config": { "ccxt_async_config": {},
"enableRateLimit": true,
"rateLimit": 500,
"aiohttp_trust_env": false
},
"pair_whitelist": [ "pair_whitelist": [
"ALGO/BTC", "ALGO/BTC",
"ATOM/BTC", "ATOM/BTC",
@@ -149,7 +146,9 @@
}, },
"sell_fill": "on", "sell_fill": "on",
"buy_cancel": "on", "buy_cancel": "on",
"sell_cancel": "on" "sell_cancel": "on",
"protection_trigger": "off",
"protection_trigger_global": "on"
}, },
"reload": true, "reload": true,
"balance_dust_level": 0.01 "balance_dust_level": 0.01

View File

@@ -28,10 +28,8 @@
"name": "kraken", "name": "kraken",
"key": "your_exchange_key", "key": "your_exchange_key",
"secret": "your_exchange_key", "secret": "your_exchange_key",
"ccxt_config": {"enableRateLimit": true}, "ccxt_config": {},
"ccxt_async_config": { "ccxt_async_config": {
"enableRateLimit": true,
"rateLimit": 1000
}, },
"pair_whitelist": [ "pair_whitelist": [
"ADA/EUR", "ADA/EUR",

View File

@@ -15,10 +15,10 @@ services:
volumes: volumes:
- "./user_data:/freqtrade/user_data" - "./user_data:/freqtrade/user_data"
# Expose api on port 8080 (localhost only) # Expose api on port 8080 (localhost only)
# Please read the https://www.freqtrade.io/en/latest/rest-api/ documentation # Please read the https://www.freqtrade.io/en/stable/rest-api/ documentation
# before enabling this. # before enabling this.
# ports: ports:
# - "127.0.0.1:8080:8080" - "127.0.0.1:8080:8080"
# Default command used when running `docker compose up` # Default command used when running `docker compose up`
command: > command: >
trade trade

View File

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

View File

@@ -13,7 +13,7 @@ A sample of this can be found below, which is identical to the Default Hyperopt
``` python ``` python
from datetime import datetime from datetime import datetime
from typing import Dict from typing import Any, Dict
from pandas import DataFrame from pandas import DataFrame
@@ -67,10 +67,10 @@ Currently, the arguments are:
This function needs to return a floating point number (`float`). Smaller numbers will be interpreted as better results. The parameters and balancing for this is up to you. This function needs to return a floating point number (`float`). Smaller numbers will be interpreted as better results. The parameters and balancing for this is up to you.
!!! Note !!! Note
This function is called once per iteration - so please make sure to have this as optimized as possible to not slow hyperopt down unnecessarily. This function is called once per epoch - so please make sure to have this as optimized as possible to not slow hyperopt down unnecessarily.
!!! Note !!! Note "`*args` and `**kwargs`"
Please keep the arguments `*args` and `**kwargs` in the interface to allow us to extend this interface later. Please keep the arguments `*args` and `**kwargs` in the interface to allow us to extend this interface in the future.
## Overriding pre-defined spaces ## Overriding pre-defined spaces
@@ -80,10 +80,56 @@ To override a pre-defined space (`roi_space`, `generate_roi_table`, `stoploss_sp
class MyAwesomeStrategy(IStrategy): class MyAwesomeStrategy(IStrategy):
class HyperOpt: class HyperOpt:
# Define a custom stoploss space. # Define a custom stoploss space.
def stoploss_space(self): def stoploss_space():
return [SKDecimal(-0.05, -0.01, decimals=3, name='stoploss')] return [SKDecimal(-0.05, -0.01, decimals=3, name='stoploss')]
# Define custom ROI space
def roi_space() -> List[Dimension]:
return [
Integer(10, 120, name='roi_t1'),
Integer(10, 60, name='roi_t2'),
Integer(10, 40, name='roi_t3'),
SKDecimal(0.01, 0.04, decimals=3, name='roi_p1'),
SKDecimal(0.01, 0.07, decimals=3, name='roi_p2'),
SKDecimal(0.01, 0.20, decimals=3, name='roi_p3'),
]
``` ```
!!! Note
All overrides are optional and can be mixed/matched as necessary.
### Overriding Base estimator
You can define your own estimator for Hyperopt by implementing `generate_estimator()` in the Hyperopt subclass.
```python
class MyAwesomeStrategy(IStrategy):
class HyperOpt:
def generate_estimator():
return "RF"
```
Possible values are either one of "GP", "RF", "ET", "GBRT" (Details can be found in the [scikit-optimize documentation](https://scikit-optimize.github.io/)), or "an instance of a class that inherits from `RegressorMixin` (from sklearn) and where the `predict` method has an optional `return_std` argument, which returns `std(Y | x)` along with `E[Y | x]`".
Some research will be necessary to find additional Regressors.
Example for `ExtraTreesRegressor` ("ET") with additional parameters:
```python
class MyAwesomeStrategy(IStrategy):
class HyperOpt:
def generate_estimator():
from skopt.learning import ExtraTreesRegressor
# Corresponds to "ET" - but allows additional parameters.
return ExtraTreesRegressor(n_estimators=100)
```
!!! Note
While custom estimators can be provided, it's up to you as User to do research on possible parameters and analyze / understand which ones should be used.
If you're unsure about this, best use one of the Defaults (`"ET"` has proven to be the most versatile) without further parameters.
## Space options ## Space options
For the additional spaces, scikit-optimize (in combination with Freqtrade) provides the following space types: For the additional spaces, scikit-optimize (in combination with Freqtrade) provides the following space types:
@@ -105,281 +151,3 @@ from freqtrade.optimize.space import Categorical, Dimension, Integer, SKDecimal,
Assuming the definition of a rather small space (`SKDecimal(0.10, 0.15, decimals=2, name='xxx')`) - SKDecimal will have 5 possibilities (`[0.10, 0.11, 0.12, 0.13, 0.14, 0.15]`). Assuming the definition of a rather small space (`SKDecimal(0.10, 0.15, decimals=2, name='xxx')`) - SKDecimal will have 5 possibilities (`[0.10, 0.11, 0.12, 0.13, 0.14, 0.15]`).
A corresponding real space `Real(0.10, 0.15 name='xxx')` on the other hand has an almost unlimited number of possibilities (`[0.10, 0.010000000001, 0.010000000002, ... 0.014999999999, 0.01500000000]`). A corresponding real space `Real(0.10, 0.15 name='xxx')` on the other hand has an almost unlimited number of possibilities (`[0.10, 0.010000000001, 0.010000000002, ... 0.014999999999, 0.01500000000]`).
---
## Legacy Hyperopt
This Section explains the configuration of an explicit Hyperopt file (separate to the strategy).
!!! Warning "Deprecated / legacy mode"
Since the 2021.4 release you no longer have to write a separate hyperopt class, but all strategies can be hyperopted.
Please read the [main hyperopt page](hyperopt.md) for more details.
### Prepare hyperopt file
Configuring an explicit hyperopt file is similar to writing your own strategy, and many tasks will be similar.
!!! Tip "About this page"
For this page, we will be using a fictional strategy called `AwesomeStrategy` - which will be optimized using the `AwesomeHyperopt` class.
#### Create a Custom Hyperopt File
The simplest way to get started is to use the following command, which will create a new hyperopt file from a template, which will be located under `user_data/hyperopts/AwesomeHyperopt.py`.
Let assume you want a hyperopt file `AwesomeHyperopt.py`:
``` bash
freqtrade new-hyperopt --hyperopt AwesomeHyperopt
```
#### Legacy Hyperopt checklist
Checklist on all tasks / possibilities in hyperopt
Depending on the space you want to optimize, only some of the below are required:
* fill `buy_strategy_generator` - for buy signal optimization
* fill `indicator_space` - for buy signal optimization
* fill `sell_strategy_generator` - for sell signal optimization
* fill `sell_indicator_space` - for sell signal optimization
!!! Note
`populate_indicators` needs to create all indicators any of thee spaces may use, otherwise hyperopt will not work.
Optional in hyperopt - can also be loaded from a strategy (recommended):
* `populate_indicators` - fallback to create indicators
* `populate_buy_trend` - fallback if not optimizing for buy space. should come from strategy
* `populate_sell_trend` - fallback if not optimizing for sell space. should come from strategy
!!! Note
You always have to provide a strategy to Hyperopt, even if your custom Hyperopt class contains all methods.
Assuming the optional methods are not in your hyperopt file, please use `--strategy AweSomeStrategy` which contains these methods so hyperopt can use these methods instead.
Rarely you may also need to override:
* `roi_space` - for custom ROI optimization (if you need the ranges for the ROI parameters in the optimization hyperspace that differ from default)
* `generate_roi_table` - for custom ROI optimization (if you need the ranges for the values in the ROI table that differ from default or the number of entries (steps) in the ROI table which differs from the default 4 steps)
* `stoploss_space` - for custom stoploss optimization (if you need the range for the stoploss parameter in the optimization hyperspace that differs from default)
* `trailing_space` - for custom trailing stop optimization (if you need the ranges for the trailing stop parameters in the optimization hyperspace that differ from default)
#### Defining a buy signal optimization
Let's say you are curious: should you use MACD crossings or lower Bollinger
Bands to trigger your buys. And you also wonder should you use RSI or ADX to
help with those buy decisions. If you decide to use RSI or ADX, which values
should I use for them? So let's use hyperparameter optimization to solve this
mystery.
We will start by defining a search space:
```python
def indicator_space() -> List[Dimension]:
"""
Define your Hyperopt space for searching strategy parameters
"""
return [
Integer(20, 40, name='adx-value'),
Integer(20, 40, name='rsi-value'),
Categorical([True, False], name='adx-enabled'),
Categorical([True, False], name='rsi-enabled'),
Categorical(['bb_lower', 'macd_cross_signal'], name='trigger')
]
```
Above definition says: I have five parameters I want you to randomly combine
to find the best combination. Two of them are integer values (`adx-value` and `rsi-value`) and I want you test in the range of values 20 to 40.
Then we have three category variables. First two are either `True` or `False`.
We use these to either enable or disable the ADX and RSI guards.
The last one we call `trigger` and use it to decide which buy trigger we want to use.
So let's write the buy strategy generator using these values:
```python
@staticmethod
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
"""
Define the buy strategy parameters to be used by Hyperopt.
"""
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
conditions = []
# GUARDS AND TRENDS
if 'adx-enabled' in params and params['adx-enabled']:
conditions.append(dataframe['adx'] > params['adx-value'])
if 'rsi-enabled' in params and params['rsi-enabled']:
conditions.append(dataframe['rsi'] < params['rsi-value'])
# TRIGGERS
if 'trigger' in params:
if params['trigger'] == 'bb_lower':
conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
if params['trigger'] == 'macd_cross_signal':
conditions.append(qtpylib.crossed_above(
dataframe['macd'], dataframe['macdsignal']
))
# Check that volume is not 0
conditions.append(dataframe['volume'] > 0)
if conditions:
dataframe.loc[
reduce(lambda x, y: x & y, conditions),
'buy'] = 1
return dataframe
return populate_buy_trend
```
Hyperopt will now call `populate_buy_trend()` many times (`epochs`) with different value combinations.
It will use the given historical data and make buys based on the buy signals generated with the above function.
Based on the results, hyperopt will tell you which parameter combination produced the best results (based on the configured [loss function](#loss-functions)).
!!! Note
The above setup expects to find ADX, RSI and Bollinger Bands in the populated indicators.
When you want to test an indicator that isn't used by the bot currently, remember to
add it to the `populate_indicators()` method in your strategy or hyperopt file.
#### Sell optimization
Similar to the buy-signal above, sell-signals can also be optimized.
Place the corresponding settings into the following methods
* Inside `sell_indicator_space()` - the parameters hyperopt shall be optimizing.
* Within `sell_strategy_generator()` - populate the nested method `populate_sell_trend()` to apply the parameters.
The configuration and rules are the same than for buy signals.
To avoid naming collisions in the search-space, please prefix all sell-spaces with `sell-`.
### Execute Hyperopt
Once you have updated your hyperopt configuration you can run it.
Because hyperopt tries a lot of combinations to find the best parameters it will take time to get a good result. More time usually results in better results.
We strongly recommend to use `screen` or `tmux` to prevent any connection loss.
```bash
freqtrade hyperopt --config config.json --hyperopt <hyperoptname> --hyperopt-loss <hyperoptlossname> --strategy <strategyname> -e 500 --spaces all
```
Use `<hyperoptname>` as the name of the custom hyperopt used.
The `-e` option will set how many evaluations hyperopt will do. Since hyperopt uses Bayesian search, running too many epochs at once may not produce greater results. Experience has shown that best results are usually not improving much after 500-1000 epochs.
Doing multiple runs (executions) with a few 1000 epochs and different random state will most likely produce different results.
The `--spaces all` option determines that all possible parameters should be optimized. Possibilities are listed below.
!!! Note
Hyperopt will store hyperopt results with the timestamp of the hyperopt start time.
Reading commands (`hyperopt-list`, `hyperopt-show`) can use `--hyperopt-filename <filename>` to read and display older hyperopt results.
You can find a list of filenames with `ls -l user_data/hyperopt_results/`.
#### Running Hyperopt using methods from a strategy
Hyperopt can reuse `populate_indicators`, `populate_buy_trend`, `populate_sell_trend` from your strategy, assuming these methods are **not** in your custom hyperopt file, and a strategy is provided.
```bash
freqtrade hyperopt --hyperopt AwesomeHyperopt --hyperopt-loss SharpeHyperOptLossDaily --strategy AwesomeStrategy
```
### Understand the Hyperopt Result
Once Hyperopt is completed you can use the result to create a new strategy.
Given the following result from hyperopt:
```
Best result:
44/100: 135 trades. Avg profit 0.57%. Total profit 0.03871918 BTC (0.7722%). Avg duration 180.4 mins. Objective: 1.94367
Buy hyperspace params:
{ 'adx-value': 44,
'rsi-value': 29,
'adx-enabled': False,
'rsi-enabled': True,
'trigger': 'bb_lower'}
```
You should understand this result like:
* The buy trigger that worked best was `bb_lower`.
* You should not use ADX because `adx-enabled: False`)
* You should **consider** using the RSI indicator (`rsi-enabled: True` and the best value is `29.0` (`rsi-value: 29.0`)
You have to look inside your strategy file into `buy_strategy_generator()`
method, what those values match to.
So for example you had `rsi-value: 29.0` so we would look at `rsi`-block, that translates to the following code block:
```python
(dataframe['rsi'] < 29.0)
```
Translating your whole hyperopt result as the new buy-signal would then look like:
```python
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
dataframe.loc[
(
(dataframe['rsi'] < 29.0) & # rsi-value
dataframe['close'] < dataframe['bb_lowerband'] # trigger
),
'buy'] = 1
return dataframe
```
### Validate backtesting results
Once the optimized parameters and conditions have been implemented into your strategy, you should backtest the strategy to make sure everything is working as expected.
To achieve same results (number of trades, their durations, profit, etc.) than during Hyperopt, please use same configuration and parameters (timerange, timeframe, ...) used for hyperopt `--dmmp`/`--disable-max-market-positions` and `--eps`/`--enable-position-stacking` for Backtesting.
Should results don't match, please double-check to make sure you transferred all conditions correctly.
Pay special care to the stoploss (and trailing stoploss) parameters, as these are often set in configuration files, which override changes to the strategy.
You should also carefully review the log of your backtest to ensure that there were no parameters inadvertently set by the configuration (like `stoploss` or `trailing_stop`).
### Sharing methods with your strategy
Hyperopt classes provide access to the Strategy via the `strategy` class attribute.
This can be a great way to reduce code duplication if used correctly, but will also complicate usage for inexperienced users.
``` python
from pandas import DataFrame
from freqtrade.strategy.interface import IStrategy
import freqtrade.vendor.qtpylib.indicators as qtpylib
class MyAwesomeStrategy(IStrategy):
buy_params = {
'rsi-value': 30,
'adx-value': 35,
}
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
return self.buy_strategy_generator(self.buy_params, dataframe, metadata)
@staticmethod
def buy_strategy_generator(params, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe.loc[
(
qtpylib.crossed_above(dataframe['rsi'], params['rsi-value']) &
dataframe['adx'] > params['adx-value']) &
dataframe['volume'] > 0
)
, 'buy'] = 1
return dataframe
class MyAwesomeHyperOpt(IHyperOpt):
...
@staticmethod
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
"""
Define the buy strategy parameters to be used by Hyperopt.
"""
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
# Call strategy's buy strategy generator
return self.StrategyClass.buy_strategy_generator(params, dataframe, metadata)
return populate_buy_trend
```

View File

@@ -52,6 +52,71 @@ freqtrade trade -c MyConfigUSDT.json -s MyCustomStrategy --db-url sqlite:///user
For more information regarding usage of the sqlite databases, for example to manually enter or remove trades, please refer to the [SQL Cheatsheet](sql_cheatsheet.md). For more information regarding usage of the sqlite databases, for example to manually enter or remove trades, please refer to the [SQL Cheatsheet](sql_cheatsheet.md).
### Multiple instances using docker
To run multiple instances of freqtrade using docker you will need to edit the docker-compose.yml file and add all the instances you want as separate services. Remember, you can separate your configuration into multiple files, so it's a good idea to think about making them modular, then if you need to edit something common to all bots, you can do that in a single config file.
``` yml
---
version: '3'
services:
freqtrade1:
image: freqtradeorg/freqtrade:stable
# image: freqtradeorg/freqtrade:develop
# Use plotting image
# image: freqtradeorg/freqtrade:develop_plot
# Build step - only needed when additional dependencies are needed
# build:
# context: .
# dockerfile: "./docker/Dockerfile.custom"
restart: always
container_name: freqtrade1
volumes:
- "./user_data:/freqtrade/user_data"
# Expose api on port 8080 (localhost only)
# Please read the https://www.freqtrade.io/en/latest/rest-api/ documentation
# before enabling this.
ports:
- "127.0.0.1:8080:8080"
# Default command used when running `docker compose up`
command: >
trade
--logfile /freqtrade/user_data/logs/freqtrade1.log
--db-url sqlite:////freqtrade/user_data/tradesv3_freqtrade1.sqlite
--config /freqtrade/user_data/config.json
--config /freqtrade/user_data/config.freqtrade1.json
--strategy SampleStrategy
freqtrade2:
image: freqtradeorg/freqtrade:stable
# image: freqtradeorg/freqtrade:develop
# Use plotting image
# image: freqtradeorg/freqtrade:develop_plot
# Build step - only needed when additional dependencies are needed
# build:
# context: .
# dockerfile: "./docker/Dockerfile.custom"
restart: always
container_name: freqtrade2
volumes:
- "./user_data:/freqtrade/user_data"
# Expose api on port 8080 (localhost only)
# Please read the https://www.freqtrade.io/en/latest/rest-api/ documentation
# before enabling this.
ports:
- "127.0.0.1:8081:8080"
# Default command used when running `docker compose up`
command: >
trade
--logfile /freqtrade/user_data/logs/freqtrade2.log
--db-url sqlite:////freqtrade/user_data/tradesv3_freqtrade2.sqlite
--config /freqtrade/user_data/config.json
--config /freqtrade/user_data/config.freqtrade2.json
--strategy SampleStrategy
```
You can use whatever naming convention you want, freqtrade1 and 2 are arbitrary. Note, that you will need to use different database files, port mappings and telegram configurations for each instance, as mentioned above.
## Configure the bot running as a systemd service ## Configure the bot running as a systemd service
Copy the `freqtrade.service` file to your systemd user directory (usually `~/.config/systemd/user`) and update `WorkingDirectory` and `ExecStart` to match your setup. Copy the `freqtrade.service` file to your systemd user directory (usually `~/.config/systemd/user`) and update `WorkingDirectory` and `ExecStart` to match your setup.

BIN
docs/assets/frequi_url.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -18,8 +18,10 @@ usage: freqtrade backtesting [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-p PAIRS [PAIRS ...]] [--eps] [--dmmp] [-p PAIRS [PAIRS ...]] [--eps] [--dmmp]
[--enable-protections] [--enable-protections]
[--dry-run-wallet DRY_RUN_WALLET] [--dry-run-wallet DRY_RUN_WALLET]
[--timeframe-detail TIMEFRAME_DETAIL]
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]] [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
[--export {none,trades}] [--export-filename PATH] [--export {none,trades}] [--export-filename PATH]
[--breakdown {day,week,month} [{day,week,month} ...]]
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
@@ -29,7 +31,7 @@ optional arguments:
Specify what timerange of data to use. Specify what timerange of data to use.
--data-format-ohlcv {json,jsongz,hdf5} --data-format-ohlcv {json,jsongz,hdf5}
Storage format for downloaded candle (OHLCV) data. Storage format for downloaded candle (OHLCV) data.
(default: `None`). (default: `json`).
--max-open-trades INT --max-open-trades INT
Override the value of the `max_open_trades` Override the value of the `max_open_trades`
configuration setting. configuration setting.
@@ -55,14 +57,16 @@ optional arguments:
--dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET --dry-run-wallet DRY_RUN_WALLET, --starting-balance DRY_RUN_WALLET
Starting balance, used for backtesting / hyperopt and Starting balance, used for backtesting / hyperopt and
dry-runs. dry-runs.
--timeframe-detail TIMEFRAME_DETAIL
Specify detail timeframe for backtesting (`1m`, `5m`,
`30m`, `1h`, `1d`).
--strategy-list STRATEGY_LIST [STRATEGY_LIST ...] --strategy-list STRATEGY_LIST [STRATEGY_LIST ...]
Provide a space-separated list of strategies to Provide a space-separated list of strategies to
backtest. Please note that ticker-interval needs to be backtest. Please note that ticker-interval needs to be
set either in config or via command line. When using set either in config or via command line. When using
this together with `--export trades`, the strategy- this together with `--export trades`, the strategy-
name is injected into the filename (so `backtest- name is injected into the filename (so `backtest-
data.json` becomes `backtest-data- data.json` becomes `backtest-data-SampleStrategy.json`
SampleStrategy.json`
--export {none,trades} --export {none,trades}
Export backtest results (default: trades). Export backtest results (default: trades).
--export-filename PATH --export-filename PATH
@@ -70,6 +74,8 @@ optional arguments:
Requires `--export` to be set as well. Example: Requires `--export` to be set as well. Example:
`--export-filename=user_data/backtest_results/backtest `--export-filename=user_data/backtest_results/backtest
_today.json` _today.json`
--breakdown {day,week,month} [{day,week,month} ...]
Show backtesting breakdown per [day, week, month].
Common arguments: Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages). -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
@@ -109,7 +115,7 @@ The result of backtesting will confirm if your bot has better odds of making a p
All profit calculations include fees, and freqtrade will use the exchange's default fees for the calculation. All profit calculations include fees, and freqtrade will use the exchange's default fees for the calculation.
!!! Warning "Using dynamic pairlists for backtesting" !!! Warning "Using dynamic pairlists for backtesting"
Using dynamic pairlists is possible, however it relies on the current market conditions - which will not reflect the historic status of the pairlist. Using dynamic pairlists is possible (not all of the handlers are allowed to be used in backtest mode), however it relies on the current market conditions - which will not reflect the historic status of the pairlist.
Also, when using pairlists other than StaticPairlist, reproducibility of backtesting-results cannot be guaranteed. Also, when using pairlists other than StaticPairlist, reproducibility of backtesting-results cannot be guaranteed.
Please read the [pairlists documentation](plugins.md#pairlists) for more information. Please read the [pairlists documentation](plugins.md#pairlists) for more information.
@@ -425,7 +431,37 @@ It contains some useful key metrics about performance of your strategy on backte
- `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command). - `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command).
- `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. - `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column.
### Assumptions made by backtesting ### Daily / Weekly / Monthly breakdown
You can get an overview over daily / weekly or monthly results by using the `--breakdown <>` switch.
To visualize daily and weekly breakdowns, you can use the following:
``` bash
freqtrade backtesting --strategy MyAwesomeStrategy --breakdown day month
```
``` output
======================== DAY BREAKDOWN =========================
| Day | Tot Profit USDT | Wins | Draws | Losses |
|------------+-------------------+--------+---------+----------|
| 03/07/2021 | 200.0 | 2 | 0 | 0 |
| 04/07/2021 | -50.31 | 0 | 0 | 2 |
| 05/07/2021 | 220.611 | 3 | 2 | 0 |
| 06/07/2021 | 150.974 | 3 | 0 | 2 |
| 07/07/2021 | -70.193 | 1 | 0 | 2 |
| 08/07/2021 | 212.413 | 2 | 0 | 3 |
```
The output will show a table containing the realized absolute Profit (in stake currency) for the given timeperiod, as well as wins, draws and losses that materialized (closed) on this day.
### Further backtest-result analysis
To further analyze your backtest results, you can [export the trades](#exporting-trades-to-file).
You can then load the trades to perform further analysis as shown in the [data analysis](data-analysis.md#backtesting) backtesting section.
## Assumptions made by backtesting
Since backtesting lacks some detailed information about what happens within a candle, it needs to take a few assumptions: Since backtesting lacks some detailed information about what happens within a candle, it needs to take a few assumptions:
@@ -442,6 +478,7 @@ Since backtesting lacks some detailed information about what happens within a ca
- Low happens before high for stoploss, protecting capital first - Low happens before high for stoploss, protecting capital first
- Trailing stoploss - Trailing stoploss
- Trailing Stoploss is only adjusted if it's below the candle's low (otherwise it would be triggered) - Trailing Stoploss is only adjusted if it's below the candle's low (otherwise it would be triggered)
- On trade entry candles that trigger trailing stoploss, the "minimum offset" (`stop_positive_offset`) is assumed (instead of high) - and the stop is calculated from this point
- High happens first - adjusting stoploss - High happens first - adjusting stoploss
- Low uses the adjusted stoploss (so sells with large high-low difference are backtested correctly) - Low uses the adjusted stoploss (so sells with large high-low difference are backtested correctly)
- ROI applies before trailing-stop, ensuring profits are "top-capped" at ROI if both ROI and trailing stop applies - ROI applies before trailing-stop, ensuring profits are "top-capped" at ROI if both ROI and trailing stop applies
@@ -456,10 +493,30 @@ Also, keep in mind that past results don't guarantee future success.
In addition to the above assumptions, strategy authors should carefully read the [Common Mistakes](strategy-customization.md#common-mistakes-when-developing-strategies) section, to avoid using data in backtesting which is not available in real market conditions. In addition to the above assumptions, strategy authors should carefully read the [Common Mistakes](strategy-customization.md#common-mistakes-when-developing-strategies) section, to avoid using data in backtesting which is not available in real market conditions.
### Further backtest-result analysis ### Improved backtest accuracy
To further analyze your backtest results, you can [export the trades](#exporting-trades-to-file). One big limitation of backtesting is it's inability to know how prices moved intra-candle (was high before close, or viceversa?).
You can then load the trades to perform further analysis as shown in our [data analysis](data-analysis.md#backtesting) backtesting section. So assuming you run backtesting with a 1h timeframe, there will be 4 prices for that candle (Open, High, Low, Close).
While backtesting does take some assumptions (read above) about this - this can never be perfect, and will always be biased in one way or the other.
To mitigate this, freqtrade can use a lower (faster) timeframe to simulate intra-candle movements.
To utilize this, you can append `--timeframe-detail 5m` to your regular backtesting command.
``` bash
freqtrade backtesting --strategy AwesomeStrategy --timeframe 1h --timeframe-detail 5m
```
This will load 1h data as well as 5m data for the timeframe. The strategy will be analyzed with the 1h timeframe - and for every "open trade candle" (candles where a trade is open) the 5m data will be used to simulate intra-candle movements.
All callback functions (`custom_sell()`, `custom_stoploss()`, ... ) will be running for each 5m candle once the trade is opened (so 12 times in the above example of 1h timeframe, and 5m detailed timeframe).
`--timeframe-detail` must be smaller than the original timeframe, otherwise backtesting will fail to start.
Obviously this will require more memory (5m data is bigger than 1h data), and will also impact runtime (depending on the amount of trades and trade durations).
Also, data must be available / downloaded already.
!!! Tip
You can use this function as the last part of strategy development, to ensure your strategy is not exploiting one of the [backtesting assumptions](#assumptions-made-by-backtesting). Strategies that perform similarly well with this mode have a good chance to perform well in dry/live modes too (although only forward-testing (dry-mode) can really confirm a strategy).
## Backtesting multiple strategies ## Backtesting multiple strategies

View File

@@ -7,7 +7,7 @@ This page provides you some basic concepts on how Freqtrade works and operates.
* **Strategy**: Your trading strategy, telling the bot what to do. * **Strategy**: Your trading strategy, telling the bot what to do.
* **Trade**: Open position. * **Trade**: Open position.
* **Open Order**: Order which is currently placed on the exchange, and is not yet complete. * **Open Order**: Order which is currently placed on the exchange, and is not yet complete.
* **Pair**: Tradable pair, usually in the format of Quote/Base (e.g. XRP/USDT). * **Pair**: Tradable pair, usually in the format of Base/Quote (e.g. XRP/USDT).
* **Timeframe**: Candle length to use (e.g. `"5m"`, `"1h"`, ...). * **Timeframe**: Candle length to use (e.g. `"5m"`, `"1h"`, ...).
* **Indicators**: Technical indicators (SMA, EMA, RSI, ...). * **Indicators**: Technical indicators (SMA, EMA, RSI, ...).
* **Limit order**: Limit orders which execute at the defined limit price or better. * **Limit order**: Limit orders which execute at the defined limit price or better.
@@ -56,7 +56,11 @@ This loop will be repeated again and again until the bot is stopped.
* Calculate buy / sell signals (calls `populate_buy_trend()` and `populate_sell_trend()` once per pair). * Calculate buy / sell signals (calls `populate_buy_trend()` and `populate_sell_trend()` once per pair).
* Loops per candle simulating entry and exit points. * Loops per candle simulating entry and exit points.
* Confirm trade buy / sell (calls `confirm_trade_entry()` and `confirm_trade_exit()` if implemented in the strategy). * Confirm trade buy / sell (calls `confirm_trade_entry()` and `confirm_trade_exit()` if implemented in the strategy).
* Call `custom_entry_price()` (if implemented in the strategy) to determine entry price (Prices are moved to be within the opening candle).
* Determine stake size by calling the `custom_stake_amount()` callback.
* Call `custom_stoploss()` and `custom_sell()` to find custom exit points. * Call `custom_stoploss()` and `custom_sell()` to find custom exit points.
* For sells based on sell-signal and custom-sell: Call `custom_exit_price()` to determine exit price (Prices are moved to be within the closing candle).
* Generate backtest report output * Generate backtest report output
!!! Note !!! Note

View File

@@ -12,22 +12,22 @@ This page explains the different parameters of the bot and how to run it.
``` ```
usage: freqtrade [-h] [-V] usage: freqtrade [-h] [-V]
{trade,create-userdir,new-config,new-hyperopt,new-strategy,download-data,convert-data,convert-trade-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,plot-dataframe,plot-profit} {trade,create-userdir,new-config,new-strategy,download-data,convert-data,convert-trade-data,list-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,install-ui,plot-dataframe,plot-profit,webserver}
... ...
Free, open source crypto trading bot Free, open source crypto trading bot
positional arguments: positional arguments:
{trade,create-userdir,new-config,new-hyperopt,new-strategy,download-data,convert-data,convert-trade-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,plot-dataframe,plot-profit} {trade,create-userdir,new-config,new-strategy,download-data,convert-data,convert-trade-data,list-data,backtesting,edge,hyperopt,hyperopt-list,hyperopt-show,list-exchanges,list-hyperopts,list-markets,list-pairs,list-strategies,list-timeframes,show-trades,test-pairlist,install-ui,plot-dataframe,plot-profit,webserver}
trade Trade module. trade Trade module.
create-userdir Create user-data directory. create-userdir Create user-data directory.
new-config Create new config new-config Create new config
new-hyperopt Create new hyperopt
new-strategy Create new strategy new-strategy Create new strategy
download-data Download backtesting data. download-data Download backtesting data.
convert-data Convert candle (OHLCV) data from one format to convert-data Convert candle (OHLCV) data from one format to
another. another.
convert-trade-data Convert trade data from one format to another. convert-trade-data Convert trade data from one format to another.
list-data List downloaded data.
backtesting Backtesting module. backtesting Backtesting module.
edge Edge module. edge Edge module.
hyperopt Hyperopt module. hyperopt Hyperopt module.
@@ -41,8 +41,10 @@ positional arguments:
list-timeframes Print available timeframes for the exchange. list-timeframes Print available timeframes for the exchange.
show-trades Show trades. show-trades Show trades.
test-pairlist Test your pairlist configuration. test-pairlist Test your pairlist configuration.
install-ui Install FreqUI
plot-dataframe Plot candles with indicators. plot-dataframe Plot candles with indicators.
plot-profit Generate plot showing profits. plot-profit Generate plot showing profits.
webserver Webserver module.
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit

View File

@@ -37,6 +37,15 @@ Using this scheme, all configuration settings will also be available as environm
Please note that Environment variables will overwrite corresponding settings in your configuration, but command line Arguments will always win. Please note that Environment variables will overwrite corresponding settings in your configuration, but command line Arguments will always win.
Common example:
```
FREQTRADE__TELEGRAM__CHAT_ID=<telegramchatid>
FREQTRADE__TELEGRAM__TOKEN=<telegramToken>
FREQTRADE__EXCHANGE__KEY=<yourExchangeKey>
FREQTRADE__EXCHANGE__SECRET=<yourExchangeSecret>
```
!!! Note !!! Note
Environment variables detected are logged at startup - so if you can't find why a value is not what you think it should be based on the configuration, make sure it's not loaded from an environment variable. Environment variables detected are logged at startup - so if you can't find why a value is not what you think it should be based on the configuration, make sure it's not loaded from an environment variable.
@@ -93,6 +102,7 @@ Mandatory parameters are marked as **Required**, which means that they are requi
| `unfilledtimeout.buy` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Integer | `unfilledtimeout.buy` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Integer
| `unfilledtimeout.sell` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Integer | `unfilledtimeout.sell` | **Required.** How long (in minutes or seconds) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled and repeated at current (new) price, as long as there is a signal. [Strategy Override](#parameters-in-the-strategy).<br> **Datatype:** Integer
| `unfilledtimeout.unit` | Unit to use in unfilledtimeout setting. Note: If you set unfilledtimeout.unit to "seconds", "internals.process_throttle_secs" must be inferior or equal to timeout [Strategy Override](#parameters-in-the-strategy). <br> *Defaults to `minutes`.* <br> **Datatype:** String | `unfilledtimeout.unit` | Unit to use in unfilledtimeout setting. Note: If you set unfilledtimeout.unit to "seconds", "internals.process_throttle_secs" must be inferior or equal to timeout [Strategy Override](#parameters-in-the-strategy). <br> *Defaults to `minutes`.* <br> **Datatype:** String
| `unfilledtimeout.exit_timeout_count` | How many times can exit orders time out. Once this number of timeouts is reached, an emergency sell is triggered. 0 to disable and allow unlimited order cancels. [Strategy Override](#parameters-in-the-strategy).<br>*Defaults to `0`.* <br> **Datatype:** Integer
| `bid_strategy.price_side` | Select the side of the spread the bot should look at to get the buy rate. [More information below](#buy-price-side).<br> *Defaults to `bid`.* <br> **Datatype:** String (either `ask` or `bid`). | `bid_strategy.price_side` | Select the side of the spread the bot should look at to get the buy rate. [More information below](#buy-price-side).<br> *Defaults to `bid`.* <br> **Datatype:** String (either `ask` or `bid`).
| `bid_strategy.ask_last_balance` | **Required.** Interpolate the bidding price. More information [below](#buy-price-without-orderbook-enabled). | `bid_strategy.ask_last_balance` | **Required.** Interpolate the bidding price. More information [below](#buy-price-without-orderbook-enabled).
| `bid_strategy.use_order_book` | Enable buying using the rates in [Order Book Bids](#buy-price-with-orderbook-enabled). <br> **Datatype:** Boolean | `bid_strategy.use_order_book` | Enable buying using the rates in [Order Book Bids](#buy-price-with-orderbook-enabled). <br> **Datatype:** Boolean
@@ -116,14 +126,16 @@ Mandatory parameters are marked as **Required**, which means that they are requi
| `exchange.key` | API key to use for the exchange. Only required when you are in production mode.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String | `exchange.key` | API key to use for the exchange. Only required when you are in production mode.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
| `exchange.secret` | API secret to use for the exchange. Only required when you are in production mode.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String | `exchange.secret` | API secret to use for the exchange. Only required when you are in production mode.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
| `exchange.password` | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String | `exchange.password` | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
| `exchange.uid` | API uid to use for the exchange. Only required when you are in production mode and for exchanges that use uid for API requests.<br>**Keep it in secret, do not disclose publicly.** <br> **Datatype:** String
| `exchange.pair_whitelist` | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Supports regex pairs as `.*/BTC`. Not used by VolumePairList. [More information](plugins.md#pairlists-and-pairlist-handlers). <br> **Datatype:** List | `exchange.pair_whitelist` | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Supports regex pairs as `.*/BTC`. Not used by VolumePairList. [More information](plugins.md#pairlists-and-pairlist-handlers). <br> **Datatype:** List
| `exchange.pair_blacklist` | List of pairs the bot must absolutely avoid for trading and backtesting. [More information](plugins.md#pairlists-and-pairlist-handlers). <br> **Datatype:** List | `exchange.pair_blacklist` | List of pairs the bot must absolutely avoid for trading and backtesting. [More information](plugins.md#pairlists-and-pairlist-handlers). <br> **Datatype:** List
| `exchange.ccxt_config` | Additional CCXT parameters passed to both ccxt instances (sync and async). This is usually the correct place for ccxt configurations. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) <br> **Datatype:** Dict | `exchange.ccxt_config` | Additional CCXT parameters passed to both ccxt instances (sync and async). This is usually the correct place for additional ccxt configurations. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation). Please avoid adding exchange secrets here (use the dedicated fields instead), as they may be contained in logs. <br> **Datatype:** Dict
| `exchange.ccxt_sync_config` | Additional CCXT parameters passed to the regular (sync) ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) <br> **Datatype:** Dict | `exchange.ccxt_sync_config` | Additional CCXT parameters passed to the regular (sync) ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) <br> **Datatype:** Dict
| `exchange.ccxt_async_config` | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) <br> **Datatype:** Dict | `exchange.ccxt_async_config` | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) <br> **Datatype:** Dict
| `exchange.markets_refresh_interval` | The interval in minutes in which markets are reloaded. <br>*Defaults to `60` minutes.* <br> **Datatype:** Positive Integer | `exchange.markets_refresh_interval` | The interval in minutes in which markets are reloaded. <br>*Defaults to `60` minutes.* <br> **Datatype:** Positive Integer
| `exchange.skip_pair_validation` | Skip pairlist validation on startup.<br>*Defaults to `false`<br> **Datatype:** Boolean | `exchange.skip_pair_validation` | Skip pairlist validation on startup.<br>*Defaults to `false`<br> **Datatype:** Boolean
| `exchange.skip_open_order_update` | Skips open order updates on startup should the exchange cause problems. Only relevant in live conditions.<br>*Defaults to `false`<br> **Datatype:** Boolean | `exchange.skip_open_order_update` | Skips open order updates on startup should the exchange cause problems. Only relevant in live conditions.<br>*Defaults to `false`<br> **Datatype:** Boolean
| `exchange.unknown_fee_rate` | Fallback value to use when calculating trading fees. This can be useful for exchanges which have fees in non-tradable currencies. The value provided here will be multiplied with the "fee cost".<br>*Defaults to `None`<br> **Datatype:** float
| `exchange.log_responses` | Log relevant exchange responses. For debug mode only - use with care.<br>*Defaults to `false`<br> **Datatype:** Boolean | `exchange.log_responses` | Log relevant exchange responses. For debug mode only - use with care.<br>*Defaults to `false`<br> **Datatype:** Boolean
| `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation. | `edge.*` | Please refer to [edge configuration document](edge.md) for detailed explanation.
| `experimental.block_bad_exchanges` | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now. <br>*Defaults to `true`.* <br> **Datatype:** Boolean | `experimental.block_bad_exchanges` | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now. <br>*Defaults to `true`.* <br> **Datatype:** Boolean
@@ -192,9 +204,8 @@ There are several methods to configure how much of the stake currency the bot wi
#### Minimum trade stake #### Minimum trade stake
The minimum stake amount will depend on exchange and pair and is usually listed in the exchange support pages. The minimum stake amount will depend on exchange and pair and is usually listed in the exchange support pages.
Assuming the minimum tradable amount for XRP/USD is 20 XRP (given by the exchange), and the price is 0.6$.
The minimum stake amount to buy this pair is, therefore, `20 * 0.6 ~= 12`. Assuming the minimum tradable amount for XRP/USD is 20 XRP (given by the exchange), and the price is 0.6$, the minimum stake amount to buy this pair is `20 * 0.6 ~= 12`.
This exchange has also a limit on USD - where all orders must be > 10$ - which however does not apply in this case. This exchange has also a limit on USD - where all orders must be > 10$ - which however does not apply in this case.
To guarantee safe execution, freqtrade will not allow buying with a stake-amount of 10.1$, instead, it'll make sure that there's enough space to place a stoploss below the pair (+ an offset, defined by `amount_reserve_percent`, which defaults to 5%). To guarantee safe execution, freqtrade will not allow buying with a stake-amount of 10.1$, instead, it'll make sure that there's enough space to place a stoploss below the pair (+ an offset, defined by `amount_reserve_percent`, which defaults to 5%).
@@ -204,7 +215,7 @@ With a reserve of 5%, the minimum stake amount would be ~12.6$ (`12 * (1 + 0.05)
To limit this calculation in case of large stoploss values, the calculated minimum stake-limit will never be more than 50% above the real limit. To limit this calculation in case of large stoploss values, the calculated minimum stake-limit will never be more than 50% above the real limit.
!!! Warning !!! Warning
Since the limits on exchanges are usually stable and are not updated often, some pairs can show pretty high minimum limits, simply because the price increased a lot since the last limit adjustment by the exchange. Since the limits on exchanges are usually stable and are not updated often, some pairs can show pretty high minimum limits, simply because the price increased a lot since the last limit adjustment by the exchange. Freqtrade adjusts the stake-amount to this value, unless it's > 30% more than the calculated/desired stake-amount - in which case the trade is rejected.
#### Tradable balance #### Tradable balance
@@ -444,47 +455,8 @@ The possible values are: `gtc` (default), `fok` or `ioc`.
``` ```
!!! Warning !!! Warning
This is ongoing work. For now, it is supported only for binance. This is ongoing work. For now, it is supported only for binance and kucoin.
Please don't change the default value unless you know what you are doing and have researched the impact of using different values. Please don't change the default value unless you know what you are doing and have researched the impact of using different values for your particular exchange.
### Exchange configuration
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports over 100 cryptocurrency
exchange markets and trading APIs. The complete up-to-date list can be found in the
[CCXT repo homepage](https://github.com/ccxt/ccxt/tree/master/python).
However, the bot was tested by the development team with only Bittrex, Binance and Kraken,
so these are the only officially supported exchanges:
- [Bittrex](https://bittrex.com/): "bittrex"
- [Binance](https://www.binance.com/): "binance"
- [Kraken](https://kraken.com/): "kraken"
Feel free to test other exchanges and submit your PR to improve the bot.
Some exchanges require special configuration, which can be found on the [Exchange-specific Notes](exchanges.md) documentation page.
#### Sample exchange configuration
A exchange configuration for "binance" would look as follows:
```json
"exchange": {
"name": "binance",
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"ccxt_config": {"enableRateLimit": true},
"ccxt_async_config": {
"enableRateLimit": true,
"rateLimit": 200
},
```
This configuration enables binance, as well as rate-limiting to avoid bans from the exchange.
`"rateLimit": 200` defines a wait-event of 0.2s between each call. This can also be completely disabled by setting `"enableRateLimit"` to false.
!!! Note
Optimal settings for rate-limiting depend on the exchange and the size of the whitelist, so an ideal parameter will vary on many other settings.
We try to provide sensible defaults per exchange where possible, if you encounter bans please make sure that `"enableRateLimit"` is enabled and increase the `"rateLimit"` parameter step by step.
### What values can be used for fiat_display_currency? ### What values can be used for fiat_display_currency?

View File

@@ -11,7 +11,7 @@ Otherwise `--exchange` becomes mandatory.
You can use a relative timerange (`--days 20`) or an absolute starting point (`--timerange 20200101-`). For incremental downloads, the relative approach should be used. You can use a relative timerange (`--days 20`) or an absolute starting point (`--timerange 20200101-`). For incremental downloads, the relative approach should be used.
!!! Tip "Tip: Updating existing data" !!! Tip "Tip: Updating existing data"
If you already have backtesting data available in your data-directory and would like to refresh this data up to today, do not use `--days` or `--timerange` parameters. Freqtrade will keep the available data and only download the missing data. If you already have backtesting data available in your data-directory and would like to refresh this data up to today, freqtrade will automatically calculate the data missing for the existing pairs and the download will occur from the latest available point until "now", neither --days or --timerange parameters are required. Freqtrade will keep the available data and only download the missing data.
If you are updating existing data after inserting new pairs that you have no data for, use `--new-pairs-days xx` parameter. Specified number of days will be downloaded for new pairs while old pairs will be updated with missing data only. If you are updating existing data after inserting new pairs that you have no data for, use `--new-pairs-days xx` parameter. Specified number of days will be downloaded for new pairs while old pairs will be updated with missing data only.
If you use `--days xx` parameter alone - data for specified number of days will be downloaded for _all_ pairs. Be careful, if specified number of days is smaller than gap between now and last downloaded candle - freqtrade will delete all existing data to avoid gaps in candle data. If you use `--days xx` parameter alone - data for specified number of days will be downloaded for _all_ pairs. Be careful, if specified number of days is smaller than gap between now and last downloaded candle - freqtrade will delete all existing data to avoid gaps in candle data.
@@ -22,6 +22,7 @@ usage: freqtrade download-data [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH] [-d PATH] [--userdir PATH]
[-p PAIRS [PAIRS ...]] [--pairs-file FILE] [-p PAIRS [PAIRS ...]] [--pairs-file FILE]
[--days INT] [--new-pairs-days INT] [--days INT] [--new-pairs-days INT]
[--include-inactive-pairs]
[--timerange TIMERANGE] [--dl-trades] [--timerange TIMERANGE] [--dl-trades]
[--exchange EXCHANGE] [--exchange EXCHANGE]
[-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]] [-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]]
@@ -38,6 +39,8 @@ optional arguments:
--days INT Download data for given number of days. --days INT Download data for given number of days.
--new-pairs-days INT Download data of new pairs for given number of days. --new-pairs-days INT Download data of new pairs for given number of days.
Default: `None`. Default: `None`.
--include-inactive-pairs
Also download data from inactive pairs.
--timerange TIMERANGE --timerange TIMERANGE
Specify what timerange of data to use. Specify what timerange of data to use.
--dl-trades Download trades instead of OHLCV data. The bot will --dl-trades Download trades instead of OHLCV data. The bot will
@@ -52,10 +55,10 @@ optional arguments:
exchange/pairs/timeframes. exchange/pairs/timeframes.
--data-format-ohlcv {json,jsongz,hdf5} --data-format-ohlcv {json,jsongz,hdf5}
Storage format for downloaded candle (OHLCV) data. Storage format for downloaded candle (OHLCV) data.
(default: `None`). (default: `json`).
--data-format-trades {json,jsongz,hdf5} --data-format-trades {json,jsongz,hdf5}
Storage format for downloaded trades data. (default: Storage format for downloaded trades data. (default:
`None`). `jsongz`).
Common arguments: Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages). -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
@@ -80,6 +83,82 @@ Common arguments:
For that reason, `download-data` does not care about the "startup-period" defined in a strategy. It's up to the user to download additional days if the backtest should start at a specific point in time (while respecting startup period). For that reason, `download-data` does not care about the "startup-period" defined in a strategy. It's up to the user to download additional days if the backtest should start at a specific point in time (while respecting startup period).
### Pairs file
In alternative to the whitelist from `config.json`, a `pairs.json` file can be used.
If you are using Binance for example:
- create a directory `user_data/data/binance` and copy or create the `pairs.json` file in that directory.
- update the `pairs.json` file to contain the currency pairs you are interested in.
```bash
mkdir -p user_data/data/binance
touch user_data/data/binance/pairs.json
```
The format of the `pairs.json` file is a simple json list.
Mixing different stake-currencies is allowed for this file, since it's only used for downloading.
``` json
[
"ETH/BTC",
"ETH/USDT",
"BTC/USDT",
"XRP/ETH"
]
```
!!! Tip "Downloading all data for one quote currency"
Often, you'll want to download data for all pairs of a specific quote-currency. In such cases, you can use the following shorthand:
`freqtrade download-data --exchange binance --pairs .*/USDT <...>`. The provided "pairs" string will be expanded to contain all active pairs on the exchange.
To also download data for inactive (delisted) pairs, add `--include-inactive-pairs` to the command.
??? Note "Permission denied errors"
If your configuration directory `user_data` was made by docker, you may get the following error:
```
cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission denied
```
You can fix the permissions of your user-data directory as follows:
```
sudo chown -R $UID:$GID user_data
```
### Start download
Then run:
```bash
freqtrade download-data --exchange binance
```
This will download historical candle (OHLCV) data for all the currency pairs you defined in `pairs.json`.
Alternatively, specify the pairs directly
```bash
freqtrade download-data --exchange binance --pairs ETH/USDT XRP/USDT BTC/USDT
```
or as regex (to download all active USDT pairs)
```bash
freqtrade download-data --exchange binance --pairs .*/USDT
```
### Other Notes
- To use a different directory than the exchange specific default, use `--datadir user_data/data/some_directory`.
- To change the exchange used to download the historical data from, please use a different configuration file (you'll probably need to adjust rate limits etc.)
- To use `pairs.json` from some other directory, use `--pairs-file some_other_dir/pairs.json`.
- To download historical candle (OHLCV) data for only 10 days, use `--days 10` (defaults to 30 days).
- To download historical candle (OHLCV) data from a fixed starting point, use `--timerange 20200101-` - which will download all data from January 1st, 2020. Eventually set end dates are ignored.
- Use `--timeframes` to specify what timeframe download the historical candle (OHLCV) data for. Default is `--timeframes 1m 5m` which will download 1-minute and 5-minute data.
- To use exchange, timeframe and list of pairs as defined in your configuration file, use the `-c/--config` option. With this, the script uses the whitelist defined in the config as the list of currency pairs to download data for and does not require the pairs.json file. You can combine `-c/--config` with most other options.
### Data format ### Data format
Freqtrade currently supports 3 data-formats for both OHLCV and trades data: Freqtrade currently supports 3 data-formats for both OHLCV and trades data:
@@ -204,6 +283,61 @@ It'll also remove original jsongz data files (`--erase` parameter).
freqtrade convert-trade-data --format-from jsongz --format-to json --datadir ~/.freqtrade/data/kraken --erase freqtrade convert-trade-data --format-from jsongz --format-to json --datadir ~/.freqtrade/data/kraken --erase
``` ```
### Sub-command trades to ohlcv
When you need to use `--dl-trades` (kraken only) to download data, conversion of trades data to ohlcv data is the last step.
This command will allow you to repeat this last step for additional timeframes without re-downloading the data.
```
usage: freqtrade trades-to-ohlcv [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[-p PAIRS [PAIRS ...]]
[-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]]
[--exchange EXCHANGE]
[--data-format-ohlcv {json,jsongz,hdf5}]
[--data-format-trades {json,jsongz,hdf5}]
optional arguments:
-h, --help show this help message and exit
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space-
separated.
-t {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...], --timeframes {1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} [{1m,3m,5m,15m,30m,1h,2h,4h,6h,8h,12h,1d,3d,1w,2w,1M,1y} ...]
Specify which tickers to download. Space-separated
list. Default: `1m 5m`.
--exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no
config is provided.
--data-format-ohlcv {json,jsongz,hdf5}
Storage format for downloaded candle (OHLCV) data.
(default: `json`).
--data-format-trades {json,jsongz,hdf5}
Storage format for downloaded trades data. (default:
`jsongz`).
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile 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
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
```
#### Example trade-to-ohlcv conversion
``` bash
freqtrade trades-to-ohlcv --exchange kraken -t 5m 1h 1d --pairs BTC/EUR ETH/EUR
```
### Sub-command list-data ### Sub-command list-data
You can get a list of downloaded data using the `list-data` sub-command. You can get a list of downloaded data using the `list-data` sub-command.
@@ -257,64 +391,6 @@ ETH/BTC 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d
ETH/USDT 5m, 15m, 30m, 1h, 2h, 4h ETH/USDT 5m, 15m, 30m, 1h, 2h, 4h
``` ```
### Pairs file
In alternative to the whitelist from `config.json`, a `pairs.json` file can be used.
If you are using Binance for example:
- create a directory `user_data/data/binance` and copy or create the `pairs.json` file in that directory.
- update the `pairs.json` file to contain the currency pairs you are interested in.
```bash
mkdir -p user_data/data/binance
cp tests/testdata/pairs.json user_data/data/binance
```
If your configuration directory `user_data` was made by docker, you may get the following error:
```
cp: cannot create regular file 'user_data/data/binance/pairs.json': Permission denied
```
You can fix the permissions of your user-data directory as follows:
```
sudo chown -R $UID:$GID user_data
```
The format of the `pairs.json` file is a simple json list.
Mixing different stake-currencies is allowed for this file, since it's only used for downloading.
``` json
[
"ETH/BTC",
"ETH/USDT",
"BTC/USDT",
"XRP/ETH"
]
```
### Start download
Then run:
```bash
freqtrade download-data --exchange binance
```
This will download historical candle (OHLCV) data for all the currency pairs you defined in `pairs.json`.
### Other Notes
- To use a different directory than the exchange specific default, use `--datadir user_data/data/some_directory`.
- To change the exchange used to download the historical data from, please use a different configuration file (you'll probably need to adjust rate limits etc.)
- To use `pairs.json` from some other directory, use `--pairs-file some_other_dir/pairs.json`.
- To download historical candle (OHLCV) data for only 10 days, use `--days 10` (defaults to 30 days).
- To download historical candle (OHLCV) data from a fixed starting point, use `--timerange 20200101-` - which will download all data from January 1st, 2020. Eventually set end dates are ignored.
- Use `--timeframes` to specify what timeframe download the historical candle (OHLCV) data for. Default is `--timeframes 1m 5m` which will download 1-minute and 5-minute data.
- To use exchange, timeframe and list of pairs as defined in your configuration file, use the `-c/--config` option. With this, the script uses the whitelist defined in the config as the list of currency pairs to download data for and does not require the pairs.json file. You can combine `-c/--config` with most other options.
### Trades (tick) data ### Trades (tick) data
By default, `download-data` sub-command downloads Candles (OHLCV) data. Some exchanges also provide historic trade-data via their API. By default, `download-data` sub-command downloads Candles (OHLCV) data. Some exchanges also provide historic trade-data via their API.

View File

@@ -38,3 +38,8 @@ Since only quoteVolume can be compared between assets, the other options (bidVol
Using `order_book_min` and `order_book_max` used to allow stepping the orderbook and trying to find the next ROI slot - trying to place sell-orders early. Using `order_book_min` and `order_book_max` used to allow stepping the orderbook and trying to find the next ROI slot - trying to place sell-orders early.
As this does however increase risk and provides no benefit, it's been removed for maintainability purposes in 2021.7. As this does however increase risk and provides no benefit, it's been removed for maintainability purposes in 2021.7.
### Legacy Hyperopt mode
Using separate hyperopt files was deprecated in 2021.4 and was removed in 2021.9.
Please switch to the new [Parametrized Strategies](hyperopt.md) to benefit from the new hyperopt interface.

View File

@@ -8,7 +8,7 @@ All contributions, bug reports, bug fixes, documentation improvements, enhanceme
Documentation is available at [https://freqtrade.io](https://www.freqtrade.io/) and needs to be provided with every new feature PR. Documentation is available at [https://freqtrade.io](https://www.freqtrade.io/) and needs to be provided with every new feature PR.
Special fields for the documentation (like Note boxes, ...) can be found [here](https://squidfunk.github.io/mkdocs-material/extensions/admonition/). Special fields for the documentation (like Note boxes, ...) can be found [here](https://squidfunk.github.io/mkdocs-material/reference/admonitions/).
To test the documentation locally use the following commands. To test the documentation locally use the following commands.
@@ -26,6 +26,8 @@ Alternatively (e.g. if your system is not supported by the setup.sh script), fol
This will install all required tools for development, including `pytest`, `flake8`, `mypy`, and `coveralls`. This will install all required tools for development, including `pytest`, `flake8`, `mypy`, and `coveralls`.
Before opening a pull request, please familiarize yourself with our [Contributing Guidelines](https://github.com/freqtrade/freqtrade/blob/develop/CONTRIBUTING.md).
### Devcontainer setup ### Devcontainer setup
The fastest and easiest way to get started is to use [VSCode](https://code.visualstudio.com/) with the Remote container extension. The fastest and easiest way to get started is to use [VSCode](https://code.visualstudio.com/) with the Remote container extension.
@@ -250,7 +252,23 @@ Most exchanges supported by CCXT should work out of the box.
To quickly test the public endpoints of an exchange, add a configuration for your exchange to `test_ccxt_compat.py` and run these tests with `pytest --longrun tests/exchange/test_ccxt_compat.py`. To quickly test the public endpoints of an exchange, add a configuration for your exchange to `test_ccxt_compat.py` and run these tests with `pytest --longrun tests/exchange/test_ccxt_compat.py`.
Completing these tests successfully a good basis point (it's a requirement, actually), however these won't guarantee correct exchange functioning, as this only tests public endpoints, but no private endpoint (like generate order or similar). Completing these tests successfully a good basis point (it's a requirement, actually), however these won't guarantee correct exchange functioning, as this only tests public endpoints, but no private endpoint (like generate order or similar).
Also try to use `freqtrade download-data` for an extended timerange and verify that the data downloaded correctly (no holes, the specified timerange was actually downloaded). Also try to use `freqtrade download-data` for an extended timerange (multiple months) and verify that the data downloaded correctly (no holes, the specified timerange was actually downloaded).
These are prerequisites to have an exchange listed as either Supported or Community tested (listed on the homepage).
The below are "extras", which will make an exchange better (feature-complete) - but are not absolutely necessary for either of the 2 categories.
Additional tests / steps to complete:
* Verify data provided by `fetch_ohlcv()` - and eventually adjust `ohlcv_candle_limit` for this exchange
* Check L2 orderbook limit range (API documentation) - and eventually set as necessary
* Check if balance shows correctly (*)
* Create market order (*)
* Create limit order (*)
* Complete trade (buy + sell) (*)
* Compare result calculation between exchange and bot
* Ensure fees are applied correctly (check the database against the exchange)
(*) Requires API keys and Balance on the exchange.
### Stoploss On Exchange ### Stoploss On Exchange
@@ -306,9 +324,8 @@ jupyter nbconvert --ClearOutputPreprocessor.enabled=True --to markdown freqtrade
This documents some decisions taken for the CI Pipeline. This documents some decisions taken for the CI Pipeline.
* CI runs on all OS variants, Linux (ubuntu), macOS and Windows. * CI runs on all OS variants, Linux (ubuntu), macOS and Windows.
* Docker images are build for the branches `stable` and `develop`. * Docker images are build for the branches `stable` and `develop`, and are built as multiarch builds, supporting multiple platforms via the same tag.
* Docker images containing Plot dependencies are also available as `stable_plot` and `develop_plot`. * Docker images containing Plot dependencies are also available as `stable_plot` and `develop_plot`.
* Raspberry PI Docker images are postfixed with `_pi` - so tags will be `:stable_pi` and `develop_pi`.
* Docker images contain a file, `/freqtrade/freqtrade_commit` containing the commit this image is based of. * Docker images contain a file, `/freqtrade/freqtrade_commit` containing the commit this image is based of.
* Full docker image rebuilds are run once a week via schedule. * Full docker image rebuilds are run once a week via schedule.
* Deployments run on ubuntu. * Deployments run on ubuntu.

View File

@@ -70,6 +70,18 @@ docker-compose up -d
!!! Warning "Default configuration" !!! Warning "Default configuration"
While the configuration generated will be mostly functional, you will still need to verify that all options correspond to what you want (like Pricing, pairlist, ...) before starting the bot. While the configuration generated will be mostly functional, you will still need to verify that all options correspond to what you want (like Pricing, pairlist, ...) before starting the bot.
#### Accessing the UI
If you've selected to enable FreqUI in the `new-config` step, you will have freqUI available at port `localhost:8080`.
You can now access the UI by typing localhost:8080 in your browser.
??? Note "UI Access on a remote servers"
If you're running on a VPS, you should consider using either a ssh tunnel, or setup a VPN (openVPN, wireguard) to connect to your bot.
This will ensure that freqUI is not directly exposed to the internet, which is not recommended for security reasons (freqUI does not support https out of the box).
Setup of these tools is not part of this tutorial, however many good tutorials can be found on the internet.
Please also read the [API configuration with docker](rest-api.md#configuration-with-docker) section to learn more about this configuration.
#### Monitoring the bot #### Monitoring the bot
You can check for running instances with `docker-compose ps`. You can check for running instances with `docker-compose ps`.
@@ -109,6 +121,7 @@ All freqtrade arguments will be available by running `docker-compose run --rm fr
!!! Warning "`docker-compose` for trade commands" !!! Warning "`docker-compose` for trade commands"
Trade commands (`freqtrade trade <...>`) should not be ran via `docker-compose run` - but should use `docker-compose up -d` instead. Trade commands (`freqtrade trade <...>`) should not be ran via `docker-compose run` - but should use `docker-compose up -d` instead.
This makes sure that the container is properly started (including port forwardings) and will make sure that the container will restart after a system reboot. This makes sure that the container is properly started (including port forwardings) and will make sure that the container will restart after a system reboot.
If you intend to use freqUI, please also ensure to adjust the [configuration accordingly](rest-api.md#configuration-with-docker), otherwise the UI will not be available.
!!! Note "`docker-compose run --rm`" !!! Note "`docker-compose run --rm`"
Including `--rm` will remove the container after completion, and is highly recommended for all modes except trading mode (running with `freqtrade trade` command). Including `--rm` will remove the container after completion, and is highly recommended for all modes except trading mode (running with `freqtrade trade` command).
@@ -147,9 +160,9 @@ You'll then also need to modify the `docker-compose.yml` file and uncomment the
dockerfile: "./Dockerfile.<yourextension>" dockerfile: "./Dockerfile.<yourextension>"
``` ```
You can then run `docker-compose build` to build the docker image, and run it using the commands described above. You can then run `docker-compose build --pull` to build the docker image, and run it using the commands described above.
## Plotting with docker-compose ### Plotting with docker-compose
Commands `freqtrade plot-profit` and `freqtrade plot-dataframe` ([Documentation](plotting.md)) are available by changing the image to `*_plot` in your docker-compose.yml file. Commands `freqtrade plot-profit` and `freqtrade plot-dataframe` ([Documentation](plotting.md)) are available by changing the image to `*_plot` in your docker-compose.yml file.
You can then use these commands as follows: You can then use these commands as follows:
@@ -160,7 +173,7 @@ docker-compose run --rm freqtrade plot-dataframe --strategy AwesomeStrategy -p B
The output will be stored in the `user_data/plot` directory, and can be opened with any modern browser. The output will be stored in the `user_data/plot` directory, and can be opened with any modern browser.
## Data analysis using docker compose ### Data analysis using docker compose
Freqtrade provides a docker-compose file which starts up a jupyter lab server. Freqtrade provides a docker-compose file which starts up a jupyter lab server.
You can run this server using the following command: You can run this server using the following command:
@@ -177,3 +190,22 @@ Since part of this image is built on your machine, it is recommended to rebuild
``` bash ``` bash
docker-compose -f docker/docker-compose-jupyter.yml build --no-cache docker-compose -f docker/docker-compose-jupyter.yml build --no-cache
``` ```
## Troubleshooting
### Docker on Windows
* Error: `"Timestamp for this request is outside of the recvWindow."`
* The market api requests require a synchronized clock but the time in the docker container shifts a bit over time into the past.
To fix this issue temporarily you need to run `wsl --shutdown` and restart docker again (a popup on windows 10 will ask you to do so).
A permanent solution is either to host the docker container on a linux host or restart the wsl from time to time with the scheduler.
``` bash
taskkill /IM "Docker Desktop.exe" /F
wsl --shutdown
start "" "C:\Program Files\Docker\Docker\Docker Desktop.exe"
```
!!! Warning
Due to the above, we do not recommend the usage of docker on windows for production setups, but only for experimentation, datadownload and backtesting.
Best use a linux-VPS for running freqtrade reliably.

View File

@@ -3,7 +3,7 @@
The `Edge Positioning` module uses probability to calculate your win rate and risk reward ratio. It will use these statistics to control your strategy trade entry points, position size and, stoploss. The `Edge Positioning` module uses probability to calculate your win rate and risk reward ratio. It will use these statistics to control your strategy trade entry points, position size and, stoploss.
!!! Warning !!! Warning
WHen using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data. When using `Edge positioning` with a dynamic whitelist (VolumePairList), make sure to also use `AgeFilter` and set it to at least `calculate_since_number_of_days` to avoid problems with missing data.
!!! Note !!! Note
`Edge Positioning` only considers *its own* buy/sell/stoploss signals. It ignores the stoploss, trailing stoploss, and ROI settings in the strategy configuration file. `Edge Positioning` only considers *its own* buy/sell/stoploss signals. It ignores the stoploss, trailing stoploss, and ROI settings in the strategy configuration file.

View File

@@ -2,8 +2,60 @@
This page combines common gotchas and informations which are exchange-specific and most likely don't apply to other exchanges. This page combines common gotchas and informations which are exchange-specific and most likely don't apply to other exchanges.
## Exchange configuration
Freqtrade is based on [CCXT library](https://github.com/ccxt/ccxt) that supports over 100 cryptocurrency
exchange markets and trading APIs. The complete up-to-date list can be found in the
[CCXT repo homepage](https://github.com/ccxt/ccxt/tree/master/python).
However, the bot was tested by the development team with only a few exchanges.
A current list of these can be found in the "Home" section of this documentation.
Feel free to test other exchanges and submit your feedback or PR to improve the bot or confirm exchanges that work flawlessly..
Some exchanges require special configuration, which can be found below.
### Sample exchange configuration
A exchange configuration for "binance" would look as follows:
```json
"exchange": {
"name": "binance",
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"ccxt_config": {},
"ccxt_async_config": {},
// ...
```
### Setting rate limits
Usually, rate limits set by CCXT are reliable and work well.
In case of problems related to rate-limits (usually DDOS Exceptions in your logs), it's easy to change rateLimit settings to other values.
```json
"exchange": {
"name": "kraken",
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"ccxt_config": {"enableRateLimit": true},
"ccxt_async_config": {
"enableRateLimit": true,
"rateLimit": 3100
},
```
This configuration enables kraken, as well as rate-limiting to avoid bans from the exchange.
`"rateLimit": 3100` defines a wait-event of 3.1s between each call. This can also be completely disabled by setting `"enableRateLimit"` to false.
!!! Note
Optimal settings for rate-limiting depend on the exchange and the size of the whitelist, so an ideal parameter will vary on many other settings.
We try to provide sensible defaults per exchange where possible, if you encounter bans please make sure that `"enableRateLimit"` is enabled and increase the `"rateLimit"` parameter step by step.
## Binance ## Binance
Binance supports [time_in_force](configuration.md#understand-order_time_in_force).
!!! Tip "Stoploss on Exchange" !!! Tip "Stoploss on Exchange"
Binance supports `stoploss_on_exchange` and uses stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it. Binance supports `stoploss_on_exchange` and uses stop-loss-limit orders. It provides great advantages, so we recommend to benefit from it.
@@ -56,6 +108,12 @@ Bittrex does not support market orders. If you have a message at the bot startup
Bittrex also does not support `VolumePairlist` due to limited / split API constellation at the moment. Bittrex also does not support `VolumePairlist` due to limited / split API constellation at the moment.
Please use `StaticPairlist`. Other pairlists (other than `VolumePairlist`) should not be affected. Please use `StaticPairlist`. Other pairlists (other than `VolumePairlist`) should not be affected.
### Volume pairlist
Bittrex does not support the direct usage of VolumePairList. This can however be worked around by using the advanced mode with `lookback_days: 1` (or more), which will emulate 24h volume.
Read more in the [pairlist documentation](plugins.md#volumepairlist-advanced-mode).
### Restricted markets ### Restricted markets
Bittrex split its exchange into US and International versions. Bittrex split its exchange into US and International versions.
@@ -113,13 +171,39 @@ Kucoin requires a passphrase for each api key, you will therefore need to add th
"key": "your_exchange_key", "key": "your_exchange_key",
"secret": "your_exchange_secret", "secret": "your_exchange_secret",
"password": "your_exchange_api_key_password", "password": "your_exchange_api_key_password",
// ...
}
``` ```
Kucoin supports [time_in_force](configuration.md#understand-order_time_in_force).
### Kucoin Blacklists ### Kucoin Blacklists
For Kucoin, please add `"KCS/<STAKE>"` to your blacklist to avoid issues. For Kucoin, please add `"KCS/<STAKE>"` to your blacklist to avoid issues.
Accounts having KCS accounts use this to pay for fees - if your first trade happens to be on `KCS`, further trades will consume this position and make the initial KCS trade unsellable as the expected amount is not there anymore. Accounts having KCS accounts use this to pay for fees - if your first trade happens to be on `KCS`, further trades will consume this position and make the initial KCS trade unsellable as the expected amount is not there anymore.
## OKEX
OKEX requires a passphrase for each api key, you will therefore need to add this key into the configuration so your exchange section looks as follows:
```json
"exchange": {
"name": "okex",
"key": "your_exchange_key",
"secret": "your_exchange_secret",
"password": "your_exchange_api_key_password",
// ...
}
```
!!! Warning
OKEX only provides 100 candles per api call. Therefore, the strategy will only have a pretty low amount of data available in backtesting mode.
## Gate.io
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.
## All exchanges ## 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. 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.
@@ -158,6 +242,8 @@ For example, to test the order type `FOK` with Kraken, and modify candle limit t
"order_time_in_force": ["gtc", "fok"], "order_time_in_force": ["gtc", "fok"],
"ohlcv_candle_limit": 200 "ohlcv_candle_limit": 200
} }
//...
}
``` ```
!!! Warning !!! Warning

View File

@@ -42,7 +42,7 @@ position for a trade. Be patient!
### I have made 12 trades already, why is my total profit negative? ### I have made 12 trades already, why is my total profit negative?
I understand your disappointment but unfortunately 12 trades is just I understand your disappointment but unfortunately 12 trades is just
not enough to say anything. If you run backtesting, you can see that our not enough to say anything. If you run backtesting, you can see that the
current algorithm does leave you on the plus side, but that is after current algorithm does leave you on the plus side, but that is after
thousands of trades and even there, you will be left with losses on thousands of trades and even there, you will be left with losses on
specific coins that you have traded tens if not hundreds of times. We specific coins that you have traded tens if not hundreds of times. We
@@ -54,9 +54,26 @@ you can't say much from few trades.
Yes. You can edit your config and use the `/reload_config` command to reload the configuration. The bot will stop, reload the configuration and strategy and will restart with the new configuration and strategy. Yes. You can edit your config and use the `/reload_config` command to reload the configuration. The bot will stop, reload the configuration and strategy and will restart with the new configuration and strategy.
### I want to improve the bot with a new strategy ### Why does my bot not sell everything it bought?
That's great. We have a nice backtesting and hyperoptimization setup. See the tutorial [here|Testing-new-strategies-with-Hyperopt](bot-usage.md#hyperopt-commands). This is called "coin dust" and can happen on all exchanges.
It happens because many exchanges subtract fees from the "receiving currency" - so you buy 100 COIN - but you only get 99.9 COIN.
As COIN is trading in full lot sizes (1COIN steps), you cannot sell 0.9 COIN (or 99.9 COIN) - but you need to round down to 99 COIN.
This is not a bot-problem, but will also happen while manual trading.
While freqtrade can handle this (it'll sell 99 COIN), fees are often below the minimum tradable lot-size (you can only trade full COIN, not 0.9 COIN).
Leaving the dust (0.9 COIN) on the exchange makes usually sense, as the next time freqtrade buys COIN, it'll eat into the remaining small balance, this time selling everything it bought, and therefore slowly declining the dust balance (although it most likely will never reach exactly 0).
Where possible (e.g. on binance), the use of the exchange's dedicated fee currency will fix this.
On binance, it's sufficient to have BNB in your account, and have "Pay fees in BNB" enabled in your profile. Your BNB balance will slowly decline (as it's used to pay fees) - but you'll no longer encounter dust (Freqtrade will include the fees in the profit calculations).
Other exchanges don't offer such possibilities, where it's simply something you'll have to accept or move to a different exchange.
### I want to use incomplete candles
Freqtrade will not provide incomplete candles to strategies. Using incomplete candles will lead to repainting and consequently to strategies with "ghost" buys, which are impossible to both backtest, and verify after they happened.
You can use "current" market data by using the [dataprovider](strategy-customization.md#orderbookpair-maximum)'s orderbook or ticker methods - which however cannot be used during backtesting.
### Is there a setting to only SELL the coins being held and not perform anymore BUYS? ### Is there a setting to only SELL the coins being held and not perform anymore BUYS?
@@ -76,17 +93,29 @@ If this happens for all pairs in the pairlist, this might indicate a recent exch
Irrespectively of the reason, Freqtrade will fill up these candles with "empty" candles, where open, high, low and close are set to the previous candle close - and volume is empty. In a chart, this will look like a `_` - and is aligned with how exchanges usually represent 0 volume candles. Irrespectively of the reason, Freqtrade will fill up these candles with "empty" candles, where open, high, low and close are set to the previous candle close - and volume is empty. In a chart, this will look like a `_` - and is aligned with how exchanges usually represent 0 volume candles.
### I'm getting "Outdated history for pair xxx" in the log
The bot is trying to tell you that it got an outdated last candle (not the last complete candle).
As a consequence, Freqtrade will not enter a trade for this pair - as trading on old information is usually not what is desired.
This warning can point to one of the below problems:
* Exchange downtime -> Check your exchange status page / blog / twitter feed for details.
* Wrong system time -> Ensure your system-time is correct.
* Barely traded pair -> Check the pair on the exchange webpage, look at the timeframe your strategy uses. If the pair does not have any volume in some candles (usually visualized with a "volume 0" bar, and a "_" as candle), this pair did not have any trades in this timeframe. These pairs should ideally be avoided, as they can cause problems with order-filling.
* API problem -> API returns wrong data (this only here for completeness, and should not happen with supported exchanges).
### I'm getting the "RESTRICTED_MARKET" message in the log ### I'm getting the "RESTRICTED_MARKET" message in the log
Currently known to happen for US Bittrex users. Currently known to happen for US Bittrex users.
Read [the Bittrex section about restricted markets](exchanges.md#restricted-markets) for more information. Read [the Bittrex section about restricted markets](exchanges.md#restricted-markets) for more information.
### I'm getting the "Exchange Bittrex does not support market orders." message and cannot run my strategy ### I'm getting the "Exchange XXX does not support market orders." message and cannot run my strategy
As the message says, Bittrex does not support market orders and you have one of the [order types](configuration.md/#understand-order_types) set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Bittrex). As the message says, your exchange does not support market orders and you have one of the [order types](configuration.md/#understand-order_types) set to "market". Your strategy was probably written with other exchanges in mind and sets "market" orders for "stoploss" orders, which is correct and preferable for most of the exchanges supporting market orders (but not for Bittrex and Gate.io).
To fix it for Bittrex, redefine order types in the strategy to use "limit" instead of "market": To fix this, redefine order types in the strategy to use "limit" instead of "market":
``` ```
order_types = { order_types = {
@@ -136,6 +165,8 @@ On Windows, the `--logfile` option is also supported by Freqtrade and you can us
> type \path\to\mylogfile.log | findstr "something" > type \path\to\mylogfile.log | findstr "something"
``` ```
## Hyperopt module
### Why does freqtrade not have GPU support? ### Why does freqtrade not have GPU support?
First of all, most indicator libraries don't have GPU support - as such, there would be little benefit for indicator calculations. First of all, most indicator libraries don't have GPU support - as such, there would be little benefit for indicator calculations.
@@ -152,8 +183,6 @@ The benefit of using GPU would therefore be pretty slim - and will not justify t
There is however nothing preventing you from using GPU-enabled indicators within your strategy if you think you must have this - you will however probably be disappointed by the slim gain that will give you (compared to the complexity). There is however nothing preventing you from using GPU-enabled indicators within your strategy if you think you must have this - you will however probably be disappointed by the slim gain that will give you (compared to the complexity).
## Hyperopt module
### How many epochs do I need to get a good Hyperopt result? ### How many epochs do I need to get a good Hyperopt result?
Per default Hyperopt called without the `-e`/`--epochs` command line option will only Per default Hyperopt called without the `-e`/`--epochs` command line option will only
@@ -167,7 +196,7 @@ Since hyperopt uses Bayesian search, running for too many epochs may not produce
It's therefore recommended to run between 500-1000 epochs over and over until you hit at least 10.000 epochs in total (or are satisfied with the result). You can best judge by looking at the results - if the bot keeps discovering better strategies, it's best to keep on going. It's therefore recommended to run between 500-1000 epochs over and over until you hit at least 10.000 epochs in total (or are satisfied with the result). You can best judge by looking at the results - if the bot keeps discovering better strategies, it's best to keep on going.
```bash ```bash
freqtrade hyperopt --hyperopt SampleHyperopt --hyperopt-loss SharpeHyperOptLossDaily --strategy SampleStrategy -e 1000 freqtrade hyperopt --hyperopt-loss SharpeHyperOptLossDaily --strategy SampleStrategy -e 1000
``` ```
### Why does it take a long time to run hyperopt? ### Why does it take a long time to run hyperopt?

View File

@@ -44,14 +44,14 @@ usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH]
[--data-format-ohlcv {json,jsongz,hdf5}] [--data-format-ohlcv {json,jsongz,hdf5}]
[--max-open-trades INT] [--max-open-trades INT]
[--stake-amount STAKE_AMOUNT] [--fee FLOAT] [--stake-amount STAKE_AMOUNT] [--fee FLOAT]
[-p PAIRS [PAIRS ...]] [--hyperopt NAME] [-p PAIRS [PAIRS ...]] [--hyperopt-path PATH]
[--hyperopt-path PATH] [--eps] [--dmmp] [--eps] [--dmmp] [--enable-protections]
[--enable-protections]
[--dry-run-wallet DRY_RUN_WALLET] [-e INT] [--dry-run-wallet DRY_RUN_WALLET] [-e INT]
[--spaces {all,buy,sell,roi,stoploss,trailing,protection,default} [{all,buy,sell,roi,stoploss,trailing,protection,default} ...]] [--spaces {all,buy,sell,roi,stoploss,trailing,protection,default} [{all,buy,sell,roi,stoploss,trailing,protection,default} ...]]
[--print-all] [--no-color] [--print-json] [-j JOBS] [--print-all] [--no-color] [--print-json] [-j JOBS]
[--random-state INT] [--min-trades INT] [--random-state INT] [--min-trades INT]
[--hyperopt-loss NAME] [--disable-param-export] [--hyperopt-loss NAME] [--disable-param-export]
[--ignore-missing-spaces]
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
@@ -61,7 +61,7 @@ optional arguments:
Specify what timerange of data to use. Specify what timerange of data to use.
--data-format-ohlcv {json,jsongz,hdf5} --data-format-ohlcv {json,jsongz,hdf5}
Storage format for downloaded candle (OHLCV) data. Storage format for downloaded candle (OHLCV) data.
(default: `None`). (default: `json`).
--max-open-trades INT --max-open-trades INT
Override the value of the `max_open_trades` Override the value of the `max_open_trades`
configuration setting. configuration setting.
@@ -73,10 +73,8 @@ optional arguments:
-p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...] -p PAIRS [PAIRS ...], --pairs PAIRS [PAIRS ...]
Limit command to these pairs. Pairs are space- Limit command to these pairs. Pairs are space-
separated. separated.
--hyperopt NAME Specify hyperopt class name which will be used by the --hyperopt-path PATH Specify additional lookup path for Hyperopt Loss
bot. functions.
--hyperopt-path PATH Specify additional lookup path for Hyperopt and
Hyperopt Loss functions.
--eps, --enable-position-stacking --eps, --enable-position-stacking
Allow buying the same pair multiple times (position Allow buying the same pair multiple times (position
stacking). stacking).
@@ -117,9 +115,13 @@ optional arguments:
Hyperopt-loss-functions are: Hyperopt-loss-functions are:
ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss, ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss,
SharpeHyperOptLoss, SharpeHyperOptLossDaily, SharpeHyperOptLoss, SharpeHyperOptLossDaily,
SortinoHyperOptLoss, SortinoHyperOptLossDaily SortinoHyperOptLoss, SortinoHyperOptLossDaily,
CalmarHyperOptLoss, MaxDrawDownHyperOptLoss
--disable-param-export --disable-param-export
Disable automatic hyperopt parameter export. Disable automatic hyperopt parameter export.
--ignore-missing-spaces, --ignore-unparameterized-spaces
Suppress errors for any requested Hyperopt spaces that
do not contain any parameters.
Common arguments: Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages). -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
@@ -456,7 +458,7 @@ class MyAwesomeStrategy(IStrategy):
"only_per_pair": False "only_per_pair": False
}) })
return protection return prot
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# ... # ...
@@ -515,12 +517,14 @@ This class should be in its own file within the `user_data/hyperopts/` directory
Currently, the following loss functions are builtin: Currently, the following loss functions are builtin:
* `ShortTradeDurHyperOptLoss` (default legacy Freqtrade hyperoptimization loss function) - Mostly for short trade duration and avoiding losses. * `ShortTradeDurHyperOptLoss` - (default legacy Freqtrade hyperoptimization loss function) - Mostly for short trade duration and avoiding losses.
* `OnlyProfitHyperOptLoss` (which takes only amount of profit into consideration) * `OnlyProfitHyperOptLoss` - takes only amount of profit into consideration.
* `SharpeHyperOptLoss` (optimizes Sharpe Ratio calculated on trade returns relative to standard deviation) * `SharpeHyperOptLoss` - optimizes Sharpe Ratio calculated on trade returns relative to standard deviation.
* `SharpeHyperOptLossDaily` (optimizes Sharpe Ratio calculated on **daily** trade returns relative to standard deviation) * `SharpeHyperOptLossDaily` - optimizes Sharpe Ratio calculated on **daily** trade returns relative to standard deviation.
* `SortinoHyperOptLoss` (optimizes Sortino Ratio calculated on trade returns relative to **downside** standard deviation) * `SortinoHyperOptLoss` - optimizes Sortino Ratio calculated on trade returns relative to **downside** standard deviation.
* `SortinoHyperOptLossDaily` (optimizes Sortino Ratio calculated on **daily** trade returns relative to **downside** standard deviation) * `SortinoHyperOptLossDaily` - optimizes Sortino Ratio calculated on **daily** trade returns relative to **downside** standard deviation.
* `MaxDrawDownHyperOptLoss` - Optimizes Maximum drawdown.
* `CalmarHyperOptLoss` - Optimizes Calmar Ratio calculated on trade returns relative to max drawdown.
Creation of a custom loss function is covered in the [Advanced Hyperopt](advanced-hyperopt.md) part of the documentation. Creation of a custom loss function is covered in the [Advanced Hyperopt](advanced-hyperopt.md) part of the documentation.
@@ -558,7 +562,7 @@ For example, to use one month of data, pass `--timerange 20210101-20210201` (fro
Full command: Full command:
```bash ```bash
freqtrade hyperopt --hyperopt <hyperoptname> --strategy <strategyname> --timerange 20210101-20210201 freqtrade hyperopt --strategy <strategyname> --timerange 20210101-20210201
``` ```
### Running Hyperopt with Smaller Search Space ### Running Hyperopt with Smaller Search Space
@@ -680,11 +684,11 @@ If you are optimizing ROI, Freqtrade creates the 'roi' optimization hyperspace f
These ranges should be sufficient in most cases. The minutes in the steps (ROI dict keys) are scaled linearly depending on the timeframe used. The ROI values in the steps (ROI dict values) are scaled logarithmically depending on the timeframe used. These ranges should be sufficient in most cases. The minutes in the steps (ROI dict keys) are scaled linearly depending on the timeframe used. The ROI values in the steps (ROI dict values) are scaled logarithmically depending on the timeframe used.
If you have the `generate_roi_table()` and `roi_space()` methods in your custom hyperopt file, remove them in order to utilize these adaptive ROI tables and the ROI hyperoptimization space generated by Freqtrade by default. If you have the `generate_roi_table()` and `roi_space()` methods in your custom hyperopt, remove them in order to utilize these adaptive ROI tables and the ROI hyperoptimization space generated by Freqtrade by default.
Override the `roi_space()` method if you need components of the ROI tables to vary in other ranges. Override the `generate_roi_table()` and `roi_space()` methods and implement your own custom approach for generation of the ROI tables during hyperoptimization if you need a different structure of the ROI tables or other amount of rows (steps). Override the `roi_space()` method if you need components of the ROI tables to vary in other ranges. Override the `generate_roi_table()` and `roi_space()` methods and implement your own custom approach for generation of the ROI tables during hyperoptimization if you need a different structure of the ROI tables or other amount of rows (steps).
A sample for these methods can be found in [sample_hyperopt_advanced.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_advanced.py). A sample for these methods can be found in the [overriding pre-defined spaces section](advanced-hyperopt.md#overriding-pre-defined-spaces).
!!! Note "Reduced search space" !!! Note "Reduced search space"
To limit the search space further, Decimals are limited to 3 decimal places (a precision of 0.001). This is usually sufficient, every value more precise than this will usually result in overfitted results. You can however [overriding pre-defined spaces](advanced-hyperopt.md#pverriding-pre-defined-spaces) to change this to your needs. To limit the search space further, Decimals are limited to 3 decimal places (a precision of 0.001). This is usually sufficient, every value more precise than this will usually result in overfitted results. You can however [overriding pre-defined spaces](advanced-hyperopt.md#pverriding-pre-defined-spaces) to change this to your needs.
@@ -726,7 +730,7 @@ If you are optimizing stoploss values, Freqtrade creates the 'stoploss' optimiza
If you have the `stoploss_space()` method in your custom hyperopt file, remove it in order to utilize Stoploss hyperoptimization space generated by Freqtrade by default. If you have the `stoploss_space()` method in your custom hyperopt file, remove it in order to utilize Stoploss hyperoptimization space generated by Freqtrade by default.
Override the `stoploss_space()` method and define the desired range in it if you need stoploss values to vary in other range during hyperoptimization. A sample for this method can be found in [user_data/hyperopts/sample_hyperopt_advanced.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_advanced.py). Override the `stoploss_space()` method and define the desired range in it if you need stoploss values to vary in other range during hyperoptimization. A sample for this method can be found in the [overriding pre-defined spaces section](advanced-hyperopt.md#overriding-pre-defined-spaces).
!!! Note "Reduced search space" !!! Note "Reduced search space"
To limit the search space further, Decimals are limited to 3 decimal places (a precision of 0.001). This is usually sufficient, every value more precise than this will usually result in overfitted results. You can however [overriding pre-defined spaces](advanced-hyperopt.md#pverriding-pre-defined-spaces) to change this to your needs. To limit the search space further, Decimals are limited to 3 decimal places (a precision of 0.001). This is usually sufficient, every value more precise than this will usually result in overfitted results. You can however [overriding pre-defined spaces](advanced-hyperopt.md#pverriding-pre-defined-spaces) to change this to your needs.
@@ -764,10 +768,10 @@ As stated in the comment, you can also use it as the values of the corresponding
If you are optimizing trailing stop values, Freqtrade creates the 'trailing' optimization hyperspace for you. By default, the `trailing_stop` parameter is always set to True in that hyperspace, the value of the `trailing_only_offset_is_reached` vary between True and False, the values of the `trailing_stop_positive` and `trailing_stop_positive_offset` parameters vary in the ranges 0.02...0.35 and 0.01...0.1 correspondingly, which is sufficient in most cases. If you are optimizing trailing stop values, Freqtrade creates the 'trailing' optimization hyperspace for you. By default, the `trailing_stop` parameter is always set to True in that hyperspace, the value of the `trailing_only_offset_is_reached` vary between True and False, the values of the `trailing_stop_positive` and `trailing_stop_positive_offset` parameters vary in the ranges 0.02...0.35 and 0.01...0.1 correspondingly, which is sufficient in most cases.
Override the `trailing_space()` method and define the desired range in it if you need values of the trailing stop parameters to vary in other ranges during hyperoptimization. A sample for this method can be found in [user_data/hyperopts/sample_hyperopt_advanced.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_advanced.py). Override the `trailing_space()` method and define the desired range in it if you need values of the trailing stop parameters to vary in other ranges during hyperoptimization. A sample for this method can be found in the [overriding pre-defined spaces section](advanced-hyperopt.md#overriding-pre-defined-spaces).
!!! Note "Reduced search space" !!! Note "Reduced search space"
To limit the search space further, Decimals are limited to 3 decimal places (a precision of 0.001). This is usually sufficient, every value more precise than this will usually result in overfitted results. You can however [overriding pre-defined spaces](advanced-hyperopt.md#pverriding-pre-defined-spaces) to change this to your needs. To limit the search space further, Decimals are limited to 3 decimal places (a precision of 0.001). This is usually sufficient, every value more precise than this will usually result in overfitted results. You can however [overriding pre-defined spaces](advanced-hyperopt.md#overriding-pre-defined-spaces) to change this to your needs.
### Reproducible results ### Reproducible results
@@ -827,8 +831,8 @@ After you run Hyperopt for the desired amount of epochs, you can later list all
Once the optimized strategy has been implemented into your strategy, you should backtest this strategy to make sure everything is working as expected. Once the optimized strategy has been implemented into your strategy, you should backtest this strategy to make sure everything is working as expected.
To achieve same results (number of trades, their durations, profit, etc.) than during Hyperopt, please use same configuration and parameters (timerange, timeframe, ...) used for hyperopt `--dmmp`/`--disable-max-market-positions` and `--eps`/`--enable-position-stacking` for Backtesting. To achieve same the results (number of trades, their durations, profit, etc.) as during Hyperopt, please use the same configuration and parameters (timerange, timeframe, ...) used for hyperopt `--dmmp`/`--disable-max-market-positions` and `--eps`/`--enable-position-stacking` for Backtesting.
Should results don't match, please double-check to make sure you transferred all conditions correctly. Should results not match, please double-check to make sure you transferred all conditions correctly.
Pay special care to the stoploss (and trailing stoploss) parameters, as these are often set in configuration files, which override changes to the strategy. Pay special care to the stoploss (and trailing stoploss) parameters, as these are often set in configuration files, which override changes to the strategy.
You should also carefully review the log of your backtest to ensure that there were no parameters inadvertently set by the configuration (like `stoploss` or `trailing_stop`). You should also carefully review the log of your backtest to ensure that there were no parameters inadvertently set by the configuration (like `stoploss` or `trailing_stop`).

View File

@@ -52,6 +52,8 @@ To skip pair validation against active markets, set `"allow_inactive": true` wit
This can be useful for backtesting expired pairs (like quarterly spot-markets). This can be useful for backtesting expired pairs (like quarterly spot-markets).
This option must be configured along with `exchange.skip_pair_validation` in the exchange configuration. This option must be configured along with `exchange.skip_pair_validation` in the exchange configuration.
When used in a "follow-up" position (e.g. after VolumePairlist), all pairs in `'pair_whitelist'` will be added to the end of the pairlist.
#### Volume Pair List #### Volume Pair List
`VolumePairList` employs sorting/filtering of pairs by their trading volume. It selects `number_assets` top pairs with sorting based on the `sort_key` (which can only be `quoteVolume`). `VolumePairList` employs sorting/filtering of pairs by their trading volume. It selects `number_assets` top pairs with sorting based on the `sort_key` (which can only be `quoteVolume`).
@@ -82,6 +84,8 @@ Filtering instances (not the first position in the list) will not apply any cach
You can define a minimum volume with `min_value` - which will filter out pairs with a volume lower than the specified value in the specified timerange. You can define a minimum volume with `min_value` - which will filter out pairs with a volume lower than the specified value in the specified timerange.
### VolumePairList Advanced mode
`VolumePairList` can also operate in an advanced mode to build volume over a given timerange of specified candle size. It utilizes exchange historical candle data, builds a typical price (calculated by (open+high+low)/3) and multiplies the typical price with every candle's volume. The sum is the `quoteVolume` over the given range. This allows different scenarios, for a more smoothened volume, when using longer ranges with larger candle sizes, or the opposite when using a short range with small candles. `VolumePairList` can also operate in an advanced mode to build volume over a given timerange of specified candle size. It utilizes exchange historical candle data, builds a typical price (calculated by (open+high+low)/3) and multiplies the typical price with every candle's volume. The sum is the `quoteVolume` over the given range. This allows different scenarios, for a more smoothened volume, when using longer ranges with larger candle sizes, or the opposite when using a short range with small candles.
For convenience `lookback_days` can be specified, which will imply that 1d candles will be used for the lookback. In the example below the pairlist would be created based on the last 7 days: For convenience `lookback_days` can be specified, which will imply that 1d candles will be used for the lookback. In the example below the pairlist would be created based on the last 7 days:
@@ -105,6 +109,24 @@ For convenience `lookback_days` can be specified, which will imply that 1d candl
!!! Warning "Performance implications when using lookback range" !!! Warning "Performance implications when using lookback range"
If used in first position in combination with lookback, the computation of the range based volume can be time and resource consuming, as it downloads candles for all tradable pairs. Hence it's highly advised to use the standard approach with `VolumeFilter` to narrow the pairlist down for further range volume calculation. If used in first position in combination with lookback, the computation of the range based volume can be time and resource consuming, as it downloads candles for all tradable pairs. Hence it's highly advised to use the standard approach with `VolumeFilter` to narrow the pairlist down for further range volume calculation.
??? Tip "Unsupported exchanges (Bittrex, Gemini)"
On some exchanges (like Bittrex and Gemini), regular VolumePairList does not work as the api does not natively provide 24h volume. This can be worked around by using candle data to build the volume.
To roughly simulate 24h volume, you can use the following configuration.
Please note that These pairlists will only refresh once per day.
```json
"pairlists": [
{
"method": "VolumePairList",
"number_assets": 20,
"sort_key": "quoteVolume",
"min_value": 0,
"refresh_period": 86400,
"lookback_days": 1
}
],
```
More sophisticated approach can be used, by using `lookback_timeframe` for candle size and `lookback_period` which specifies the amount of candles. This example will build the volume pairs based on a rolling period of 3 days of 1h candles: More sophisticated approach can be used, by using `lookback_timeframe` for candle size and `lookback_period` which specifies the amount of candles. This example will build the volume pairs based on a rolling period of 3 days of 1h candles:
```json ```json
@@ -145,6 +167,7 @@ Example to remove the first 10 pairs from the pairlist:
```json ```json
"pairlists": [ "pairlists": [
// ...
{ {
"method": "OffsetFilter", "method": "OffsetFilter",
"offset": 10 "offset": 10
@@ -170,13 +193,36 @@ Sorts pairs by past trade performance, as follows:
Trade count is used as a tie breaker. Trade count is used as a tie breaker.
!!! Note You can use the `minutes` parameter to only consider performance of the past X minutes (rolling window).
Not defining this parameter (or setting it to 0) will use all-time performance.
The optional `min_profit` (as ratio -> a setting of `0.01` corresponds to 1%) parameter defines the minimum profit a pair must have to be considered.
Pairs below this level will be filtered out.
Using this parameter without `minutes` is highly discouraged, as it can lead to an empty pairlist without a way to recover.
```json
"pairlists": [
// ...
{
"method": "PerformanceFilter",
"minutes": 1440, // rolling 24h
"min_profit": 0.01 // minimal profit 1%
}
],
```
As this Filter uses past performance of the bot, it'll have some startup-period - and should only be used after the bot has a few 100 trades in the database.
!!! Warning "Backtesting"
`PerformanceFilter` does not support backtesting mode. `PerformanceFilter` does not support backtesting mode.
#### PrecisionFilter #### PrecisionFilter
Filters low-value coins which would not allow setting stoplosses. Filters low-value coins which would not allow setting stoplosses.
!!! Warning "Backtesting"
`PrecisionFilter` does not support backtesting mode using multiple strategies.
#### PriceFilter #### PriceFilter
The `PriceFilter` allows filtering of pairs by price. Currently the following price filters are supported: The `PriceFilter` allows filtering of pairs by price. Currently the following price filters are supported:
@@ -214,7 +260,7 @@ Min price precision for SHITCOIN/BTC is 8 decimals. If its price is 0.00000011 -
Shuffles (randomizes) pairs in the pairlist. It can be used for preventing the bot from trading some of the pairs more frequently then others when you want all pairs be treated with the same priority. Shuffles (randomizes) pairs in the pairlist. It can be used for preventing the bot from trading some of the pairs more frequently then others when you want all pairs be treated with the same priority.
!!! Tip !!! Tip
You may set the `seed` value for this Pairlist to obtain reproducible results, which can be useful for repeated backtesting sessions. If `seed` is not set, the pairs are shuffled in the non-repeatable random order. You may set the `seed` value for this Pairlist to obtain reproducible results, which can be useful for repeated backtesting sessions. If `seed` is not set, the pairs are shuffled in the non-repeatable random order. ShuffleFilter will automatically detect runmodes and apply the `seed` only for backtesting modes - if a `seed` value is set.
#### SpreadFilter #### SpreadFilter
@@ -249,7 +295,7 @@ If the trading range over the last 10 days is <1% or >99%, remove the pair from
#### VolatilityFilter #### VolatilityFilter
Volatility is the degree of historical variation of a pairs over time, is is measured by the standard deviation of logarithmic daily returns. Returns are assumed to be normally distributed, although actual distribution might be different. In a normal distribution, 68% of observations fall within one standard deviation and 95% of observations fall within two standard deviations. Assuming a volatility of 0.05 means that the expected returns for 20 out of 30 days is expected to be less than 5% (one standard deviation). Volatility is a positive ratio of the expected deviation of return and can be greater than 1.00. Please refer to the wikipedia definition of [`volatility`](https://en.wikipedia.org/wiki/Volatility_(finance)). Volatility is the degree of historical variation of a pairs over time, it is measured by the standard deviation of logarithmic daily returns. Returns are assumed to be normally distributed, although actual distribution might be different. In a normal distribution, 68% of observations fall within one standard deviation and 95% of observations fall within two standard deviations. Assuming a volatility of 0.05 means that the expected returns for 20 out of 30 days is expected to be less than 5% (one standard deviation). Volatility is a positive ratio of the expected deviation of return and can be greater than 1.00. Please refer to the wikipedia definition of [`volatility`](https://en.wikipedia.org/wiki/Volatility_(finance)).
This filter removes pairs if the average volatility over a `lookback_days` days is below `min_volatility` or above `max_volatility`. Since this is a filter that requires additional data, the results are cached for `refresh_period`. This filter removes pairs if the average volatility over a `lookback_days` days is below `min_volatility` or above `max_volatility`. Since this is a filter that requires additional data, the results are cached for `refresh_period`.
@@ -303,5 +349,5 @@ The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets,
"refresh_period": 86400 "refresh_period": 86400
}, },
{"method": "ShuffleFilter", "seed": 42} {"method": "ShuffleFilter", "seed": 42}
], ],
``` ```

View File

@@ -36,10 +36,12 @@ Freqtrade is a crypto-currency algorithmic trading software developed in python
Please read the [exchange specific notes](exchanges.md) to learn about eventual, special configurations needed for each exchange. Please read the [exchange specific notes](exchanges.md) to learn about eventual, special configurations needed for each exchange.
- [X] [Binance](https://www.binance.com/) ([*Note for binance users](docs/exchanges.md#binance-blacklist)) - [X] [Binance](https://www.binance.com/) ([*Note for binance users](exchanges.md#binance-blacklist))
- [X] [Bittrex](https://bittrex.com/) - [X] [Bittrex](https://bittrex.com/)
- [X] [FTX](https://ftx.com) - [X] [FTX](https://ftx.com)
- [X] [Gate.io](https://www.gate.io/ref/6266643)
- [X] [Kraken](https://kraken.com/) - [X] [Kraken](https://kraken.com/)
- [X] [OKEX](https://www.okex.com/)
- [ ] [potentially many others through <img alt="ccxt" width="30px" src="assets/ccxt-logo.svg" />](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_ - [ ] [potentially many others through <img alt="ccxt" width="30px" src="assets/ccxt-logo.svg" />](https://github.com/ccxt/ccxt/). _(We cannot guarantee they will work)_
### Community tested ### Community tested
@@ -79,4 +81,4 @@ For any questions not covered by the documentation or for further information ab
## Ready to try? ## Ready to try?
Begin by reading our installation guide [for docker](docker_quickstart.md) (recommended), or for [installation without docker](installation.md). Begin by reading the installation guide [for docker](docker_quickstart.md) (recommended), or for [installation without docker](installation.md).

View File

@@ -36,6 +36,10 @@ The easiest way to install and run Freqtrade is to clone the bot Github reposito
These requirements apply to both [Script Installation](#script-installation) and [Manual Installation](#manual-installation). These requirements apply to both [Script Installation](#script-installation) and [Manual Installation](#manual-installation).
!!! Note "ARM64 systems"
If you are running an ARM64 system (like a MacOS M1 or an Oracle VM), please use [docker](docker_quickstart.md) to run freqtrade.
While native installation is possible with some manual effort, this is not supported at the moment.
### Install guide ### Install guide
* [Python >= 3.7.x](http://docs.python-guide.org/en/latest/starting/installation/) * [Python >= 3.7.x](http://docs.python-guide.org/en/latest/starting/installation/)
@@ -52,6 +56,10 @@ OS Specific steps are listed first, the [Common](#common) section below is neces
!!! Note !!! Note
Python3.7 or higher and the corresponding pip are assumed to be available. Python3.7 or higher and the corresponding pip are assumed to be available.
!!! Warning "Python 3.10 support"
Due to issues with dependencies, freqtrade is currently unable to support python 3.10.
We're working on supporting python 3.10, are however dependant on support from dependencies.
=== "Debian/Ubuntu" === "Debian/Ubuntu"
#### Install necessary dependencies #### Install necessary dependencies
@@ -60,7 +68,7 @@ OS Specific steps are listed first, the [Common](#common) section below is neces
sudo apt-get update sudo apt-get update
# install packages # install packages
sudo apt install -y python3-pip python3-venv python3-dev python3-pandas git sudo apt install -y python3-pip python3-venv python3-dev python3-pandas git curl
``` ```
=== "RaspberryPi/Raspbian" === "RaspberryPi/Raspbian"
@@ -71,7 +79,7 @@ OS Specific steps are listed first, the [Common](#common) section below is neces
```bash ```bash
sudo apt-get install python3-venv libatlas-base-dev cmake sudo apt-get install python3-venv libatlas-base-dev cmake curl
# Use pywheels.org to speed up installation # Use pywheels.org to speed up installation
sudo echo "[global]\nextra-index-url=https://www.piwheels.org/simple" > tee /etc/pip.conf sudo echo "[global]\nextra-index-url=https://www.piwheels.org/simple" > tee /etc/pip.conf
@@ -113,6 +121,13 @@ git checkout develop
You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands. You may later switch between branches at any time with the `git checkout stable`/`git checkout develop` commands.
??? Note "Install from pypi"
An alternative way to install Freqtrade is from [pypi](https://pypi.org/project/freqtrade/). The downside is that this method requires ta-lib to be correctly installed beforehand, and is therefore currently not the recommended way to install Freqtrade.
``` bash
pip install freqtrade
```
------ ------
## Script Installation ## Script Installation

View File

@@ -164,7 +164,7 @@ The resulting plot will have the following elements:
An advanced plot configuration can be specified in the strategy in the `plot_config` parameter. An advanced plot configuration can be specified in the strategy in the `plot_config` parameter.
Additional features when using plot_config include: Additional features when using `plot_config` include:
* Specify colors per indicator * Specify colors per indicator
* Specify additional subplots * Specify additional subplots
@@ -174,6 +174,7 @@ The sample plot configuration below specifies fixed colors for the indicators. O
It also allows multiple subplots to display both MACD and RSI at the same time. It also allows multiple subplots to display both MACD and RSI at the same time.
Plot type can be configured using `type` key. Possible types are: Plot type can be configured using `type` key. Possible types are:
* `scatter` corresponding to `plotly.graph_objects.Scatter` class (default). * `scatter` corresponding to `plotly.graph_objects.Scatter` class (default).
* `bar` corresponding to `plotly.graph_objects.Bar` class. * `bar` corresponding to `plotly.graph_objects.Bar` class.
@@ -182,6 +183,54 @@ Extra parameters to `plotly.graph_objects.*` constructor can be specified in `pl
Sample configuration with inline comments explaining the process: Sample configuration with inline comments explaining the process:
``` python ``` python
@property
def plot_config(self):
"""
There are a lot of solutions how to build the return dictionary.
The only important point is the return value.
Example:
plot_config = {'main_plot': {}, 'subplots': {}}
"""
plot_config = {}
plot_config['main_plot'] = {
# Configuration for main plot indicators.
# Assumes 2 parameters, emashort and emalong to be specified.
f'ema_{self.emashort.value}': {'color': 'red'},
f'ema_{self.emalong.value}': {'color': '#CCCCCC'},
# By omitting color, a random color is selected.
'sar': {},
# fill area between senkou_a and senkou_b
'senkou_a': {
'color': 'green', #optional
'fill_to': 'senkou_b',
'fill_label': 'Ichimoku Cloud', #optional
'fill_color': 'rgba(255,76,46,0.2)', #optional
},
# plot senkou_b, too. Not only the area to it.
'senkou_b': {}
}
plot_config['subplots'] = {
# Create subplot MACD
"MACD": {
'macd': {'color': 'blue', 'fill_to': 'macdhist'},
'macdsignal': {'color': 'orange'},
'macdhist': {'type': 'bar', 'plotly': {'opacity': 0.9}}
},
# Additional subplot RSI
"RSI": {
'rsi': {'color': 'red'}
}
}
return plot_config
```
??? Note "As attribute (former method)"
Assigning plot_config is also possible as Attribute (this used to be the default way).
This has the disadvantage that strategy parameters are not available, preventing certain configurations from working.
``` python
plot_config = { plot_config = {
'main_plot': { 'main_plot': {
# Configuration for main plot indicators. # Configuration for main plot indicators.
@@ -214,7 +263,8 @@ Sample configuration with inline comments explaining the process:
} }
} }
``` ```
!!! Note !!! Note
The above configuration assumes that `ema10`, `ema50`, `senkou_a`, `senkou_b`, The above configuration assumes that `ema10`, `ema50`, `senkou_a`, `senkou_b`,

View File

@@ -1,4 +1,4 @@
mkdocs==1.2.2 mkdocs==1.2.3
mkdocs-material==7.2.4 mkdocs-material==8.1.3
mdx_truly_sane_lists==1.2 mdx_truly_sane_lists==1.2
pymdown-extensions==8.2 pymdown-extensions==9.1

View File

@@ -38,6 +38,11 @@ Sample configuration:
!!! Danger "Security warning" !!! Danger "Security warning"
By default, the configuration listens on localhost only (so it's not reachable from other systems). We strongly recommend to not expose this API to the internet and choose a strong, unique password, since others will potentially be able to control your bot. By default, the configuration listens on localhost only (so it's not reachable from other systems). We strongly recommend to not expose this API to the internet and choose a strong, unique password, since others will potentially be able to control your bot.
??? Note "API/UI Access on a remote servers"
If you're running on a VPS, you should consider using either a ssh tunnel, or setup a VPN (openVPN, wireguard) to connect to your bot.
This will ensure that freqUI is not directly exposed to the internet, which is not recommended for security reasons (freqUI does not support https out of the box).
Setup of these tools is not part of this tutorial, however many good tutorials can be found on the internet.
You can then access the API by going to `http://127.0.0.1:8080/api/v1/ping` in a browser to check if the API is running correctly. You can then access the API by going to `http://127.0.0.1:8080/api/v1/ping` in a browser to check if the API is running correctly.
This should return the response: This should return the response:
@@ -78,7 +83,7 @@ If you run your bot using docker, you'll need to have the bot listen to incoming
}, },
``` ```
Uncomment the following from your docker-compose file: Make sure that the following 2 lines are available in your docker-compose file:
```yml ```yml
ports: ports:
@@ -330,12 +335,15 @@ Since the access token has a short timeout (15 min) - the `token/refresh` reques
### CORS ### CORS
All web-based front-ends are subject to [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) - Cross-Origin Resource Sharing. This whole section is only necessary in cross-origin cases (where you multiple bot API's running on `localhost:8081`, `localhost:8082`, ...), and want to combine them into one FreqUI instance.
Since most of the requests to the Freqtrade API must be authenticated, a proper CORS policy is key to avoid security problems.
Also, the standard disallows `*` CORS policies for requests with credentials, so this setting must be set appropriately.
Users can configure this themselves via the `CORS_origins` configuration setting. ??? info "Technical explanation"
It consists of a list of allowed sites that are allowed to consume resources from the bot's API. All web-based front-ends are subject to [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) - Cross-Origin Resource Sharing.
Since most of the requests to the Freqtrade API must be authenticated, a proper CORS policy is key to avoid security problems.
Also, the standard disallows `*` CORS policies for requests with credentials, so this setting must be set appropriately.
Users can allow access from different origin URL's to the bot API via the `CORS_origins` configuration setting.
It consists of a list of allowed URL's that are allowed to consume resources from the bot's API.
Assuming your application is deployed as `https://frequi.freqtrade.io/home/` - this would mean that the following configuration becomes necessary: Assuming your application is deployed as `https://frequi.freqtrade.io/home/` - this would mean that the following configuration becomes necessary:
@@ -348,5 +356,19 @@ Assuming your application is deployed as `https://frequi.freqtrade.io/home/` - t
} }
``` ```
In the following (pretty common) case, FreqUI is accessible on `http://localhost:8080/trade` (this is what you see in your navbar when navigating to freqUI).
![freqUI url](assets/frequi_url.png)
The correct configuration for this case is `http://localhost:8080` - the main part of the URL including the port.
```jsonc
{
//...
"jwt_secret_key": "somethingrandom",
"CORS_origins": ["http://localhost:8080"],
//...
}
```
!!! Note !!! Note
We strongly recommend to also set `jwt_secret_key` to something random and known only to yourself to avoid unauthorized access to your bot. We strongly recommend to also set `jwt_secret_key` to something random and known only to yourself to avoid unauthorized access to your bot.

View File

@@ -182,7 +182,7 @@ For example, simplified math:
* the bot buys an asset at a price of 100$ * the bot buys an asset at a price of 100$
* the stop loss is defined at -10% * the stop loss is defined at -10%
* the stop loss would get triggered once the asset drops below 90$ * the stop loss would get triggered once the asset drops below 90$
* stoploss will remain at 90$ unless asset increases to or above our configured offset * stoploss will remain at 90$ unless asset increases to or above the configured offset
* assuming the asset now increases to 103$ (where we have the offset configured) * assuming the asset now increases to 103$ (where we have the offset configured)
* the stop loss will now be -2% of 103$ = 100.94$ * the stop loss will now be -2% of 103$ = 100.94$
* now the asset drops in value to 101\$, the stop loss will still be 100.94$ and would trigger at 100.94$ * now the asset drops in value to 101\$, the stop loss will still be 100.94$ and would trigger at 100.94$

View File

@@ -77,43 +77,6 @@ class AwesomeStrategy(IStrategy):
*** ***
## Custom sell signal
It is possible to define custom sell signals, indicating that specified position should be sold. This is very useful when we need to customize sell conditions for each individual trade, or if you need the trade profit to take the sell decision.
For example you could implement a 1:2 risk-reward ROI with `custom_sell()`.
Using custom_sell() signals in place of stoploss though *is not recommended*. It is a inferior method to using `custom_stoploss()` in this regard - which also allows you to keep the stoploss on exchange.
!!! Note
Returning a `string` or `True` from this method is equal to setting sell signal on a candle at specified time. This method is not called when sell signal is set already, or if sell signals are disabled (`use_sell_signal=False` or `sell_profit_only=True` while profit is below `sell_profit_offset`). `string` max length is 64 characters. Exceeding this limit will cause the message to be truncated to 64 characters.
An example of how we can use different indicators depending on the current profit and also sell trades that were open longer than one day:
``` python
class AwesomeStrategy(IStrategy):
def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
current_profit: float, **kwargs):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
# Above 20% profit, sell when rsi < 80
if current_profit > 0.2:
if last_candle['rsi'] < 80:
return 'rsi_below_80'
# Between 2% and 10%, sell if EMA-long above EMA-short
if 0.02 < current_profit < 0.1:
if last_candle['emalong'] > last_candle['emashort']:
return 'ema_long_below_80'
# Sell any positions at a loss if they are held for more than one day.
if current_profit < 0.0 and (current_time - trade.open_date_utc).days >= 1:
return 'unclog'
```
See [Dataframe access](#dataframe-access) for more information about dataframe use in strategy callbacks.
## Buy Tag ## Buy Tag
When your strategy has multiple buy signals, you can name the signal that triggered. When your strategy has multiple buy signals, you can name the signal that triggered.
@@ -143,500 +106,41 @@ def custom_sell(self, pair: str, trade: Trade, current_time: datetime, current_r
!!! Note !!! Note
`buy_tag` is limited to 100 characters, remaining data will be truncated. `buy_tag` is limited to 100 characters, remaining data will be truncated.
## Exit tag
## Custom stoploss Similar to [Buy Tagging](#buy-tag), you can also specify a sell tag.
The stoploss price can only ever move upwards - if the stoploss value returned from `custom_stoploss` would result in a lower stoploss price than was previously set, it will be ignored. The traditional `stoploss` value serves as an absolute lower level and will be instated as the initial stoploss.
The usage of the custom stoploss method must be enabled by setting `use_custom_stoploss=True` on the strategy object.
The method must return a stoploss value (float / number) as a percentage of the current price.
E.g. If the `current_rate` is 200 USD, then returning `0.02` will set the stoploss price 2% lower, at 196 USD.
The absolute value of the return value is used (the sign is ignored), so returning `0.05` or `-0.05` have the same result, a stoploss 5% below the current price.
To simulate a regular trailing stoploss of 4% (trailing 4% behind the maximum reached price) you would use the following very simple method:
``` python ``` python
# additional imports required def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
from datetime import datetime dataframe.loc[
from freqtrade.persistence import Trade (
(dataframe['rsi'] > 70) &
(dataframe['volume'] > 0)
),
['sell', 'exit_tag']] = (1, 'exit_rsi')
class AwesomeStrategy(IStrategy): return dataframe
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
"""
Custom stoploss logic, returning the new distance relative to current_rate (as ratio).
e.g. returning -0.05 would create a stoploss 5% below current_rate.
The custom stoploss can never be below self.stoploss, which serves as a hard maximum loss.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
When not implemented by a strategy, returns the initial stoploss value
Only called when use_custom_stoploss is set to True.
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New stoploss value, relative to the current rate
"""
return -0.04
``` ```
Stoploss on exchange works similar to `trailing_stop`, and the stoploss on exchange is updated as configured in `stoploss_on_exchange_interval` ([More details about stoploss on exchange](stoploss.md#stop-loss-on-exchange-freqtrade)). The provided exit-tag is then used as sell-reason - and shown as such in backtest results.
!!! Note "Use of dates"
All time-based calculations should be done based on `current_time` - using `datetime.now()` or `datetime.utcnow()` is discouraged, as this will break backtesting support.
!!! Tip "Trailing stoploss"
It's recommended to disable `trailing_stop` when using custom stoploss values. Both can work in tandem, but you might encounter the trailing stop to move the price higher while your custom function would not want this, causing conflicting behavior.
### Custom stoploss examples
The next section will show some examples on what's possible with the custom stoploss function.
Of course, many more things are possible, and all examples can be combined at will.
#### Time based trailing stop
Use the initial stoploss for the first 60 minutes, after this change to 10% trailing stoploss, and after 2 hours (120 minutes) we use a 5% trailing stoploss.
``` python
from datetime import datetime, timedelta
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
# Make sure you have the longest interval first - these conditions are evaluated from top to bottom.
if current_time - timedelta(minutes=120) > trade.open_date_utc:
return -0.05
elif current_time - timedelta(minutes=60) > trade.open_date_utc:
return -0.10
return 1
```
#### Different stoploss per pair
Use a different stoploss depending on the pair.
In this example, we'll trail the highest price with 10% trailing stoploss for `ETH/BTC` and `XRP/BTC`, with 5% trailing stoploss for `LTC/BTC` and with 15% for all other pairs.
``` python
from datetime import datetime
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
if pair in ('ETH/BTC', 'XRP/BTC'):
return -0.10
elif pair in ('LTC/BTC'):
return -0.05
return -0.15
```
#### Trailing stoploss with positive offset
Use the initial stoploss until the profit is above 4%, then use a trailing stoploss of 50% of the current profit with a minimum of 2.5% and a maximum of 5%.
Please note that the stoploss can only increase, values lower than the current stoploss are ignored.
``` python
from datetime import datetime, timedelta
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
if current_profit < 0.04:
return -1 # return a value bigger than the initial stoploss to keep using the initial stoploss
# After reaching the desired offset, allow the stoploss to trail by half the profit
desired_stoploss = current_profit / 2
# Use a minimum of 2.5% and a maximum of 5%
return max(min(desired_stoploss, 0.05), 0.025)
```
#### Calculating stoploss relative to open price
Stoploss values returned from `custom_stoploss()` always specify a percentage relative to `current_rate`. In order to set a stoploss relative to the *open* price, we need to use `current_profit` to calculate what percentage relative to the `current_rate` will give you the same result as if the percentage was specified from the open price.
The helper function [`stoploss_from_open()`](strategy-customization.md#stoploss_from_open) can be used to convert from an open price relative stop, to a current price relative stop which can be returned from `custom_stoploss()`.
#### Stepped stoploss
Instead of continuously trailing behind the current price, this example sets fixed stoploss price levels based on the current profit.
* Use the regular stoploss until 20% profit is reached
* Once profit is > 20% - set stoploss to 7% above open price.
* Once profit is > 25% - set stoploss to 15% above open price.
* Once profit is > 40% - set stoploss to 25% above open price.
``` python
from datetime import datetime
from freqtrade.persistence import Trade
from freqtrade.strategy import stoploss_from_open
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
# evaluate highest to lowest, so that highest possible stop is used
if current_profit > 0.40:
return stoploss_from_open(0.25, current_profit)
elif current_profit > 0.25:
return stoploss_from_open(0.15, current_profit)
elif current_profit > 0.20:
return stoploss_from_open(0.07, current_profit)
# return maximum stoploss value, keeping current stoploss price unchanged
return 1
```
#### Custom stoploss using an indicator from dataframe example
Absolute stoploss value may be derived from indicators stored in dataframe. Example uses parabolic SAR below the price as stoploss.
``` python
class AwesomeStrategy(IStrategy):
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# <...>
dataframe['sar'] = ta.SAR(dataframe)
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
# Use parabolic sar as absolute stoploss price
stoploss_price = last_candle['sar']
# Convert absolute price to percentage relative to current_rate
if stoploss_price < current_rate:
return (stoploss_price / current_rate) - 1
# return maximum stoploss value, keeping current stoploss price unchanged
return 1
```
See [Dataframe access](#dataframe-access) for more information about dataframe use in strategy callbacks.
---
## Custom order price rules
By default, freqtrade use the orderbook to automatically set an order price([Relevant documentation](configuration.md#prices-used-for-orders)), you also have the option to create custom order prices based on your strategy.
You can use this feature by creating a `custom_entry_price()` function in your strategy file to customize entry prices and `custom_exit_price()` for exits.
!!! Note !!! Note
If your custom pricing function return None or an invalid value, price will fall back to `proposed_rate`, which is based on the regular pricing configuration. `sell_reason` is limited to 100 characters, remaining data will be truncated.
### Custom order entry and exit price example ## Strategy version
You can implement custom strategy versioning by using the "version" method, and returning the version you would like this strategy to have.
``` python ``` python
from datetime import datetime, timedelta, timezone def version(self) -> str:
from freqtrade.persistence import Trade """
Returns version of the strategy.
class AwesomeStrategy(IStrategy): """
return "1.1"
# ... populate_* methods
def custom_entry_price(self, pair: str, current_time: datetime,
proposed_rate, **kwargs) -> float:
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
timeframe=self.timeframe)
new_entryprice = dataframe['bollinger_10_lowerband'].iat[-1]
return new_entryprice
def custom_exit_price(self, pair: str, trade: Trade,
current_time: datetime, proposed_rate: float,
current_profit: float, **kwargs) -> float:
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
timeframe=self.timeframe)
new_exitprice = dataframe['bollinger_10_upperband'].iat[-1]
return new_exitprice
```
!!! Warning
Modifying entry and exit prices will only work for limit orders. Depending on the price chosen, this can result in a lot of unfilled orders. By default the maximum allowed distance between the current price and the custom price is 2%, this value can be changed in config with the `custom_price_max_distance_ratio` parameter.
!!! Example
If the new_entryprice is 97, the proposed_rate is 100 and the `custom_price_max_distance_ratio` is set to 2%, The retained valid custom entry price will be 98.
!!! Warning "No backtesting support"
Custom entry-prices are currently not supported during backtesting.
## Custom order timeout rules
Simple, time-based order-timeouts can be configured either via strategy or in the configuration in the `unfilledtimeout` section.
However, freqtrade also offers a custom callback for both order types, which allows you to decide based on custom criteria if an order did time out or not.
!!! Note
Unfilled order timeouts are not relevant during backtesting or hyperopt, and are only relevant during real (live) trading. Therefore these methods are only called in these circumstances.
### Custom order timeout example
A simple example, which applies different unfilled-timeouts depending on the price of the asset can be seen below.
It applies a tight timeout for higher priced assets, while allowing more time to fill on cheap coins.
The function must return either `True` (cancel order) or `False` (keep order alive).
``` python
from datetime import datetime, timedelta, timezone
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
# Set unfilledtimeout to 25 hours, since our maximum timeout from below is 24 hours.
unfilledtimeout = {
'buy': 60 * 25,
'sell': 60 * 25
}
def check_buy_timeout(self, pair: str, trade: 'Trade', order: dict, **kwargs) -> bool:
if trade.open_rate > 100 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(minutes=5):
return True
elif trade.open_rate > 10 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(minutes=3):
return True
elif trade.open_rate < 1 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(hours=24):
return True
return False
def check_sell_timeout(self, pair: str, trade: 'Trade', order: dict, **kwargs) -> bool:
if trade.open_rate > 100 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(minutes=5):
return True
elif trade.open_rate > 10 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(minutes=3):
return True
elif trade.open_rate < 1 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(hours=24):
return True
return False
``` ```
!!! Note !!! Note
For the above example, `unfilledtimeout` must be set to something bigger than 24h, otherwise that type of timeout will apply first. You should make sure to implement proper version control (like a git repository) alongside this, as freqtrade will not keep historic versions of your strategy, so it's up to the user to be able to eventually roll back to a prior version of the strategy.
### Custom order timeout example (using additional data)
``` python
from datetime import datetime
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
# Set unfilledtimeout to 25 hours, since our maximum timeout from below is 24 hours.
unfilledtimeout = {
'buy': 60 * 25,
'sell': 60 * 25
}
def check_buy_timeout(self, pair: str, trade: Trade, order: dict, **kwargs) -> bool:
ob = self.dp.orderbook(pair, 1)
current_price = ob['bids'][0][0]
# Cancel buy order if price is more than 2% above the order.
if current_price > order['price'] * 1.02:
return True
return False
def check_sell_timeout(self, pair: str, trade: Trade, order: dict, **kwargs) -> bool:
ob = self.dp.orderbook(pair, 1)
current_price = ob['asks'][0][0]
# Cancel sell order if price is more than 2% below the order.
if current_price < order['price'] * 0.98:
return True
return False
```
---
## Bot loop start callback
A simple callback which is called once at the start of every bot throttling iteration.
This can be used to perform calculations which are pair independent (apply to all pairs), loading of external data, etc.
``` python
import requests
class AwesomeStrategy(IStrategy):
# ... populate_* methods
def bot_loop_start(self, **kwargs) -> None:
"""
Called at the start of the bot iteration (one loop).
Might be used to perform pair-independent tasks
(e.g. gather some remote resource for comparison)
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
"""
if self.config['runmode'].value in ('live', 'dry_run'):
# Assign this to the class by using self.*
# can then be used by populate_* methods
self.remote_data = requests.get('https://some_remote_source.example.com')
```
## Bot order confirmation
### Trade entry (buy order) confirmation
`confirm_trade_entry()` can be used to abort a trade entry at the latest second (maybe because the price is not what we expect).
``` python
class AwesomeStrategy(IStrategy):
# ... populate_* methods
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time: datetime, **kwargs) -> bool:
"""
Called right before placing a buy order.
Timing for this function is critical, so avoid doing heavy computations or
network requests in this method.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
When not implemented by a strategy, returns True (always confirming).
:param pair: Pair that's about to be bought.
:param order_type: Order type (as configured in order_types). usually limit or market.
:param amount: Amount in target (quote) currency that's going to be traded.
:param rate: Rate that's going to be used when using limit orders
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
:param current_time: datetime object, containing the current datetime
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return bool: When True is returned, then the buy-order is placed on the exchange.
False aborts the process
"""
return True
```
### Trade exit (sell order) confirmation
`confirm_trade_exit()` can be used to abort a trade exit (sell) at the latest second (maybe because the price is not what we expect).
``` python
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
rate: float, time_in_force: str, sell_reason: str,
current_time: datetime, **kwargs) -> bool:
"""
Called right before placing a regular sell order.
Timing for this function is critical, so avoid doing heavy computations or
network requests in this method.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
When not implemented by a strategy, returns True (always confirming).
:param pair: Pair that's about to be sold.
:param order_type: Order type (as configured in order_types). usually limit or market.
:param amount: Amount in quote currency.
:param rate: Rate that's going to be used when using limit orders
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
:param sell_reason: Sell reason.
Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss',
'sell_signal', 'force_sell', 'emergency_sell']
:param current_time: datetime object, containing the current datetime
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return bool: When True is returned, then the sell-order is placed on the exchange.
False aborts the process
"""
if sell_reason == 'force_sell' and trade.calc_profit_ratio(rate) < 0:
# Reject force-sells with negative profit
# This is just a sample, please adjust to your needs
# (this does not necessarily make sense, assuming you know when you're force-selling)
return False
return True
```
### Stake size management
It is possible to manage your risk by reducing or increasing stake amount when placing a new trade.
```python
class AwesomeStrategy(IStrategy):
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: float, max_stake: float,
**kwargs) -> float:
dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
current_candle = dataframe.iloc[-1].squeeze()
if current_candle['fastk_rsi_1h'] > current_candle['fastd_rsi_1h']:
if self.config['stake_amount'] == 'unlimited':
# Use entire available wallet during favorable conditions when in compounding mode.
return max_stake
else:
# Compound profits during favorable conditions instead of using a static stake.
return self.wallets.get_total_stake_amount() / self.config['max_open_trades']
# Use default stake amount.
return proposed_stake
```
Freqtrade will fall back to the `proposed_stake` value should your code raise an exception. The exception itself will be logged.
!!! Tip
You do not _have_ to ensure that `min_stake <= returned_value <= max_stake`. Trades will succeed as the returned value will be clamped to supported range and this acton will be logged.
!!! Tip
Returning `0` or `None` will prevent trades from being placed.
---
## Derived strategies ## Derived strategies
@@ -695,3 +199,33 @@ The variable 'content', will contain the strategy file in a BASE64 encoded form.
``` ```
Please ensure that 'NameOfStrategy' is identical to the strategy name! Please ensure that 'NameOfStrategy' is identical to the strategy name!
## Performance warning
When executing a strategy, one can sometimes be greeted by the following in the logs
> PerformanceWarning: DataFrame is highly fragmented.
This is a warning from [`pandas`](https://github.com/pandas-dev/pandas) and as the warning continues to say:
use `pd.concat(axis=1)`.
This can have slight performance implications, which are usually only visible during hyperopt (when optimizing an indicator).
For example:
```python
for val in self.buy_ema_short.range:
dataframe[f'ema_short_{val}'] = ta.EMA(dataframe, timeperiod=val)
```
should be rewritten to
```python
frames = [dataframe]
for val in self.buy_ema_short.range:
frames.append({
f'ema_short_{val}': ta.EMA(dataframe, timeperiod=val)
})
# Append columns to existing dataframe
merged_frame = pd.concat(frames, axis=1)
```

570
docs/strategy-callbacks.md Normal file
View File

@@ -0,0 +1,570 @@
# Strategy Callbacks
While the main strategy functions (`populate_indicators()`, `populate_buy_trend()`, `populate_sell_trend()`) should be used in a vectorized way, and are only called [once during backtesting](bot-basics.md#backtesting-hyperopt-execution-logic), callbacks are called "whenever needed".
As such, you should avoid doing heavy calculations in callbacks to avoid delays during operations.
Depending on the callback used, they may be called when entering / exiting a trade, or throughout the duration of a trade.
Currently available callbacks:
* [`bot_loop_start()`](#bot-loop-start)
* [`custom_stake_amount()`](#custom-stake-size)
* [`custom_sell()`](#custom-sell-signal)
* [`custom_stoploss()`](#custom-stoploss)
* [`custom_entry_price()` and `custom_exit_price()`](#custom-order-price-rules)
* [`check_buy_timeout()` and `check_sell_timeout()](#custom-order-timeout-rules)
* [`confirm_trade_entry()`](#trade-entry-buy-order-confirmation)
* [`confirm_trade_exit()`](#trade-exit-sell-order-confirmation)
!!! Tip "Callback calling sequence"
You can find the callback calling sequence in [bot-basics](bot-basics.md#bot-execution-logic)
## Bot loop start
A simple callback which is called once at the start of every bot throttling iteration (roughly every 5 seconds, unless configured differently).
This can be used to perform calculations which are pair independent (apply to all pairs), loading of external data, etc.
``` python
import requests
class AwesomeStrategy(IStrategy):
# ... populate_* methods
def bot_loop_start(self, **kwargs) -> None:
"""
Called at the start of the bot iteration (one loop).
Might be used to perform pair-independent tasks
(e.g. gather some remote resource for comparison)
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
"""
if self.config['runmode'].value in ('live', 'dry_run'):
# Assign this to the class by using self.*
# can then be used by populate_* methods
self.remote_data = requests.get('https://some_remote_source.example.com')
```
## Custom Stake size
Called before entering a trade, makes it possible to manage your position size when placing a new trade.
```python
class AwesomeStrategy(IStrategy):
def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float,
proposed_stake: float, min_stake: float, max_stake: float,
**kwargs) -> float:
dataframe, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe)
current_candle = dataframe.iloc[-1].squeeze()
if current_candle['fastk_rsi_1h'] > current_candle['fastd_rsi_1h']:
if self.config['stake_amount'] == 'unlimited':
# Use entire available wallet during favorable conditions when in compounding mode.
return max_stake
else:
# Compound profits during favorable conditions instead of using a static stake.
return self.wallets.get_total_stake_amount() / self.config['max_open_trades']
# Use default stake amount.
return proposed_stake
```
Freqtrade will fall back to the `proposed_stake` value should your code raise an exception. The exception itself will be logged.
!!! Tip
You do not _have_ to ensure that `min_stake <= returned_value <= max_stake`. Trades will succeed as the returned value will be clamped to supported range and this acton will be logged.
!!! Tip
Returning `0` or `None` will prevent trades from being placed.
## Custom sell signal
Called for open trade every throttling iteration (roughly every 5 seconds) until a trade is closed.
Allows to define custom sell signals, indicating that specified position should be sold. This is very useful when we need to customize sell conditions for each individual trade, or if you need trade data to make an exit decision.
For example you could implement a 1:2 risk-reward ROI with `custom_sell()`.
Using custom_sell() signals in place of stoploss though *is not recommended*. It is a inferior method to using `custom_stoploss()` in this regard - which also allows you to keep the stoploss on exchange.
!!! Note
Returning a (none-empty) `string` or `True` from this method is equal to setting sell signal on a candle at specified time. This method is not called when sell signal is set already, or if sell signals are disabled (`use_sell_signal=False` or `sell_profit_only=True` while profit is below `sell_profit_offset`). `string` max length is 64 characters. Exceeding this limit will cause the message to be truncated to 64 characters.
An example of how we can use different indicators depending on the current profit and also sell trades that were open longer than one day:
``` python
class AwesomeStrategy(IStrategy):
def custom_sell(self, pair: str, trade: 'Trade', current_time: 'datetime', current_rate: float,
current_profit: float, **kwargs):
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
# Above 20% profit, sell when rsi < 80
if current_profit > 0.2:
if last_candle['rsi'] < 80:
return 'rsi_below_80'
# Between 2% and 10%, sell if EMA-long above EMA-short
if 0.02 < current_profit < 0.1:
if last_candle['emalong'] > last_candle['emashort']:
return 'ema_long_below_80'
# Sell any positions at a loss if they are held for more than one day.
if current_profit < 0.0 and (current_time - trade.open_date_utc).days >= 1:
return 'unclog'
```
See [Dataframe access](strategy-advanced.md#dataframe-access) for more information about dataframe use in strategy callbacks.
## Custom stoploss
Called for open trade every throttling iteration (roughly every 5 seconds) until a trade is closed.
The usage of the custom stoploss method must be enabled by setting `use_custom_stoploss=True` on the strategy object.
The stoploss price can only ever move upwards - if the stoploss value returned from `custom_stoploss` would result in a lower stoploss price than was previously set, it will be ignored. The traditional `stoploss` value serves as an absolute lower level and will be instated as the initial stoploss (before this method is called for the first time for a trade).
The method must return a stoploss value (float / number) as a percentage of the current price.
E.g. If the `current_rate` is 200 USD, then returning `0.02` will set the stoploss price 2% lower, at 196 USD.
The absolute value of the return value is used (the sign is ignored), so returning `0.05` or `-0.05` have the same result, a stoploss 5% below the current price.
To simulate a regular trailing stoploss of 4% (trailing 4% behind the maximum reached price) you would use the following very simple method:
``` python
# additional imports required
from datetime import datetime
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
"""
Custom stoploss logic, returning the new distance relative to current_rate (as ratio).
e.g. returning -0.05 would create a stoploss 5% below current_rate.
The custom stoploss can never be below self.stoploss, which serves as a hard maximum loss.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
When not implemented by a strategy, returns the initial stoploss value
Only called when use_custom_stoploss is set to True.
:param pair: Pair that's currently analyzed
:param trade: trade object.
:param current_time: datetime object, containing the current datetime
:param current_rate: Rate, calculated based on pricing settings in ask_strategy.
:param current_profit: Current profit (as ratio), calculated based on current_rate.
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return float: New stoploss value, relative to the current rate
"""
return -0.04
```
Stoploss on exchange works similar to `trailing_stop`, and the stoploss on exchange is updated as configured in `stoploss_on_exchange_interval` ([More details about stoploss on exchange](stoploss.md#stop-loss-on-exchange-freqtrade)).
!!! Note "Use of dates"
All time-based calculations should be done based on `current_time` - using `datetime.now()` or `datetime.utcnow()` is discouraged, as this will break backtesting support.
!!! Tip "Trailing stoploss"
It's recommended to disable `trailing_stop` when using custom stoploss values. Both can work in tandem, but you might encounter the trailing stop to move the price higher while your custom function would not want this, causing conflicting behavior.
### Custom stoploss examples
The next section will show some examples on what's possible with the custom stoploss function.
Of course, many more things are possible, and all examples can be combined at will.
#### Time based trailing stop
Use the initial stoploss for the first 60 minutes, after this change to 10% trailing stoploss, and after 2 hours (120 minutes) we use a 5% trailing stoploss.
``` python
from datetime import datetime, timedelta
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
# Make sure you have the longest interval first - these conditions are evaluated from top to bottom.
if current_time - timedelta(minutes=120) > trade.open_date_utc:
return -0.05
elif current_time - timedelta(minutes=60) > trade.open_date_utc:
return -0.10
return 1
```
#### Different stoploss per pair
Use a different stoploss depending on the pair.
In this example, we'll trail the highest price with 10% trailing stoploss for `ETH/BTC` and `XRP/BTC`, with 5% trailing stoploss for `LTC/BTC` and with 15% for all other pairs.
``` python
from datetime import datetime
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
if pair in ('ETH/BTC', 'XRP/BTC'):
return -0.10
elif pair in ('LTC/BTC'):
return -0.05
return -0.15
```
#### Trailing stoploss with positive offset
Use the initial stoploss until the profit is above 4%, then use a trailing stoploss of 50% of the current profit with a minimum of 2.5% and a maximum of 5%.
Please note that the stoploss can only increase, values lower than the current stoploss are ignored.
``` python
from datetime import datetime, timedelta
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
if current_profit < 0.04:
return -1 # return a value bigger than the initial stoploss to keep using the initial stoploss
# After reaching the desired offset, allow the stoploss to trail by half the profit
desired_stoploss = current_profit / 2
# Use a minimum of 2.5% and a maximum of 5%
return max(min(desired_stoploss, 0.05), 0.025)
```
#### Stepped stoploss
Instead of continuously trailing behind the current price, this example sets fixed stoploss price levels based on the current profit.
* Use the regular stoploss until 20% profit is reached
* Once profit is > 20% - set stoploss to 7% above open price.
* Once profit is > 25% - set stoploss to 15% above open price.
* Once profit is > 40% - set stoploss to 25% above open price.
``` python
from datetime import datetime
from freqtrade.persistence import Trade
from freqtrade.strategy import stoploss_from_open
class AwesomeStrategy(IStrategy):
# ... populate_* methods
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
# evaluate highest to lowest, so that highest possible stop is used
if current_profit > 0.40:
return stoploss_from_open(0.25, current_profit)
elif current_profit > 0.25:
return stoploss_from_open(0.15, current_profit)
elif current_profit > 0.20:
return stoploss_from_open(0.07, current_profit)
# return maximum stoploss value, keeping current stoploss price unchanged
return 1
```
#### Custom stoploss using an indicator from dataframe example
Absolute stoploss value may be derived from indicators stored in dataframe. Example uses parabolic SAR below the price as stoploss.
``` python
class AwesomeStrategy(IStrategy):
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# <...>
dataframe['sar'] = ta.SAR(dataframe)
use_custom_stoploss = True
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
last_candle = dataframe.iloc[-1].squeeze()
# Use parabolic sar as absolute stoploss price
stoploss_price = last_candle['sar']
# Convert absolute price to percentage relative to current_rate
if stoploss_price < current_rate:
return (stoploss_price / current_rate) - 1
# return maximum stoploss value, keeping current stoploss price unchanged
return 1
```
See [Dataframe access](strategy-advanced.md#dataframe-access) for more information about dataframe use in strategy callbacks.
### Common helpers for stoploss calculations
#### Stoploss relative to open price
Stoploss values returned from `custom_stoploss()` always specify a percentage relative to `current_rate`. In order to set a stoploss relative to the *open* price, we need to use `current_profit` to calculate what percentage relative to the `current_rate` will give you the same result as if the percentage was specified from the open price.
The helper function [`stoploss_from_open()`](strategy-customization.md#stoploss_from_open) can be used to convert from an open price relative stop, to a current price relative stop which can be returned from `custom_stoploss()`.
#### Stoploss percentage from absolute price
Stoploss values returned from `custom_stoploss()` always specify a percentage relative to `current_rate`. In order to set a stoploss at specified absolute price level, we need to use `stop_rate` to calculate what percentage relative to the `current_rate` will give you the same result as if the percentage was specified from the open price.
The helper function [`stoploss_from_absolute()`](strategy-customization.md#stoploss_from_absolute) can be used to convert from an absolute price, to a current price relative stop which can be returned from `custom_stoploss()`.
---
## Custom order price rules
By default, freqtrade use the orderbook to automatically set an order price([Relevant documentation](configuration.md#prices-used-for-orders)), you also have the option to create custom order prices based on your strategy.
You can use this feature by creating a `custom_entry_price()` function in your strategy file to customize entry prices and `custom_exit_price()` for exits.
Each of these methods are called right before placing an order on the exchange.
!!! Note
If your custom pricing function return None or an invalid value, price will fall back to `proposed_rate`, which is based on the regular pricing configuration.
### Custom order entry and exit price example
``` python
from datetime import datetime, timedelta, timezone
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
def custom_entry_price(self, pair: str, current_time: datetime,
proposed_rate, **kwargs) -> float:
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
timeframe=self.timeframe)
new_entryprice = dataframe['bollinger_10_lowerband'].iat[-1]
return new_entryprice
def custom_exit_price(self, pair: str, trade: Trade,
current_time: datetime, proposed_rate: float,
current_profit: float, **kwargs) -> float:
dataframe, last_updated = self.dp.get_analyzed_dataframe(pair=pair,
timeframe=self.timeframe)
new_exitprice = dataframe['bollinger_10_upperband'].iat[-1]
return new_exitprice
```
!!! Warning
Modifying entry and exit prices will only work for limit orders. Depending on the price chosen, this can result in a lot of unfilled orders. By default the maximum allowed distance between the current price and the custom price is 2%, this value can be changed in config with the `custom_price_max_distance_ratio` parameter.
**Example**:
If the new_entryprice is 97, the proposed_rate is 100 and the `custom_price_max_distance_ratio` is set to 2%, The retained valid custom entry price will be 98, which is 2% below the current (proposed) rate.
!!! Warning "Backtesting"
While Custom prices are supported in backtesting (starting with 2021.12), prices will be moved to within the candle's high/low prices.
This behavior is currently being tested, and might be changed at a later point.
`custom_exit_price()` is only called for sells of type Sell_signal and Custom sell. All other sell-types will use regular backtesting prices.
## Custom order timeout rules
Simple, time-based order-timeouts can be configured either via strategy or in the configuration in the `unfilledtimeout` section.
However, freqtrade also offers a custom callback for both order types, which allows you to decide based on custom criteria if an order did time out or not.
!!! Note
Unfilled order timeouts are not relevant during backtesting or hyperopt, and are only relevant during real (live) trading. Therefore these methods are only called in these circumstances.
### Custom order timeout example
Called for every open order until that order is either filled or cancelled.
`check_buy_timeout()` is called for trade entries, while `check_sell_timeout()` is called for trade exit orders.
A simple example, which applies different unfilled-timeouts depending on the price of the asset can be seen below.
It applies a tight timeout for higher priced assets, while allowing more time to fill on cheap coins.
The function must return either `True` (cancel order) or `False` (keep order alive).
``` python
from datetime import datetime, timedelta, timezone
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
# Set unfilledtimeout to 25 hours, since the maximum timeout from below is 24 hours.
unfilledtimeout = {
'buy': 60 * 25,
'sell': 60 * 25
}
def check_buy_timeout(self, pair: str, trade: 'Trade', order: dict, **kwargs) -> bool:
if trade.open_rate > 100 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(minutes=5):
return True
elif trade.open_rate > 10 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(minutes=3):
return True
elif trade.open_rate < 1 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(hours=24):
return True
return False
def check_sell_timeout(self, pair: str, trade: 'Trade', order: dict, **kwargs) -> bool:
if trade.open_rate > 100 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(minutes=5):
return True
elif trade.open_rate > 10 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(minutes=3):
return True
elif trade.open_rate < 1 and trade.open_date_utc < datetime.now(timezone.utc) - timedelta(hours=24):
return True
return False
```
!!! Note
For the above example, `unfilledtimeout` must be set to something bigger than 24h, otherwise that type of timeout will apply first.
### Custom order timeout example (using additional data)
``` python
from datetime import datetime
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
# Set unfilledtimeout to 25 hours, since the maximum timeout from below is 24 hours.
unfilledtimeout = {
'buy': 60 * 25,
'sell': 60 * 25
}
def check_buy_timeout(self, pair: str, trade: Trade, order: dict, **kwargs) -> bool:
ob = self.dp.orderbook(pair, 1)
current_price = ob['bids'][0][0]
# Cancel buy order if price is more than 2% above the order.
if current_price > order['price'] * 1.02:
return True
return False
def check_sell_timeout(self, pair: str, trade: Trade, order: dict, **kwargs) -> bool:
ob = self.dp.orderbook(pair, 1)
current_price = ob['asks'][0][0]
# Cancel sell order if price is more than 2% below the order.
if current_price < order['price'] * 0.98:
return True
return False
```
---
## Bot order confirmation
Confirm trade entry / exits.
This are the last methods that will be called before an order is placed.
### Trade entry (buy order) confirmation
`confirm_trade_entry()` can be used to abort a trade entry at the latest second (maybe because the price is not what we expect).
``` python
class AwesomeStrategy(IStrategy):
# ... populate_* methods
def confirm_trade_entry(self, pair: str, order_type: str, amount: float, rate: float,
time_in_force: str, current_time: datetime, **kwargs) -> bool:
"""
Called right before placing a buy order.
Timing for this function is critical, so avoid doing heavy computations or
network requests in this method.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
When not implemented by a strategy, returns True (always confirming).
:param pair: Pair that's about to be bought.
:param order_type: Order type (as configured in order_types). usually limit or market.
:param amount: Amount in target (quote) currency that's going to be traded.
:param rate: Rate that's going to be used when using limit orders
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
:param current_time: datetime object, containing the current datetime
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return bool: When True is returned, then the buy-order is placed on the exchange.
False aborts the process
"""
return True
```
### Trade exit (sell order) confirmation
`confirm_trade_exit()` can be used to abort a trade exit (sell) at the latest second (maybe because the price is not what we expect).
``` python
from freqtrade.persistence import Trade
class AwesomeStrategy(IStrategy):
# ... populate_* methods
def confirm_trade_exit(self, pair: str, trade: Trade, order_type: str, amount: float,
rate: float, time_in_force: str, sell_reason: str,
current_time: datetime, **kwargs) -> bool:
"""
Called right before placing a regular sell order.
Timing for this function is critical, so avoid doing heavy computations or
network requests in this method.
For full documentation please go to https://www.freqtrade.io/en/latest/strategy-advanced/
When not implemented by a strategy, returns True (always confirming).
:param pair: Pair that's about to be sold.
:param order_type: Order type (as configured in order_types). usually limit or market.
:param amount: Amount in quote currency.
:param rate: Rate that's going to be used when using limit orders
:param time_in_force: Time in force. Defaults to GTC (Good-til-cancelled).
:param sell_reason: Sell reason.
Can be any of ['roi', 'stop_loss', 'stoploss_on_exchange', 'trailing_stop_loss',
'sell_signal', 'force_sell', 'emergency_sell']
:param current_time: datetime object, containing the current datetime
:param **kwargs: Ensure to keep this here so updates to this won't break your strategy.
:return bool: When True is returned, then the sell-order is placed on the exchange.
False aborts the process
"""
if sell_reason == 'force_sell' and trade.calc_profit_ratio(rate) < 0:
# Reject force-sells with negative profit
# This is just a sample, please adjust to your needs
# (this does not necessarily make sense, assuming you know when you're force-selling)
return False
return True
```

View File

@@ -4,33 +4,23 @@ This page explains how to customize your strategies, add new indicators and set
Please familiarize yourself with [Freqtrade basics](bot-basics.md) first, which provides overall info on how the bot operates. Please familiarize yourself with [Freqtrade basics](bot-basics.md) first, which provides overall info on how the bot operates.
## Install a custom strategy file
This is very simple. Copy paste your strategy file into the directory `user_data/strategies`.
Let assume you have a class called `AwesomeStrategy` in the file `AwesomeStrategy.py`:
1. Move your file into `user_data/strategies` (you should have `user_data/strategies/AwesomeStrategy.py`
2. Start the bot with the param `--strategy AwesomeStrategy` (the parameter is the class name)
```bash
freqtrade trade --strategy AwesomeStrategy
```
## Develop your own strategy ## Develop your own strategy
The bot includes a default strategy file. The bot includes a default strategy file.
Also, several other strategies are available in the [strategy repository](https://github.com/freqtrade/freqtrade-strategies). Also, several other strategies are available in the [strategy repository](https://github.com/freqtrade/freqtrade-strategies).
You will however most likely have your own idea for a strategy. You will however most likely have your own idea for a strategy.
This document intends to help you develop one for yourself. This document intends to help you convert your strategy idea into your own strategy.
To get started, use `freqtrade new-strategy --strategy AwesomeStrategy`. To get started, use `freqtrade new-strategy --strategy AwesomeStrategy` (you can obviously use your own naming for your strategy).
This will create a new strategy file from a template, which will be located under `user_data/strategies/AwesomeStrategy.py`. This will create a new strategy file from a template, which will be located under `user_data/strategies/AwesomeStrategy.py`.
!!! Note !!! Note
This is just a template file, which will most likely not be profitable out of the box. This is just a template file, which will most likely not be profitable out of the box.
??? Hint "Different template levels"
`freqtrade new-strategy` has an additional parameter, `--template`, which controls the amount of pre-build information you get in the created strategy. Use `--template minimal` to get an empty strategy without any indicator examples, or `--template advanced` to get a template with most callbacks defined.
### Anatomy of a strategy ### Anatomy of a strategy
A strategy file contains all the information needed to build a good strategy: A strategy file contains all the information needed to build a good strategy:
@@ -67,6 +57,46 @@ file as reference.**
needs to take care to avoid having the strategy utilize data from the future. needs to take care to avoid having the strategy utilize data from the future.
Some common patterns for this are listed in the [Common Mistakes](#common-mistakes-when-developing-strategies) section of this document. Some common patterns for this are listed in the [Common Mistakes](#common-mistakes-when-developing-strategies) section of this document.
### Dataframe
Freqtrade uses [pandas](https://pandas.pydata.org/) to store/provide the candlestick (OHLCV) data.
Pandas is a great library developed for processing large amounts of data.
Each row in a dataframe corresponds to one candle on a chart, with the latest candle always being the last in the dataframe (sorted by date).
``` output
> dataframe.head()
date open high low close volume
0 2021-11-09 23:25:00+00:00 67279.67 67321.84 67255.01 67300.97 44.62253
1 2021-11-09 23:30:00+00:00 67300.97 67301.34 67183.03 67187.01 61.38076
2 2021-11-09 23:35:00+00:00 67187.02 67187.02 67031.93 67123.81 113.42728
3 2021-11-09 23:40:00+00:00 67123.80 67222.40 67080.33 67160.48 78.96008
4 2021-11-09 23:45:00+00:00 67160.48 67160.48 66901.26 66943.37 111.39292
```
Pandas provides fast ways to calculate metrics. To benefit from this speed, it's advised to not use loops, but use vectorized methods instead.
Vectorized operations perform calculations across the whole range of data and are therefore, compared to looping through each row, a lot faster when calculating indicators.
As a dataframe is a table, simple python comparisons like the following will not work
``` python
if dataframe['rsi'] > 30:
dataframe['buy'] = 1
```
The above section will fail with `The truth value of a Series is ambiguous. [...]`.
This must instead be written in a pandas-compatible way, so the operation is performed across the whole dataframe.
``` python
dataframe.loc[
(dataframe['rsi'] > 30)
, 'buy'] = 1
```
With this section, you have a new column in your dataframe, which has `1` assigned whenever RSI is above 30.
### Customize Indicators ### Customize Indicators
Buy and sell strategies need indicators. You can add more indicators by extending the list contained in the method `populate_indicators()` from your strategy file. Buy and sell strategies need indicators. You can add more indicators by extending the list contained in the method `populate_indicators()` from your strategy file.
@@ -122,9 +152,19 @@ def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame
Look into the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_strategy.py). Look into the [user_data/strategies/sample_strategy.py](https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_strategy.py).
Then uncomment indicators you need. Then uncomment indicators you need.
#### Indicator libraries
Out of the box, freqtrade installs the following technical libraries:
* [ta-lib](http://mrjbq7.github.io/ta-lib/)
* [pandas-ta](https://twopirllc.github.io/pandas-ta/)
* [technical](https://github.com/freqtrade/technical/)
Additional technical libraries can be installed as necessary, or custom indicators may be written / invented by the strategy author.
### Strategy startup period ### Strategy startup period
Most indicators have an instable startup period, in which they are either not available, or the calculation is incorrect. This can lead to inconsistencies, since Freqtrade does not know how long this instable period should be. Most indicators have an instable startup period, in which they are either not available (NaN), or the calculation is incorrect. This can lead to inconsistencies, since Freqtrade does not know how long this instable period should be.
To account for this, the strategy can be assigned the `startup_candle_count` attribute. To account for this, the strategy can be assigned the `startup_candle_count` attribute.
This should be set to the maximum number of candles that the strategy requires to calculate stable indicators. This should be set to the maximum number of candles that the strategy requires to calculate stable indicators.
@@ -136,8 +176,14 @@ In this example strategy, this should be set to 100 (`startup_candle_count = 100
By letting the bot know how much history is needed, backtest trades can start at the specified timerange during backtesting and hyperopt. By letting the bot know how much history is needed, backtest trades can start at the specified timerange during backtesting and hyperopt.
!!! Warning "Using x calls to get OHLCV"
If you receive a warning like `WARNING - Using 3 calls to get OHLCV. This can result in slower operations for the bot. Please check if you really need 1500 candles for your strategy` - you should consider if you really need this much historic data for your signals.
Having this will cause Freqtrade to make multiple calls for the same pair, which will obviously be slower than one network request.
As a consequence, Freqtrade will take longer to refresh candles - and should therefore be avoided if possible.
This is capped to 5 total calls to avoid overloading the exchange, or make freqtrade too slow.
!!! Warning !!! Warning
`startup_candle_count` should be below `ohlcv_candle_limit` (which is 500 for most exchanges) - since only this amount of candles will be available during Dry-Run/Live Trade operations. `startup_candle_count` should be below `ohlcv_candle_limit * 5` (which is 500 * 5 for most exchanges) - since only this amount of candles will be available during Dry-Run/Live Trade operations.
#### Example #### Example
@@ -271,20 +317,14 @@ class AwesomeStrategy(IStrategy):
Setting a stoploss is highly recommended to protect your capital from strong moves against you. Setting a stoploss is highly recommended to protect your capital from strong moves against you.
Sample: Sample of setting a 10% stoploss:
``` python ``` python
stoploss = -0.10 stoploss = -0.10
``` ```
This would signify a stoploss of -10%.
For the full documentation on stoploss features, look at the dedicated [stoploss page](stoploss.md). For the full documentation on stoploss features, look at the dedicated [stoploss page](stoploss.md).
If your exchange supports it, it's recommended to also set `"stoploss_on_exchange"` in the order_types dictionary, so your stoploss is on the exchange and cannot be missed due to network problems, high load or other reasons.
For more information on order_types please look [here](configuration.md#understand-order_types).
### Timeframe (formerly ticker interval) ### Timeframe (formerly ticker interval)
This is the set of candles the bot should download and use for the analysis. This is the set of candles the bot should download and use for the analysis.
@@ -300,9 +340,22 @@ The metadata-dict (available for `populate_buy_trend`, `populate_sell_trend`, `p
Currently this is `pair`, which can be accessed using `metadata['pair']` - and will return a pair in the format `XRP/BTC`. Currently this is `pair`, which can be accessed using `metadata['pair']` - and will return a pair in the format `XRP/BTC`.
The Metadata-dict should not be modified and does not persist information across multiple calls. The Metadata-dict should not be modified and does not persist information across multiple calls.
Instead, have a look at the section [Storing information](strategy-advanced.md#Storing-information) Instead, have a look at the [Storing information](strategy-advanced.md#Storing-information) section.
## Additional data (informative_pairs) ## Strategy file loading
By default, freqtrade will attempt to load strategies from all `.py` files within `user_data/strategies`.
Assuming your strategy is called `AwesomeStrategy`, stored in the file `user_data/strategies/AwesomeStrategy.py`, then you can start freqtrade with `freqtrade trade --strategy AwesomeStrategy`.
Note that we're using the class-name, not the file name.
You can use `freqtrade list-strategies` to see a list of all strategies Freqtrade is able to load (all strategies in the correct folder).
It will also include a "status" field, highlighting potential problems.
??? Hint "Customize strategy directory"
You can use a different directory by using `--strategy-path user_data/otherPath`. This parameter is available to all commands that require a strategy.
## Informative Pairs
### Get data for non-tradeable pairs ### Get data for non-tradeable pairs
@@ -331,6 +384,133 @@ A full sample can be found [in the DataProvider section](#complete-data-provider
*** ***
### Informative pairs decorator (`@informative()`)
In most common case it is possible to easily define informative pairs by using a decorator. All decorated `populate_indicators_*` methods run in isolation,
not having access to data from other informative pairs, in the end all informative dataframes are merged and passed to main `populate_indicators()` method.
When hyperopting, use of hyperoptable parameter `.value` attribute is not supported. Please use `.range` attribute. See [optimizing an indicator parameter](hyperopt.md#optimizing-an-indicator-parameter)
for more information.
??? info "Full documentation"
``` python
def informative(timeframe: str, asset: str = '',
fmt: Optional[Union[str, Callable[[KwArg(str)], str]]] = None,
ffill: bool = True) -> Callable[[PopulateIndicators], PopulateIndicators]:
"""
A decorator for populate_indicators_Nn(self, dataframe, metadata), allowing these functions to
define informative indicators.
Example usage:
@informative('1h')
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
:param timeframe: Informative timeframe. Must always be equal or higher than strategy timeframe.
:param asset: Informative asset, for example BTC, BTC/USDT, ETH/BTC. Do not specify to use
current pair.
:param fmt: Column format (str) or column formatter (callable(name, asset, timeframe)). When not
specified, defaults to:
* {base}_{quote}_{column}_{timeframe} if asset is specified.
* {column}_{timeframe} if asset is not specified.
Format string supports these format variables:
* {asset} - full name of the asset, for example 'BTC/USDT'.
* {base} - base currency in lower case, for example 'eth'.
* {BASE} - same as {base}, except in upper case.
* {quote} - quote currency in lower case, for example 'usdt'.
* {QUOTE} - same as {quote}, except in upper case.
* {column} - name of dataframe column.
* {timeframe} - timeframe of informative dataframe.
:param ffill: ffill dataframe after merging informative pair.
"""
```
??? Example "Fast and easy way to define informative pairs"
Most of the time we do not need power and flexibility offered by `merge_informative_pair()`, therefore we can use a decorator to quickly define informative pairs.
``` python
from datetime import datetime
from freqtrade.persistence import Trade
from freqtrade.strategy import IStrategy, informative
class AwesomeStrategy(IStrategy):
# This method is not required.
# def informative_pairs(self): ...
# Define informative upper timeframe for each pair. Decorators can be stacked on same
# method. Available in populate_indicators as 'rsi_30m' and 'rsi_1h'.
@informative('30m')
@informative('1h')
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
# Define BTC/STAKE informative pair. Available in populate_indicators and other methods as
# 'btc_rsi_1h'. Current stake currency should be specified as {stake} format variable
# instead of hardcoding actual stake currency. Available in populate_indicators and other
# methods as 'btc_usdt_rsi_1h' (when stake currency is USDT).
@informative('1h', 'BTC/{stake}')
def populate_indicators_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
# Define BTC/ETH informative pair. You must specify quote currency if it is different from
# stake currency. Available in populate_indicators and other methods as 'eth_btc_rsi_1h'.
@informative('1h', 'ETH/BTC')
def populate_indicators_eth_btc_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
# Define BTC/STAKE informative pair. A custom formatter may be specified for formatting
# column names. A callable `fmt(**kwargs) -> str` may be specified, to implement custom
# formatting. Available in populate_indicators and other methods as 'rsi_upper'.
@informative('1h', 'BTC/{stake}', '{column}')
def populate_indicators_btc_1h_2(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['rsi_upper'] = ta.RSI(dataframe, timeperiod=14)
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Strategy timeframe indicators for current pair.
dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14)
# Informative pairs are available in this method.
dataframe['rsi_less'] = dataframe['rsi'] < dataframe['rsi_1h']
return dataframe
```
!!! Note
Do not use `@informative` decorator if you need to use data of one informative pair when generating another informative pair. Instead, define informative pairs
manually as described [in the DataProvider section](#complete-data-provider-sample).
!!! Note
Use string formatting when accessing informative dataframes of other pairs. This will allow easily changing stake currency in config without having to adjust strategy code.
``` python
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
stake = self.config['stake_currency']
dataframe.loc[
(
(dataframe[f'btc_{stake}_rsi_1h'] < 35)
&
(dataframe['volume'] > 0)
),
['buy', 'buy_tag']] = (1, 'buy_signal_rsi')
return dataframe
```
Alternatively column renaming may be used to remove stake currency from column names: `@informative('1h', 'BTC/{stake}', fmt='{base}_{column}_{timeframe}')`.
!!! Warning "Duplicate method names"
Methods tagged with `@informative()` decorator must always have unique names! Re-using same name (for example when copy-pasting already defined informative method)
will overwrite previously defined method and not produce any errors due to limitations of Python programming language. In such cases you will find that indicators
created in earlier-defined methods are not available in the dataframe. Carefully review method names and make sure they are unique!
## Additional data (DataProvider) ## Additional data (DataProvider)
The strategy provides access to the `DataProvider`. This allows you to get additional data to use in your strategy. The strategy provides access to the `DataProvider`. This allows you to get additional data to use in your strategy.
@@ -374,9 +554,9 @@ The strategy might look something like this:
*Scan through the top 10 pairs by volume using the `VolumePairList` every 5 minutes and use a 14 day RSI to buy and sell.* *Scan through the top 10 pairs by volume using the `VolumePairList` every 5 minutes and use a 14 day RSI to buy and sell.*
Due to the limited available data, it's very difficult to resample our `5m` candles into daily candles for use in a 14 day RSI. Most exchanges limit us to just 500 candles which effectively gives us around 1.74 daily candles. We need 14 days at least! Due to the limited available data, it's very difficult to resample `5m` candles into daily candles for use in a 14 day RSI. Most exchanges limit us to just 500 candles which effectively gives us around 1.74 daily candles. We need 14 days at least!
Since we can't resample our data we will have to use an informative pair; and since our whitelist will be dynamic we don't know which pair(s) to use. Since we can't resample the data we will have to use an informative pair; and since the whitelist will be dynamic we don't know which pair(s) to use.
This is where calling `self.dp.current_whitelist()` comes in handy. This is where calling `self.dp.current_whitelist()` comes in handy.
@@ -639,6 +819,42 @@ Stoploss values returned from `custom_stoploss` must specify a percentage relati
Full examples can be found in the [Custom stoploss](strategy-advanced.md#custom-stoploss) section of the Documentation. Full examples can be found in the [Custom stoploss](strategy-advanced.md#custom-stoploss) section of the Documentation.
!!! Note
Providing invalid input to `stoploss_from_open()` may produce "CustomStoploss function did not return valid stoploss" warnings.
This may happen if `current_profit` parameter is below specified `open_relative_stop`. Such situations may arise when closing trade
is blocked by `confirm_trade_exit()` method. Warnings can be solved by never blocking stop loss sells by checking `sell_reason` in
`confirm_trade_exit()`, or by using `return stoploss_from_open(...) or 1` idiom, which will request to not change stop loss when
`current_profit < open_relative_stop`.
### *stoploss_from_absolute()*
In some situations it may be confusing to deal with stops relative to current rate. Instead, you may define a stoploss level using an absolute price.
??? Example "Returning a stoploss using absolute price from the custom stoploss function"
If we want to trail a stop price at 2xATR below current proce we can call `stoploss_from_absolute(current_rate - (candle['atr'] * 2), current_rate)`.
``` python
from datetime import datetime
from freqtrade.persistence import Trade
from freqtrade.strategy import IStrategy, stoploss_from_open
class AwesomeStrategy(IStrategy):
use_custom_stoploss = True
def populate_indicators_1h(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
dataframe['atr'] = ta.ATR(dataframe, timeperiod=14)
return dataframe
def custom_stoploss(self, pair: str, trade: 'Trade', current_time: datetime,
current_rate: float, current_profit: float, **kwargs) -> float:
dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe)
candle = dataframe.iloc[-1].squeeze()
return stoploss_from_absolute(current_rate - (candle['atr'] * 2), current_rate)
```
## Additional data (Wallets) ## Additional data (Wallets)
@@ -723,7 +939,8 @@ Sometimes it may be desired to lock a pair after certain events happen (e.g. mul
Freqtrade has an easy method to do this from within the strategy, by calling `self.lock_pair(pair, until, [reason])`. Freqtrade has an easy method to do this from within the strategy, by calling `self.lock_pair(pair, until, [reason])`.
`until` must be a datetime object in the future, after which trading will be re-enabled for that pair, while `reason` is an optional string detailing why the pair was locked. `until` must be a datetime object in the future, after which trading will be re-enabled for that pair, while `reason` is an optional string detailing why the pair was locked.
Locks can also be lifted manually, by calling `self.unlock_pair(pair)`. Locks can also be lifted manually, by calling `self.unlock_pair(pair)` or `self.unlock_reason(<reason>)` - providing reason the pair was locked with.
`self.unlock_reason(<reason>)` will unlock all pairs currently locked with the provided reason.
To verify if a pair is currently locked, use `self.is_pair_locked(pair)`. To verify if a pair is currently locked, use `self.is_pair_locked(pair)`.
@@ -781,6 +998,8 @@ Printing more than a few rows is also possible (simply use `print(dataframe)` i
## Common mistakes when developing strategies ## Common mistakes when developing strategies
### Peeking into the future while backtesting
Backtesting analyzes the whole time-range at once for performance reasons. Because of this, strategy authors need to make sure that strategies do not look-ahead into the future. Backtesting analyzes the whole time-range at once for performance reasons. Because of this, strategy authors need to make sure that strategies do not look-ahead into the future.
This is a common pain-point, which can cause huge differences between backtesting and dry/live run methods, since they all use data which is not available during dry/live runs, so these strategies will perform well during backtesting, but will fail / perform badly in real conditions. This is a common pain-point, which can cause huge differences between backtesting and dry/live run methods, since they all use data which is not available during dry/live runs, so these strategies will perform well during backtesting, but will fail / perform badly in real conditions.
@@ -791,9 +1010,13 @@ The following lists some common patterns which should be avoided to prevent frus
- don't use `dataframe['volume'].mean()`. This uses the full DataFrame for backtesting, including data from the future. Use `dataframe['volume'].rolling(<window>).mean()` instead - don't use `dataframe['volume'].mean()`. This uses the full DataFrame for backtesting, including data from the future. Use `dataframe['volume'].rolling(<window>).mean()` instead
- don't use `.resample('1h')`. This uses the left border of the interval, so moves data from an hour to the start of the hour. Use `.resample('1h', label='right')` instead. - don't use `.resample('1h')`. This uses the left border of the interval, so moves data from an hour to the start of the hour. Use `.resample('1h', label='right')` instead.
### Colliding signals
When buy and sell signals collide (both `'buy'` and `'sell'` are 1), freqtrade will do nothing and ignore the entry (buy) signal. This will avoid trades that buy, and sell immediately. Obviously, this can potentially lead to missed entries.
## Further strategy ideas ## Further strategy ideas
To get additional Ideas for strategies, head over to our [strategy repository](https://github.com/freqtrade/freqtrade-strategies). Feel free to use them as they are - but results will depend on the current market situation, pairs used etc. - therefore please backtest the strategy for your exchange/desired pairs first, evaluate carefully, use at your own risk. To get additional Ideas for strategies, head over to the [strategy repository](https://github.com/freqtrade/freqtrade-strategies). Feel free to use them as they are - but results will depend on the current market situation, pairs used etc. - therefore please backtest the strategy for your exchange/desired pairs first, evaluate carefully, use at your own risk.
Feel free to use any of them as inspiration for your own strategies. Feel free to use any of them as inspiration for your own strategies.
We're happy to accept Pull Requests containing new Strategies to that repo. We're happy to accept Pull Requests containing new Strategies to that repo.

View File

@@ -50,7 +50,9 @@ candles.head()
```python ```python
# Load strategy using values set above # Load strategy using values set above
from freqtrade.resolvers import StrategyResolver from freqtrade.resolvers import StrategyResolver
from freqtrade.data.dataprovider import DataProvider
strategy = StrategyResolver.load_strategy(config) strategy = StrategyResolver.load_strategy(config)
strategy.dp = DataProvider(config, None, None)
# Generate buy/sell signals using strategy # Generate buy/sell signals using strategy
df = strategy.analyze_ticker(candles, {'pair': pair}) df = strategy.analyze_ticker(candles, {'pair': pair})
@@ -228,7 +230,7 @@ graph = generate_candlestick_graph(pair=pair,
# Show graph inline # Show graph inline
# graph.show() # graph.show()
# Render graph in a separate window # Render graph in a seperate window
graph.show(renderer="browser") graph.show(renderer="browser")
``` ```

View File

@@ -58,6 +58,8 @@ For the Freqtrade configuration, you can then use the the full value (including
```json ```json
"chat_id": "-1001332619709" "chat_id": "-1001332619709"
``` ```
!!! Warning "Using telegram groups"
When using telegram groups, you're giving every member of the telegram group access to your freqtrade bot and to all commands possible via telegram. Please make sure that you can trust everyone in the telegram group to avoid unpleasent surprises.
## Control telegram noise ## Control telegram noise
@@ -93,7 +95,9 @@ Example configuration showing the different settings:
"buy_cancel": "silent", "buy_cancel": "silent",
"sell_cancel": "on", "sell_cancel": "on",
"buy_fill": "off", "buy_fill": "off",
"sell_fill": "off" "sell_fill": "off",
"protection_trigger": "off",
"protection_trigger_global": "on"
}, },
"reload": true, "reload": true,
"balance_dust_level": 0.01 "balance_dust_level": 0.01
@@ -103,6 +107,7 @@ Example configuration showing the different settings:
`buy` notifications are sent when the order is placed, while `buy_fill` notifications are sent when the order is filled on the exchange. `buy` notifications are sent when the order is placed, while `buy_fill` notifications are sent when the order is filled on the exchange.
`sell` notifications are sent when the order is placed, while `sell_fill` notifications are sent when the order is filled on the exchange. `sell` notifications are sent when the order is placed, while `sell_fill` notifications are sent when the order is filled on the exchange.
`*_fill` notifications are off by default and must be explicitly enabled. `*_fill` notifications are off by default and must be explicitly enabled.
`protection_trigger` notifications are sent when a protection triggers and `protection_trigger_global` notifications trigger when global protections are triggered.
`balance_dust_level` will define what the `/balance` command takes as "dust" - Currencies with a balance below this will be shown. `balance_dust_level` will define what the `/balance` command takes as "dust" - Currencies with a balance below this will be shown.
@@ -168,10 +173,12 @@ official commands. You can ask at any moment for help with `/help`.
| `/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) | `/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)
| `/forcesell <trade_id>` | Instantly sells the given trade (Ignoring `minimum_roi`). | `/forcesell <trade_id>` | Instantly sells the given trade (Ignoring `minimum_roi`).
| `/forcesell all` | Instantly sells all open trades (Ignoring `minimum_roi`). | `/forcesell all` | Instantly sells all open trades (Ignoring `minimum_roi`).
| `/forcebuy <pair> [rate]` | Instantly buys the given pair. Rate is optional. (`forcebuy_enable` must be set to True) | `/forcebuy <pair> [rate]` | Instantly buys the given pair. Rate is optional and only applies to limit orders. (`forcebuy_enable` must be set to True)
| `/performance` | Show performance of each finished trade grouped by pair | `/performance` | Show performance of each finished trade grouped by pair
| `/balance` | Show account balance per currency | `/balance` | Show account balance per currency
| `/daily <n>` | Shows profit or loss per day, over the last n days (n defaults to 7) | `/daily <n>` | Shows profit or loss per day, over the last n days (n defaults to 7)
| `/weekly <n>` | Shows profit or loss per week, over the last n weeks (n defaults to 8)
| `/monthly <n>` | Shows profit or loss per month, over the last n months (n defaults to 6)
| `/stats` | Shows Wins / losses by Sell reason as well as Avg. holding durations for buys and sells | `/stats` | Shows Wins / losses by Sell reason as well as Avg. holding durations for buys and sells
| `/whitelist` | Show the current whitelist | `/whitelist` | Show the current whitelist
| `/blacklist [pair]` | Show the current blacklist, or adds a pair to the blacklist. | `/blacklist [pair]` | Show the current blacklist, or adds a pair to the blacklist.
@@ -304,8 +311,7 @@ Return the balance of all crypto-currency your have on the exchange.
### /daily <n> ### /daily <n>
Per default `/daily` will return the 7 last days. Per default `/daily` will return the 7 last days. The example below if for `/daily 3`:
The example below if for `/daily 3`:
> **Daily Profit over the last 3 days:** > **Daily Profit over the last 3 days:**
``` ```
@@ -316,6 +322,34 @@ Day Profit BTC Profit USD
2018-01-01 0.00269130 BTC 34.986 USD 2018-01-01 0.00269130 BTC 34.986 USD
``` ```
### /weekly <n>
Per default `/weekly` will return the 8 last weeks, including the current week. Each week starts
from Monday. The example below if for `/weekly 3`:
> **Weekly Profit over the last 3 weeks (starting from Monday):**
```
Monday Profit BTC Profit USD
---------- -------------- ------------
2018-01-03 0.00224175 BTC 29,142 USD
2017-12-27 0.00033131 BTC 4,307 USD
2017-12-20 0.00269130 BTC 34.986 USD
```
### /monthly <n>
Per default `/monthly` will return the 6 last months, including the current month. The example below
if for `/monthly 3`:
> **Monthly Profit over the last 3 months:**
```
Month Profit BTC Profit USD
---------- -------------- ------------
2018-01 0.00224175 BTC 29,142 USD
2017-12 0.00033131 BTC 4,307 USD
2017-11 0.00269130 BTC 34.986 USD
```
### /whitelist ### /whitelist
Shows the current whitelist Shows the current whitelist

View File

@@ -26,9 +26,7 @@ optional arguments:
├── data ├── data
├── hyperopt_results ├── hyperopt_results
├── hyperopts ├── hyperopts
│   ├── sample_hyperopt_advanced.py
│   ├── sample_hyperopt_loss.py │   ├── sample_hyperopt_loss.py
│   └── sample_hyperopt.py
├── notebooks ├── notebooks
│   └── strategy_analysis_example.ipynb │   └── strategy_analysis_example.ipynb
├── plot ├── plot
@@ -111,46 +109,11 @@ Using the advanced template (populates all optional functions and methods)
freqtrade new-strategy --strategy AwesomeStrategy --template advanced freqtrade new-strategy --strategy AwesomeStrategy --template advanced
``` ```
## Create new hyperopt ## List Strategies
Creates a new hyperopt from a template similar to SampleHyperopt. Use the `list-strategies` subcommand to see all strategies in one particular directory.
The file will be named inline with your class name, and will not overwrite existing files.
Results will be located in `user_data/hyperopts/<classname>.py`. This subcommand is useful for finding problems in your environment with loading strategies: modules with strategies that contain errors and failed to load are printed in red (LOAD FAILED), while strategies with duplicate names are printed in yellow (DUPLICATE NAME).
``` output
usage: freqtrade new-hyperopt [-h] [--userdir PATH] [--hyperopt NAME]
[--template {full,minimal,advanced}]
optional arguments:
-h, --help show this help message and exit
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
--hyperopt NAME Specify hyperopt class name which will be used by the
bot.
--template {full,minimal,advanced}
Use a template which is either `minimal`, `full`
(containing multiple sample indicators) or `advanced`.
Default: `full`.
```
### Sample usage of new-hyperopt
```bash
freqtrade new-hyperopt --hyperopt AwesomeHyperopt
```
With custom user directory
```bash
freqtrade new-hyperopt --userdir ~/.freqtrade/ --hyperopt AwesomeHyperopt
```
## List Strategies and List Hyperopts
Use the `list-strategies` subcommand to see all strategies in one particular directory and the `list-hyperopts` subcommand to list custom Hyperopts.
These subcommands are useful for finding problems in your environment with loading strategies or hyperopt classes: modules with strategies or hyperopt classes that contain errors and failed to load are printed in red (LOAD FAILED), while strategies or hyperopt classes with duplicate names are printed in yellow (DUPLICATE NAME).
``` ```
usage: freqtrade list-strategies [-h] [-v] [--logfile FILE] [-V] [-c PATH] usage: freqtrade list-strategies [-h] [-v] [--logfile FILE] [-V] [-c PATH]
@@ -164,34 +127,6 @@ optional arguments:
--no-color Disable colorization of hyperopt results. May be --no-color Disable colorization of hyperopt results. May be
useful if you are redirecting output to a file. useful if you are redirecting output to a file.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile 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: `config.json`).
Multiple --config options may be used. Can be set to
`-` to read config from stdin.
-d PATH, --datadir PATH
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
```
```
usage: freqtrade list-hyperopts [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[--hyperopt-path PATH] [-1] [--no-color]
optional arguments:
-h, --help show this help message and exit
--hyperopt-path PATH Specify additional lookup path for Hyperopt and
Hyperopt Loss functions.
-1, --one-column Print output in one column.
--no-color Disable colorization of hyperopt results. May be
useful if you are redirecting output to a file.
Common arguments: Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages). -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile FILE Log to the file specified. Special values are: --logfile FILE Log to the file specified. Special values are:
@@ -211,18 +146,16 @@ Common arguments:
!!! Warning !!! Warning
Using these commands will try to load all python files from a directory. This can be a security risk if untrusted files reside in this directory, since all module-level code is executed. Using these commands will try to load all python files from a directory. This can be a security risk if untrusted files reside in this directory, since all module-level code is executed.
Example: Search default strategies and hyperopts directories (within the default userdir). Example: Search default strategies directories (within the default userdir).
``` bash ``` bash
freqtrade list-strategies freqtrade list-strategies
freqtrade list-hyperopts
``` ```
Example: Search strategies and hyperopts directory within the userdir. Example: Search strategies directory within the userdir.
``` bash ``` bash
freqtrade list-strategies --userdir ~/.freqtrade/ freqtrade list-strategies --userdir ~/.freqtrade/
freqtrade list-hyperopts --userdir ~/.freqtrade/
``` ```
Example: Search dedicated strategy path. Example: Search dedicated strategy path.
@@ -231,12 +164,6 @@ Example: Search dedicated strategy path.
freqtrade list-strategies --strategy-path ~/.freqtrade/strategies/ freqtrade list-strategies --strategy-path ~/.freqtrade/strategies/
``` ```
Example: Search dedicated hyperopt path.
``` bash
freqtrade list-hyperopt --hyperopt-path ~/.freqtrade/hyperopts/
```
## List Exchanges ## List Exchanges
Use the `list-exchanges` subcommand to see the exchanges available for the bot. Use the `list-exchanges` subcommand to see the exchanges available for the bot.
@@ -354,7 +281,7 @@ bitmax True missing opt: fetchMyTrades
bitmex False Various reasons. bitmex False Various reasons.
bitpanda True bitpanda True
bitso False missing: fetchOHLCV bitso False missing: fetchOHLCV
bitstamp False Does not provide history. Details in https://github.com/freqtrade/freqtrade/issues/1983 bitstamp True missing opt: fetchTickers
bitstamp1 False missing: fetchOrder, fetchOHLCV bitstamp1 False missing: fetchOrder, fetchOHLCV
bittrex True bittrex True
bitvavo True bitvavo True
@@ -650,6 +577,46 @@ Common arguments:
``` ```
## Show previous Backtest results
Allows you to show previous backtest results.
Adding `--show-pair-list` outputs a sorted pair list you can easily copy/paste into your configuration (omitting bad pairs).
??? Warning "Strategy overfitting"
Only using winning pairs can lead to an overfitted strategy, which will not work well on future data. Make sure to extensively test your strategy in dry-run before risking real money.
```
usage: freqtrade backtesting-show [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[-d PATH] [--userdir PATH]
[--export-filename PATH] [--show-pair-list]
optional arguments:
-h, --help show this help message and exit
--export-filename PATH
Save backtest results to the file with this filename.
Requires `--export` to be set as well. Example:
`--export-filename=user_data/backtest_results/backtest
_today.json`
--show-pair-list Show backtesting pairlist sorted by profit.
Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages).
--logfile 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
Path to directory with historical backtesting data.
--userdir PATH, --user-data-dir PATH
Path to userdata directory.
```
## List Hyperopt results ## List Hyperopt results
You can list the hyperoptimization epochs the Hyperopt module evaluated previously with the `hyperopt-list` sub-command. You can list the hyperoptimization epochs the Hyperopt module evaluated previously with the `hyperopt-list` sub-command.
@@ -740,6 +707,7 @@ usage: freqtrade hyperopt-show [-h] [-v] [--logfile FILE] [-V] [-c PATH]
[--profitable] [-n INT] [--print-json] [--profitable] [-n INT] [--print-json]
[--hyperopt-filename FILENAME] [--no-header] [--hyperopt-filename FILENAME] [--no-header]
[--disable-param-export] [--disable-param-export]
[--breakdown {day,week,month} [{day,week,month} ...]]
optional arguments: optional arguments:
-h, --help show this help message and exit -h, --help show this help message and exit
@@ -753,6 +721,8 @@ optional arguments:
--no-header Do not print epoch details header. --no-header Do not print epoch details header.
--disable-param-export --disable-param-export
Disable automatic hyperopt parameter export. Disable automatic hyperopt parameter export.
--breakdown {day,week,month} [{day,week,month} ...]
Show backtesting breakdown per [day, week, month].
Common arguments: Common arguments:
-v, --verbose Verbose mode (-vv for more, -vvv to get all messages). -v, --verbose Verbose mode (-vv for more, -vvv to get all messages).

View File

@@ -48,9 +48,9 @@ Sample configuration (tested using IFTTT).
}, },
``` ```
The url in `webhook.url` should point to the correct url for your webhook. If you're using [IFTTT](https://ifttt.com) (as shown in the sample above) please insert our event and key to the url. The url in `webhook.url` should point to the correct url for your webhook. If you're using [IFTTT](https://ifttt.com) (as shown in the sample above) please insert your event and key to the url.
You can set the POST body format to Form-Encoded (default) or JSON-Encoded. Use `"format": "form"` or `"format": "json"` respectively. Example configuration for Mattermost Cloud integration: You can set the POST body format to Form-Encoded (default), JSON-Encoded, or raw data. Use `"format": "form"`, `"format": "json"`, or `"format": "raw"` respectively. Example configuration for Mattermost Cloud integration:
```json ```json
"webhook": { "webhook": {
@@ -63,7 +63,36 @@ You can set the POST body format to Form-Encoded (default) or JSON-Encoded. Use
}, },
``` ```
The result would be POST request with e.g. `{"text":"Status: running"}` body and `Content-Type: application/json` header which results `Status: running` message in the Mattermost channel. The result would be a POST request with e.g. `{"text":"Status: running"}` body and `Content-Type: application/json` header which results `Status: running` message in the Mattermost channel.
When using the Form-Encoded or JSON-Encoded configuration you can configure any number of payload values, and both the key and value will be ouput in the POST request. However, when using the raw data format you can only configure one value and it **must** be named `"data"`. In this instance the data key will not be output in the POST request, only the value. For example:
```json
"webhook": {
"enabled": true,
"url": "https://<YOURHOOKURL>",
"format": "raw",
"webhookstatus": {
"data": "Status: {status}"
}
},
```
The result would be a POST request with e.g. `Status: running` body and `Content-Type: text/plain` header.
Optional parameters are available to enable automatic retries for webhook messages. The `webhook.retries` parameter can be set for the maximum number of retries the webhook request should attempt if it is unsuccessful (i.e. HTTP response status is not 200). By default this is set to `0` which is disabled. An additional `webhook.retry_delay` parameter can be set to specify the time in seconds between retry attempts. By default this is set to `0.1` (i.e. 100ms). Note that increasing the number of retries or retry delay may slow down the trader if there are connectivity issues with the webhook. Example configuration for retries:
```json
"webhook": {
"enabled": true,
"url": "https://<YOURHOOKURL>",
"retries": 3,
"retry_delay": 0.2,
"webhookstatus": {
"status": "Status: {status}"
}
},
```
Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called. Different payloads can be configured for different events. Not all fields are necessary, but you should configure at least one of the dicts, otherwise the webhook will never be called.
@@ -75,11 +104,13 @@ Possible parameters are:
* `trade_id` * `trade_id`
* `exchange` * `exchange`
* `pair` * `pair`
* `limit` * ~~`limit` # Deprecated - should no longer be used.~~
* `open_rate`
* `amount` * `amount`
* `open_date` * `open_date`
* `stake_amount` * `stake_amount`
* `stake_currency` * `stake_currency`
* `base_currency`
* `fiat_currency` * `fiat_currency`
* `order_type` * `order_type`
* `current_rate` * `current_rate`
@@ -98,6 +129,7 @@ Possible parameters are:
* `open_date` * `open_date`
* `stake_amount` * `stake_amount`
* `stake_currency` * `stake_currency`
* `base_currency`
* `fiat_currency` * `fiat_currency`
* `order_type` * `order_type`
* `current_rate` * `current_rate`
@@ -116,7 +148,10 @@ Possible parameters are:
* `open_date` * `open_date`
* `stake_amount` * `stake_amount`
* `stake_currency` * `stake_currency`
* `base_currency`
* `fiat_currency` * `fiat_currency`
* `order_type`
* `current_rate`
* `buy_tag` * `buy_tag`
### Webhooksell ### Webhooksell
@@ -134,6 +169,7 @@ Possible parameters are:
* `profit_amount` * `profit_amount`
* `profit_ratio` * `profit_ratio`
* `stake_currency` * `stake_currency`
* `base_currency`
* `fiat_currency` * `fiat_currency`
* `sell_reason` * `sell_reason`
* `order_type` * `order_type`
@@ -156,6 +192,7 @@ Possible parameters are:
* `profit_amount` * `profit_amount`
* `profit_ratio` * `profit_ratio`
* `stake_currency` * `stake_currency`
* `base_currency`
* `fiat_currency` * `fiat_currency`
* `sell_reason` * `sell_reason`
* `order_type` * `order_type`
@@ -178,6 +215,7 @@ Possible parameters are:
* `profit_amount` * `profit_amount`
* `profit_ratio` * `profit_ratio`
* `stake_currency` * `stake_currency`
* `base_currency`
* `fiat_currency` * `fiat_currency`
* `sell_reason` * `sell_reason`
* `order_type` * `order_type`

View File

@@ -23,9 +23,9 @@ git clone https://github.com/freqtrade/freqtrade.git
Install ta-lib according to the [ta-lib documentation](https://github.com/mrjbq7/ta-lib#windows). Install ta-lib according to the [ta-lib documentation](https://github.com/mrjbq7/ta-lib#windows).
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.21-cp38-cp38-win_amd64.whl` (make sure to use the version matching your python version). 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_Lib0.4.22cp38cp38win_amd64.whl` (make sure to use the version matching your python version).
Freqtrade provides these dependencies for the latest 2 Python versions (3.7 and 3.8) and for 64bit Windows. Freqtrade provides these dependencies for the latest 3 Python versions (3.7, 3.8 and 3.9) and for 64bit Windows.
Other versions must be downloaded from the above link. Other versions must be downloaded from the above link.
``` powershell ``` powershell

View File

@@ -16,7 +16,6 @@ dependencies:
- cachetools - cachetools
- requests - requests
- urllib3 - urllib3
- wrapt
- jsonschema - jsonschema
- TA-Lib - TA-Lib
- tabulate - tabulate
@@ -64,7 +63,6 @@ dependencies:
- py_find_1st - py_find_1st
- tables - tables
- pytest-random-order - pytest-random-order
- flake8-type-annotations
- ccxt - ccxt
- flake8-tidy-imports - flake8-tidy-imports
- -e . - -e .

View File

@@ -1,5 +1,5 @@
""" Freqtrade bot """ """ Freqtrade bot """
__version__ = '2021.8' __version__ = '2021.12'
if __version__ == 'develop': if __version__ == 'develop':
@@ -22,7 +22,7 @@ if __version__ == 'develop':
# subprocess.check_output( # subprocess.check_output(
# ['git', 'log', '--format="%h"', '-n 1'], # ['git', 'log', '--format="%h"', '-n 1'],
# stderr=subprocess.DEVNULL).decode("utf-8").rstrip().strip('"') # stderr=subprocess.DEVNULL).decode("utf-8").rstrip().strip('"')
except Exception: except Exception: # pragma: no cover
# git not available, ignore # git not available, ignore
try: try:
# Try Fallback to freqtrade_commit file (created by CI while building docker image) # Try Fallback to freqtrade_commit file (created by CI while building docker image)

View File

@@ -8,15 +8,16 @@ Note: Be careful with file-scoped imports in these subfiles.
""" """
from freqtrade.commands.arguments import Arguments from freqtrade.commands.arguments import Arguments
from freqtrade.commands.build_config_commands import start_new_config from freqtrade.commands.build_config_commands import start_new_config
from freqtrade.commands.data_commands import (start_convert_data, start_download_data, from freqtrade.commands.data_commands import (start_convert_data, start_convert_trades,
start_list_data) start_download_data, start_list_data)
from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui, from freqtrade.commands.deploy_commands import (start_create_userdir, start_install_ui,
start_new_hyperopt, start_new_strategy) start_new_strategy)
from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show from freqtrade.commands.hyperopt_commands import start_hyperopt_list, start_hyperopt_show
from freqtrade.commands.list_commands import (start_list_exchanges, start_list_hyperopts, from freqtrade.commands.list_commands import (start_list_exchanges, start_list_markets,
start_list_markets, start_list_strategies, start_list_strategies, start_list_timeframes,
start_list_timeframes, start_show_trades) start_show_trades)
from freqtrade.commands.optimize_commands import start_backtesting, start_edge, start_hyperopt from freqtrade.commands.optimize_commands import (start_backtesting, start_backtesting_show,
start_edge, start_hyperopt)
from freqtrade.commands.pairlist_commands import start_test_pairlist from freqtrade.commands.pairlist_commands import start_test_pairlist
from freqtrade.commands.plot_commands import start_plot_dataframe, start_plot_profit from freqtrade.commands.plot_commands import start_plot_dataframe, start_plot_profit
from freqtrade.commands.trade_commands import start_trading from freqtrade.commands.trade_commands import start_trading

View File

@@ -22,8 +22,9 @@ ARGS_COMMON_OPTIMIZE = ["timeframe", "timerange", "dataformat_ohlcv",
"max_open_trades", "stake_amount", "fee", "pairs"] "max_open_trades", "stake_amount", "fee", "pairs"]
ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions", ARGS_BACKTEST = ARGS_COMMON_OPTIMIZE + ["position_stacking", "use_max_market_positions",
"enable_protections", "dry_run_wallet", "enable_protections", "dry_run_wallet", "timeframe_detail",
"strategy_list", "export", "exportfilename"] "strategy_list", "export", "exportfilename",
"backtest_breakdown"]
ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path", ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path",
"position_stacking", "use_max_market_positions", "position_stacking", "use_max_market_positions",
@@ -31,7 +32,8 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path",
"epochs", "spaces", "print_all", "epochs", "spaces", "print_all",
"print_colorized", "print_json", "hyperopt_jobs", "print_colorized", "print_json", "hyperopt_jobs",
"hyperopt_random_state", "hyperopt_min_trades", "hyperopt_random_state", "hyperopt_min_trades",
"hyperopt_loss", "disableparamexport"] "hyperopt_loss", "disableparamexport",
"hyperopt_ignore_missing_space"]
ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"]
@@ -39,6 +41,8 @@ ARGS_LIST_STRATEGIES = ["strategy_path", "print_one_column", "print_colorized"]
ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column", "print_colorized"] ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column", "print_colorized"]
ARGS_BACKTEST_SHOW = ["exportfilename", "backtest_show_pair_list"]
ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"] ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all"]
ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"] ARGS_LIST_TIMEFRAMES = ["exchange", "print_one_column"]
@@ -55,16 +59,16 @@ ARGS_BUILD_CONFIG = ["config"]
ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"] ARGS_BUILD_STRATEGY = ["user_data_dir", "strategy", "template"]
ARGS_BUILD_HYPEROPT = ["user_data_dir", "hyperopt", "template"]
ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase"] ARGS_CONVERT_DATA = ["pairs", "format_from", "format_to", "erase"]
ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes"] ARGS_CONVERT_DATA_OHLCV = ARGS_CONVERT_DATA + ["timeframes"]
ARGS_CONVERT_TRADES = ["pairs", "timeframes", "exchange", "dataformat_ohlcv", "dataformat_trades"]
ARGS_LIST_DATA = ["exchange", "dataformat_ohlcv", "pairs"] ARGS_LIST_DATA = ["exchange", "dataformat_ohlcv", "pairs"]
ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "new_pairs_days", "timerange", ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "new_pairs_days", "include_inactive",
"download_trades", "exchange", "timeframes", "erase", "dataformat_ohlcv", "timerange", "download_trades", "exchange", "timeframes",
"dataformat_trades"] "erase", "dataformat_ohlcv", "dataformat_trades"]
ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit",
"db_url", "trade_source", "export", "exportfilename", "db_url", "trade_source", "export", "exportfilename",
@@ -73,7 +77,7 @@ ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit",
ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url", ARGS_PLOT_PROFIT = ["pairs", "timerange", "export", "exportfilename", "db_url",
"trade_source", "timeframe", "plot_auto_open"] "trade_source", "timeframe", "plot_auto_open"]
ARGS_INSTALL_UI = ["erase_ui_only"] ARGS_INSTALL_UI = ["erase_ui_only", 'ui_version']
ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"] ARGS_SHOW_TRADES = ["db_url", "trade_ids", "print_json"]
@@ -88,14 +92,14 @@ ARGS_HYPEROPT_LIST = ["hyperopt_list_best", "hyperopt_list_profitable",
ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_show_index", ARGS_HYPEROPT_SHOW = ["hyperopt_list_best", "hyperopt_list_profitable", "hyperopt_show_index",
"print_json", "hyperoptexportfilename", "hyperopt_show_no_header", "print_json", "hyperoptexportfilename", "hyperopt_show_no_header",
"disableparamexport"] "disableparamexport", "backtest_breakdown"]
NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes", NO_CONF_REQURIED = ["convert-data", "convert-trade-data", "download-data", "list-timeframes",
"list-markets", "list-pairs", "list-strategies", "list-data", "list-markets", "list-pairs", "list-strategies", "list-data",
"list-hyperopts", "hyperopt-list", "hyperopt-show", "hyperopt-list", "hyperopt-show", "backtest-filter",
"plot-dataframe", "plot-profit", "show-trades"] "plot-dataframe", "plot-profit", "show-trades", "trades-to-ohlcv"]
NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-hyperopt", "new-strategy"] NO_CONF_ALLOWED = ["create-userdir", "list-exchanges", "new-strategy"]
class Arguments: class Arguments:
@@ -171,15 +175,15 @@ class Arguments:
self.parser = argparse.ArgumentParser(description='Free, open source crypto trading bot') self.parser = argparse.ArgumentParser(description='Free, open source crypto trading bot')
self._build_args(optionlist=['version'], parser=self.parser) self._build_args(optionlist=['version'], parser=self.parser)
from freqtrade.commands import (start_backtesting, start_convert_data, start_create_userdir, from freqtrade.commands import (start_backtesting, start_backtesting_show,
start_download_data, start_edge, start_hyperopt, start_convert_data, start_convert_trades,
start_hyperopt_list, start_hyperopt_show, start_install_ui, start_create_userdir, start_download_data, start_edge,
start_list_data, start_list_exchanges, start_list_hyperopts, start_hyperopt, start_hyperopt_list, start_hyperopt_show,
start_install_ui, start_list_data, start_list_exchanges,
start_list_markets, start_list_strategies, start_list_markets, start_list_strategies,
start_list_timeframes, start_new_config, start_new_hyperopt, start_list_timeframes, start_new_config, start_new_strategy,
start_new_strategy, start_plot_dataframe, start_plot_profit, start_plot_dataframe, start_plot_profit, start_show_trades,
start_show_trades, start_test_pairlist, start_trading, start_test_pairlist, start_trading, start_webserver)
start_webserver)
subparsers = self.parser.add_subparsers(dest='command', subparsers = self.parser.add_subparsers(dest='command',
# Use custom message when no subhandler is added # Use custom message when no subhandler is added
@@ -206,12 +210,6 @@ class Arguments:
build_config_cmd.set_defaults(func=start_new_config) build_config_cmd.set_defaults(func=start_new_config)
self._build_args(optionlist=ARGS_BUILD_CONFIG, parser=build_config_cmd) self._build_args(optionlist=ARGS_BUILD_CONFIG, parser=build_config_cmd)
# add new-hyperopt subcommand
build_hyperopt_cmd = subparsers.add_parser('new-hyperopt',
help="Create new hyperopt")
build_hyperopt_cmd.set_defaults(func=start_new_hyperopt)
self._build_args(optionlist=ARGS_BUILD_HYPEROPT, parser=build_hyperopt_cmd)
# add new-strategy subcommand # add new-strategy subcommand
build_strategy_cmd = subparsers.add_parser('new-strategy', build_strategy_cmd = subparsers.add_parser('new-strategy',
help="Create new strategy") help="Create new strategy")
@@ -245,6 +243,15 @@ class Arguments:
convert_trade_data_cmd.set_defaults(func=partial(start_convert_data, ohlcv=False)) convert_trade_data_cmd.set_defaults(func=partial(start_convert_data, ohlcv=False))
self._build_args(optionlist=ARGS_CONVERT_DATA, parser=convert_trade_data_cmd) self._build_args(optionlist=ARGS_CONVERT_DATA, parser=convert_trade_data_cmd)
# Add trades-to-ohlcv subcommand
convert_trade_data_cmd = subparsers.add_parser(
'trades-to-ohlcv',
help='Convert trade data to OHLCV data.',
parents=[_common_parser],
)
convert_trade_data_cmd.set_defaults(func=start_convert_trades)
self._build_args(optionlist=ARGS_CONVERT_TRADES, parser=convert_trade_data_cmd)
# Add list-data subcommand # Add list-data subcommand
list_data_cmd = subparsers.add_parser( list_data_cmd = subparsers.add_parser(
'list-data', 'list-data',
@@ -260,6 +267,15 @@ class Arguments:
backtesting_cmd.set_defaults(func=start_backtesting) backtesting_cmd.set_defaults(func=start_backtesting)
self._build_args(optionlist=ARGS_BACKTEST, parser=backtesting_cmd) self._build_args(optionlist=ARGS_BACKTEST, parser=backtesting_cmd)
# Add backtesting-show subcommand
backtesting_show_cmd = subparsers.add_parser(
'backtesting-show',
help='Show past Backtest results',
parents=[_common_parser],
)
backtesting_show_cmd.set_defaults(func=start_backtesting_show)
self._build_args(optionlist=ARGS_BACKTEST_SHOW, parser=backtesting_show_cmd)
# Add edge subcommand # Add edge subcommand
edge_cmd = subparsers.add_parser('edge', help='Edge module.', edge_cmd = subparsers.add_parser('edge', help='Edge module.',
parents=[_common_parser, _strategy_parser]) parents=[_common_parser, _strategy_parser])
@@ -300,15 +316,6 @@ class Arguments:
list_exchanges_cmd.set_defaults(func=start_list_exchanges) list_exchanges_cmd.set_defaults(func=start_list_exchanges)
self._build_args(optionlist=ARGS_LIST_EXCHANGES, parser=list_exchanges_cmd) self._build_args(optionlist=ARGS_LIST_EXCHANGES, parser=list_exchanges_cmd)
# Add list-hyperopts subcommand
list_hyperopts_cmd = subparsers.add_parser(
'list-hyperopts',
help='Print available hyperopt classes.',
parents=[_common_parser],
)
list_hyperopts_cmd.set_defaults(func=start_list_hyperopts)
self._build_args(optionlist=ARGS_LIST_HYPEROPTS, parser=list_hyperopts_cmd)
# Add list-markets subcommand # Add list-markets subcommand
list_markets_cmd = subparsers.add_parser( list_markets_cmd = subparsers.add_parser(
'list-markets', 'list-markets',

View File

@@ -61,27 +61,41 @@ def ask_user_config() -> Dict[str, Any]:
"type": "text", "type": "text",
"name": "stake_currency", "name": "stake_currency",
"message": "Please insert your stake currency:", "message": "Please insert your stake currency:",
"default": 'BTC', "default": 'USDT',
}, },
{ {
"type": "text", "type": "text",
"name": "stake_amount", "name": "stake_amount",
"message": "Please insert your stake amount:", "message": f"Please insert your stake amount (Number or '{UNLIMITED_STAKE_AMOUNT}'):",
"default": "0.01", "default": "100",
"validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val), "validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val),
"filter": lambda val: '"' + UNLIMITED_STAKE_AMOUNT + '"'
if val == UNLIMITED_STAKE_AMOUNT
else val
}, },
{ {
"type": "text", "type": "text",
"name": "max_open_trades", "name": "max_open_trades",
"message": f"Please insert max_open_trades (Integer or '{UNLIMITED_STAKE_AMOUNT}'):", "message": f"Please insert max_open_trades (Integer or '{UNLIMITED_STAKE_AMOUNT}'):",
"default": "3", "default": "3",
"validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_int(val) "validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_int(val),
"filter": lambda val: '"' + UNLIMITED_STAKE_AMOUNT + '"'
if val == UNLIMITED_STAKE_AMOUNT
else val
},
{
"type": "select",
"name": "timeframe_in_config",
"message": "Tim",
"choices": ["Have the strategy define timeframe.", "Override in configuration."]
}, },
{ {
"type": "text", "type": "text",
"name": "timeframe", "name": "timeframe",
"message": "Please insert your desired timeframe (e.g. 5m):", "message": "Please insert your desired timeframe (e.g. 5m):",
"default": "5m", "default": "5m",
"when": lambda x: x["timeframe_in_config"] == 'Override in configuration.'
}, },
{ {
"type": "text", "type": "text",
@@ -99,6 +113,9 @@ def ask_user_config() -> Dict[str, Any]:
"bittrex", "bittrex",
"kraken", "kraken",
"ftx", "ftx",
"kucoin",
"gateio",
"okex",
Separator(), Separator(),
"other", "other",
], ],
@@ -122,6 +139,12 @@ def ask_user_config() -> Dict[str, Any]:
"message": "Insert Exchange Secret", "message": "Insert Exchange Secret",
"when": lambda x: not x['dry_run'] "when": lambda x: not x['dry_run']
}, },
{
"type": "password",
"name": "exchange_key_password",
"message": "Insert Exchange API Key password",
"when": lambda x: not x['dry_run'] and x['exchange_name'] in ('kucoin', 'okex')
},
{ {
"type": "confirm", "type": "confirm",
"name": "telegram", "name": "telegram",
@@ -149,7 +172,8 @@ def ask_user_config() -> Dict[str, Any]:
{ {
"type": "text", "type": "text",
"name": "api_server_listen_addr", "name": "api_server_listen_addr",
"message": "Insert Api server Listen Address (best left untouched default!)", "message": ("Insert Api server Listen Address (0.0.0.0 for docker, "
"otherwise best left untouched)"),
"default": "127.0.0.1", "default": "127.0.0.1",
"when": lambda x: x['api_server'] "when": lambda x: x['api_server']
}, },

View File

@@ -1,7 +1,7 @@
""" """
Definition of cli arguments used in arguments.py Definition of cli arguments used in arguments.py
""" """
from argparse import ArgumentTypeError from argparse import SUPPRESS, ArgumentTypeError
from freqtrade import __version__, constants from freqtrade import __version__, constants
from freqtrade.constants import HYPEROPT_LOSS_BUILTIN from freqtrade.constants import HYPEROPT_LOSS_BUILTIN
@@ -135,6 +135,10 @@ AVAILABLE_CLI_OPTIONS = {
help='Override the value of the `stake_amount` configuration setting.', help='Override the value of the `stake_amount` configuration setting.',
), ),
# Backtesting # Backtesting
"timeframe_detail": Arg(
'--timeframe-detail',
help='Specify detail timeframe for backtesting (`1m`, `5m`, `30m`, `1h`, `1d`).',
),
"position_stacking": Arg( "position_stacking": Arg(
'--eps', '--enable-position-stacking', '--eps', '--enable-position-stacking',
help='Allow buying the same pair multiple times (position stacking).', help='Allow buying the same pair multiple times (position stacking).',
@@ -148,6 +152,12 @@ AVAILABLE_CLI_OPTIONS = {
action='store_false', action='store_false',
default=True, default=True,
), ),
"backtest_show_pair_list": Arg(
'--show-pair-list',
help='Show backtesting pairlist sorted by profit.',
action='store_true',
default=False,
),
"enable_protections": Arg( "enable_protections": Arg(
'--enable-protections', '--enableprotections', '--enable-protections', '--enableprotections',
help='Enable protections for backtesting.' help='Enable protections for backtesting.'
@@ -189,6 +199,12 @@ AVAILABLE_CLI_OPTIONS = {
type=float, type=float,
metavar='FLOAT', metavar='FLOAT',
), ),
"backtest_breakdown": Arg(
'--breakdown',
help='Show backtesting breakdown per [day, week, month].',
nargs='+',
choices=constants.BACKTEST_BREAKDOWNS
),
# Edge # Edge
"stoploss_range": Arg( "stoploss_range": Arg(
'--stoplosses', '--stoplosses',
@@ -199,13 +215,13 @@ AVAILABLE_CLI_OPTIONS = {
# Hyperopt # Hyperopt
"hyperopt": Arg( "hyperopt": Arg(
'--hyperopt', '--hyperopt',
help='Specify hyperopt class name which will be used by the bot.', help=SUPPRESS,
metavar='NAME', metavar='NAME',
required=False, required=False,
), ),
"hyperopt_path": Arg( "hyperopt_path": Arg(
'--hyperopt-path', '--hyperopt-path',
help='Specify additional lookup path for Hyperopt and Hyperopt Loss functions.', help='Specify additional lookup path for Hyperopt Loss functions.',
metavar='PATH', metavar='PATH',
), ),
"epochs": Arg( "epochs": Arg(
@@ -351,6 +367,11 @@ AVAILABLE_CLI_OPTIONS = {
type=check_int_positive, type=check_int_positive,
metavar='INT', metavar='INT',
), ),
"include_inactive": Arg(
'--include-inactive-pairs',
help='Also download data from inactive pairs.',
action='store_true',
),
"new_pairs_days": Arg( "new_pairs_days": Arg(
'--new-pairs-days', '--new-pairs-days',
help='Download data of new pairs for given number of days. Default: `%(default)s`.', help='Download data of new pairs for given number of days. Default: `%(default)s`.',
@@ -377,12 +398,12 @@ AVAILABLE_CLI_OPTIONS = {
), ),
"dataformat_ohlcv": Arg( "dataformat_ohlcv": Arg(
'--data-format-ohlcv', '--data-format-ohlcv',
help='Storage format for downloaded candle (OHLCV) data. (default: `%(default)s`).', help='Storage format for downloaded candle (OHLCV) data. (default: `json`).',
choices=constants.AVAILABLE_DATAHANDLERS, choices=constants.AVAILABLE_DATAHANDLERS,
), ),
"dataformat_trades": Arg( "dataformat_trades": Arg(
'--data-format-trades', '--data-format-trades',
help='Storage format for downloaded trades data. (default: `%(default)s`).', help='Storage format for downloaded trades data. (default: `jsongz`).',
choices=constants.AVAILABLE_DATAHANDLERS, choices=constants.AVAILABLE_DATAHANDLERS,
), ),
"exchange": Arg( "exchange": Arg(
@@ -410,6 +431,12 @@ AVAILABLE_CLI_OPTIONS = {
action='store_true', action='store_true',
default=False, default=False,
), ),
"ui_version": Arg(
'--ui-version',
help=('Specify a specific version of FreqUI to install. '
'Not specifying this installs the latest version.'),
type=str,
),
# Templating options # Templating options
"template": Arg( "template": Arg(
'--template', '--template',
@@ -548,4 +575,10 @@ AVAILABLE_CLI_OPTIONS = {
help='Do not print epoch details header.', help='Do not print epoch details header.',
action='store_true', action='store_true',
), ),
"hyperopt_ignore_missing_space": Arg(
"--ignore-missing-spaces", "--ignore-unparameterized-spaces",
help=("Suppress errors for any requested Hyperopt spaces "
"that do not contain any parameters."),
action="store_true",
),
} }

View File

@@ -11,6 +11,7 @@ from freqtrade.data.history import (convert_trades_to_ohlcv, refresh_backtest_oh
from freqtrade.enums import RunMode from freqtrade.enums import RunMode
from freqtrade.exceptions import OperationalException from freqtrade.exceptions import OperationalException
from freqtrade.exchange import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.exchange.exchange import market_is_active
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
from freqtrade.resolvers import ExchangeResolver from freqtrade.resolvers import ExchangeResolver
@@ -47,11 +48,13 @@ def start_download_data(args: Dict[str, Any]) -> None:
# Init exchange # Init exchange
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False) exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False)
markets = [p for p, m in exchange.markets.items() if market_is_active(m)
or config.get('include_inactive')]
expanded_pairs = expand_pairlist(config['pairs'], markets)
# Manual validations of relevant settings # Manual validations of relevant settings
if not config['exchange'].get('skip_pair_validation', False): if not config['exchange'].get('skip_pair_validation', False):
exchange.validate_pairs(config['pairs']) exchange.validate_pairs(expanded_pairs)
expanded_pairs = expand_pairlist(config['pairs'], list(exchange.markets))
logger.info(f"About to download pairs: {expanded_pairs}, " logger.info(f"About to download pairs: {expanded_pairs}, "
f"intervals: {config['timeframes']} to {config['datadir']}") f"intervals: {config['timeframes']} to {config['datadir']}")
@@ -89,6 +92,41 @@ def start_download_data(args: Dict[str, Any]) -> None:
f"on exchange {exchange.name}.") f"on exchange {exchange.name}.")
def start_convert_trades(args: Dict[str, Any]) -> None:
config = setup_utils_configuration(args, RunMode.UTIL_EXCHANGE)
timerange = TimeRange()
# 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.")
# Init exchange
exchange = ExchangeResolver.load_exchange(config['exchange']['name'], config, validate=False)
# Manual validations of relevant settings
if not config['exchange'].get('skip_pair_validation', False):
exchange.validate_pairs(config['pairs'])
expanded_pairs = expand_pairlist(config['pairs'], list(exchange.markets))
logger.info(f"About to Convert pairs: {expanded_pairs}, "
f"intervals: {config['timeframes']} to {config['datadir']}")
for timeframe in config['timeframes']:
exchange.validate_timeframes(timeframe)
# Convert downloaded trade data to different timeframes
convert_trades_to_ohlcv(
pairs=expanded_pairs, timeframes=config['timeframes'],
datadir=config['datadir'], timerange=timerange, erase=bool(config.get('erase')),
data_format_ohlcv=config['dataformat_ohlcv'],
data_format_trades=config['dataformat_trades'],
)
def start_convert_data(args: Dict[str, Any], ohlcv: bool = True) -> None: def start_convert_data(args: Dict[str, Any], ohlcv: bool = True) -> None:
""" """
Convert data from one format to another Convert data from one format to another

View File

@@ -7,7 +7,7 @@ import requests
from freqtrade.configuration import setup_utils_configuration from freqtrade.configuration import setup_utils_configuration
from freqtrade.configuration.directory_operations import copy_sample_files, create_userdata_dir from freqtrade.configuration.directory_operations import copy_sample_files, create_userdata_dir
from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES from freqtrade.constants import USERPATH_STRATEGIES
from freqtrade.enums import RunMode from freqtrade.enums import RunMode
from freqtrade.exceptions import OperationalException from freqtrade.exceptions import OperationalException
from freqtrade.misc import render_template, render_template_with_fallback from freqtrade.misc import render_template, render_template_with_fallback
@@ -87,56 +87,6 @@ def start_new_strategy(args: Dict[str, Any]) -> None:
raise OperationalException("`new-strategy` requires --strategy to be set.") raise OperationalException("`new-strategy` requires --strategy to be set.")
def deploy_new_hyperopt(hyperopt_name: str, hyperopt_path: Path, subtemplate: str) -> None:
"""
Deploys a new hyperopt template to hyperopt_path
"""
fallback = 'full'
buy_guards = render_template_with_fallback(
templatefile=f"subtemplates/hyperopt_buy_guards_{subtemplate}.j2",
templatefallbackfile=f"subtemplates/hyperopt_buy_guards_{fallback}.j2",
)
sell_guards = render_template_with_fallback(
templatefile=f"subtemplates/hyperopt_sell_guards_{subtemplate}.j2",
templatefallbackfile=f"subtemplates/hyperopt_sell_guards_{fallback}.j2",
)
buy_space = render_template_with_fallback(
templatefile=f"subtemplates/hyperopt_buy_space_{subtemplate}.j2",
templatefallbackfile=f"subtemplates/hyperopt_buy_space_{fallback}.j2",
)
sell_space = render_template_with_fallback(
templatefile=f"subtemplates/hyperopt_sell_space_{subtemplate}.j2",
templatefallbackfile=f"subtemplates/hyperopt_sell_space_{fallback}.j2",
)
strategy_text = render_template(templatefile='base_hyperopt.py.j2',
arguments={"hyperopt": hyperopt_name,
"buy_guards": buy_guards,
"sell_guards": sell_guards,
"buy_space": buy_space,
"sell_space": sell_space,
})
logger.info(f"Writing hyperopt to `{hyperopt_path}`.")
hyperopt_path.write_text(strategy_text)
def start_new_hyperopt(args: Dict[str, Any]) -> None:
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
if 'hyperopt' in args and args['hyperopt']:
new_path = config['user_data_dir'] / USERPATH_HYPEROPTS / (args['hyperopt'] + '.py')
if new_path.exists():
raise OperationalException(f"`{new_path}` already exists. "
"Please choose another Hyperopt Name.")
deploy_new_hyperopt(args['hyperopt'], new_path, args['template'])
else:
raise OperationalException("`new-hyperopt` requires --hyperopt to be set.")
def clean_ui_subdir(directory: Path): def clean_ui_subdir(directory: Path):
if directory.is_dir(): if directory.is_dir():
logger.info("Removing UI directory content.") logger.info("Removing UI directory content.")
@@ -178,7 +128,7 @@ def download_and_install_ui(dest_folder: Path, dl_url: str, version: str):
f.write(version) f.write(version)
def get_ui_download_url() -> Tuple[str, str]: def get_ui_download_url(version: Optional[str] = None) -> Tuple[str, str]:
base_url = 'https://api.github.com/repos/freqtrade/frequi/' base_url = 'https://api.github.com/repos/freqtrade/frequi/'
# Get base UI Repo path # Get base UI Repo path
@@ -186,6 +136,14 @@ def get_ui_download_url() -> Tuple[str, str]:
resp.raise_for_status() resp.raise_for_status()
r = resp.json() r = resp.json()
if version:
tmp = [x for x in r if x['name'] == version]
if tmp:
latest_version = tmp[0]['name']
assets = tmp[0].get('assets', [])
else:
raise ValueError("UI-Version not found.")
else:
latest_version = r[0]['name'] latest_version = r[0]['name']
assets = r[0].get('assets', []) assets = r[0].get('assets', [])
dl_url = '' dl_url = ''
@@ -206,7 +164,7 @@ def start_install_ui(args: Dict[str, Any]) -> None:
dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui/installed/' dest_folder = Path(__file__).parents[1] / 'rpc/api_server/ui/installed/'
# First make sure the assets are removed. # First make sure the assets are removed.
dl_url, latest_version = get_ui_download_url() dl_url, latest_version = get_ui_download_url(args.get('ui_version'))
curr_version = read_ui_version(dest_folder) curr_version = read_ui_version(dest_folder)
if curr_version == latest_version and not args.get('erase_ui_only'): if curr_version == latest_version and not args.get('erase_ui_only'):

View File

@@ -53,7 +53,7 @@ def start_hyperopt_list(args: Dict[str, Any]) -> None:
if epochs and export_csv: if epochs and export_csv:
HyperoptTools.export_csv_file( HyperoptTools.export_csv_file(
config, epochs, total_epochs, not config.get('hyperopt_list_best', False), export_csv config, epochs, export_csv
) )
@@ -96,7 +96,7 @@ def start_hyperopt_show(args: Dict[str, Any]) -> None:
if 'strategy_name' in metrics: if 'strategy_name' in metrics:
strategy_name = metrics['strategy_name'] strategy_name = metrics['strategy_name']
show_backtest_result(strategy_name, metrics, show_backtest_result(strategy_name, metrics,
metrics['stake_currency']) metrics['stake_currency'], config.get('backtest_breakdown', []))
HyperoptTools.try_export_params(config, strategy_name, val) HyperoptTools.try_export_params(config, strategy_name, val)

View File

@@ -10,7 +10,7 @@ from colorama import init as colorama_init
from tabulate import tabulate from tabulate import tabulate
from freqtrade.configuration import setup_utils_configuration from freqtrade.configuration import setup_utils_configuration
from freqtrade.constants import USERPATH_HYPEROPTS, USERPATH_STRATEGIES from freqtrade.constants import USERPATH_STRATEGIES
from freqtrade.enums import RunMode from freqtrade.enums import RunMode
from freqtrade.exceptions import OperationalException from freqtrade.exceptions import OperationalException
from freqtrade.exchange import market_is_active, validate_exchanges from freqtrade.exchange import market_is_active, validate_exchanges
@@ -92,25 +92,6 @@ def start_list_strategies(args: Dict[str, Any]) -> None:
_print_objs_tabular(strategy_objs, config.get('print_colorized', False)) _print_objs_tabular(strategy_objs, config.get('print_colorized', False))
def start_list_hyperopts(args: Dict[str, Any]) -> None:
"""
Print files with HyperOpt custom classes available in the directory
"""
from freqtrade.resolvers.hyperopt_resolver import HyperOptResolver
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
directory = Path(config.get('hyperopt_path', config['user_data_dir'] / USERPATH_HYPEROPTS))
hyperopt_objs = HyperOptResolver.search_all_objects(directory, not args['print_one_column'])
# Sort alphabetically
hyperopt_objs = sorted(hyperopt_objs, key=lambda x: x['name'])
if args['print_one_column']:
print('\n'.join([s['name'] for s in hyperopt_objs]))
else:
_print_objs_tabular(hyperopt_objs, config.get('print_colorized', False))
def start_list_timeframes(args: Dict[str, Any]) -> None: def start_list_timeframes(args: Dict[str, Any]) -> None:
""" """
Print timeframes available on Exchange Print timeframes available on Exchange

View File

@@ -54,6 +54,22 @@ def start_backtesting(args: Dict[str, Any]) -> None:
backtesting.start() backtesting.start()
def start_backtesting_show(args: Dict[str, Any]) -> None:
"""
Show previous backtest result
"""
config = setup_utils_configuration(args, RunMode.UTIL_NO_EXCHANGE)
from freqtrade.data.btanalysis import load_backtest_stats
from freqtrade.optimize.optimize_reports import show_backtest_results, show_sorted_pairlist
results = load_backtest_stats(config['exportfilename'])
show_backtest_results(config, results)
show_sorted_pairlist(config, results)
def start_hyperopt(args: Dict[str, Any]) -> None: def start_hyperopt(args: Dict[str, Any]) -> None:
""" """
Start hyperopt script Start hyperopt script

View File

@@ -0,0 +1,19 @@
from datetime import datetime, timezone
from cachetools import TTLCache
class PeriodicCache(TTLCache):
"""
Special cache that expires at "straight" times
A timer with ttl of 3600 (1h) will expire at every full hour (:00).
"""
def __init__(self, maxsize, ttl, getsizeof=None):
def local_timer():
ts = datetime.now(timezone.utc).timestamp()
offset = (ts % ttl)
return ts - offset
# Init with smlight offset
super().__init__(maxsize=maxsize, ttl=ttl-1e-5, timer=local_timer, getsizeof=getsizeof)

View File

@@ -1,7 +1,8 @@
# flake8: noqa: F401 # flake8: noqa: F401
from freqtrade.configuration.check_exchange import check_exchange, remove_credentials from freqtrade.configuration.check_exchange import check_exchange
from freqtrade.configuration.config_setup import setup_utils_configuration from freqtrade.configuration.config_setup import setup_utils_configuration
from freqtrade.configuration.config_validation import validate_config_consistency from freqtrade.configuration.config_validation import validate_config_consistency
from freqtrade.configuration.configuration import Configuration from freqtrade.configuration.configuration import Configuration
from freqtrade.configuration.PeriodicCache import PeriodicCache
from freqtrade.configuration.timerange import TimeRange from freqtrade.configuration.timerange import TimeRange

View File

@@ -10,19 +10,6 @@ from freqtrade.exchange import (available_exchanges, is_exchange_known_ccxt,
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def remove_credentials(config: Dict[str, Any]) -> None:
"""
Removes exchange keys from the configuration and specifies dry-run
Used for backtesting / hyperopt / edge and utils.
Modifies the input dict!
"""
config['exchange']['key'] = ''
config['exchange']['secret'] = ''
config['exchange']['password'] = ''
config['exchange']['uid'] = ''
config['dry_run'] = True
def check_exchange(config: Dict[str, Any], check_for_bad: bool = True) -> bool: def check_exchange(config: Dict[str, Any], check_for_bad: bool = True) -> bool:
""" """
Check if the exchange name in the config file is supported by Freqtrade Check if the exchange name in the config file is supported by Freqtrade

View File

@@ -3,7 +3,6 @@ from typing import Any, Dict
from freqtrade.enums import RunMode from freqtrade.enums import RunMode
from .check_exchange import remove_credentials
from .config_validation import validate_config_consistency from .config_validation import validate_config_consistency
from .configuration import Configuration from .configuration import Configuration
@@ -21,8 +20,8 @@ def setup_utils_configuration(args: Dict[str, Any], method: RunMode) -> Dict[str
configuration = Configuration(args, method) configuration = Configuration(args, method)
config = configuration.get_config() config = configuration.get_config()
# Ensure we do not use Exchange credentials # Ensure these modes are using Dry-run
remove_credentials(config) config['dry_run'] = True
validate_config_consistency(config) validate_config_consistency(config)
return config return config

View File

@@ -242,6 +242,13 @@ class Configuration:
except ValueError: except ValueError:
pass pass
self._args_to_config(config, argname='timeframe_detail',
logstring='Parameter --timeframe-detail detected, '
'using {} for intra-candle backtesting ...')
self._args_to_config(config, argname='backtest_show_pair_list',
logstring='Parameter --show-pair-list detected.')
self._args_to_config(config, argname='stake_amount', self._args_to_config(config, argname='stake_amount',
logstring='Parameter --stake-amount detected, ' logstring='Parameter --stake-amount detected, '
'overriding stake_amount to: {} ...') 'overriding stake_amount to: {} ...')
@@ -266,8 +273,12 @@ class Configuration:
self._args_to_config(config, argname='export', self._args_to_config(config, argname='export',
logstring='Parameter --export detected: {} ...') logstring='Parameter --export detected: {} ...')
self._args_to_config(config, argname='backtest_breakdown',
logstring='Parameter --breakdown detected ...')
self._args_to_config(config, argname='disableparamexport', self._args_to_config(config, argname='disableparamexport',
logstring='Parameter --disableparamexport detected: {} ...') logstring='Parameter --disableparamexport detected: {} ...')
# Edge section: # Edge section:
if 'stoploss_range' in self.args and self.args["stoploss_range"]: if 'stoploss_range' in self.args and self.args["stoploss_range"]:
txt_range = eval(self.args["stoploss_range"]) txt_range = eval(self.args["stoploss_range"])
@@ -366,6 +377,9 @@ class Configuration:
self._args_to_config(config, argname='hyperopt_show_no_header', self._args_to_config(config, argname='hyperopt_show_no_header',
logstring='Parameter --no-header detected: {}') logstring='Parameter --no-header detected: {}')
self._args_to_config(config, argname="hyperopt_ignore_missing_space",
logstring="Paramter --ignore-missing-space detected: {}")
def _process_plot_options(self, config: Dict[str, Any]) -> None: def _process_plot_options(self, config: Dict[str, Any]) -> None:
self._args_to_config(config, argname='pairs', self._args_to_config(config, argname='pairs',
@@ -401,6 +415,9 @@ class Configuration:
self._args_to_config(config, argname='days', self._args_to_config(config, argname='days',
logstring='Detected --days: {}') logstring='Detected --days: {}')
self._args_to_config(config, argname='include_inactive',
logstring='Detected --include-inactive-pairs: {}')
self._args_to_config(config, argname='download_trades', self._args_to_config(config, argname='download_trades',
logstring='Detected --dl-trades: {}') logstring='Detected --dl-trades: {}')

View File

@@ -32,6 +32,7 @@ def flat_vars_to_nested_dict(env_dict: Dict[str, Any], prefix: str) -> Dict[str,
:param prefix: Prefix to consider (usually FREQTRADE__) :param prefix: Prefix to consider (usually FREQTRADE__)
:return: Nested dict based on available and relevant variables. :return: Nested dict based on available and relevant variables.
""" """
no_convert = ['CHAT_ID']
relevant_vars: Dict[str, Any] = {} relevant_vars: Dict[str, Any] = {}
for env_var, val in sorted(env_dict.items()): for env_var, val in sorted(env_dict.items()):
@@ -39,9 +40,9 @@ def flat_vars_to_nested_dict(env_dict: Dict[str, Any], prefix: str) -> Dict[str,
logger.info(f"Loading variable '{env_var}'") logger.info(f"Loading variable '{env_var}'")
key = env_var.replace(prefix, '') key = env_var.replace(prefix, '')
for k in reversed(key.split('__')): for k in reversed(key.split('__')):
val = {k.lower(): get_var_typed(val) if type(val) != dict else val} val = {k.lower(): get_var_typed(val)
if type(val) != dict and k not in no_convert else val}
relevant_vars = deep_merge_dicts(val, relevant_vars) relevant_vars = deep_merge_dicts(val, relevant_vars)
return relevant_vars return relevant_vars

View File

@@ -24,13 +24,16 @@ ORDERTYPE_POSSIBILITIES = ['limit', 'market']
ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc'] ORDERTIF_POSSIBILITIES = ['gtc', 'fok', 'ioc']
HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss', HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss',
'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily', 'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily',
'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily'] 'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily',
'CalmarHyperOptLoss',
'MaxDrawDownHyperOptLoss']
AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList', AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList',
'AgeFilter', 'OffsetFilter', 'PerformanceFilter', 'AgeFilter', 'OffsetFilter', 'PerformanceFilter',
'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter', 'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter',
'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter'] 'ShuffleFilter', 'SpreadFilter', 'VolatilityFilter']
AVAILABLE_PROTECTIONS = ['CooldownPeriod', 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard'] AVAILABLE_PROTECTIONS = ['CooldownPeriod', 'LowProfitPairs', 'MaxDrawdown', 'StoplossGuard']
AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5'] AVAILABLE_DATAHANDLERS = ['json', 'jsongz', 'hdf5']
BACKTEST_BREAKDOWNS = ['day', 'week', 'month']
DRY_RUN_WALLET = 1000 DRY_RUN_WALLET = 1000
DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S' DATETIME_PRINT_FORMAT = '%Y-%m-%d %H:%M:%S'
MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons MATH_CLOSE_PREC = 1e-14 # Precision used for float comparisons
@@ -47,11 +50,12 @@ USERPATH_STRATEGIES = 'strategies'
USERPATH_NOTEBOOKS = 'notebooks' USERPATH_NOTEBOOKS = 'notebooks'
TELEGRAM_SETTING_OPTIONS = ['on', 'off', 'silent'] TELEGRAM_SETTING_OPTIONS = ['on', 'off', 'silent']
WEBHOOK_FORMAT_OPTIONS = ['form', 'json', 'raw']
ENV_VAR_PREFIX = 'FREQTRADE__' ENV_VAR_PREFIX = 'FREQTRADE__'
NON_OPEN_EXCHANGE_STATES = ('cancelled', 'canceled', 'closed', 'expired') NON_OPEN_EXCHANGE_STATES = ('cancelled', 'canceled', 'closed', 'expired')
# Define decimals per coin for outputs # Define decimals per coin for outputs
# Only used for outputs. # Only used for outputs.
DECIMAL_PER_COIN_FALLBACK = 3 # Should be low to avoid listing all possible FIAT's DECIMAL_PER_COIN_FALLBACK = 3 # Should be low to avoid listing all possible FIAT's
@@ -65,13 +69,10 @@ DUST_PER_COIN = {
'ETH': 0.01 'ETH': 0.01
} }
# Source files with destination directories within user-directory # Source files with destination directories within user-directory
USER_DATA_FILES = { USER_DATA_FILES = {
'sample_strategy.py': USERPATH_STRATEGIES, 'sample_strategy.py': USERPATH_STRATEGIES,
'sample_hyperopt_advanced.py': USERPATH_HYPEROPTS,
'sample_hyperopt_loss.py': USERPATH_HYPEROPTS, 'sample_hyperopt_loss.py': USERPATH_HYPEROPTS,
'sample_hyperopt.py': USERPATH_HYPEROPTS,
'strategy_analysis_example.ipynb': USERPATH_NOTEBOOKS, 'strategy_analysis_example.ipynb': USERPATH_NOTEBOOKS,
} }
@@ -112,7 +113,7 @@ CONF_SCHEMA = {
}, },
'tradable_balance_ratio': { 'tradable_balance_ratio': {
'type': 'number', 'type': 'number',
'minimum': 0.1, 'minimum': 0.0,
'maximum': 1, 'maximum': 1,
'default': 0.99 'default': 0.99
}, },
@@ -147,12 +148,17 @@ CONF_SCHEMA = {
'sell_profit_offset': {'type': 'number'}, 'sell_profit_offset': {'type': 'number'},
'ignore_roi_if_buy_signal': {'type': 'boolean'}, 'ignore_roi_if_buy_signal': {'type': 'boolean'},
'ignore_buying_expired_candle_after': {'type': 'number'}, 'ignore_buying_expired_candle_after': {'type': 'number'},
'backtest_breakdown': {
'type': 'array',
'items': {'type': 'string', 'enum': BACKTEST_BREAKDOWNS}
},
'bot_name': {'type': 'string'}, 'bot_name': {'type': 'string'},
'unfilledtimeout': { 'unfilledtimeout': {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'buy': {'type': 'number', 'minimum': 1}, 'buy': {'type': 'number', 'minimum': 1},
'sell': {'type': 'number', 'minimum': 1}, 'sell': {'type': 'number', 'minimum': 1},
'exit_timeout_count': {'type': 'number', 'minimum': 0, 'default': 0},
'unit': {'type': 'string', 'enum': TIMEOUT_UNITS, 'default': 'minutes'} 'unit': {'type': 'string', 'enum': TIMEOUT_UNITS, 'default': 'minutes'}
} }
}, },
@@ -203,7 +209,10 @@ CONF_SCHEMA = {
'sell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, 'sell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'forcesell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, 'forcesell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'forcebuy': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, 'forcebuy': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'emergencysell': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, 'emergencysell': {
'type': 'string',
'enum': ORDERTYPE_POSSIBILITIES,
'default': 'market'},
'stoploss': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES}, 'stoploss': {'type': 'string', 'enum': ORDERTYPE_POSSIBILITIES},
'stoploss_on_exchange': {'type': 'boolean'}, 'stoploss_on_exchange': {'type': 'boolean'},
'stoploss_on_exchange_interval': {'type': 'number'}, 'stoploss_on_exchange_interval': {'type': 'number'},
@@ -286,6 +295,15 @@ CONF_SCHEMA = {
'enum': TELEGRAM_SETTING_OPTIONS, 'enum': TELEGRAM_SETTING_OPTIONS,
'default': 'off' 'default': 'off'
}, },
'protection_trigger': {
'type': 'string',
'enum': TELEGRAM_SETTING_OPTIONS,
'default': 'off'
},
'protection_trigger_global': {
'type': 'string',
'enum': TELEGRAM_SETTING_OPTIONS,
},
} }
}, },
'reload': {'type': 'boolean'}, 'reload': {'type': 'boolean'},
@@ -296,10 +314,16 @@ CONF_SCHEMA = {
'type': 'object', 'type': 'object',
'properties': { 'properties': {
'enabled': {'type': 'boolean'}, 'enabled': {'type': 'boolean'},
'url': {'type': 'string'},
'format': {'type': 'string', 'enum': WEBHOOK_FORMAT_OPTIONS, 'default': 'form'},
'retries': {'type': 'integer', 'minimum': 0},
'retry_delay': {'type': 'number', 'minimum': 0},
'webhookbuy': {'type': 'object'}, 'webhookbuy': {'type': 'object'},
'webhookbuycancel': {'type': 'object'}, 'webhookbuycancel': {'type': 'object'},
'webhookbuyfill': {'type': 'object'},
'webhooksell': {'type': 'object'}, 'webhooksell': {'type': 'object'},
'webhooksellcancel': {'type': 'object'}, 'webhooksellcancel': {'type': 'object'},
'webhooksellfill': {'type': 'object'},
'webhookstatus': {'type': 'object'}, 'webhookstatus': {'type': 'object'},
}, },
}, },
@@ -371,6 +395,7 @@ CONF_SCHEMA = {
}, },
'uniqueItems': True 'uniqueItems': True
}, },
'unknown_fee_rate': {'type': 'number'},
'outdated_offset': {'type': 'integer', 'minimum': 1}, 'outdated_offset': {'type': 'integer', 'minimum': 1},
'markets_refresh_interval': {'type': 'integer'}, 'markets_refresh_interval': {'type': 'integer'},
'ccxt_config': {'type': 'object'}, 'ccxt_config': {'type': 'object'},

View File

@@ -113,7 +113,7 @@ def ohlcv_fill_up_missing_data(dataframe: DataFrame, timeframe: str, pair: str)
pct_missing = (len_after - len_before) / len_before if len_before > 0 else 0 pct_missing = (len_after - len_before) / len_before if len_before > 0 else 0
if len_before != len_after: if len_before != len_after:
message = (f"Missing data fillup for {pair}: before: {len_before} - after: {len_after}" message = (f"Missing data fillup for {pair}: before: {len_before} - after: {len_after}"
f" - {round(pct_missing * 100, 2)}%") f" - {pct_missing:.2%}")
if pct_missing > 0.01: if pct_missing > 0.01:
logger.info(message) logger.info(message)
else: else:

View File

@@ -149,6 +149,8 @@ class DataProvider:
Clear pair dataframe cache. Clear pair dataframe cache.
""" """
self.__cached_pairs = {} self.__cached_pairs = {}
self.__cached_pairs_backtesting = {}
self.__slice_index = 0
# Exchange functions # Exchange functions

View File

@@ -6,7 +6,6 @@ from typing import List, Optional
import numpy as np import numpy as np
import pandas as pd import pandas as pd
from freqtrade import misc
from freqtrade.configuration import TimeRange from freqtrade.configuration import TimeRange
from freqtrade.constants import (DEFAULT_DATAFRAME_COLUMNS, DEFAULT_TRADES_COLUMNS, from freqtrade.constants import (DEFAULT_DATAFRAME_COLUMNS, DEFAULT_TRADES_COLUMNS,
ListPairsWithTimeframes, TradeList) ListPairsWithTimeframes, TradeList)
@@ -61,10 +60,10 @@ class HDF5DataHandler(IDataHandler):
filename = self._pair_data_filename(self._datadir, pair, timeframe) filename = self._pair_data_filename(self._datadir, pair, timeframe)
ds = pd.HDFStore(filename, mode='a', complevel=9, complib='blosc') _data.loc[:, self._columns].to_hdf(
ds.put(key, _data.loc[:, self._columns], format='table', data_columns=['date']) filename, key, mode='a', complevel=9, complib='blosc',
format='table', data_columns=['date']
ds.close() )
def _ohlcv_load(self, pair: str, timeframe: str, def _ohlcv_load(self, pair: str, timeframe: str,
timerange: Optional[TimeRange] = None) -> pd.DataFrame: timerange: Optional[TimeRange] = None) -> pd.DataFrame:
@@ -99,19 +98,6 @@ class HDF5DataHandler(IDataHandler):
'low': 'float', 'close': 'float', 'volume': 'float'}) 'low': 'float', 'close': 'float', 'volume': 'float'})
return pairdata return pairdata
def ohlcv_purge(self, pair: str, timeframe: str) -> bool:
"""
Remove data for this pair
:param pair: Delete data for this pair.
:param timeframe: Timeframe (e.g. "5m")
:return: True when deleted, false if file did not exist.
"""
filename = self._pair_data_filename(self._datadir, pair, timeframe)
if filename.exists():
filename.unlink()
return True
return False
def ohlcv_append(self, pair: str, timeframe: str, data: pd.DataFrame) -> None: def ohlcv_append(self, pair: str, timeframe: str, data: pd.DataFrame) -> None:
""" """
Append data to existing data structures Append data to existing data structures
@@ -142,11 +128,11 @@ class HDF5DataHandler(IDataHandler):
""" """
key = self._pair_trades_key(pair) key = self._pair_trades_key(pair)
ds = pd.HDFStore(self._pair_trades_filename(self._datadir, pair), pd.DataFrame(data, columns=DEFAULT_TRADES_COLUMNS).to_hdf(
mode='a', complevel=9, complib='blosc') self._pair_trades_filename(self._datadir, pair), key,
ds.put(key, pd.DataFrame(data, columns=DEFAULT_TRADES_COLUMNS), mode='a', complevel=9, complib='blosc',
format='table', data_columns=['timestamp']) format='table', data_columns=['timestamp']
ds.close() )
def trades_append(self, pair: str, data: TradeList): def trades_append(self, pair: str, data: TradeList):
""" """
@@ -180,17 +166,9 @@ class HDF5DataHandler(IDataHandler):
trades[['id', 'type']] = trades[['id', 'type']].replace({np.nan: None}) trades[['id', 'type']] = trades[['id', 'type']].replace({np.nan: None})
return trades.values.tolist() return trades.values.tolist()
def trades_purge(self, pair: str) -> bool: @classmethod
""" def _get_file_extension(cls):
Remove data for this pair return "h5"
:param pair: Delete data for this pair.
:return: True when deleted, false if file did not exist.
"""
filename = self._pair_trades_filename(self._datadir, pair)
if filename.exists():
filename.unlink()
return True
return False
@classmethod @classmethod
def _pair_ohlcv_key(cls, pair: str, timeframe: str) -> str: def _pair_ohlcv_key(cls, pair: str, timeframe: str) -> str:
@@ -199,15 +177,3 @@ class HDF5DataHandler(IDataHandler):
@classmethod @classmethod
def _pair_trades_key(cls, pair: str) -> str: def _pair_trades_key(cls, pair: str) -> str:
return f"{pair}/trades" return f"{pair}/trades"
@classmethod
def _pair_data_filename(cls, datadir: Path, pair: str, timeframe: str) -> Path:
pair_s = misc.pair_to_filename(pair)
filename = datadir.joinpath(f'{pair_s}-{timeframe}.h5')
return filename
@classmethod
def _pair_trades_filename(cls, datadir: Path, pair: str) -> Path:
pair_s = misc.pair_to_filename(pair)
filename = datadir.joinpath(f'{pair_s}-trades.h5')
return filename

View File

@@ -197,7 +197,8 @@ def _download_pair_history(pair: str, *,
timeframe=timeframe, timeframe=timeframe,
since_ms=since_ms if since_ms else since_ms=since_ms if since_ms else
arrow.utcnow().shift( arrow.utcnow().shift(
days=-new_pairs_days).int_timestamp * 1000 days=-new_pairs_days).int_timestamp * 1000,
is_new_pair=data.empty
) )
# TODO: Maybe move parsing to exchange class (?) # TODO: Maybe move parsing to exchange class (?)
new_dataframe = ohlcv_to_dataframe(new_data, timeframe, pair, new_dataframe = ohlcv_to_dataframe(new_data, timeframe, pair,

View File

@@ -12,6 +12,7 @@ from typing import List, Optional, Type
from pandas import DataFrame from pandas import DataFrame
from freqtrade import misc
from freqtrade.configuration import TimeRange from freqtrade.configuration import TimeRange
from freqtrade.constants import ListPairsWithTimeframes, TradeList from freqtrade.constants import ListPairsWithTimeframes, TradeList
from freqtrade.data.converter import clean_ohlcv_dataframe, trades_remove_duplicates, trim_dataframe from freqtrade.data.converter import clean_ohlcv_dataframe, trades_remove_duplicates, trim_dataframe
@@ -26,6 +27,13 @@ class IDataHandler(ABC):
def __init__(self, datadir: Path) -> None: def __init__(self, datadir: Path) -> None:
self._datadir = datadir self._datadir = datadir
@classmethod
def _get_file_extension(cls) -> str:
"""
Get file extension for this particular datahandler
"""
raise NotImplementedError()
@abstractclassmethod @abstractclassmethod
def ohlcv_get_available_data(cls, datadir: Path) -> ListPairsWithTimeframes: def ohlcv_get_available_data(cls, datadir: Path) -> ListPairsWithTimeframes:
""" """
@@ -70,7 +78,6 @@ class IDataHandler(ABC):
:return: DataFrame with ohlcv data, or empty DataFrame :return: DataFrame with ohlcv data, or empty DataFrame
""" """
@abstractmethod
def ohlcv_purge(self, pair: str, timeframe: str) -> bool: def ohlcv_purge(self, pair: str, timeframe: str) -> bool:
""" """
Remove data for this pair Remove data for this pair
@@ -78,6 +85,11 @@ class IDataHandler(ABC):
:param timeframe: Timeframe (e.g. "5m") :param timeframe: Timeframe (e.g. "5m")
:return: True when deleted, false if file did not exist. :return: True when deleted, false if file did not exist.
""" """
filename = self._pair_data_filename(self._datadir, pair, timeframe)
if filename.exists():
filename.unlink()
return True
return False
@abstractmethod @abstractmethod
def ohlcv_append(self, pair: str, timeframe: str, data: DataFrame) -> None: def ohlcv_append(self, pair: str, timeframe: str, data: DataFrame) -> None:
@@ -123,13 +135,17 @@ class IDataHandler(ABC):
:return: List of trades :return: List of trades
""" """
@abstractmethod
def trades_purge(self, pair: str) -> bool: def trades_purge(self, pair: str) -> bool:
""" """
Remove data for this pair Remove data for this pair
:param pair: Delete data for this pair. :param pair: Delete data for this pair.
:return: True when deleted, false if file did not exist. :return: True when deleted, false if file did not exist.
""" """
filename = self._pair_trades_filename(self._datadir, pair)
if filename.exists():
filename.unlink()
return True
return False
def trades_load(self, pair: str, timerange: Optional[TimeRange] = None) -> TradeList: def trades_load(self, pair: str, timerange: Optional[TimeRange] = None) -> TradeList:
""" """
@@ -141,6 +157,18 @@ class IDataHandler(ABC):
""" """
return trades_remove_duplicates(self._trades_load(pair, timerange=timerange)) return trades_remove_duplicates(self._trades_load(pair, timerange=timerange))
@classmethod
def _pair_data_filename(cls, datadir: Path, pair: str, timeframe: str) -> Path:
pair_s = misc.pair_to_filename(pair)
filename = datadir.joinpath(f'{pair_s}-{timeframe}.{cls._get_file_extension()}')
return filename
@classmethod
def _pair_trades_filename(cls, datadir: Path, pair: str) -> Path:
pair_s = misc.pair_to_filename(pair)
filename = datadir.joinpath(f'{pair_s}-trades.{cls._get_file_extension()}')
return filename
def ohlcv_load(self, pair, timeframe: str, def ohlcv_load(self, pair, timeframe: str,
timerange: Optional[TimeRange] = None, timerange: Optional[TimeRange] = None,
fill_missing: bool = True, fill_missing: bool = True,

View File

@@ -174,34 +174,10 @@ class JsonDataHandler(IDataHandler):
pass pass
return tradesdata return tradesdata
def trades_purge(self, pair: str) -> bool:
"""
Remove data for this pair
:param pair: Delete data for this pair.
:return: True when deleted, false if file did not exist.
"""
filename = self._pair_trades_filename(self._datadir, pair)
if filename.exists():
filename.unlink()
return True
return False
@classmethod
def _pair_data_filename(cls, datadir: Path, pair: str, timeframe: str) -> Path:
pair_s = misc.pair_to_filename(pair)
filename = datadir.joinpath(f'{pair_s}-{timeframe}.{cls._get_file_extension()}')
return filename
@classmethod @classmethod
def _get_file_extension(cls): def _get_file_extension(cls):
return "json.gz" if cls._use_zip else "json" return "json.gz" if cls._use_zip else "json"
@classmethod
def _pair_trades_filename(cls, datadir: Path, pair: str) -> Path:
pair_s = misc.pair_to_filename(pair)
filename = datadir.joinpath(f'{pair_s}-trades.{cls._get_file_extension()}')
return filename
class JsonGzDataHandler(JsonDataHandler): class JsonGzDataHandler(JsonDataHandler):

View File

@@ -119,7 +119,7 @@ class Edge:
) )
# Download informative pairs too # Download informative pairs too
res = defaultdict(list) res = defaultdict(list)
for p, t in self.strategy.informative_pairs(): for p, t in self.strategy.gather_informative_pairs():
res[t].append(p) res[t].append(p)
for timeframe, inf_pairs in res.items(): for timeframe, inf_pairs in res.items():
timerange_startup = deepcopy(self._timerange) timerange_startup = deepcopy(self._timerange)

View File

@@ -1,5 +1,6 @@
# flake8: noqa: F401 # flake8: noqa: F401
from freqtrade.enums.backteststate import BacktestState from freqtrade.enums.backteststate import BacktestState
from freqtrade.enums.ordertypevalue import OrderTypeValues
from freqtrade.enums.rpcmessagetype import RPCMessageType from freqtrade.enums.rpcmessagetype import RPCMessageType
from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode from freqtrade.enums.runmode import NON_UTIL_MODES, OPTIMIZE_MODES, TRADING_MODES, RunMode
from freqtrade.enums.selltype import SellType from freqtrade.enums.selltype import SellType

View File

@@ -0,0 +1,6 @@
from enum import Enum
class OrderTypeValues(str, Enum):
limit = 'limit'
market = 'market'

View File

@@ -11,6 +11,8 @@ class RPCMessageType(Enum):
SELL = 'sell' SELL = 'sell'
SELL_FILL = 'sell_fill' SELL_FILL = 'sell_fill'
SELL_CANCEL = 'sell_cancel' SELL_CANCEL = 'sell_cancel'
PROTECTION_TRIGGER = 'protection_trigger'
PROTECTION_TRIGGER_GLOBAL = 'protection_trigger_global'
def __repr__(self): def __repr__(self):
return self.value return self.value

View File

@@ -14,3 +14,4 @@ class SignalTagType(Enum):
Enum for signal columns Enum for signal columns
""" """
BUY_TAG = "buy_tag" BUY_TAG = "buy_tag"
EXIT_TAG = "exit_tag"

View File

@@ -1,5 +1,3 @@
class FreqtradeException(Exception): class FreqtradeException(Exception):
""" """
Freqtrade base exception. Handled at the outermost level. Freqtrade base exception. Handled at the outermost level.

View File

@@ -1,10 +1,11 @@
# flake8: noqa: F401 # flake8: noqa: F401
# isort: off # isort: off
from freqtrade.exchange.common import MAP_EXCHANGE_CHILDCLASS from freqtrade.exchange.common import remove_credentials, MAP_EXCHANGE_CHILDCLASS
from freqtrade.exchange.exchange import Exchange from freqtrade.exchange.exchange import Exchange
# isort: on # isort: on
from freqtrade.exchange.bibox import Bibox from freqtrade.exchange.bibox import Bibox
from freqtrade.exchange.binance import Binance from freqtrade.exchange.binance import Binance
from freqtrade.exchange.bitpanda import Bitpanda
from freqtrade.exchange.bittrex import Bittrex from freqtrade.exchange.bittrex import Bittrex
from freqtrade.exchange.bybit import Bybit from freqtrade.exchange.bybit import Bybit
from freqtrade.exchange.coinbasepro import Coinbasepro from freqtrade.exchange.coinbasepro import Coinbasepro
@@ -19,3 +20,4 @@ from freqtrade.exchange.gateio import Gateio
from freqtrade.exchange.hitbtc import Hitbtc from freqtrade.exchange.hitbtc import Hitbtc
from freqtrade.exchange.kraken import Kraken from freqtrade.exchange.kraken import Kraken
from freqtrade.exchange.kucoin import Kucoin from freqtrade.exchange.kucoin import Kucoin
from freqtrade.exchange.okex import Okex

View File

@@ -1,7 +1,8 @@
""" Binance exchange subclass """ """ Binance exchange subclass """
import logging import logging
from typing import Dict from typing import Dict, List, Tuple
import arrow
import ccxt import ccxt
from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException, from freqtrade.exceptions import (DDosProtection, InsufficientFundsError, InvalidOrderException,
@@ -18,6 +19,7 @@ class Binance(Exchange):
_ft_has: Dict = { _ft_has: Dict = {
"stoploss_on_exchange": True, "stoploss_on_exchange": True,
"order_time_in_force": ['gtc', 'fok', 'ioc'], "order_time_in_force": ['gtc', 'fok', 'ioc'],
"time_in_force_parameter": "timeInForce",
"ohlcv_candle_limit": 1000, "ohlcv_candle_limit": 1000,
"trades_pagination": "id", "trades_pagination": "id",
"trades_pagination_arg": "fromId", "trades_pagination_arg": "fromId",
@@ -89,3 +91,22 @@ class Binance(Exchange):
f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e f'Could not place sell order due to {e.__class__.__name__}. Message: {e}') from e
except ccxt.BaseError as e: except ccxt.BaseError as e:
raise OperationalException(e) from e raise OperationalException(e) from e
async def _async_get_historic_ohlcv(self, pair: str, timeframe: str,
since_ms: int, is_new_pair: bool = False,
raise_: bool = False
) -> Tuple[str, str, List]:
"""
Overwrite to introduce "fast new pair" functionality by detecting the pair's listing date
Does not work for other exchanges, which don't return the earliest data when called with "0"
"""
if is_new_pair:
x = await self._async_get_candle_history(pair, timeframe, 0)
if x and x[2] and x[2][0] and x[2][0][0] > since_ms:
# Set starting date to first available candle.
since_ms = x[2][0][0]
logger.info(f"Candle-data for {pair} available starting with "
f"{arrow.get(since_ms // 1000).isoformat()}.")
return await super()._async_get_historic_ohlcv(
pair=pair, timeframe=timeframe, since_ms=since_ms, is_new_pair=is_new_pair,
raise_=raise_)

View File

@@ -0,0 +1,37 @@
""" Bitpanda exchange subclass """
import logging
from datetime import datetime, timezone
from typing import Dict, List, Optional
from freqtrade.exchange import Exchange
logger = logging.getLogger(__name__)
class Bitpanda(Exchange):
"""
Bitpanda exchange class. Contains adjustments needed for Freqtrade to work
with this exchange.
"""
def get_trades_for_order(self, order_id: str, pair: str, since: datetime,
params: Optional[Dict] = None) -> List:
"""
Fetch Orders using the "fetch_my_trades" endpoint and filter them by order-id.
The "since" argument passed in is coming from the database and is in UTC,
as timezone-native datetime object.
From the python documentation:
> Naive datetime instances are assumed to represent local time
Therefore, calling "since.timestamp()" will get the UTC timestamp, after applying the
transformation from local timezone to UTC.
This works for timezones UTC+ since then the result will contain trades from a few hours
instead of from the last 5 seconds, however fails for UTC- timezones,
since we're then asking for trades with a "since" argument in the future.
:param order_id order_id: Order-id as given when creating the order
:param pair: Pair the order is for
:param since: datetime object of the order creation time. Assumes object is in UTC.
"""
params = {'to': int(datetime.now(timezone.utc).timestamp() * 1000)}
return super().get_trades_for_order(order_id, pair, since, params)

View File

@@ -16,8 +16,6 @@ API_FETCH_ORDER_RETRY_COUNT = 5
BAD_EXCHANGES = { BAD_EXCHANGES = {
"bitmex": "Various reasons.", "bitmex": "Various reasons.",
"bitstamp": "Does not provide history. "
"Details in https://github.com/freqtrade/freqtrade/issues/1983",
"phemex": "Does not provide history. ", "phemex": "Does not provide history. ",
"poloniex": "Does not provide fetch_order endpoint to fetch both open and closed orders.", "poloniex": "Does not provide fetch_order endpoint to fetch both open and closed orders.",
} }
@@ -51,6 +49,19 @@ EXCHANGE_HAS_OPTIONAL = [
] ]
def remove_credentials(config) -> None:
"""
Removes exchange keys from the configuration and specifies dry-run
Used for backtesting / hyperopt / edge and utils.
Modifies the input dict!
"""
if config.get('dry_run', False):
config['exchange']['key'] = ''
config['exchange']['secret'] = ''
config['exchange']['password'] = ''
config['exchange']['uid'] = ''
def calculate_backoff(retrycount, max_retries): def calculate_backoff(retrycount, max_retries):
""" """
Calculate backoff Calculate backoff
@@ -70,6 +81,13 @@ def retrier_async(f):
count -= 1 count -= 1
kwargs.update({'count': count}) kwargs.update({'count': count})
if isinstance(ex, DDosProtection): if isinstance(ex, DDosProtection):
if "kucoin" in str(ex) and "429000" in str(ex):
# Temporary fix for 429000 error on kucoin
# see https://github.com/freqtrade/freqtrade/issues/5700 for details.
logger.warning(
f"Kucoin 429 error, avoid triggering DDosProtection backoff delay. "
f"{count} tries left before giving up")
else:
backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT) backoff_delay = calculate_backoff(count + 1, API_RETRY_COUNT)
logger.info(f"Applying DDosProtection backoff delay: {backoff_delay}") logger.info(f"Applying DDosProtection backoff delay: {backoff_delay}")
await asyncio.sleep(backoff_delay) await asyncio.sleep(backoff_delay)

View File

@@ -7,7 +7,7 @@ import http
import inspect import inspect
import logging import logging
from copy import deepcopy from copy import deepcopy
from datetime import datetime, timezone from datetime import datetime, timedelta, timezone
from math import ceil from math import ceil
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
@@ -26,9 +26,9 @@ from freqtrade.exceptions import (DDosProtection, ExchangeError, InsufficientFun
InvalidOrderException, OperationalException, PricingError, InvalidOrderException, OperationalException, PricingError,
RetryableOrderError, TemporaryError) RetryableOrderError, TemporaryError)
from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, BAD_EXCHANGES, from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, BAD_EXCHANGES,
EXCHANGE_HAS_OPTIONAL, EXCHANGE_HAS_REQUIRED, retrier, EXCHANGE_HAS_OPTIONAL, EXCHANGE_HAS_REQUIRED,
retrier_async) remove_credentials, retrier, retrier_async)
from freqtrade.misc import deep_merge_dicts, safe_value_fallback2 from freqtrade.misc import chunks, deep_merge_dicts, safe_value_fallback2
from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist
@@ -54,12 +54,16 @@ class Exchange:
# Parameters to add directly to buy/sell calls (like agreeing to trading agreement) # Parameters to add directly to buy/sell calls (like agreeing to trading agreement)
_params: Dict = {} _params: Dict = {}
# Additional headers - added to the ccxt object
_headers: Dict = {}
# Dict to specify which options each exchange implements # Dict to specify which options each exchange implements
# This defines defaults, which can be selectively overridden by subclasses using _ft_has # This defines defaults, which can be selectively overridden by subclasses using _ft_has
# or by specifying them in the configuration. # or by specifying them in the configuration.
_ft_has_default: Dict = { _ft_has_default: Dict = {
"stoploss_on_exchange": False, "stoploss_on_exchange": False,
"order_time_in_force": ["gtc"], "order_time_in_force": ["gtc"],
"time_in_force_parameter": "timeInForce",
"ohlcv_params": {}, "ohlcv_params": {},
"ohlcv_candle_limit": 500, "ohlcv_candle_limit": 500,
"ohlcv_partial_candle": True, "ohlcv_partial_candle": True,
@@ -100,6 +104,7 @@ class Exchange:
# Holds all open sell orders for dry_run # Holds all open sell orders for dry_run
self._dry_run_open_orders: Dict[str, Any] = {} self._dry_run_open_orders: Dict[str, Any] = {}
remove_credentials(config)
if config['dry_run']: if config['dry_run']:
logger.info('Instance is running with dry_run enabled') logger.info('Instance is running with dry_run enabled')
@@ -150,8 +155,8 @@ class Exchange:
self.validate_pairs(config['exchange']['pair_whitelist']) self.validate_pairs(config['exchange']['pair_whitelist'])
self.validate_ordertypes(config.get('order_types', {})) self.validate_ordertypes(config.get('order_types', {}))
self.validate_order_time_in_force(config.get('order_time_in_force', {})) self.validate_order_time_in_force(config.get('order_time_in_force', {}))
self.validate_required_startup_candles(config.get('startup_candle_count', 0), self.required_candle_call_count = self.validate_required_startup_candles(
config.get('timeframe', '')) config.get('startup_candle_count', 0), config.get('timeframe', ''))
# Converts the interval provided in minutes in config to seconds # Converts the interval provided in minutes in config to seconds
self.markets_refresh_interval: int = exchange_config.get( self.markets_refresh_interval: int = exchange_config.get(
@@ -169,7 +174,7 @@ class Exchange:
asyncio.get_event_loop().run_until_complete(self._api_async.close()) asyncio.get_event_loop().run_until_complete(self._api_async.close())
def _init_ccxt(self, exchange_config: Dict[str, Any], ccxt_module: CcxtModuleType = ccxt, def _init_ccxt(self, exchange_config: Dict[str, Any], ccxt_module: CcxtModuleType = ccxt,
ccxt_kwargs: dict = None) -> ccxt.Exchange: ccxt_kwargs: Dict = {}) -> ccxt.Exchange:
""" """
Initialize ccxt with given config and return valid Initialize ccxt with given config and return valid
ccxt instance. ccxt instance.
@@ -188,6 +193,10 @@ class Exchange:
} }
if ccxt_kwargs: if ccxt_kwargs:
logger.info('Applying additional ccxt config: %s', ccxt_kwargs) logger.info('Applying additional ccxt config: %s', ccxt_kwargs)
if self._headers:
# Inject static headers after the above output to not confuse users.
ccxt_kwargs = deep_merge_dicts({'headers': self._headers}, ccxt_kwargs)
if ccxt_kwargs:
ex_config.update(ccxt_kwargs) ex_config.update(ccxt_kwargs)
try: try:
@@ -352,9 +361,16 @@ class Exchange:
def validate_stakecurrency(self, stake_currency: str) -> None: def validate_stakecurrency(self, stake_currency: str) -> None:
""" """
Checks stake-currency against available currencies on the exchange. Checks stake-currency against available currencies on the exchange.
Only runs on startup. If markets have not been loaded, there's been a problem with
the connection to the exchange.
:param stake_currency: Stake-currency to validate :param stake_currency: Stake-currency to validate
:raise: OperationalException if stake-currency is not available. :raise: OperationalException if stake-currency is not available.
""" """
if not self._markets:
raise OperationalException(
'Could not load markets, therefore cannot start. '
'Please investigate the above error for more details.'
)
quote_currencies = self.get_quote_currencies() quote_currencies = self.get_quote_currencies()
if stake_currency not in quote_currencies: if stake_currency not in quote_currencies:
raise OperationalException( raise OperationalException(
@@ -455,16 +471,29 @@ class Exchange:
raise OperationalException( raise OperationalException(
f'Time in force policies are not supported for {self.name} yet.') f'Time in force policies are not supported for {self.name} yet.')
def validate_required_startup_candles(self, startup_candles: int, timeframe: str) -> None: def validate_required_startup_candles(self, startup_candles: int, timeframe: str) -> int:
""" """
Checks if required startup_candles is more than ohlcv_candle_limit(). Checks if required startup_candles is more than ohlcv_candle_limit().
Requires a grace-period of 5 candles - so a startup-period up to 494 is allowed by default. Requires a grace-period of 5 candles - so a startup-period up to 494 is allowed by default.
""" """
candle_limit = self.ohlcv_candle_limit(timeframe) candle_limit = self.ohlcv_candle_limit(timeframe)
if startup_candles + 5 > candle_limit: # Require one more candle - to account for the still open candle.
candle_count = startup_candles + 1
# Allow 5 calls to the exchange per pair
required_candle_call_count = int(
(candle_count / candle_limit) + (0 if candle_count % candle_limit == 0 else 1))
if required_candle_call_count > 5:
# Only allow 5 calls per pair to somewhat limit the impact
raise OperationalException( raise OperationalException(
f"This strategy requires {startup_candles} candles to start. " f"This strategy requires {startup_candles} candles to start, which is more than 5x "
f"{self.name} only provides {candle_limit} for {timeframe}.") f"the amount of candles {self.name} provides for {timeframe}.")
if required_candle_call_count > 1:
logger.warning(f"Using {required_candle_call_count} calls to get OHLCV. "
f"This can result in slower operations for the bot. Please check "
f"if you really need {startup_candles} candles for your strategy")
return required_candle_call_count
def exchange_has(self, endpoint: str) -> bool: def exchange_has(self, endpoint: str) -> bool:
""" """
@@ -507,7 +536,7 @@ class Exchange:
precision = self.markets[pair]['precision']['price'] precision = self.markets[pair]['precision']['price']
missing = price % precision missing = price % precision
if missing != 0: if missing != 0:
price = price - missing + precision price = round(price - missing + precision, 10)
else: else:
symbol_prec = self.markets[pair]['precision']['price'] symbol_prec = self.markets[pair]['precision']['price']
big_price = price * pow(10, symbol_prec) big_price = price * pow(10, symbol_prec)
@@ -656,6 +685,7 @@ class Exchange:
if not self.exchange_has('fetchL2OrderBook'): if not self.exchange_has('fetchL2OrderBook'):
return True return True
ob = self.fetch_l2_order_book(pair, 1) ob = self.fetch_l2_order_book(pair, 1)
try:
if side == 'buy': if side == 'buy':
price = ob['asks'][0][0] price = ob['asks'][0][0]
logger.debug(f"{pair} checking dry buy-order: price={price}, limit={limit}") logger.debug(f"{pair} checking dry buy-order: price={price}, limit={limit}")
@@ -666,6 +696,9 @@ class Exchange:
logger.debug(f"{pair} checking dry sell-order: price={price}, limit={limit}") logger.debug(f"{pair} checking dry sell-order: price={price}, limit={limit}")
if limit <= price: if limit <= price:
return True return True
except IndexError:
# Ignore empty orderbooks when filling - can be filled with the next iteration.
pass
return False return False
def check_dry_limit_order_filled(self, order: Dict[str, Any]) -> Dict[str, Any]: def check_dry_limit_order_filled(self, order: Dict[str, Any]) -> Dict[str, Any]:
@@ -709,7 +742,8 @@ class Exchange:
params = self._params.copy() params = self._params.copy()
if time_in_force != 'gtc' and ordertype != 'market': if time_in_force != 'gtc' and ordertype != 'market':
params.update({'timeInForce': time_in_force}) param = self._ft_has.get('time_in_force_parameter', '')
params.update({param: time_in_force})
try: try:
# Set the precision for amount and price(rate) as accepted by the exchange # Set the precision for amount and price(rate) as accepted by the exchange
@@ -1041,7 +1075,7 @@ class Exchange:
ticker_rate = ticker[conf_strategy['price_side']] ticker_rate = ticker[conf_strategy['price_side']]
if ticker['last'] and ticker_rate: if ticker['last'] and ticker_rate:
if side == 'buy' and ticker_rate > ticker['last']: if side == 'buy' and ticker_rate > ticker['last']:
balance = conf_strategy['ask_last_balance'] balance = conf_strategy.get('ask_last_balance', 0.0)
ticker_rate = ticker_rate + balance * (ticker['last'] - ticker_rate) ticker_rate = ticker_rate + balance * (ticker['last'] - ticker_rate)
elif side == 'sell' and ticker_rate < ticker['last']: elif side == 'sell' and ticker_rate < ticker['last']:
balance = conf_strategy.get('bid_last_balance', 0.0) balance = conf_strategy.get('bid_last_balance', 0.0)
@@ -1057,7 +1091,8 @@ class Exchange:
# Fee handling # Fee handling
@retrier @retrier
def get_trades_for_order(self, order_id: str, pair: str, since: datetime) -> List: def get_trades_for_order(self, order_id: str, pair: str, since: datetime,
params: Optional[Dict] = None) -> List:
""" """
Fetch Orders using the "fetch_my_trades" endpoint and filter them by order-id. Fetch Orders using the "fetch_my_trades" endpoint and filter them by order-id.
The "since" argument passed in is coming from the database and is in UTC, The "since" argument passed in is coming from the database and is in UTC,
@@ -1081,8 +1116,10 @@ class Exchange:
try: try:
# Allow 5s offset to catch slight time offsets (discovered in #1185) # Allow 5s offset to catch slight time offsets (discovered in #1185)
# since needs to be int in milliseconds # since needs to be int in milliseconds
_params = params if params else {}
my_trades = self._api.fetch_my_trades( my_trades = self._api.fetch_my_trades(
pair, int((since.replace(tzinfo=timezone.utc).timestamp() - 5) * 1000)) pair, int((since.replace(tzinfo=timezone.utc).timestamp() - 5) * 1000),
params=_params)
matched_trades = [trade for trade in my_trades if trade['order'] == order_id] matched_trades = [trade for trade in my_trades if trade['order'] == order_id]
self._log_exchange_response('get_trades_for_order', matched_trades) self._log_exchange_response('get_trades_for_order', matched_trades)
@@ -1160,9 +1197,11 @@ class Exchange:
tick = self.fetch_ticker(comb) tick = self.fetch_ticker(comb)
fee_to_quote_rate = safe_value_fallback2(tick, tick, 'last', 'ask') fee_to_quote_rate = safe_value_fallback2(tick, tick, 'last', 'ask')
return round((order['fee']['cost'] * fee_to_quote_rate) / order['cost'], 8)
except ExchangeError: except ExchangeError:
fee_to_quote_rate = self._config['exchange'].get('unknown_fee_rate', None)
if not fee_to_quote_rate:
return None return None
return round((order['fee']['cost'] * fee_to_quote_rate) / order['cost'], 8)
def extract_cost_curr_rate(self, order: Dict) -> Tuple[float, str, Optional[float]]: def extract_cost_curr_rate(self, order: Dict) -> Tuple[float, str, Optional[float]]:
""" """
@@ -1178,7 +1217,7 @@ class Exchange:
# Historic data # Historic data
def get_historic_ohlcv(self, pair: str, timeframe: str, def get_historic_ohlcv(self, pair: str, timeframe: str,
since_ms: int) -> List: since_ms: int, is_new_pair: bool = False) -> List:
""" """
Get candle history using asyncio and returns the list of candles. Get candle history using asyncio and returns the list of candles.
Handles all async work for this. Handles all async work for this.
@@ -1188,9 +1227,11 @@ class Exchange:
:param since_ms: Timestamp in milliseconds to get history from :param since_ms: Timestamp in milliseconds to get history from
:return: List with candle (OHLCV) data :return: List with candle (OHLCV) data
""" """
return asyncio.get_event_loop().run_until_complete( pair, timeframe, data = asyncio.get_event_loop().run_until_complete(
self._async_get_historic_ohlcv(pair=pair, timeframe=timeframe, self._async_get_historic_ohlcv(pair=pair, timeframe=timeframe,
since_ms=since_ms)) since_ms=since_ms, is_new_pair=is_new_pair))
logger.info(f"Downloaded data for {pair} with length {len(data)}.")
return data
def get_historic_ohlcv_as_df(self, pair: str, timeframe: str, def get_historic_ohlcv_as_df(self, pair: str, timeframe: str,
since_ms: int) -> DataFrame: since_ms: int) -> DataFrame:
@@ -1205,11 +1246,13 @@ class Exchange:
return ohlcv_to_dataframe(ticks, timeframe, pair=pair, fill_missing=True, return ohlcv_to_dataframe(ticks, timeframe, pair=pair, fill_missing=True,
drop_incomplete=self._ohlcv_partial_candle) drop_incomplete=self._ohlcv_partial_candle)
async def _async_get_historic_ohlcv(self, pair: str, async def _async_get_historic_ohlcv(self, pair: str, timeframe: str,
timeframe: str, since_ms: int, is_new_pair: bool = False,
since_ms: int) -> List: raise_: bool = False
) -> Tuple[str, str, List]:
""" """
Download historic ohlcv Download historic ohlcv
:param is_new_pair: used by binance subclass to allow "fast" new pair downloading
""" """
one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe) one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe)
@@ -1222,22 +1265,25 @@ class Exchange:
pair, timeframe, since) for since in pair, timeframe, since) for since in
range(since_ms, arrow.utcnow().int_timestamp * 1000, one_call)] range(since_ms, arrow.utcnow().int_timestamp * 1000, one_call)]
results = await asyncio.gather(*input_coroutines, return_exceptions=True)
# Combine gathered results
data: List = [] data: List = []
# Chunk requests into batches of 100 to avoid overwelming ccxt Throttling
for input_coro in chunks(input_coroutines, 100):
results = await asyncio.gather(*input_coro, return_exceptions=True)
for res in results: for res in results:
if isinstance(res, Exception): if isinstance(res, Exception):
logger.warning("Async code raised an exception: %s", res.__class__.__name__) logger.warning(f"Async code raised an exception: {repr(res)}")
if raise_:
raise
continue continue
else:
# Deconstruct tuple if it's not an exception # Deconstruct tuple if it's not an exception
p, _, new_data = res p, _, new_data = res
if p == pair: if p == pair:
data.extend(new_data) data.extend(new_data)
# Sort data again after extending the result - above calls return in "async order" # Sort data again after extending the result - above calls return in "async order"
data = sorted(data, key=lambda x: x[0]) data = sorted(data, key=lambda x: x[0])
logger.info("Downloaded data for %s with length %s.", pair, len(data)) return pair, timeframe, data
return data
def refresh_latest_ohlcv(self, pair_list: ListPairsWithTimeframes, *, def refresh_latest_ohlcv(self, pair_list: ListPairsWithTimeframes, *,
since_ms: Optional[int] = None, cache: bool = True since_ms: Optional[int] = None, cache: bool = True
@@ -1257,10 +1303,22 @@ class Exchange:
cached_pairs = [] cached_pairs = []
# Gather coroutines to run # Gather coroutines to run
for pair, timeframe in set(pair_list): for pair, timeframe in set(pair_list):
if (((pair, timeframe) not in self._klines) if ((pair, timeframe) not in self._klines or not cache
or self._now_is_time_to_refresh(pair, timeframe)): or self._now_is_time_to_refresh(pair, timeframe)):
input_coroutines.append(self._async_get_candle_history(pair, timeframe, if not since_ms and self.required_candle_call_count > 1:
since_ms=since_ms)) # Multiple calls for one pair - to get more history
one_call = timeframe_to_msecs(timeframe) * self.ohlcv_candle_limit(timeframe)
move_to = one_call * self.required_candle_call_count
now = timeframe_to_next_date(timeframe)
since_ms = int((now - timedelta(seconds=move_to // 1000)).timestamp() * 1000)
if since_ms:
input_coroutines.append(self._async_get_historic_ohlcv(
pair, timeframe, since_ms=since_ms, raise_=True))
else:
# One call ... "regular" refresh
input_coroutines.append(self._async_get_candle_history(
pair, timeframe, since_ms=since_ms))
else: else:
logger.debug( logger.debug(
"Using cached candle (OHLCV) data for pair %s, timeframe %s ...", "Using cached candle (OHLCV) data for pair %s, timeframe %s ...",
@@ -1268,14 +1326,16 @@ class Exchange:
) )
cached_pairs.append((pair, timeframe)) cached_pairs.append((pair, timeframe))
results = asyncio.get_event_loop().run_until_complete(
asyncio.gather(*input_coroutines, return_exceptions=True))
results_df = {} results_df = {}
# Chunk requests into batches of 100 to avoid overwelming ccxt Throttling
for input_coro in chunks(input_coroutines, 100):
results = asyncio.get_event_loop().run_until_complete(
asyncio.gather(*input_coro, return_exceptions=True))
# handle caching # handle caching
for res in results: for res in results:
if isinstance(res, Exception): if isinstance(res, Exception):
logger.warning("Async code raised an exception: %s", res.__class__.__name__) logger.warning(f"Async code raised an exception: {repr(res)}")
continue continue
# Deconstruct tuple (has 3 elements) # Deconstruct tuple (has 3 elements)
pair, timeframe, ticks = res pair, timeframe, ticks = res
@@ -1289,6 +1349,7 @@ class Exchange:
results_df[(pair, timeframe)] = ohlcv_df results_df[(pair, timeframe)] = ohlcv_df
if cache: if cache:
self._klines[(pair, timeframe)] = ohlcv_df self._klines[(pair, timeframe)] = ohlcv_df
# Return cached klines # Return cached klines
for pair, timeframe in cached_pairs: for pair, timeframe in cached_pairs:
results_df[(pair, timeframe)] = self.klines((pair, timeframe), copy=False) results_df[(pair, timeframe)] = self.klines((pair, timeframe), copy=False)
@@ -1515,7 +1576,7 @@ def is_exchange_known_ccxt(exchange_name: str, ccxt_module: CcxtModuleType = Non
def is_exchange_officially_supported(exchange_name: str) -> bool: def is_exchange_officially_supported(exchange_name: str) -> bool:
return exchange_name in ['bittrex', 'binance', 'kraken'] return exchange_name in ['bittrex', 'binance', 'kraken', 'ftx', 'gateio', 'okex']
def ccxt_exchanges(ccxt_module: CcxtModuleType = None) -> List[str]: def ccxt_exchanges(ccxt_module: CcxtModuleType = None) -> List[str]:

View File

@@ -2,6 +2,7 @@
import logging import logging
from typing import Dict from typing import Dict
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import Exchange from freqtrade.exchange import Exchange
@@ -21,3 +22,12 @@ class Gateio(Exchange):
_ft_has: Dict = { _ft_has: Dict = {
"ohlcv_candle_limit": 1000, "ohlcv_candle_limit": 1000,
} }
_headers = {'X-Gate-Channel-Id': 'freqtrade'}
def validate_ordertypes(self, order_types: Dict) -> None:
super().validate_ordertypes(order_types)
if any(v == 'market' for k, v in order_types.items()):
raise OperationalException(
f'Exchange {self.name} does not support market orders.')

View File

@@ -1,4 +1,4 @@
""" Kucoin exchange subclass """ """Kucoin exchange subclass."""
import logging import logging
from typing import Dict from typing import Dict
@@ -9,9 +9,9 @@ logger = logging.getLogger(__name__)
class Kucoin(Exchange): class Kucoin(Exchange):
""" """Kucoin exchange class.
Kucoin exchange class. Contains adjustments needed for Freqtrade to work
with this exchange. Contains adjustments needed for Freqtrade to work with this exchange.
Please note that this exchange is not included in the list of exchanges Please note that this exchange is not included in the list of exchanges
officially supported by the Freqtrade development team. So some features officially supported by the Freqtrade development team. So some features
@@ -21,4 +21,6 @@ class Kucoin(Exchange):
_ft_has: Dict = { _ft_has: Dict = {
"l2_limit_range": [20, 100], "l2_limit_range": [20, 100],
"l2_limit_range_required": False, "l2_limit_range_required": False,
"order_time_in_force": ['gtc', 'fok', 'ioc'],
"time_in_force_parameter": "timeInForce",
} }

View File

@@ -0,0 +1,18 @@
import logging
from typing import Dict
from freqtrade.exchange import Exchange
logger = logging.getLogger(__name__)
class Okex(Exchange):
"""Okex exchange class.
Contains adjustments needed for Freqtrade to work with this exchange.
"""
_ft_has: Dict = {
"ohlcv_candle_limit": 100,
}

View File

@@ -83,10 +83,10 @@ class FreqtradeBot(LoggingMixin):
self.dataprovider = DataProvider(self.config, self.exchange, self.pairlists) self.dataprovider = DataProvider(self.config, self.exchange, self.pairlists)
# Attach Dataprovider to Strategy baseclass # Attach Dataprovider to strategy instance
IStrategy.dp = self.dataprovider self.strategy.dp = self.dataprovider
# Attach Wallets to Strategy baseclass # Attach Wallets to strategy instance
IStrategy.wallets = self.wallets self.strategy.wallets = self.wallets
# Initializing Edge only if enabled # Initializing Edge only if enabled
self.edge = Edge(self.config, self.exchange, self.strategy) if \ self.edge = Edge(self.config, self.exchange, self.strategy) if \
@@ -99,7 +99,7 @@ class FreqtradeBot(LoggingMixin):
self.state = State[initial_state.upper()] if initial_state else State.STOPPED self.state = State[initial_state.upper()] if initial_state else State.STOPPED
# Protect sell-logic from forcesell and vice versa # Protect sell-logic from forcesell and vice versa
self._sell_lock = Lock() self._exit_lock = Lock()
LoggingMixin.__init__(self, logger, timeframe_to_seconds(self.strategy.timeframe)) LoggingMixin.__init__(self, logger, timeframe_to_seconds(self.strategy.timeframe))
def notify_status(self, msg: str) -> None: def notify_status(self, msg: str) -> None:
@@ -139,7 +139,7 @@ class FreqtradeBot(LoggingMixin):
# Only update open orders on startup # Only update open orders on startup
# This will update the database after the initial migration # This will update the database after the initial migration
self.update_open_orders() self.startup_update_open_orders()
def process(self) -> None: def process(self) -> None:
""" """
@@ -160,20 +160,20 @@ class FreqtradeBot(LoggingMixin):
# Refreshing candles # Refreshing candles
self.dataprovider.refresh(self.pairlists.create_pair_list(self.active_pair_whitelist), self.dataprovider.refresh(self.pairlists.create_pair_list(self.active_pair_whitelist),
self.strategy.informative_pairs()) self.strategy.gather_informative_pairs())
strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)() strategy_safe_wrapper(self.strategy.bot_loop_start, supress_error=True)()
self.strategy.analyze(self.active_pair_whitelist) self.strategy.analyze(self.active_pair_whitelist)
with self._sell_lock: with self._exit_lock:
# Check and handle any timed out open orders # Check and handle any timed out open orders
self.check_handle_timedout() self.check_handle_timedout()
# Protect from collisions with forcesell. # Protect from collisions with forcesell.
# Without this, freqtrade my try to recreate stoploss_on_exchange orders # Without this, freqtrade my try to recreate stoploss_on_exchange orders
# while selling is in process, since telegram messages arrive in an different thread. # while selling is in process, since telegram messages arrive in an different thread.
with self._sell_lock: with self._exit_lock:
trades = Trade.get_open_trades() trades = Trade.get_open_trades()
# First process current opened trades (positions) # First process current opened trades (positions)
self.exit_positions(trades) self.exit_positions(trades)
@@ -193,19 +193,20 @@ class FreqtradeBot(LoggingMixin):
def check_for_open_trades(self): def check_for_open_trades(self):
""" """
Notify the user when the bot is stopped Notify the user when the bot is stopped (not reloaded)
and there are still open trades active. and there are still open trades active.
""" """
open_trades = Trade.get_trades([Trade.is_open.is_(True)]).all() open_trades = Trade.get_trades([Trade.is_open.is_(True)]).all()
if len(open_trades) != 0: if len(open_trades) != 0 and self.state != State.RELOAD_CONFIG:
msg = { msg = {
'type': RPCMessageType.WARNING, 'type': RPCMessageType.WARNING,
'status': f"{len(open_trades)} open trades active.\n\n" 'status':
f"{len(open_trades)} open trades active.\n\n"
f"Handle these trades manually on {self.exchange.name}, " f"Handle these trades manually on {self.exchange.name}, "
f"or '/start' the bot again and use '/stopbuy' " f"or '/start' the bot again and use '/stopbuy' "
f"to handle open trades gracefully. \n" f"to handle open trades gracefully. \n"
f"{'Trades are simulated.' if self.config['dry_run'] else ''}", f"{'Note: Trades are simulated (dry run).' if self.config['dry_run'] else ''}",
} }
self.rpc.send_msg(msg) self.rpc.send_msg(msg)
@@ -237,7 +238,7 @@ class FreqtradeBot(LoggingMixin):
open_trades = len(Trade.get_open_trades()) open_trades = len(Trade.get_open_trades())
return max(0, self.config['max_open_trades'] - open_trades) return max(0, self.config['max_open_trades'] - open_trades)
def update_open_orders(self): def startup_update_open_orders(self):
""" """
Updates open orders based on order list kept in the database. Updates open orders based on order list kept in the database.
Mainly updates the state of orders - but may also close trades Mainly updates the state of orders - but may also close trades
@@ -277,7 +278,8 @@ class FreqtradeBot(LoggingMixin):
if order: if order:
logger.info(f"Updating sell-fee on trade {trade} for order {order.order_id}.") logger.info(f"Updating sell-fee on trade {trade} for order {order.order_id}.")
self.update_trade_state(trade, order.order_id, self.update_trade_state(trade, order.order_id,
stoploss_order=order.ft_order_side == 'stoploss') stoploss_order=order.ft_order_side == 'stoploss',
send_msg=False)
trades: List[Trade] = Trade.get_open_trades_without_assigned_fees() trades: List[Trade] = Trade.get_open_trades_without_assigned_fees()
for trade in trades: for trade in trades:
@@ -285,7 +287,7 @@ class FreqtradeBot(LoggingMixin):
order = trade.select_order('buy', False) order = trade.select_order('buy', False)
if order: if order:
logger.info(f"Updating buy-fee on trade {trade} for order {order.order_id}.") logger.info(f"Updating buy-fee on trade {trade} for order {order.order_id}.")
self.update_trade_state(trade, order.order_id) self.update_trade_state(trade, order.order_id, send_msg=False)
def handle_insufficient_funds(self, trade: Trade): def handle_insufficient_funds(self, trade: Trade):
""" """
@@ -296,9 +298,9 @@ class FreqtradeBot(LoggingMixin):
if sell_order: if sell_order:
self.refind_lost_order(trade) self.refind_lost_order(trade)
else: else:
self.reupdate_buy_order_fees(trade) self.reupdate_enter_order_fees(trade)
def reupdate_buy_order_fees(self, trade: Trade): def reupdate_enter_order_fees(self, trade: Trade):
""" """
Get buy order from database, and try to reupdate. Get buy order from database, and try to reupdate.
Handles trades where the initial fee-update did not work. Handles trades where the initial fee-update did not work.
@@ -307,7 +309,7 @@ class FreqtradeBot(LoggingMixin):
order = trade.select_order('buy', False) order = trade.select_order('buy', False)
if order: if order:
logger.info(f"Updating buy-fee on trade {trade} for order {order.order_id}.") logger.info(f"Updating buy-fee on trade {trade} for order {order.order_id}.")
self.update_trade_state(trade, order.order_id) self.update_trade_state(trade, order.order_id, send_msg=False)
def refind_lost_order(self, trade): def refind_lost_order(self, trade):
""" """
@@ -420,7 +422,7 @@ class FreqtradeBot(LoggingMixin):
return False return False
# running get_signal on historical data fetched # running get_signal on historical data fetched
(buy, sell, buy_tag) = self.strategy.get_signal( (buy, sell, buy_tag, _) = self.strategy.get_signal(
pair, pair,
self.strategy.timeframe, self.strategy.timeframe,
analyzed_df analyzed_df
@@ -465,8 +467,8 @@ class FreqtradeBot(LoggingMixin):
logger.info(f"Bids to asks delta for {pair} does not satisfy condition.") logger.info(f"Bids to asks delta for {pair} does not satisfy condition.")
return False return False
def execute_entry(self, pair: str, stake_amount: float, price: Optional[float] = None, def execute_entry(self, pair: str, stake_amount: float, price: Optional[float] = None, *,
forcebuy: bool = False, buy_tag: Optional[str] = None) -> bool: ordertype: Optional[str] = None, buy_tag: Optional[str] = None) -> bool:
""" """
Executes a limit buy for the given pair Executes a limit buy for the given pair
:param pair: pair for which we want to create a LIMIT_BUY :param pair: pair for which we want to create a LIMIT_BUY
@@ -476,21 +478,21 @@ class FreqtradeBot(LoggingMixin):
time_in_force = self.strategy.order_time_in_force['buy'] time_in_force = self.strategy.order_time_in_force['buy']
if price: if price:
buy_limit_requested = price enter_limit_requested = price
else: else:
# Calculate price # Calculate price
proposed_buy_rate = self.exchange.get_rate(pair, refresh=True, side="buy") proposed_enter_rate = self.exchange.get_rate(pair, refresh=True, side="buy")
custom_entry_price = strategy_safe_wrapper(self.strategy.custom_entry_price, custom_entry_price = strategy_safe_wrapper(self.strategy.custom_entry_price,
default_retval=proposed_buy_rate)( default_retval=proposed_enter_rate)(
pair=pair, current_time=datetime.now(timezone.utc), pair=pair, current_time=datetime.now(timezone.utc),
proposed_rate=proposed_buy_rate) proposed_rate=proposed_enter_rate)
buy_limit_requested = self.get_valid_price(custom_entry_price, proposed_buy_rate) enter_limit_requested = self.get_valid_price(custom_entry_price, proposed_enter_rate)
if not buy_limit_requested: if not enter_limit_requested:
raise PricingError('Could not determine buy price.') raise PricingError('Could not determine buy price.')
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, buy_limit_requested, min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, enter_limit_requested,
self.strategy.stoploss) self.strategy.stoploss)
if not self.edge: if not self.edge:
@@ -498,9 +500,9 @@ class FreqtradeBot(LoggingMixin):
stake_amount = strategy_safe_wrapper(self.strategy.custom_stake_amount, stake_amount = strategy_safe_wrapper(self.strategy.custom_stake_amount,
default_retval=stake_amount)( default_retval=stake_amount)(
pair=pair, current_time=datetime.now(timezone.utc), pair=pair, current_time=datetime.now(timezone.utc),
current_rate=buy_limit_requested, proposed_stake=stake_amount, current_rate=enter_limit_requested, proposed_stake=stake_amount,
min_stake=min_stake_amount, max_stake=max_stake_amount) min_stake=min_stake_amount, max_stake=max_stake_amount)
stake_amount = self.wallets._validate_stake_amount(pair, stake_amount, min_stake_amount) stake_amount = self.wallets.validate_stake_amount(pair, stake_amount, min_stake_amount)
if not stake_amount: if not stake_amount:
return False return False
@@ -508,27 +510,24 @@ class FreqtradeBot(LoggingMixin):
logger.info(f"Buy signal found: about create a new trade for {pair} with stake_amount: " logger.info(f"Buy signal found: about create a new trade for {pair} with stake_amount: "
f"{stake_amount} ...") f"{stake_amount} ...")
amount = stake_amount / buy_limit_requested amount = stake_amount / enter_limit_requested
order_type = self.strategy.order_types['buy'] order_type = ordertype or self.strategy.order_types['buy']
if forcebuy:
# Forcebuy can define a different ordertype
order_type = self.strategy.order_types.get('forcebuy', order_type)
if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)( if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)(
pair=pair, order_type=order_type, amount=amount, rate=buy_limit_requested, pair=pair, order_type=order_type, amount=amount, rate=enter_limit_requested,
time_in_force=time_in_force, current_time=datetime.now(timezone.utc)): time_in_force=time_in_force, current_time=datetime.now(timezone.utc)):
logger.info(f"User requested abortion of buying {pair}") logger.info(f"User requested abortion of buying {pair}")
return False return False
amount = self.exchange.amount_to_precision(pair, amount) amount = self.exchange.amount_to_precision(pair, amount)
order = self.exchange.create_order(pair=pair, ordertype=order_type, side="buy", order = self.exchange.create_order(pair=pair, ordertype=order_type, side="buy",
amount=amount, rate=buy_limit_requested, amount=amount, rate=enter_limit_requested,
time_in_force=time_in_force) time_in_force=time_in_force)
order_obj = Order.parse_from_ccxt_object(order, pair, 'buy') order_obj = Order.parse_from_ccxt_object(order, pair, 'buy')
order_id = order['id'] order_id = order['id']
order_status = order.get('status', None) order_status = order.get('status', None)
# we assume the order is executed at the price requested # we assume the order is executed at the price requested
buy_limit_filled_price = buy_limit_requested enter_limit_filled_price = enter_limit_requested
amount_requested = amount amount_requested = amount
if order_status == 'expired' or order_status == 'rejected': if order_status == 'expired' or order_status == 'rejected':
@@ -551,13 +550,13 @@ class FreqtradeBot(LoggingMixin):
) )
stake_amount = order['cost'] stake_amount = order['cost']
amount = safe_value_fallback(order, 'filled', 'amount') amount = safe_value_fallback(order, 'filled', 'amount')
buy_limit_filled_price = safe_value_fallback(order, 'average', 'price') enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
# in case of FOK the order may be filled immediately and fully # in case of FOK the order may be filled immediately and fully
elif order_status == 'closed': elif order_status == 'closed':
stake_amount = order['cost'] stake_amount = order['cost']
amount = safe_value_fallback(order, 'filled', 'amount') amount = safe_value_fallback(order, 'filled', 'amount')
buy_limit_filled_price = safe_value_fallback(order, 'average', 'price') enter_limit_filled_price = safe_value_fallback(order, 'average', 'price')
# Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL # Fee is applied twice because we make a LIMIT_BUY and LIMIT_SELL
fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker') fee = self.exchange.get_fee(symbol=pair, taker_or_maker='maker')
@@ -569,8 +568,8 @@ class FreqtradeBot(LoggingMixin):
amount_requested=amount_requested, amount_requested=amount_requested,
fee_open=fee, fee_open=fee,
fee_close=fee, fee_close=fee,
open_rate=buy_limit_filled_price, open_rate=enter_limit_filled_price,
open_rate_requested=buy_limit_requested, open_rate_requested=enter_limit_requested,
open_date=datetime.utcnow(), open_date=datetime.utcnow(),
exchange=self.exchange.id, exchange=self.exchange.id,
open_order_id=order_id, open_order_id=order_id,
@@ -580,31 +579,33 @@ class FreqtradeBot(LoggingMixin):
) )
trade.orders.append(order_obj) trade.orders.append(order_obj)
# Update fees if order is closed
if order_status == 'closed':
self.update_trade_state(trade, order_id, order)
Trade.query.session.add(trade) Trade.query.session.add(trade)
Trade.commit() Trade.commit()
# Updating wallets # Updating wallets
self.wallets.update() self.wallets.update()
self._notify_buy(trade, order_type) self._notify_enter(trade, order_type)
# Update fees if order is closed
if order_status == 'closed':
self.update_trade_state(trade, order_id, order)
return True return True
def _notify_buy(self, trade: Trade, order_type: str) -> None: def _notify_enter(self, trade: Trade, order_type: Optional[str] = None,
fill: bool = False) -> None:
""" """
Sends rpc notification when a buy occurred. Sends rpc notification when a buy occurred.
""" """
msg = { msg = {
'trade_id': trade.id, 'trade_id': trade.id,
'type': RPCMessageType.BUY, 'type': RPCMessageType.BUY_FILL if fill else RPCMessageType.BUY,
'buy_tag': trade.buy_tag, 'buy_tag': trade.buy_tag,
'exchange': self.exchange.name.capitalize(), 'exchange': self.exchange.name.capitalize(),
'pair': trade.pair, 'pair': trade.pair,
'limit': trade.open_rate, 'limit': trade.open_rate, # Deprecated (?)
'open_rate': trade.open_rate,
'order_type': order_type, 'order_type': order_type,
'stake_amount': trade.stake_amount, 'stake_amount': trade.stake_amount,
'stake_currency': self.config['stake_currency'], 'stake_currency': self.config['stake_currency'],
@@ -617,7 +618,7 @@ class FreqtradeBot(LoggingMixin):
# Send the message # Send the message
self.rpc.send_msg(msg) self.rpc.send_msg(msg)
def _notify_buy_cancel(self, trade: Trade, order_type: str, reason: str) -> None: def _notify_enter_cancel(self, trade: Trade, order_type: str, reason: str) -> None:
""" """
Sends rpc notification when a buy cancel occurred. Sends rpc notification when a buy cancel occurred.
""" """
@@ -643,22 +644,6 @@ class FreqtradeBot(LoggingMixin):
# Send the message # Send the message
self.rpc.send_msg(msg) self.rpc.send_msg(msg)
def _notify_buy_fill(self, trade: Trade) -> None:
msg = {
'trade_id': trade.id,
'type': RPCMessageType.BUY_FILL,
'buy_tag': trade.buy_tag,
'exchange': self.exchange.name.capitalize(),
'pair': trade.pair,
'open_rate': trade.open_rate,
'stake_amount': trade.stake_amount,
'stake_currency': self.config['stake_currency'],
'fiat_currency': self.config.get('fiat_display_currency', None),
'amount': trade.amount,
'open_date': trade.open_date,
}
self.rpc.send_msg(msg)
# #
# SELL / exit positions / close trades logic and methods # SELL / exit positions / close trades logic and methods
# #
@@ -681,7 +666,7 @@ class FreqtradeBot(LoggingMixin):
trades_closed += 1 trades_closed += 1
except DependencyException as exception: except DependencyException as exception:
logger.warning('Unable to sell trade %s: %s', trade.pair, exception) logger.warning(f'Unable to sell trade {trade.pair}: {exception}')
# Updating wallets if any trade occurred # Updating wallets if any trade occurred
if trades_closed: if trades_closed:
@@ -700,13 +685,14 @@ class FreqtradeBot(LoggingMixin):
logger.debug('Handling %s ...', trade) logger.debug('Handling %s ...', trade)
(buy, sell) = (False, False) (buy, sell) = (False, False)
exit_tag = None
if (self.config.get('use_sell_signal', True) or if (self.config.get('use_sell_signal', True) or
self.config.get('ignore_roi_if_buy_signal', False)): self.config.get('ignore_roi_if_buy_signal', False)):
analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair, analyzed_df, _ = self.dataprovider.get_analyzed_dataframe(trade.pair,
self.strategy.timeframe) self.strategy.timeframe)
(buy, sell, _) = self.strategy.get_signal( (buy, sell, _, exit_tag) = self.strategy.get_signal(
trade.pair, trade.pair,
self.strategy.timeframe, self.strategy.timeframe,
analyzed_df analyzed_df
@@ -714,7 +700,7 @@ class FreqtradeBot(LoggingMixin):
logger.debug('checking sell') logger.debug('checking sell')
sell_rate = self.exchange.get_rate(trade.pair, refresh=True, side="sell") sell_rate = self.exchange.get_rate(trade.pair, refresh=True, side="sell")
if self._check_and_execute_sell(trade, sell_rate, buy, sell): if self._check_and_execute_exit(trade, sell_rate, buy, sell, exit_tag):
return True return True
logger.debug('Found no sell signal for %s.', trade) logger.debug('Found no sell signal for %s.', trade)
@@ -744,7 +730,7 @@ class FreqtradeBot(LoggingMixin):
except InvalidOrderException as e: except InvalidOrderException as e:
trade.stoploss_order_id = None trade.stoploss_order_id = None
logger.error(f'Unable to place a stoploss order on exchange. {e}') logger.error(f'Unable to place a stoploss order on exchange. {e}')
logger.warning('Selling the trade forcefully') logger.warning('Exiting the trade forcefully')
self.execute_trade_exit(trade, trade.stop_loss, sell_reason=SellCheckTuple( self.execute_trade_exit(trade, trade.stop_loss, sell_reason=SellCheckTuple(
sell_type=SellType.EMERGENCY_SELL)) sell_type=SellType.EMERGENCY_SELL))
@@ -782,7 +768,7 @@ class FreqtradeBot(LoggingMixin):
# Lock pair for one candle to prevent immediate rebuys # Lock pair for one candle to prevent immediate rebuys
self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc), self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc),
reason='Auto lock') reason='Auto lock')
self._notify_sell(trade, "stoploss") self._notify_exit(trade, "stoploss")
return True return True
if trade.open_order_id or not trade.is_open: if trade.open_order_id or not trade.is_open:
@@ -851,19 +837,22 @@ class FreqtradeBot(LoggingMixin):
logger.warning(f"Could not create trailing stoploss order " logger.warning(f"Could not create trailing stoploss order "
f"for pair {trade.pair}.") f"for pair {trade.pair}.")
def _check_and_execute_sell(self, trade: Trade, sell_rate: float, def _check_and_execute_exit(self, trade: Trade, exit_rate: float,
buy: bool, sell: bool) -> bool: buy: bool, sell: bool, exit_tag: Optional[str]) -> bool:
""" """
Check and execute sell Check and execute exit
""" """
should_sell = self.strategy.should_sell( should_sell = self.strategy.should_sell(
trade, sell_rate, datetime.now(timezone.utc), buy, sell, trade, exit_rate, datetime.now(timezone.utc), buy, sell,
force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0 force_stoploss=self.edge.stoploss(trade.pair) if self.edge else 0
) )
if should_sell.sell_flag: if should_sell.sell_flag:
logger.info(f'Executing Sell for {trade.pair}. Reason: {should_sell.sell_type}') logger.info(
self.execute_trade_exit(trade, sell_rate, should_sell) f'Executing Sell for {trade.pair}. Reason: {should_sell.sell_type}. '
f'Tag: {exit_tag if exit_tag is not None else "None"}')
self.execute_trade_exit(trade, exit_rate, should_sell, exit_tag=exit_tag)
return True return True
return False return False
@@ -906,7 +895,7 @@ class FreqtradeBot(LoggingMixin):
default_retval=False)(pair=trade.pair, default_retval=False)(pair=trade.pair,
trade=trade, trade=trade,
order=order))): order=order))):
self.handle_cancel_buy(trade, order, constants.CANCEL_REASON['TIMEOUT']) self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['TIMEOUT'])
elif (order['side'] == 'sell' and (order['status'] == 'open' or fully_cancelled) and ( elif (order['side'] == 'sell' and (order['status'] == 'open' or fully_cancelled) and (
fully_cancelled fully_cancelled
@@ -915,7 +904,18 @@ class FreqtradeBot(LoggingMixin):
default_retval=False)(pair=trade.pair, default_retval=False)(pair=trade.pair,
trade=trade, trade=trade,
order=order))): order=order))):
self.handle_cancel_sell(trade, order, constants.CANCEL_REASON['TIMEOUT']) self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['TIMEOUT'])
canceled_count = trade.get_exit_order_count()
max_timeouts = self.config.get('unfilledtimeout', {}).get('exit_timeout_count', 0)
if max_timeouts > 0 and canceled_count >= max_timeouts:
logger.warning(f'Emergencyselling trade {trade}, as the sell order '
f'timed out {max_timeouts} times.')
try:
self.execute_trade_exit(
trade, order.get('price'),
sell_reason=SellCheckTuple(sell_type=SellType.EMERGENCY_SELL))
except DependencyException as exception:
logger.warning(f'Unable to emergency sell trade {trade.pair}: {exception}')
def cancel_all_open_orders(self) -> None: def cancel_all_open_orders(self) -> None:
""" """
@@ -931,13 +931,13 @@ class FreqtradeBot(LoggingMixin):
continue continue
if order['side'] == 'buy': if order['side'] == 'buy':
self.handle_cancel_buy(trade, order, constants.CANCEL_REASON['ALL_CANCELLED']) self.handle_cancel_enter(trade, order, constants.CANCEL_REASON['ALL_CANCELLED'])
elif order['side'] == 'sell': elif order['side'] == 'sell':
self.handle_cancel_sell(trade, order, constants.CANCEL_REASON['ALL_CANCELLED']) self.handle_cancel_exit(trade, order, constants.CANCEL_REASON['ALL_CANCELLED'])
Trade.commit() Trade.commit()
def handle_cancel_buy(self, trade: Trade, order: Dict, reason: str) -> bool: def handle_cancel_enter(self, trade: Trade, order: Dict, reason: str) -> bool:
""" """
Buy cancel - cancel order Buy cancel - cancel order
:return: True if order was fully cancelled :return: True if order was fully cancelled
@@ -994,11 +994,11 @@ class FreqtradeBot(LoggingMixin):
reason += f", {constants.CANCEL_REASON['PARTIALLY_FILLED']}" reason += f", {constants.CANCEL_REASON['PARTIALLY_FILLED']}"
self.wallets.update() self.wallets.update()
self._notify_buy_cancel(trade, order_type=self.strategy.order_types['buy'], self._notify_enter_cancel(trade, order_type=self.strategy.order_types['buy'],
reason=reason) reason=reason)
return was_trade_fully_canceled return was_trade_fully_canceled
def handle_cancel_sell(self, trade: Trade, order: Dict, reason: str) -> str: def handle_cancel_exit(self, trade: Trade, order: Dict, reason: str) -> str:
""" """
Sell cancel - cancel order and update trade Sell cancel - cancel order and update trade
:return: Reason for cancel :return: Reason for cancel
@@ -1032,14 +1032,14 @@ class FreqtradeBot(LoggingMixin):
reason = constants.CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN'] reason = constants.CANCEL_REASON['PARTIALLY_FILLED_KEEP_OPEN']
self.wallets.update() self.wallets.update()
self._notify_sell_cancel( self._notify_exit_cancel(
trade, trade,
order_type=self.strategy.order_types['sell'], order_type=self.strategy.order_types['sell'],
reason=reason reason=reason
) )
return reason return reason
def _safe_sell_amount(self, pair: str, amount: float) -> float: def _safe_exit_amount(self, pair: str, amount: float) -> float:
""" """
Get sellable amount. Get sellable amount.
Should be trade.amount - but will fall back to the available amount if necessary. Should be trade.amount - but will fall back to the available amount if necessary.
@@ -1064,7 +1064,15 @@ class FreqtradeBot(LoggingMixin):
raise DependencyException( raise DependencyException(
f"Not enough amount to sell. Trade-amount: {amount}, Wallet: {wallet_amount}") f"Not enough amount to sell. Trade-amount: {amount}, Wallet: {wallet_amount}")
def execute_trade_exit(self, trade: Trade, limit: float, sell_reason: SellCheckTuple) -> bool: def execute_trade_exit(
self,
trade: Trade,
limit: float,
sell_reason: SellCheckTuple,
*,
exit_tag: Optional[str] = None,
ordertype: Optional[str] = None,
) -> bool:
""" """
Executes a trade exit for the given trade and limit Executes a trade exit for the given trade and limit
:param trade: Trade instance :param trade: Trade instance
@@ -1102,16 +1110,12 @@ class FreqtradeBot(LoggingMixin):
except InvalidOrderException: except InvalidOrderException:
logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}") logger.exception(f"Could not cancel stoploss order {trade.stoploss_order_id}")
order_type = self.strategy.order_types[sell_type] order_type = ordertype or self.strategy.order_types[sell_type]
if sell_reason.sell_type == SellType.EMERGENCY_SELL: if sell_reason.sell_type == SellType.EMERGENCY_SELL:
# Emergency sells (default to market!) # Emergency sells (default to market!)
order_type = self.strategy.order_types.get("emergencysell", "market") order_type = self.strategy.order_types.get("emergencysell", "market")
if sell_reason.sell_type == SellType.FORCE_SELL:
# Force sells (default to the sell_type defined in the strategy,
# but we allow this value to be changed)
order_type = self.strategy.order_types.get("forcesell", order_type)
amount = self._safe_sell_amount(trade.pair, trade.amount) amount = self._safe_exit_amount(trade.pair, trade.amount)
time_in_force = self.strategy.order_time_in_force['sell'] time_in_force = self.strategy.order_time_in_force['sell']
if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)( if not strategy_safe_wrapper(self.strategy.confirm_trade_exit, default_retval=True)(
@@ -1140,21 +1144,21 @@ class FreqtradeBot(LoggingMixin):
trade.open_order_id = order['id'] trade.open_order_id = order['id']
trade.sell_order_status = '' trade.sell_order_status = ''
trade.close_rate_requested = limit trade.close_rate_requested = limit
trade.sell_reason = sell_reason.sell_reason trade.sell_reason = exit_tag or sell_reason.sell_reason
# In case of market sell orders the order can be closed immediately
if order.get('status', 'unknown') in ('closed', 'expired'):
self.update_trade_state(trade, trade.open_order_id, order)
Trade.commit()
# Lock pair for one candle to prevent immediate re-buys # Lock pair for one candle to prevent immediate re-buys
self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc), self.strategy.lock_pair(trade.pair, datetime.now(timezone.utc),
reason='Auto lock') reason='Auto lock')
self._notify_sell(trade, order_type) self._notify_exit(trade, order_type)
# In case of market sell orders the order can be closed immediately
if order.get('status', 'unknown') in ('closed', 'expired'):
self.update_trade_state(trade, trade.open_order_id, order)
Trade.commit()
return True return True
def _notify_sell(self, trade: Trade, order_type: str, fill: bool = False) -> None: def _notify_exit(self, trade: Trade, order_type: str, fill: bool = False) -> None:
""" """
Sends rpc notification when a sell occurred. Sends rpc notification when a sell occurred.
""" """
@@ -1181,6 +1185,7 @@ class FreqtradeBot(LoggingMixin):
'current_rate': current_rate, 'current_rate': current_rate,
'profit_amount': profit_trade, 'profit_amount': profit_trade,
'profit_ratio': profit_ratio, 'profit_ratio': profit_ratio,
'buy_tag': trade.buy_tag,
'sell_reason': trade.sell_reason, 'sell_reason': trade.sell_reason,
'open_date': trade.open_date, 'open_date': trade.open_date,
'close_date': trade.close_date or datetime.utcnow(), 'close_date': trade.close_date or datetime.utcnow(),
@@ -1196,7 +1201,7 @@ class FreqtradeBot(LoggingMixin):
# Send the message # Send the message
self.rpc.send_msg(msg) self.rpc.send_msg(msg)
def _notify_sell_cancel(self, trade: Trade, order_type: str, reason: str) -> None: def _notify_exit_cancel(self, trade: Trade, order_type: str, reason: str) -> None:
""" """
Sends rpc notification when a sell cancel occurred. Sends rpc notification when a sell cancel occurred.
""" """
@@ -1217,16 +1222,17 @@ class FreqtradeBot(LoggingMixin):
'exchange': trade.exchange.capitalize(), 'exchange': trade.exchange.capitalize(),
'pair': trade.pair, 'pair': trade.pair,
'gain': gain, 'gain': gain,
'limit': profit_rate, 'limit': profit_rate or 0,
'order_type': order_type, 'order_type': order_type,
'amount': trade.amount, 'amount': trade.amount,
'open_rate': trade.open_rate, 'open_rate': trade.open_rate,
'current_rate': current_rate, 'current_rate': current_rate,
'profit_amount': profit_trade, 'profit_amount': profit_trade,
'profit_ratio': profit_ratio, 'profit_ratio': profit_ratio,
'buy_tag': trade.buy_tag,
'sell_reason': trade.sell_reason, 'sell_reason': trade.sell_reason,
'open_date': trade.open_date, 'open_date': trade.open_date,
'close_date': trade.close_date, 'close_date': trade.close_date or datetime.now(timezone.utc),
'stake_currency': self.config['stake_currency'], 'stake_currency': self.config['stake_currency'],
'fiat_currency': self.config.get('fiat_display_currency', None), 'fiat_currency': self.config.get('fiat_display_currency', None),
'reason': reason, 'reason': reason,
@@ -1245,13 +1251,14 @@ class FreqtradeBot(LoggingMixin):
# #
def update_trade_state(self, trade: Trade, order_id: str, action_order: Dict[str, Any] = None, def update_trade_state(self, trade: Trade, order_id: str, action_order: Dict[str, Any] = None,
stoploss_order: bool = False) -> bool: stoploss_order: bool = False, send_msg: bool = True) -> bool:
""" """
Checks trades with open orders and updates the amount if necessary Checks trades with open orders and updates the amount if necessary
Handles closing both buy and sell orders. Handles closing both buy and sell orders.
:param trade: Trade object of the trade we're analyzing :param trade: Trade object of the trade we're analyzing
:param order_id: Order-id of the order we're analyzing :param order_id: Order-id of the order we're analyzing
:param action_order: Already acquired order object :param action_order: Already acquired order object
:param send_msg: Send notification - should always be True except in "recovery" methods
:return: True if order has been cancelled without being filled partially, False otherwise :return: True if order has been cancelled without being filled partially, False otherwise
""" """
if not order_id: if not order_id:
@@ -1270,6 +1277,11 @@ class FreqtradeBot(LoggingMixin):
trade.update_order(order) trade.update_order(order)
if self.exchange.check_order_canceled_empty(order):
# Trade has been cancelled on exchange
# Handling of this will happen in check_handle_timedout.
return True
# Try update amount (binance-fix) # Try update amount (binance-fix)
try: try:
new_amount = self.get_real_amount(trade, order) new_amount = self.get_real_amount(trade, order)
@@ -1281,26 +1293,34 @@ class FreqtradeBot(LoggingMixin):
except DependencyException as exception: except DependencyException as exception:
logger.warning("Could not update trade amount: %s", exception) logger.warning("Could not update trade amount: %s", exception)
if self.exchange.check_order_canceled_empty(order):
# Trade has been cancelled on exchange
# Handling of this will happen in check_handle_timeout.
return True
trade.update(order) trade.update(order)
Trade.commit() Trade.commit()
# Updating wallets when order is closed # Updating wallets when order is closed
if not trade.is_open: if not trade.is_open:
if not stoploss_order and not trade.open_order_id: if send_msg and not stoploss_order and not trade.open_order_id:
self._notify_sell(trade, '', True) self._notify_exit(trade, '', True)
self.protections.stop_per_pair(trade.pair) self.handle_protections(trade.pair)
self.protections.global_stop()
self.wallets.update() self.wallets.update()
elif not trade.open_order_id: elif send_msg and not trade.open_order_id:
# Buy fill # Buy fill
self._notify_buy_fill(trade) self._notify_enter(trade, fill=True)
return False return False
def handle_protections(self, pair: str) -> None:
prot_trig = self.protections.stop_per_pair(pair)
if prot_trig:
msg = {'type': RPCMessageType.PROTECTION_TRIGGER, }
msg.update(prot_trig.to_json())
self.rpc.send_msg(msg)
prot_trig_glb = self.protections.global_stop()
if prot_trig_glb:
msg = {'type': RPCMessageType.PROTECTION_TRIGGER_GLOBAL, }
msg.update(prot_trig_glb.to_json())
self.rpc.send_msg(msg)
def apply_fee_conditional(self, trade: Trade, trade_base_currency: str, def apply_fee_conditional(self, trade: Trade, trade_base_currency: str,
amount: float, fee_abs: float) -> float: amount: float, fee_abs: float) -> float:
""" """
@@ -1349,14 +1369,17 @@ class FreqtradeBot(LoggingMixin):
return self.apply_fee_conditional(trade, trade_base_currency, return self.apply_fee_conditional(trade, trade_base_currency,
amount=order_amount, fee_abs=fee_cost) amount=order_amount, fee_abs=fee_cost)
return order_amount return order_amount
return self.fee_detection_from_trades(trade, order, order_amount) return self.fee_detection_from_trades(trade, order, order_amount, order.get('trades', []))
def fee_detection_from_trades(self, trade: Trade, order: Dict, order_amount: float) -> float: def fee_detection_from_trades(self, trade: Trade, order: Dict, order_amount: float,
trades: List) -> float:
""" """
fee-detection fallback to Trades. Parses result of fetch_my_trades to get correct fee. fee-detection fallback to Trades.
Either uses provided trades list or the result of fetch_my_trades to get correct fee.
""" """
trades = self.exchange.get_trades_for_order(self.exchange.get_order_id_conditional(order), if not trades:
trade.pair, trade.open_date) trades = self.exchange.get_trades_for_order(
self.exchange.get_order_id_conditional(order), trade.pair, trade.open_date)
if len(trades) == 0: if len(trades) == 0:
logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade) logger.info("Applying fee on amount for %s failed: myTrade-Dict empty found", trade)

View File

@@ -87,7 +87,7 @@ def setup_logging(config: Dict[str, Any]) -> None:
# syslog config. The messages should be equal for this. # syslog config. The messages should be equal for this.
handler_sl.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s')) handler_sl.setFormatter(Formatter('%(name)s - %(levelname)s - %(message)s'))
logging.root.addHandler(handler_sl) logging.root.addHandler(handler_sl)
elif s[0] == 'journald': elif s[0] == 'journald': # pragma: no cover
try: try:
from systemd.journal import JournaldLogHandler from systemd.journal import JournaldLogHandler
except ImportError: except ImportError:

View File

@@ -9,7 +9,7 @@ from typing import Any, List
# check min. python version # check min. python version
if sys.version_info < (3, 7): if sys.version_info < (3, 7): # pragma: no cover
sys.exit("Freqtrade requires Python version >= 3.7") sys.exit("Freqtrade requires Python version >= 3.7")
from freqtrade.commands import Arguments from freqtrade.commands import Arguments
@@ -46,7 +46,7 @@ def main(sysargv: List[str] = None) -> None:
"`freqtrade --help` or `freqtrade <command> --help`." "`freqtrade --help` or `freqtrade <command> --help`."
) )
except SystemExit as e: except SystemExit as e: # pragma: no cover
return_code = e return_code = e
except KeyboardInterrupt: except KeyboardInterrupt:
logger.info('SIGINT received, aborting ...') logger.info('SIGINT received, aborting ...')
@@ -60,5 +60,5 @@ def main(sysargv: List[str] = None) -> None:
sys.exit(return_code) sys.exit(return_code)
if __name__ == '__main__': if __name__ == '__main__': # pragma: no cover
main() main()

View File

@@ -11,7 +11,7 @@ from typing import Any, Dict, List, Optional, Tuple
from pandas import DataFrame from pandas import DataFrame
from freqtrade.configuration import TimeRange, remove_credentials, validate_config_consistency from freqtrade.configuration import TimeRange, validate_config_consistency
from freqtrade.constants import DATETIME_PRINT_FORMAT from freqtrade.constants import DATETIME_PRINT_FORMAT
from freqtrade.data import history from freqtrade.data import history
from freqtrade.data.btanalysis import trade_list_to_dataframe from freqtrade.data.btanalysis import trade_list_to_dataframe
@@ -44,6 +44,7 @@ SELL_IDX = 4
LOW_IDX = 5 LOW_IDX = 5
HIGH_IDX = 6 HIGH_IDX = 6
BUY_TAG_IDX = 7 BUY_TAG_IDX = 7
EXIT_TAG_IDX = 8
class Backtesting: class Backtesting:
@@ -61,13 +62,12 @@ class Backtesting:
self.config = config self.config = config
self.results: Optional[Dict[str, Any]] = None self.results: Optional[Dict[str, Any]] = None
# Reset keys for backtesting config['dry_run'] = True
remove_credentials(self.config)
self.strategylist: List[IStrategy] = [] self.strategylist: List[IStrategy] = []
self.all_results: Dict[str, Dict] = {} self.all_results: Dict[str, Dict] = {}
self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config)
self.dataprovider = DataProvider(self.config, None) self.dataprovider = DataProvider(self.config, self.exchange)
if self.config.get('strategy_list', None): if self.config.get('strategy_list', None):
for strat in list(self.config['strategy_list']): for strat in list(self.config['strategy_list']):
@@ -86,10 +86,11 @@ class Backtesting:
"configuration or as cli argument `--timeframe 5m`") "configuration or as cli argument `--timeframe 5m`")
self.timeframe = str(self.config.get('timeframe')) self.timeframe = str(self.config.get('timeframe'))
self.timeframe_min = timeframe_to_minutes(self.timeframe) self.timeframe_min = timeframe_to_minutes(self.timeframe)
self.init_backtest_detail()
self.pairlists = PairListManager(self.exchange, self.config) self.pairlists = PairListManager(self.exchange, self.config)
if 'VolumePairList' in self.pairlists.name_list: if 'VolumePairList' in self.pairlists.name_list:
raise OperationalException("VolumePairList not allowed for backtesting.") raise OperationalException("VolumePairList not allowed for backtesting. "
"Please use StaticPairlist instead.")
if 'PerformanceFilter' in self.pairlists.name_list: if 'PerformanceFilter' in self.pairlists.name_list:
raise OperationalException("PerformanceFilter not allowed for backtesting.") raise OperationalException("PerformanceFilter not allowed for backtesting.")
@@ -109,14 +110,6 @@ class Backtesting:
else: else:
self.fee = self.exchange.get_fee(symbol=self.pairlists.whitelist[0]) self.fee = self.exchange.get_fee(symbol=self.pairlists.whitelist[0])
Trade.use_db = False
Trade.reset_trades()
PairLocks.timeframe = self.config['timeframe']
PairLocks.use_db = False
PairLocks.reset_locks()
self.wallets = Wallets(self.config, self.exchange, log=False)
self.timerange = TimeRange.parse_timerange( self.timerange = TimeRange.parse_timerange(
None if self.config.get('timerange') is None else str(self.config.get('timerange'))) None if self.config.get('timerange') is None else str(self.config.get('timerange')))
@@ -125,9 +118,7 @@ class Backtesting:
# Add maximum startup candle count to configuration for informative pairs support # Add maximum startup candle count to configuration for informative pairs support
self.config['startup_candle_count'] = self.required_startup self.config['startup_candle_count'] = self.required_startup
self.exchange.validate_required_startup_candles(self.required_startup, self.timeframe) self.exchange.validate_required_startup_candles(self.required_startup, self.timeframe)
self.init_backtest()
self.progress = BTProgress()
self.abort = False
def __del__(self): def __del__(self):
self.cleanup() self.cleanup()
@@ -137,6 +128,28 @@ class Backtesting:
PairLocks.use_db = True PairLocks.use_db = True
Trade.use_db = True Trade.use_db = True
def init_backtest_detail(self):
# Load detail timeframe if specified
self.timeframe_detail = str(self.config.get('timeframe_detail', ''))
if self.timeframe_detail:
self.timeframe_detail_min = timeframe_to_minutes(self.timeframe_detail)
if self.timeframe_min <= self.timeframe_detail_min:
raise OperationalException(
"Detail timeframe must be smaller than strategy timeframe.")
else:
self.timeframe_detail_min = 0
self.detail_data: Dict[str, DataFrame] = {}
def init_backtest(self):
self.prepare_backtest(False)
self.wallets = Wallets(self.config, self.exchange, log=False)
self.progress = BTProgress()
self.abort = False
def _set_strategy(self, strategy: IStrategy): def _set_strategy(self, strategy: IStrategy):
""" """
Load strategy into backtesting Load strategy into backtesting
@@ -144,7 +157,7 @@ class Backtesting:
self.strategy: IStrategy = strategy self.strategy: IStrategy = strategy
strategy.dp = self.dataprovider strategy.dp = self.dataprovider
# Attach Wallets to Strategy baseclass # Attach Wallets to Strategy baseclass
IStrategy.wallets = self.wallets strategy.wallets = self.wallets
# Set stoploss_on_exchange to false for backtesting, # Set stoploss_on_exchange to false for backtesting,
# since a "perfect" stoploss-sell is assumed anyway # since a "perfect" stoploss-sell is assumed anyway
# And the regular "stoploss" function would not apply to that case # And the regular "stoploss" function would not apply to that case
@@ -188,6 +201,23 @@ class Backtesting:
self.progress.set_new_value(1) self.progress.set_new_value(1)
return data, self.timerange return data, self.timerange
def load_bt_data_detail(self) -> None:
"""
Loads backtest detail data (smaller timeframe) if necessary.
"""
if self.timeframe_detail:
self.detail_data = history.load_data(
datadir=self.config['datadir'],
pairs=self.pairlists.whitelist,
timeframe=self.timeframe_detail,
timerange=self.timerange,
startup_candles=0,
fail_without_data=True,
data_format=self.config.get('dataformat_ohlcv', 'json'),
)
else:
self.detail_data = {}
def prepare_backtest(self, enable_protections): def prepare_backtest(self, enable_protections):
""" """
Backtesting setup method - called once for every call to "backtest()". Backtesting setup method - called once for every call to "backtest()".
@@ -199,6 +229,7 @@ class Backtesting:
Trade.reset_trades() Trade.reset_trades()
self.rejected_trades = 0 self.rejected_trades = 0
self.dataprovider.clear_cache() self.dataprovider.clear_cache()
if enable_protections:
self._load_protections(self.strategy) self._load_protections(self.strategy)
def check_abort(self): def check_abort(self):
@@ -218,7 +249,7 @@ class Backtesting:
""" """
# Every change to this headers list must evaluate further usages of the resulting tuple # Every change to this headers list must evaluate further usages of the resulting tuple
# and eventually change the constants for indexes at the top # and eventually change the constants for indexes at the top
headers = ['date', 'buy', 'open', 'close', 'sell', 'low', 'high', 'buy_tag'] headers = ['date', 'buy', 'open', 'close', 'sell', 'low', 'high', 'buy_tag', 'exit_tag']
data: Dict = {} data: Dict = {}
self.progress.init_step(BacktestState.CONVERT, len(processed)) self.progress.init_step(BacktestState.CONVERT, len(processed))
@@ -230,6 +261,7 @@ class Backtesting:
pair_data.loc[:, 'buy'] = 0 # cleanup if buy_signal is exist pair_data.loc[:, 'buy'] = 0 # cleanup if buy_signal is exist
pair_data.loc[:, 'sell'] = 0 # cleanup if sell_signal is exist pair_data.loc[:, 'sell'] = 0 # cleanup if sell_signal is exist
pair_data.loc[:, 'buy_tag'] = None # cleanup if buy_tag is exist pair_data.loc[:, 'buy_tag'] = None # cleanup if buy_tag is exist
pair_data.loc[:, 'exit_tag'] = None # cleanup if exit_tag is exist
df_analyzed = self.strategy.advise_sell( df_analyzed = self.strategy.advise_sell(
self.strategy.advise_buy(pair_data, {'pair': pair}), {'pair': pair}).copy() self.strategy.advise_buy(pair_data, {'pair': pair}), {'pair': pair}).copy()
@@ -241,6 +273,7 @@ class Backtesting:
df_analyzed.loc[:, 'buy'] = df_analyzed.loc[:, 'buy'].shift(1) df_analyzed.loc[:, 'buy'] = df_analyzed.loc[:, 'buy'].shift(1)
df_analyzed.loc[:, 'sell'] = df_analyzed.loc[:, 'sell'].shift(1) df_analyzed.loc[:, 'sell'] = df_analyzed.loc[:, 'sell'].shift(1)
df_analyzed.loc[:, 'buy_tag'] = df_analyzed.loc[:, 'buy_tag'].shift(1) df_analyzed.loc[:, 'buy_tag'] = df_analyzed.loc[:, 'buy_tag'].shift(1)
df_analyzed.loc[:, 'exit_tag'] = df_analyzed.loc[:, 'exit_tag'].shift(1)
# Update dataprovider cache # Update dataprovider cache
self.dataprovider._set_cached_df(pair, self.timeframe, df_analyzed) self.dataprovider._set_cached_df(pair, self.timeframe, df_analyzed)
@@ -283,7 +316,9 @@ class Backtesting:
# Worst case: price ticks tiny bit above open and dives down. # Worst case: price ticks tiny bit above open and dives down.
stop_rate = sell_row[OPEN_IDX] * (1 - abs(trade.stop_loss_pct)) stop_rate = sell_row[OPEN_IDX] * (1 - abs(trade.stop_loss_pct))
assert stop_rate < sell_row[HIGH_IDX] assert stop_rate < sell_row[HIGH_IDX]
return stop_rate # Limit lower-end to candle low to avoid sells below the low.
# This still remains "worst case" - but "worst realistic case".
return max(sell_row[LOW_IDX], stop_rate)
# Set close_rate to stoploss # Set close_rate to stoploss
return trade.stop_loss return trade.stop_loss
@@ -307,10 +342,7 @@ class Backtesting:
# use Open rate if open_rate > calculated sell rate # use Open rate if open_rate > calculated sell rate
return sell_row[OPEN_IDX] return sell_row[OPEN_IDX]
# Use the maximum between close_rate and low as we return close_rate
# cannot sell outside of a candle.
# Applies when a new ROI setting comes in place and the whole candle is above that.
return min(max(close_rate, sell_row[LOW_IDX]), sell_row[HIGH_IDX])
else: else:
# This should not be reached... # This should not be reached...
@@ -318,7 +350,8 @@ class Backtesting:
else: else:
return sell_row[OPEN_IDX] return sell_row[OPEN_IDX]
def _get_sell_trade_entry(self, trade: LocalTrade, sell_row: Tuple) -> Optional[LocalTrade]: def _get_sell_trade_entry_for_candle(self, trade: LocalTrade,
sell_row: Tuple) -> Optional[LocalTrade]:
sell_candle_time = sell_row[DATE_IDX].to_pydatetime() sell_candle_time = sell_row[DATE_IDX].to_pydatetime()
sell = self.strategy.should_sell(trade, sell_row[OPEN_IDX], # type: ignore sell = self.strategy.should_sell(trade, sell_row[OPEN_IDX], # type: ignore
sell_candle_time, sell_row[BUY_IDX], sell_candle_time, sell_row[BUY_IDX],
@@ -327,9 +360,20 @@ class Backtesting:
if sell.sell_flag: if sell.sell_flag:
trade.close_date = sell_candle_time trade.close_date = sell_candle_time
trade.sell_reason = sell.sell_reason
trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60) trade_dur = int((trade.close_date_utc - trade.open_date_utc).total_seconds() // 60)
closerate = self._get_close_rate(sell_row, trade, sell, trade_dur) closerate = self._get_close_rate(sell_row, trade, sell, trade_dur)
# call the custom exit price,with default value as previous closerate
current_profit = trade.calc_profit_ratio(closerate)
if sell.sell_type in (SellType.SELL_SIGNAL, SellType.CUSTOM_SELL):
# Custom exit pricing only for sell-signals
closerate = strategy_safe_wrapper(self.strategy.custom_exit_price,
default_retval=closerate)(
pair=trade.pair, trade=trade,
current_time=sell_row[DATE_IDX],
proposed_rate=closerate, current_profit=current_profit)
# Use the maximum between close_rate and low as we cannot sell outside of a candle.
closerate = min(max(closerate, sell_row[LOW_IDX]), sell_row[HIGH_IDX])
# Confirm trade exit: # Confirm trade exit:
time_in_force = self.strategy.order_time_in_force['sell'] time_in_force = self.strategy.order_time_in_force['sell']
@@ -341,25 +385,70 @@ class Backtesting:
current_time=sell_candle_time): current_time=sell_candle_time):
return None return None
trade.sell_reason = sell.sell_reason
# Checks and adds an exit tag, after checking that the length of the
# sell_row has the length for an exit tag column
if(
len(sell_row) > EXIT_TAG_IDX
and sell_row[EXIT_TAG_IDX] is not None
and len(sell_row[EXIT_TAG_IDX]) > 0
):
trade.sell_reason = sell_row[EXIT_TAG_IDX]
trade.close(closerate, show_msg=False) trade.close(closerate, show_msg=False)
return trade return trade
return None return None
def _get_sell_trade_entry(self, trade: LocalTrade, sell_row: Tuple) -> Optional[LocalTrade]:
if self.timeframe_detail and trade.pair in self.detail_data:
sell_candle_time = sell_row[DATE_IDX].to_pydatetime()
sell_candle_end = sell_candle_time + timedelta(minutes=self.timeframe_min)
detail_data = self.detail_data[trade.pair]
detail_data = detail_data.loc[
(detail_data['date'] >= sell_candle_time) &
(detail_data['date'] < sell_candle_end)
].copy()
if len(detail_data) == 0:
# Fall back to "regular" data if no detail data was found for this candle
return self._get_sell_trade_entry_for_candle(trade, sell_row)
detail_data.loc[:, 'buy'] = sell_row[BUY_IDX]
detail_data.loc[:, 'sell'] = sell_row[SELL_IDX]
headers = ['date', 'buy', 'open', 'close', 'sell', 'low', 'high']
for det_row in detail_data[headers].values.tolist():
res = self._get_sell_trade_entry_for_candle(trade, det_row)
if res:
return res
return None
else:
return self._get_sell_trade_entry_for_candle(trade, sell_row)
def _enter_trade(self, pair: str, row: List) -> Optional[LocalTrade]: def _enter_trade(self, pair: str, row: List) -> Optional[LocalTrade]:
try: try:
stake_amount = self.wallets.get_trade_stake_amount(pair, None) stake_amount = self.wallets.get_trade_stake_amount(pair, None)
except DependencyException: except DependencyException:
return None return None
# let's call the custom entry price, using the open price as default price
propose_rate = strategy_safe_wrapper(self.strategy.custom_entry_price,
default_retval=row[OPEN_IDX])(
pair=pair, current_time=row[DATE_IDX].to_pydatetime(),
proposed_rate=row[OPEN_IDX]) # default value is the open rate
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, row[OPEN_IDX], -0.05) or 0 # Move rate to within the candle's low/high rate
propose_rate = min(max(propose_rate, row[LOW_IDX]), row[HIGH_IDX])
min_stake_amount = self.exchange.get_min_pair_stake_amount(pair, propose_rate, -0.05) or 0
max_stake_amount = self.wallets.get_available_stake_amount() max_stake_amount = self.wallets.get_available_stake_amount()
stake_amount = strategy_safe_wrapper(self.strategy.custom_stake_amount, stake_amount = strategy_safe_wrapper(self.strategy.custom_stake_amount,
default_retval=stake_amount)( default_retval=stake_amount)(
pair=pair, current_time=row[DATE_IDX].to_pydatetime(), current_rate=row[OPEN_IDX], pair=pair, current_time=row[DATE_IDX].to_pydatetime(), current_rate=propose_rate,
proposed_stake=stake_amount, min_stake=min_stake_amount, max_stake=max_stake_amount) proposed_stake=stake_amount, min_stake=min_stake_amount, max_stake=max_stake_amount)
stake_amount = self.wallets._validate_stake_amount(pair, stake_amount, min_stake_amount) stake_amount = self.wallets.validate_stake_amount(pair, stake_amount, min_stake_amount)
if not stake_amount: if not stake_amount:
return None return None
@@ -368,7 +457,7 @@ class Backtesting:
time_in_force = self.strategy.order_time_in_force['sell'] time_in_force = self.strategy.order_time_in_force['sell']
# Confirm trade entry: # Confirm trade entry:
if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)( if not strategy_safe_wrapper(self.strategy.confirm_trade_entry, default_retval=True)(
pair=pair, order_type=order_type, amount=stake_amount, rate=row[OPEN_IDX], pair=pair, order_type=order_type, amount=stake_amount, rate=propose_rate,
time_in_force=time_in_force, current_time=row[DATE_IDX].to_pydatetime()): time_in_force=time_in_force, current_time=row[DATE_IDX].to_pydatetime()):
return None return None
@@ -377,10 +466,10 @@ class Backtesting:
has_buy_tag = len(row) >= BUY_TAG_IDX + 1 has_buy_tag = len(row) >= BUY_TAG_IDX + 1
trade = LocalTrade( trade = LocalTrade(
pair=pair, pair=pair,
open_rate=row[OPEN_IDX], open_rate=propose_rate,
open_date=row[DATE_IDX].to_pydatetime(), open_date=row[DATE_IDX].to_pydatetime(),
stake_amount=stake_amount, stake_amount=stake_amount,
amount=round(stake_amount / row[OPEN_IDX], 8), amount=round(stake_amount / propose_rate, 8),
fee_open=self.fee, fee_open=self.fee,
fee_close=self.fee, fee_close=self.fee,
is_open=True, is_open=True,
@@ -592,6 +681,7 @@ class Backtesting:
data: Dict[str, Any] = {} data: Dict[str, Any] = {}
data, timerange = self.load_bt_data() data, timerange = self.load_bt_data()
self.load_bt_data_detail()
logger.info("Dataload complete. Calculating indicators") logger.info("Dataload complete. Calculating indicators")
for strat in self.strategylist: for strat in self.strategylist:

View File

@@ -7,7 +7,8 @@ import logging
from typing import Any, Dict from typing import Any, Dict
from freqtrade import constants from freqtrade import constants
from freqtrade.configuration import TimeRange, remove_credentials, validate_config_consistency from freqtrade.configuration import TimeRange, validate_config_consistency
from freqtrade.data.dataprovider import DataProvider
from freqtrade.edge import Edge from freqtrade.edge import Edge
from freqtrade.optimize.optimize_reports import generate_edge_table from freqtrade.optimize.optimize_reports import generate_edge_table
from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.resolvers import ExchangeResolver, StrategyResolver
@@ -28,11 +29,12 @@ class EdgeCli:
def __init__(self, config: Dict[str, Any]) -> None: def __init__(self, config: Dict[str, Any]) -> None:
self.config = config self.config = config
# Reset keys for edge # Ensure using dry-run
remove_credentials(self.config) self.config['dry_run'] = True
self.config['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT self.config['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT
self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config) self.exchange = ExchangeResolver.load_exchange(self.config['exchange']['name'], self.config)
self.strategy = StrategyResolver.load_strategy(self.config) self.strategy = StrategyResolver.load_strategy(self.config)
self.strategy.dp = DataProvider(config, None)
validate_config_consistency(self.config) validate_config_consistency(self.config)

View File

@@ -22,6 +22,7 @@ from pandas import DataFrame
from freqtrade.constants import DATETIME_PRINT_FORMAT, FTHYPT_FILEVERSION, LAST_BT_RESULT_FN from freqtrade.constants import DATETIME_PRINT_FORMAT, FTHYPT_FILEVERSION, LAST_BT_RESULT_FN
from freqtrade.data.converter import trim_dataframes from freqtrade.data.converter import trim_dataframes
from freqtrade.data.history import get_timerange from freqtrade.data.history import get_timerange
from freqtrade.exceptions import OperationalException
from freqtrade.misc import deep_merge_dicts, file_dump_json, plural from freqtrade.misc import deep_merge_dicts, file_dump_json, plural
from freqtrade.optimize.backtesting import Backtesting from freqtrade.optimize.backtesting import Backtesting
# Import IHyperOpt and IHyperOptLoss to allow unpickling classes from these modules # Import IHyperOpt and IHyperOptLoss to allow unpickling classes from these modules
@@ -30,7 +31,7 @@ from freqtrade.optimize.hyperopt_interface import IHyperOpt # noqa: F401
from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss # noqa: F401 from freqtrade.optimize.hyperopt_loss_interface import IHyperOptLoss # noqa: F401
from freqtrade.optimize.hyperopt_tools import HyperoptTools, hyperopt_serializer from freqtrade.optimize.hyperopt_tools import HyperoptTools, hyperopt_serializer
from freqtrade.optimize.optimize_reports import generate_strategy_stats from freqtrade.optimize.optimize_reports import generate_strategy_stats
from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver, HyperOptResolver from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver
# Suppress scikit-learn FutureWarnings from skopt # Suppress scikit-learn FutureWarnings from skopt
@@ -78,10 +79,10 @@ class Hyperopt:
if not self.config.get('hyperopt'): if not self.config.get('hyperopt'):
self.custom_hyperopt = HyperOptAuto(self.config) self.custom_hyperopt = HyperOptAuto(self.config)
self.auto_hyperopt = True
else: else:
self.custom_hyperopt = HyperOptResolver.load_hyperopt(self.config) raise OperationalException(
self.auto_hyperopt = False "Using separate Hyperopt files has been removed in 2021.9. Please convert "
"your existing Hyperopt file to the new Hyperoptable strategy interface")
self.backtesting._set_strategy(self.backtesting.strategylist[0]) self.backtesting._set_strategy(self.backtesting.strategylist[0])
self.custom_hyperopt.strategy = self.backtesting.strategy self.custom_hyperopt.strategy = self.backtesting.strategy
@@ -103,31 +104,6 @@ class Hyperopt:
self.num_epochs_saved = 0 self.num_epochs_saved = 0
self.current_best_epoch: Optional[Dict[str, Any]] = None self.current_best_epoch: Optional[Dict[str, Any]] = None
if not self.auto_hyperopt:
# Populate "fallback" functions here
# (hasattr is slow so should not be run during "regular" operations)
if hasattr(self.custom_hyperopt, 'populate_indicators'):
logger.warning(
"DEPRECATED: Using `populate_indicators()` in the hyperopt file is deprecated. "
"Please move these methods to your strategy."
)
self.backtesting.strategy.populate_indicators = ( # type: ignore
self.custom_hyperopt.populate_indicators) # type: ignore
if hasattr(self.custom_hyperopt, 'populate_buy_trend'):
logger.warning(
"DEPRECATED: Using `populate_buy_trend()` in the hyperopt file is deprecated. "
"Please move these methods to your strategy."
)
self.backtesting.strategy.populate_buy_trend = ( # type: ignore
self.custom_hyperopt.populate_buy_trend) # type: ignore
if hasattr(self.custom_hyperopt, 'populate_sell_trend'):
logger.warning(
"DEPRECATED: Using `populate_sell_trend()` in the hyperopt file is deprecated. "
"Please move these methods to your strategy."
)
self.backtesting.strategy.populate_sell_trend = ( # type: ignore
self.custom_hyperopt.populate_sell_trend) # type: ignore
# Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set # Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set
if self.config.get('use_max_market_positions', True): if self.config.get('use_max_market_positions', True):
self.max_open_trades = self.config['max_open_trades'] self.max_open_trades = self.config['max_open_trades']
@@ -256,7 +232,7 @@ class Hyperopt:
""" """
Assign the dimensions in the hyperoptimization space. Assign the dimensions in the hyperoptimization space.
""" """
if self.auto_hyperopt and HyperoptTools.has_space(self.config, 'protection'): if HyperoptTools.has_space(self.config, 'protection'):
# Protections can only be optimized when using the Parameter interface # Protections can only be optimized when using the Parameter interface
logger.debug("Hyperopt has 'protection' space") logger.debug("Hyperopt has 'protection' space")
# Enable Protections if protection space is selected. # Enable Protections if protection space is selected.
@@ -265,7 +241,7 @@ class Hyperopt:
if HyperoptTools.has_space(self.config, 'buy'): if HyperoptTools.has_space(self.config, 'buy'):
logger.debug("Hyperopt has 'buy' space") logger.debug("Hyperopt has 'buy' space")
self.buy_space = self.custom_hyperopt.indicator_space() self.buy_space = self.custom_hyperopt.buy_indicator_space()
if HyperoptTools.has_space(self.config, 'sell'): if HyperoptTools.has_space(self.config, 'sell'):
logger.debug("Hyperopt has 'sell' space") logger.debug("Hyperopt has 'sell' space")
@@ -282,9 +258,19 @@ class Hyperopt:
if HyperoptTools.has_space(self.config, 'trailing'): if HyperoptTools.has_space(self.config, 'trailing'):
logger.debug("Hyperopt has 'trailing' space") logger.debug("Hyperopt has 'trailing' space")
self.trailing_space = self.custom_hyperopt.trailing_space() self.trailing_space = self.custom_hyperopt.trailing_space()
self.dimensions = (self.buy_space + self.sell_space + self.protection_space self.dimensions = (self.buy_space + self.sell_space + self.protection_space
+ self.roi_space + self.stoploss_space + self.trailing_space) + self.roi_space + self.stoploss_space + self.trailing_space)
def assign_params(self, params_dict: Dict, category: str) -> None:
"""
Assign hyperoptable parameters
"""
for attr_name, attr in self.backtesting.strategy.enumerate_parameters(category):
if attr.optimize:
# noinspection PyProtectedMember
attr.value = params_dict[attr_name]
def generate_optimizer(self, raw_params: List[Any], iteration=None) -> Dict: def generate_optimizer(self, raw_params: List[Any], iteration=None) -> Dict:
""" """
Used Optimize function. Used Optimize function.
@@ -296,18 +282,13 @@ class Hyperopt:
# Apply parameters # Apply parameters
if HyperoptTools.has_space(self.config, 'buy'): if HyperoptTools.has_space(self.config, 'buy'):
self.backtesting.strategy.advise_buy = ( # type: ignore self.assign_params(params_dict, 'buy')
self.custom_hyperopt.buy_strategy_generator(params_dict))
if HyperoptTools.has_space(self.config, 'sell'): if HyperoptTools.has_space(self.config, 'sell'):
self.backtesting.strategy.advise_sell = ( # type: ignore self.assign_params(params_dict, 'sell')
self.custom_hyperopt.sell_strategy_generator(params_dict))
if HyperoptTools.has_space(self.config, 'protection'): if HyperoptTools.has_space(self.config, 'protection'):
for attr_name, attr in self.backtesting.strategy.enumerate_parameters('protection'): self.assign_params(params_dict, 'protection')
if attr.optimize:
# noinspection PyProtectedMember
attr.value = params_dict[attr_name]
if HyperoptTools.has_space(self.config, 'roi'): if HyperoptTools.has_space(self.config, 'roi'):
self.backtesting.strategy.minimal_roi = ( # type: ignore self.backtesting.strategy.minimal_roi = ( # type: ignore
@@ -385,10 +366,20 @@ class Hyperopt:
} }
def get_optimizer(self, dimensions: List[Dimension], cpu_count) -> Optimizer: def get_optimizer(self, dimensions: List[Dimension], cpu_count) -> Optimizer:
estimator = self.custom_hyperopt.generate_estimator()
acq_optimizer = "sampling"
if isinstance(estimator, str):
if estimator not in ("GP", "RF", "ET", "GBRT"):
raise OperationalException(f"Estimator {estimator} not supported.")
else:
acq_optimizer = "auto"
logger.info(f"Using estimator {estimator}.")
return Optimizer( return Optimizer(
dimensions, dimensions,
base_estimator="ET", base_estimator=estimator,
acq_optimizer="auto", acq_optimizer=acq_optimizer,
n_initial_points=INITIAL_POINTS, n_initial_points=INITIAL_POINTS,
acq_optimizer_kwargs={'n_jobs': cpu_count}, acq_optimizer_kwargs={'n_jobs': cpu_count},
random_state=self.random_state, random_state=self.random_state,
@@ -517,7 +508,6 @@ class Hyperopt:
f"saved to '{self.results_file}'.") f"saved to '{self.results_file}'.")
if self.current_best_epoch: if self.current_best_epoch:
if self.auto_hyperopt:
HyperoptTools.try_export_params( HyperoptTools.try_export_params(
self.config, self.config,
self.backtesting.strategy.get_strategy_name(), self.backtesting.strategy.get_strategy_name(),

View File

@@ -3,16 +3,32 @@ HyperOptAuto class.
This module implements a convenience auto-hyperopt class, which can be used together with strategies This module implements a convenience auto-hyperopt class, which can be used together with strategies
that implement IHyperStrategy interface. that implement IHyperStrategy interface.
""" """
import logging
from contextlib import suppress from contextlib import suppress
from typing import Any, Callable, Dict, List from typing import Callable, Dict, List
from pandas import DataFrame from freqtrade.exceptions import OperationalException
with suppress(ImportError): with suppress(ImportError):
from skopt.space import Dimension from skopt.space import Dimension
from freqtrade.optimize.hyperopt_interface import IHyperOpt from freqtrade.optimize.hyperopt_interface import EstimatorType, IHyperOpt
logger = logging.getLogger(__name__)
def _format_exception_message(space: str, ignore_missing_space: bool) -> None:
msg = (f"The '{space}' space is included into the hyperoptimization "
f"but no parameter for this space was not found in your Strategy. "
)
if ignore_missing_space:
logger.warning(msg + "This space will be ignored.")
else:
raise OperationalException(
msg + f"Please make sure to have parameters for this space enabled for optimization "
f"or remove the '{space}' space from hyperoptimization.")
class HyperOptAuto(IHyperOpt): class HyperOptAuto(IHyperOpt):
@@ -22,26 +38,6 @@ class HyperOptAuto(IHyperOpt):
sell_indicator_space methods, but other hyperopt methods can be overridden as well. sell_indicator_space methods, but other hyperopt methods can be overridden as well.
""" """
def buy_strategy_generator(self, params: Dict[str, Any]) -> Callable:
def populate_buy_trend(dataframe: DataFrame, metadata: dict):
for attr_name, attr in self.strategy.enumerate_parameters('buy'):
if attr.optimize:
# noinspection PyProtectedMember
attr.value = params[attr_name]
return self.strategy.populate_buy_trend(dataframe, metadata)
return populate_buy_trend
def sell_strategy_generator(self, params: Dict[str, Any]) -> Callable:
def populate_sell_trend(dataframe: DataFrame, metadata: dict):
for attr_name, attr in self.strategy.enumerate_parameters('sell'):
if attr.optimize:
# noinspection PyProtectedMember
attr.value = params[attr_name]
return self.strategy.populate_sell_trend(dataframe, metadata)
return populate_sell_trend
def _get_func(self, name) -> Callable: def _get_func(self, name) -> Callable:
""" """
Return a function defined in Strategy.HyperOpt class, or one defined in super() class. Return a function defined in Strategy.HyperOpt class, or one defined in super() class.
@@ -60,21 +56,25 @@ class HyperOptAuto(IHyperOpt):
if attr.optimize: if attr.optimize:
yield attr.get_space(attr_name) yield attr.get_space(attr_name)
def _get_indicator_space(self, category, fallback_method_name): def _get_indicator_space(self, category) -> List:
# TODO: is this necessary, or can we call "generate_space" directly?
indicator_space = list(self._generate_indicator_space(category)) indicator_space = list(self._generate_indicator_space(category))
if len(indicator_space) > 0: if len(indicator_space) > 0:
return indicator_space return indicator_space
else: else:
return self._get_func(fallback_method_name)() _format_exception_message(
category,
self.config.get("hyperopt_ignore_missing_space", False))
return []
def indicator_space(self) -> List['Dimension']: def buy_indicator_space(self) -> List['Dimension']:
return self._get_indicator_space('buy', 'indicator_space') return self._get_indicator_space('buy')
def sell_indicator_space(self) -> List['Dimension']: def sell_indicator_space(self) -> List['Dimension']:
return self._get_indicator_space('sell', 'sell_indicator_space') return self._get_indicator_space('sell')
def protection_space(self) -> List['Dimension']: def protection_space(self) -> List['Dimension']:
return self._get_indicator_space('protection', 'protection_space') return self._get_indicator_space('protection')
def generate_roi_table(self, params: Dict) -> Dict[int, float]: def generate_roi_table(self, params: Dict) -> Dict[int, float]:
return self._get_func('generate_roi_table')(params) return self._get_func('generate_roi_table')(params)
@@ -90,3 +90,6 @@ class HyperOptAuto(IHyperOpt):
def trailing_space(self) -> List['Dimension']: def trailing_space(self) -> List['Dimension']:
return self._get_func('trailing_space')() return self._get_func('trailing_space')()
def generate_estimator(self) -> EstimatorType:
return self._get_func('generate_estimator')()

View File

@@ -5,11 +5,11 @@ This module defines the interface to apply for hyperopt
import logging import logging
import math import math
from abc import ABC from abc import ABC
from typing import Any, Callable, Dict, List from typing import Dict, List, Union
from sklearn.base import RegressorMixin
from skopt.space import Categorical, Dimension, Integer from skopt.space import Categorical, Dimension, Integer
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import timeframe_to_minutes from freqtrade.exchange import timeframe_to_minutes
from freqtrade.misc import round_dict from freqtrade.misc import round_dict
from freqtrade.optimize.space import SKDecimal from freqtrade.optimize.space import SKDecimal
@@ -18,12 +18,7 @@ from freqtrade.strategy import IStrategy
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
EstimatorType = Union[RegressorMixin, str]
def _format_exception_message(method: str, space: str) -> str:
return (f"The '{space}' space is included into the hyperoptimization "
f"but {method}() method is not found in your "
f"custom Hyperopt class. You should either implement this "
f"method or remove the '{space}' space from hyperoptimization.")
class IHyperOpt(ABC): class IHyperOpt(ABC):
@@ -45,36 +40,13 @@ class IHyperOpt(ABC):
IHyperOpt.ticker_interval = str(config['timeframe']) # DEPRECATED IHyperOpt.ticker_interval = str(config['timeframe']) # DEPRECATED
IHyperOpt.timeframe = str(config['timeframe']) IHyperOpt.timeframe = str(config['timeframe'])
def buy_strategy_generator(self, params: Dict[str, Any]) -> Callable: def generate_estimator(self) -> EstimatorType:
""" """
Create a buy strategy generator. Return base_estimator.
Can be any of "GP", "RF", "ET", "GBRT" or an instance of a class
inheriting from RegressorMixin (from sklearn).
""" """
raise OperationalException(_format_exception_message('buy_strategy_generator', 'buy')) return 'ET'
def sell_strategy_generator(self, params: Dict[str, Any]) -> Callable:
"""
Create a sell strategy generator.
"""
raise OperationalException(_format_exception_message('sell_strategy_generator', 'sell'))
def protection_space(self) -> List[Dimension]:
"""
Create a protection space.
Only supported by the Parameter interface.
"""
raise OperationalException(_format_exception_message('indicator_space', 'protection'))
def indicator_space(self) -> List[Dimension]:
"""
Create an indicator space.
"""
raise OperationalException(_format_exception_message('indicator_space', 'buy'))
def sell_indicator_space(self) -> List[Dimension]:
"""
Create a sell indicator space.
"""
raise OperationalException(_format_exception_message('sell_indicator_space', 'sell'))
def generate_roi_table(self, params: Dict) -> Dict[int, float]: def generate_roi_table(self, params: Dict) -> Dict[int, float]:
""" """

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