From bf257469658d1917e8fe55ec7b28917e20863849 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sat, 16 May 2020 11:09:50 +0300 Subject: [PATCH 01/22] Introduce datatype for informative pairs --- freqtrade/data/dataprovider.py | 8 +++++--- freqtrade/exchange/exchange.py | 3 ++- freqtrade/strategy/interface.py | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index 7ada4f642..58cd5442b 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -9,11 +9,13 @@ from typing import Any, Dict, List, Optional, Tuple from pandas import DataFrame +from freqtrade.data.common import ListPairsWithTimeframes from freqtrade.data.history import load_pair_history from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exchange import Exchange from freqtrade.state import RunMode + logger = logging.getLogger(__name__) @@ -25,8 +27,8 @@ class DataProvider: self._pairlists = pairlists def refresh(self, - pairlist: List[Tuple[str, str]], - helping_pairs: List[Tuple[str, str]] = None) -> None: + pairlist: ListPairsWithTimeframes, + helping_pairs: ListPairsWithTimeframes = None) -> None: """ Refresh data, called with each cycle """ @@ -36,7 +38,7 @@ class DataProvider: self._exchange.refresh_latest_ohlcv(pairlist) @property - def available_pairs(self) -> List[Tuple[str, str]]: + def available_pairs(self) -> ListPairsWithTimeframes: """ Return a list of tuples containing (pair, timeframe) for which data is currently cached. Should be whitelist + open trades. diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 6ad7ad582..43ed65787 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -18,6 +18,7 @@ from ccxt.base.decimal_to_precision import (ROUND_DOWN, ROUND_UP, TICK_SIZE, TRUNCATE, decimal_to_precision) from pandas import DataFrame +from freqtrade.data.common import ListPairsWithTimeframes from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list from freqtrade.exceptions import (DependencyException, InvalidOrderException, OperationalException, TemporaryError) @@ -676,7 +677,7 @@ class Exchange: logger.info("Downloaded data for %s with length %s.", pair, len(data)) return data - def refresh_latest_ohlcv(self, pair_list: List[Tuple[str, str]]) -> List[Tuple[str, List]]: + def refresh_latest_ohlcv(self, pair_list: ListPairsWithTimeframes) -> List[Tuple[str, List]]: """ Refresh in-memory OHLCV asynchronously and set `_klines` with the result Loops asynchronously over pair_list and downloads all pairs async (semi-parallel). diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 6268b8a43..68666efab 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -12,6 +12,7 @@ from typing import Dict, List, NamedTuple, Optional, Tuple import arrow from pandas import DataFrame +from freqtrade.data.common import ListPairsWithTimeframes from freqtrade.data.dataprovider import DataProvider from freqtrade.exceptions import StrategyError from freqtrade.exchange import timeframe_to_minutes @@ -185,7 +186,7 @@ class IStrategy(ABC): """ return False - def informative_pairs(self) -> List[Tuple[str, str]]: + def informative_pairs(self) -> ListPairsWithTimeframes: """ Define additional, informative pair/interval combinations to be cached from the exchange. These pair/interval combinations are non-tradeable, unless they are part From 035a12ce6171289c26127b6f679df6e8de1f5836 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sat, 16 May 2020 11:25:32 +0300 Subject: [PATCH 02/22] Move _create_pair_whitelist to dataprovider --- freqtrade/data/dataprovider.py | 11 +++++++++-- freqtrade/freqtradebot.py | 8 +------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index 58cd5442b..ad7b7ada3 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -25,6 +25,7 @@ class DataProvider: self._config = config self._exchange = exchange self._pairlists = pairlists + self._timeframe = self._config['ticker_interval'] def refresh(self, pairlist: ListPairsWithTimeframes, @@ -45,6 +46,12 @@ class DataProvider: """ return list(self._exchange._klines.keys()) + def create_pair_list(self, pairs: List[str], timeframe: str = None) -> ListPairsWithTimeframes: + """ + Create list of pair tuples with (pair, ticker_interval) + """ + return [(pair, timeframe or self._timeframe) for pair in pairs] + def ohlcv(self, pair: str, timeframe: str = None, copy: bool = True) -> DataFrame: """ Get candle (OHLCV) data for the given pair as DataFrame @@ -55,7 +62,7 @@ class DataProvider: Use False only for read-only operations (where the dataframe is not modified) """ if self.runmode in (RunMode.DRY_RUN, RunMode.LIVE): - return self._exchange.klines((pair, timeframe or self._config['ticker_interval']), + return self._exchange.klines((pair, timeframe or self._timeframe), copy=copy) else: return DataFrame() @@ -67,7 +74,7 @@ class DataProvider: :param timeframe: timeframe to get data for """ return load_pair_history(pair=pair, - timeframe=timeframe or self._config['ticker_interval'], + timeframe=timeframe or self._timeframe, datadir=self._config['datadir'] ) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3893a3ee0..f365a30fd 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -145,7 +145,7 @@ class FreqtradeBot: self.active_pair_whitelist = self._refresh_whitelist(trades) # Refreshing candles - self.dataprovider.refresh(self._create_pair_whitelist(self.active_pair_whitelist), + self.dataprovider.refresh(self.dataprovider.create_pair_list(self.active_pair_whitelist), self.strategy.informative_pairs()) with self._sell_lock: @@ -184,12 +184,6 @@ class FreqtradeBot: _whitelist.extend([trade.pair for trade in trades if trade.pair not in _whitelist]) return _whitelist - def _create_pair_whitelist(self, pairs: List[str]) -> List[Tuple[str, str]]: - """ - Create pair-whitelist tuple with (pair, ticker_interval) - """ - return [(pair, self.config['ticker_interval']) for pair in pairs] - def get_free_open_trades(self): """ Return the number of free open trades slots or 0 if From f8b01f5a43981e71534f2e4ce70717da9374a3ed Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sat, 16 May 2020 11:28:36 +0300 Subject: [PATCH 03/22] Make flake happy --- freqtrade/data/dataprovider.py | 2 +- freqtrade/freqtradebot.py | 2 +- freqtrade/strategy/interface.py | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index ad7b7ada3..95348e56e 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -5,7 +5,7 @@ including ticker and orderbook data, live and historical candle (OHLCV) data Common Interface for bot and strategy to access data. """ import logging -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional from pandas import DataFrame diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index f365a30fd..151a319e2 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -7,7 +7,7 @@ import traceback from datetime import datetime from math import isclose from threading import Lock -from typing import Any, Dict, List, Optional, Tuple +from typing import Any, Dict, List, Optional import arrow from cachetools import TTLCache diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 68666efab..5173265bc 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -7,7 +7,7 @@ import warnings from abc import ABC, abstractmethod from datetime import datetime, timezone from enum import Enum -from typing import Dict, List, NamedTuple, Optional, Tuple +from typing import Dict, NamedTuple, Optional, Tuple import arrow from pandas import DataFrame @@ -20,6 +20,7 @@ from freqtrade.persistence import Trade from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.wallets import Wallets + logger = logging.getLogger(__name__) From facaaabc1eaec70639919087b8dcd5a55c882599 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sat, 16 May 2020 11:49:24 +0300 Subject: [PATCH 04/22] Rename _refresh_whitelist() --- freqtrade/freqtradebot.py | 9 +++++---- tests/conftest.py | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 151a319e2..6b99e95b6 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -84,7 +84,7 @@ class FreqtradeBot: self.edge = Edge(self.config, self.exchange, self.strategy) if \ self.config.get('edge', {}).get('enabled', False) else None - self.active_pair_whitelist = self._refresh_whitelist() + self.active_pair_whitelist = self._refresh_active_whitelist() # Set initial bot state from config initial_state = self.config.get('initial_state') @@ -142,7 +142,7 @@ class FreqtradeBot: # Query trades from persistence layer trades = Trade.get_open_trades() - self.active_pair_whitelist = self._refresh_whitelist(trades) + self.active_pair_whitelist = self._refresh_active_whitelist(trades) # Refreshing candles self.dataprovider.refresh(self.dataprovider.create_pair_list(self.active_pair_whitelist), @@ -165,9 +165,10 @@ class FreqtradeBot: Trade.session.flush() - def _refresh_whitelist(self, trades: List[Trade] = []) -> List[str]: + def _refresh_active_whitelist(self, trades: List[Trade] = []) -> List[str]: """ - Refresh whitelist from pairlist or edge and extend it with trades. + Refresh active whitelist from pairlist or edge and extend it with + pairs that have open trades. """ # Refresh whitelist self.pairlists.refresh_pairlist() diff --git a/tests/conftest.py b/tests/conftest.py index 40ab436cf..623447e9c 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -92,7 +92,7 @@ def patch_wallet(mocker, free=999.9) -> None: def patch_whitelist(mocker, conf) -> None: - mocker.patch('freqtrade.freqtradebot.FreqtradeBot._refresh_whitelist', + mocker.patch('freqtrade.freqtradebot.FreqtradeBot._refresh_active_whitelist', MagicMock(return_value=conf['exchange']['pair_whitelist'])) From e7c11ed2cfe16574e455e0706da04a8982cda8bd Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sat, 16 May 2020 11:59:47 +0300 Subject: [PATCH 05/22] Fix fetching timeframe (failed in backtesting) --- freqtrade/data/dataprovider.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index 95348e56e..602a92358 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -25,7 +25,6 @@ class DataProvider: self._config = config self._exchange = exchange self._pairlists = pairlists - self._timeframe = self._config['ticker_interval'] def refresh(self, pairlist: ListPairsWithTimeframes, @@ -50,7 +49,7 @@ class DataProvider: """ Create list of pair tuples with (pair, ticker_interval) """ - return [(pair, timeframe or self._timeframe) for pair in pairs] + return [(pair, timeframe or self._config['ticker_interval']) for pair in pairs] def ohlcv(self, pair: str, timeframe: str = None, copy: bool = True) -> DataFrame: """ @@ -62,7 +61,7 @@ class DataProvider: Use False only for read-only operations (where the dataframe is not modified) """ if self.runmode in (RunMode.DRY_RUN, RunMode.LIVE): - return self._exchange.klines((pair, timeframe or self._timeframe), + return self._exchange.klines((pair, timeframe or self._config['ticker_interval']), copy=copy) else: return DataFrame() @@ -74,7 +73,7 @@ class DataProvider: :param timeframe: timeframe to get data for """ return load_pair_history(pair=pair, - timeframe=timeframe or self._timeframe, + timeframe=timeframe or self._config['ticker_interval'], datadir=self._config['datadir'] ) From 5f2a871637b62a0a327750118b4d28e86169c428 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sat, 16 May 2020 17:15:58 +0300 Subject: [PATCH 06/22] Add missing module --- freqtrade/data/common.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 freqtrade/data/common.py diff --git a/freqtrade/data/common.py b/freqtrade/data/common.py new file mode 100644 index 000000000..7a61d51ea --- /dev/null +++ b/freqtrade/data/common.py @@ -0,0 +1,7 @@ +""" +Common datatypes +""" +from typing import List, Tuple + +# List of pairs with their timeframes +ListPairsWithTimeframes = List[Tuple[str, str]] From 503a8a82431fc3b6d1c799eadabcb9f9c461f280 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 18 May 2020 07:02:57 +0200 Subject: [PATCH 07/22] Simplify sd_notify usage --- freqtrade/worker.py | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/freqtrade/worker.py b/freqtrade/worker.py index 55cf30d16..3f5ab734e 100755 --- a/freqtrade/worker.py +++ b/freqtrade/worker.py @@ -37,9 +37,7 @@ class Worker: self._heartbeat_msg: float = 0 # Tell systemd that we completed initialization phase - if self._sd_notify: - logger.debug("sd_notify: READY=1") - self._sd_notify.notify("READY=1") + self._notify("READY=1") def _init(self, reconfig: bool) -> None: """ @@ -60,6 +58,15 @@ class Worker: self._sd_notify = sdnotify.SystemdNotifier() if \ self._config.get('internals', {}).get('sd_notify', False) else None + def _notify(self, message: str) -> None: + """ + Removes the need to verify in all occurances if sd_notify is enabled + :param message: Message to send to systemd if it's enabled. + """ + if self._sd_notify: + logger.debug(f"sd_notify: {message}") + self._sd_notify.notify(message) + def run(self) -> None: state = None while True: @@ -89,17 +96,13 @@ class Worker: if state == State.STOPPED: # Ping systemd watchdog before sleeping in the stopped state - if self._sd_notify: - logger.debug("sd_notify: WATCHDOG=1\\nSTATUS=State: STOPPED.") - self._sd_notify.notify("WATCHDOG=1\nSTATUS=State: STOPPED.") + self._notify("WATCHDOG=1\nSTATUS=State: STOPPED.") self._throttle(func=self._process_stopped, throttle_secs=self._throttle_secs) elif state == State.RUNNING: # Ping systemd watchdog before throttling - if self._sd_notify: - logger.debug("sd_notify: WATCHDOG=1\\nSTATUS=State: RUNNING.") - self._sd_notify.notify("WATCHDOG=1\nSTATUS=State: RUNNING.") + self._notify("WATCHDOG=1\nSTATUS=State: RUNNING.") self._throttle(func=self._process_running, throttle_secs=self._throttle_secs) @@ -154,9 +157,7 @@ class Worker: replaces it with the new instance """ # Tell systemd that we initiated reconfiguration - if self._sd_notify: - logger.debug("sd_notify: RELOADING=1") - self._sd_notify.notify("RELOADING=1") + self._notify("RELOADING=1") # Clean up current freqtrade modules self.freqtrade.cleanup() @@ -167,15 +168,11 @@ class Worker: self.freqtrade.notify_status('config reloaded') # Tell systemd that we completed reconfiguration - if self._sd_notify: - logger.debug("sd_notify: READY=1") - self._sd_notify.notify("READY=1") + self._notify("READY=1") def exit(self) -> None: # Tell systemd that we are exiting now - if self._sd_notify: - logger.debug("sd_notify: STOPPING=1") - self._sd_notify.notify("STOPPING=1") + self._notify("STOPPING=1") if self.freqtrade: self.freqtrade.notify_status('process died') From 37fd675aace911736b5acf97757879fd1c936773 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 18 May 2020 09:00:23 +0000 Subject: [PATCH 08/22] Bump flake8 from 3.7.9 to 3.8.1 Bumps [flake8](https://gitlab.com/pycqa/flake8) from 3.7.9 to 3.8.1. - [Release notes](https://gitlab.com/pycqa/flake8/tags) - [Commits](https://gitlab.com/pycqa/flake8/compare/3.7.9...3.8.1) Signed-off-by: dependabot-preview[bot] --- requirements-dev.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index 616ca20f9..a37ac42ae 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,7 +4,7 @@ -r requirements-hyperopt.txt coveralls==2.0.0 -flake8==3.7.9 +flake8==3.8.1 flake8-type-annotations==0.1.0 flake8-tidy-imports==4.1.0 mypy==0.770 From a447efbe57d3a1b60c5d7c2ec3ca3d282ce85b1e Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 18 May 2020 09:00:45 +0000 Subject: [PATCH 09/22] Bump mkdocs-material from 5.1.6 to 5.1.7 Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 5.1.6 to 5.1.7. - [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/5.1.6...5.1.7) Signed-off-by: dependabot-preview[bot] --- docs/requirements-docs.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index c121dec64..485cd50cf 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,2 +1,2 @@ -mkdocs-material==5.1.6 +mkdocs-material==5.1.7 mdx_truly_sane_lists==1.2 From 37a10d1d30073b8f6631d30e9af9e2d744c64a37 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 18 May 2020 09:01:37 +0000 Subject: [PATCH 10/22] Bump joblib from 0.14.1 to 0.15.1 Bumps [joblib](https://github.com/joblib/joblib) from 0.14.1 to 0.15.1. - [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/0.14.1...0.15.1) Signed-off-by: dependabot-preview[bot] --- requirements-hyperopt.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index 9afd07357..c3dda6c4b 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -6,5 +6,5 @@ scipy==1.4.1 scikit-learn==0.22.2.post1 scikit-optimize==0.7.4 filelock==3.0.12 -joblib==0.14.1 +joblib==0.15.1 progressbar2==3.51.3 From 7d80f8d25c95108121baea03f717f5a765eb0629 Mon Sep 17 00:00:00 2001 From: hroff-1902 <47309513+hroff-1902@users.noreply.github.com> Date: Mon, 18 May 2020 12:02:16 +0300 Subject: [PATCH 11/22] Fix links in docs --- docs/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 7405fc92e..e6e4cb422 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -81,14 +81,14 @@ 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.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `exchange.secret` | API secret to use for the exchange. Only required when you are in production mode.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `exchange.password` | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String -| `exchange.pair_whitelist` | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Not used by VolumePairList (see [below](#dynamic-pairlists)).
**Datatype:** List -| `exchange.pair_blacklist` | List of pairs the bot must absolutely avoid for trading and backtesting (see [below](#dynamic-pairlists)).
**Datatype:** List +| `exchange.pair_whitelist` | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Not used by VolumePairList (see [below](#pairlists)).
**Datatype:** List +| `exchange.pair_blacklist` | List of pairs the bot must absolutely avoid for trading and backtesting (see [below](#pairlists)).
**Datatype:** List | `exchange.ccxt_config` | Additional CCXT parameters passed to the regular ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.ccxt_async_config` | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.markets_refresh_interval` | The interval in minutes in which markets are reloaded.
*Defaults to `60` minutes.*
**Datatype:** Positive Integer | `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.
*Defaults to `true`.*
**Datatype:** Boolean -| `pairlists` | Define one or more pairlists to be used. [More information below](#dynamic-pairlists).
*Defaults to `StaticPairList`.*
**Datatype:** List of Dicts +| `pairlists` | Define one or more pairlists to be used. [More information below](#pairlists).
*Defaults to `StaticPairList`.*
**Datatype:** List of Dicts | `telegram.enabled` | Enable the usage of Telegram.
**Datatype:** Boolean | `telegram.token` | Your Telegram bot token. Only required if `telegram.enabled` is `true`.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `telegram.chat_id` | Your personal Telegram account id. Only required if `telegram.enabled` is `true`.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String From ff8e85f2f5b451197fccf5ad7783d76dcd2c6871 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 18 May 2020 09:02:29 +0000 Subject: [PATCH 12/22] Bump sqlalchemy from 1.3.16 to 1.3.17 Bumps [sqlalchemy](https://github.com/sqlalchemy/sqlalchemy) from 1.3.16 to 1.3.17. - [Release notes](https://github.com/sqlalchemy/sqlalchemy/releases) - [Changelog](https://github.com/sqlalchemy/sqlalchemy/blob/master/CHANGES) - [Commits](https://github.com/sqlalchemy/sqlalchemy/commits) Signed-off-by: dependabot-preview[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 017974c9e..654fa0853 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,7 +1,7 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs ccxt==1.27.49 -SQLAlchemy==1.3.16 +SQLAlchemy==1.3.17 python-telegram-bot==12.7 arrow==0.15.6 cachetools==4.1.0 From 601cbd1231dbd124541b732396cf10bd406a5e57 Mon Sep 17 00:00:00 2001 From: "dependabot-preview[bot]" <27856297+dependabot-preview[bot]@users.noreply.github.com> Date: Mon, 18 May 2020 09:23:03 +0000 Subject: [PATCH 13/22] Bump ccxt from 1.27.49 to 1.27.91 Bumps [ccxt](https://github.com/ccxt/ccxt) from 1.27.49 to 1.27.91. - [Release notes](https://github.com/ccxt/ccxt/releases) - [Changelog](https://github.com/ccxt/ccxt/blob/master/doc/exchanges-by-country.rst) - [Commits](https://github.com/ccxt/ccxt/compare/1.27.49...1.27.91) Signed-off-by: dependabot-preview[bot] --- requirements-common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-common.txt b/requirements-common.txt index 654fa0853..a2038d95e 100644 --- a/requirements-common.txt +++ b/requirements-common.txt @@ -1,6 +1,6 @@ # requirements without requirements installable via conda # mainly used for Raspberry pi installs -ccxt==1.27.49 +ccxt==1.27.91 SQLAlchemy==1.3.17 python-telegram-bot==12.7 arrow==0.15.6 From d57ef6a2a662c3f9c0d2e875f4ebab1302cd7db7 Mon Sep 17 00:00:00 2001 From: hroff-1902 <47309513+hroff-1902@users.noreply.github.com> Date: Mon, 18 May 2020 12:39:52 +0300 Subject: [PATCH 14/22] Pairlist Section reworked --- docs/configuration.md | 56 +++++++++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index e6e4cb422..7d99660b8 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -549,18 +549,19 @@ A fixed slot (mirroring `bid_strategy.order_book_top`) can be defined by setting When not using orderbook (`ask_strategy.use_order_book=False`), the price at the `ask_strategy.price_side` side (defaults to `"ask"`) from the ticker will be used as the sell price. -## Pairlists +## Pairlists and Pairlist Handlers -Pairlists define the list of pairs that the bot should trade. -There are [`StaticPairList`](#static-pair-list) and dynamic Whitelists available. +Pairlist Handlers define the list of pairs (pairlist) that the bot should trade. They are configured in the `pairlists` section of the configuration settings. -[`PrecisionFilter`](#precision-filter) and [`PriceFilter`](#price-pair-filter) act as filters, removing low-value pairs. +In your configuration, you can use Static Pairlist (defined by the [`StaticPairList`](#static-pair-list) Pairlist Handler) and Dynamic Pairlist (defined by the [`VolumePairList`](#volume-pair-list) Pairlist Handler). -All pairlists can be chained, and a combination of all pairlists will become your new whitelist. Pairlists are executed in the sequence they are configured. You should always configure either `StaticPairList` or `DynamicPairList` as starting pairlists. +Additionaly, [`PrecisionFilter`](#precision-filter), [`PriceFilter`](#price-pair-filter) and [`SpreadFilter`](#spread-pair-filter) act as Pairlist Filters, removing low-value pairs. -Inactive markets and blacklisted pairs are always removed from the resulting `pair_whitelist`. +If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading / backtesting / downloading historical data. Pairlist Handlers are executed in the sequence they are configured. You should always configure either `StaticPairList` or `VolumePairList` as the starting Pairlist Handler. -### Available Pairlists +Inactive markets and blacklisted pairs are always removed from the resulting pairlist. Blacklisted pairs (those in the `pair_blacklist` configuration setting) are also always removed from the resulting pairlist. + +### Available Pairlist Handlers * [`StaticPairList`](#static-pair-list) (default, if not configured differently) * [`VolumePairList`](#volume-pair-list) @@ -569,7 +570,7 @@ Inactive markets and blacklisted pairs are always removed from the resulting `pa * [`SpreadFilter`](#spread-filter) !!! Tip "Testing pairlists" - Pairlist configurations can be quite tricky to get right. Best use the [`test-pairlist`](utils.md#test-pairlist) subcommand to test your configuration quickly. + Pairlist configurations can be quite tricky to get right. Best use the [`test-pairlist`](utils.md#test-pairlist) utility subcommand to test your configuration quickly. #### Static Pair List @@ -585,13 +586,18 @@ It uses configuration from `exchange.pair_whitelist` and `exchange.pair_blacklis #### Volume Pair List -`VolumePairList` selects `number_assets` top pairs based on `sort_key`, which can only be `quoteVolume`. +`VolumePairList` employs sorting/filtering of pairs by their trading volume. I selects `number_assets` top pairs with sorting based on the `sort_key` (which can only be `quoteVolume`). -`VolumePairList` considers outputs of previous pairlists unless it's the first configured pairlist, it does not consider `pair_whitelist`, but selects the top assets from all available markets (with matching stake-currency) on the exchange. +!!! Deprecation + Other values for `sort_key` are now deprecated and this setting will be removed in the future versions. -`refresh_period` allows setting the period (in seconds), at which the pairlist will be refreshed. Defaults to 1800s (30 minutes). +When used in the chain of Pairlist Handlers in a non-leading position (after StaticPairList and other Pairlist Filters), `VolumePairList` considers outputs of previous Pairlist Handlers, adding its sorting/selection of the pairs by the trading volume. -`VolumePairList` is based on the ticker data, as reported by the ccxt library: +When used on the leading position of the chain of Pairlist Handlers, it does not consider `pair_whitelist` configuration setting, but selects the top assets from all available markets (with matching stake-currency) on the exchange. + +The `refresh_period` setting allows to define the period (in seconds), at which the pairlist will be refreshed. Defaults to 1800s (30 minutes). + +`VolumePairList` is based on the ticker data from exchange, as reported by the ccxt library: * The `quoteVolume` is the amount of quote (stake) currency traded (bought or sold) in last 24 hours. @@ -604,30 +610,34 @@ It uses configuration from `exchange.pair_whitelist` and `exchange.pair_blacklis ], ``` -#### Precision Filter +#### PrecisionFilter -Filters low-value coins which would not allow setting a stoploss. +Filters low-value coins which would not allow setting stoplosses. -#### Price Pair Filter +#### PriceFilter The `PriceFilter` allows filtering of pairs by price. -Currently, only `low_price_ratio` is implemented, where a raise of 1 price unit (pip) is below the `low_price_ratio` ratio. + +Currently, only `low_price_ratio` setting is implemented, where a raise of 1 price unit (pip) is below the `low_price_ratio` ratio. This option is disabled by default, and will only apply if set to <> 0. -Calculation example: -Min price precision is 8 decimals. If price is 0.00000011 - one step would be 0.00000012 - which is almost 10% higher than the previous value. +Calculation example: -These pairs are dangerous since it may be impossible to place the desired stoploss - and often result in high losses. +Min price precision is 8 decimals. If price is 0.00000011 - one step would be 0.00000012 - which is almost 10% higher than the previous value. -#### Spread Filter +These pairs are dangerous since it may be impossible to place the desired stoploss - and often result in high losses. Here is what the PriceFilters takes over. + +#### SpreadFilter Removes pairs that have a difference between asks and bids above the specified ratio (default `0.005`). + Example: -If `DOGE/BTC` maximum bid is 0.00000026 and minimum ask is 0.00000027 the ratio is calculated as: `1 - bid/ask ~= 0.037` which is `> 0.005` -### Full Pairlist example +If `DOGE/BTC` maximum bid is 0.00000026 and minimum ask is 0.00000027 the ratio is calculated as: `1 - bid/ask ~= 0.037` which is `> 0.005` -The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets, sorting by `quoteVolume` and applies both [`PrecisionFilter`](#precision-filter) and [`PriceFilter`](#price-pair-filter), filtering all assets where 1 priceunit is > 1%. +### Full example of Pairlist Handlers + +The below example blacklists `BNB/BTC`, uses `VolumePairList` with `20` assets, sorting pairs by `quoteVolume` and applies both [`PrecisionFilter`](#precision-filter) and [`PriceFilter`](#price-pair-filter), filtering all assets where 1 priceunit is > 1%. ```json "exchange": { From 5a9a31351abd7e0a2cc2226eaa7904e389ad70be Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 18 May 2020 11:40:25 +0200 Subject: [PATCH 15/22] Adjust empty f-strings to be non-fstrings --- freqtrade/commands/build_config_commands.py | 2 +- freqtrade/commands/cli_options.py | 4 ++-- freqtrade/commands/deploy_commands.py | 2 +- freqtrade/exchange/exchange.py | 3 +-- freqtrade/pairlist/VolumePairList.py | 2 +- freqtrade/rpc/rpc.py | 2 +- freqtrade/rpc/telegram.py | 4 ++-- freqtrade/rpc/webhook.py | 6 +++--- tests/conftest.py | 18 +++++++++-------- tests/exchange/test_exchange.py | 6 +++--- tests/optimize/test_backtesting.py | 2 +- tests/optimize/test_hyperopt.py | 2 +- tests/rpc/test_rpc.py | 6 +++--- tests/test_configuration.py | 2 +- tests/test_freqtradebot.py | 22 +++++++++------------ 15 files changed, 40 insertions(+), 43 deletions(-) diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 58ac6ec27..87098f53c 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -163,7 +163,7 @@ def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None: ) except TemplateNotFound: selections['exchange'] = render_template( - templatefile=f"subtemplates/exchange_generic.j2", + templatefile="subtemplates/exchange_generic.j2", arguments=selections ) diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index a8f2ffdba..ee9208c33 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -372,8 +372,8 @@ AVAILABLE_CLI_OPTIONS = { ), "timeframes": Arg( '-t', '--timeframes', - help=f'Specify which tickers to download. Space-separated list. ' - f'Default: `1m 5m`.', + help='Specify which tickers to download. Space-separated list. ' + 'Default: `1m 5m`.', choices=['1m', '3m', '5m', '15m', '30m', '1h', '2h', '4h', '6h', '8h', '12h', '1d', '3d', '1w'], default=['1m', '5m'], diff --git a/freqtrade/commands/deploy_commands.py b/freqtrade/commands/deploy_commands.py index a29ba346f..86562fa7c 100644 --- a/freqtrade/commands/deploy_commands.py +++ b/freqtrade/commands/deploy_commands.py @@ -51,7 +51,7 @@ def deploy_new_strategy(strategy_name: str, strategy_path: Path, subtemplate: st ) additional_methods = render_template_with_fallback( templatefile=f"subtemplates/strategy_methods_{subtemplate}.j2", - templatefallbackfile=f"subtemplates/strategy_methods_empty.j2", + templatefallbackfile="subtemplates/strategy_methods_empty.j2", ) strategy_text = render_template(templatefile='base_strategy.py.j2', diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 6ad7ad582..68022662a 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -366,8 +366,7 @@ class Exchange: f"Invalid timeframe '{timeframe}'. This exchange supports: {self.timeframes}") if timeframe and timeframe_to_minutes(timeframe) < 1: - raise OperationalException( - f"Timeframes < 1m are currently not supported by Freqtrade.") + raise OperationalException("Timeframes < 1m are currently not supported by Freqtrade.") def validate_ordertypes(self, order_types: Dict) -> None: """ diff --git a/freqtrade/pairlist/VolumePairList.py b/freqtrade/pairlist/VolumePairList.py index e20fb3577..981e9915e 100644 --- a/freqtrade/pairlist/VolumePairList.py +++ b/freqtrade/pairlist/VolumePairList.py @@ -25,7 +25,7 @@ class VolumePairList(IPairList): if 'number_assets' not in self._pairlistconfig: raise OperationalException( - f'`number_assets` not specified. Please check your configuration ' + '`number_assets` not specified. Please check your configuration ' 'for "pairlist.config.number_assets"') self._stake_currency = config['stake_currency'] diff --git a/freqtrade/rpc/rpc.py b/freqtrade/rpc/rpc.py index 3f6d0729d..21f54de50 100644 --- a/freqtrade/rpc/rpc.py +++ b/freqtrade/rpc/rpc.py @@ -545,5 +545,5 @@ class RPC: def _rpc_edge(self) -> List[Dict[str, Any]]: """ Returns information related to Edge """ if not self._freqtrade.edge: - raise RPCException(f'Edge is not enabled.') + raise RPCException('Edge is not enabled.') return self._freqtrade.edge.accepted_pairs() diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 1d7ebb21a..dfda15a26 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -234,7 +234,7 @@ class Telegram(RPC): lines.append("*Open Order:* `{open_order}`") # Filter empty lines using list-comprehension - messages.append("\n".join([l for l in lines if l]).format(**r)) + messages.append("\n".join([line for line in lines if line]).format(**r)) for msg in messages: self._send_msg(msg) @@ -289,7 +289,7 @@ class Telegram(RPC): 'Day', f'Profit {stake_cur}', f'Profit {fiat_disp_cur}', - f'Trades', + 'Trades', ], tablefmt='simple') message = f'Daily Profit over the last {timescale} days:\n
{stats_tab}
' diff --git a/freqtrade/rpc/webhook.py b/freqtrade/rpc/webhook.py index 1309663d4..322d990ee 100644 --- a/freqtrade/rpc/webhook.py +++ b/freqtrade/rpc/webhook.py @@ -47,9 +47,9 @@ class Webhook(RPC): valuedict = self._config['webhook'].get('webhooksell', None) elif msg['type'] == RPCMessageType.SELL_CANCEL_NOTIFICATION: valuedict = self._config['webhook'].get('webhooksellcancel', None) - elif msg['type'] in(RPCMessageType.STATUS_NOTIFICATION, - RPCMessageType.CUSTOM_NOTIFICATION, - RPCMessageType.WARNING_NOTIFICATION): + elif msg['type'] in (RPCMessageType.STATUS_NOTIFICATION, + RPCMessageType.CUSTOM_NOTIFICATION, + RPCMessageType.WARNING_NOTIFICATION): valuedict = self._config['webhook'].get('webhookstatus', None) else: raise NotImplementedError('Unknown message type: {}'.format(msg['type'])) diff --git a/tests/conftest.py b/tests/conftest.py index 36c60e27e..d15cba1de 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1705,7 +1705,7 @@ def hyperopt_results(): { 'loss': 0.4366182531161519, 'params_dict': { - 'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1190, 'roi_t2': 541, 'roi_t3': 408, 'roi_p1': 0.026035863879169705, 'roi_p2': 0.12508730043628782, 'roi_p3': 0.27766427921605896, 'stoploss': -0.2562930402099556}, # noqa: E501 + 'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1190, 'roi_t2': 541, 'roi_t3': 408, 'roi_p1': 0.026035863879169705, 'roi_p2': 0.12508730043628782, 'roi_p3': 0.27766427921605896, 'stoploss': -0.2562930402099556}, # noqa: E501 'params_details': {'buy': {'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper'}, 'roi': {0: 0.4287874435315165, 408: 0.15112316431545753, 949: 0.026035863879169705, 2139: 0}, 'stoploss': {'stoploss': -0.2562930402099556}}, # noqa: E501 'results_metrics': {'trade_count': 2, 'avg_profit': -1.254995, 'total_profit': -0.00125625, 'profit': -2.50999, 'duration': 3930.0}, # noqa: E501 'results_explanation': ' 2 trades. Avg profit -1.25%. Total profit -0.00125625 BTC ( -2.51Σ%). Avg duration 3930.0 min.', # noqa: E501 @@ -1716,11 +1716,12 @@ def hyperopt_results(): }, { 'loss': 20.0, 'params_dict': { - 'mfi-value': 17, 'fastd-value': 38, 'adx-value': 48, 'rsi-value': 22, 'mfi-enabled': True, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 96, 'sell-fastd-value': 68, 'sell-adx-value': 63, 'sell-rsi-value': 81, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal', 'roi_t1': 334, 'roi_t2': 683, 'roi_t3': 140, 'roi_p1': 0.06403981740598495, 'roi_p2': 0.055519840060645045, 'roi_p3': 0.3253712811342459, 'stoploss': -0.338070047333259}, # noqa: E501 - 'params_details': {'buy': {'mfi-value': 17, 'fastd-value': 38, 'adx-value': 48, 'rsi-value': 22, 'mfi-enabled': True, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal'}, # noqa: E501 - 'sell': {'sell-mfi-value': 96, 'sell-fastd-value': 68, 'sell-adx-value': 63, 'sell-rsi-value': 81, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal'}, # noqa: E501 - 'roi': {0: 0.4449309386008759, 140: 0.11955965746663, 823: 0.06403981740598495, 1157: 0}, # noqa: E501 - 'stoploss': {'stoploss': -0.338070047333259}}, + 'mfi-value': 17, 'fastd-value': 38, 'adx-value': 48, 'rsi-value': 22, 'mfi-enabled': True, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 96, 'sell-fastd-value': 68, 'sell-adx-value': 63, 'sell-rsi-value': 81, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal', 'roi_t1': 334, 'roi_t2': 683, 'roi_t3': 140, 'roi_p1': 0.06403981740598495, 'roi_p2': 0.055519840060645045, 'roi_p3': 0.3253712811342459, 'stoploss': -0.338070047333259}, # noqa: E501 + 'params_details': { + 'buy': {'mfi-value': 17, 'fastd-value': 38, 'adx-value': 48, 'rsi-value': 22, 'mfi-enabled': True, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal'}, # noqa: E501 + 'sell': {'sell-mfi-value': 96, 'sell-fastd-value': 68, 'sell-adx-value': 63, 'sell-rsi-value': 81, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal'}, # noqa: E501 + 'roi': {0: 0.4449309386008759, 140: 0.11955965746663, 823: 0.06403981740598495, 1157: 0}, # noqa: E501 + 'stoploss': {'stoploss': -0.338070047333259}}, 'results_metrics': {'trade_count': 1, 'avg_profit': 0.12357, 'total_profit': 6.185e-05, 'profit': 0.12357, 'duration': 1200.0}, # noqa: E501 'results_explanation': ' 1 trades. Avg profit 0.12%. Total profit 0.00006185 BTC ( 0.12Σ%). Avg duration 1200.0 min.', # noqa: E501 'total_profit': 6.185e-05, @@ -1767,8 +1768,9 @@ def hyperopt_results(): }, { 'loss': 4.713497421432944, 'params_dict': {'mfi-value': 13, 'fastd-value': 41, 'adx-value': 21, 'rsi-value': 29, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower', 'sell-mfi-value': 99, 'sell-fastd-value': 60, 'sell-adx-value': 81, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 771, 'roi_t2': 620, 'roi_t3': 145, 'roi_p1': 0.0586919200378493, 'roi_p2': 0.04984118697312542, 'roi_p3': 0.37521058680247044, 'stoploss': -0.14613268022709905}, # noqa: E501 - 'params_details': {'buy': {'mfi-value': 13, 'fastd-value': 41, 'adx-value': 21, 'rsi-value': 29, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower'}, 'sell': {'sell-mfi-value': 99, 'sell-fastd-value': 60, 'sell-adx-value': 81, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.4837436938134452, 145: 0.10853310701097472, 765: 0.0586919200378493, 1536: 0}, # noqa: E501 - 'stoploss': {'stoploss': -0.14613268022709905}}, # noqa: E501 + 'params_details': { + 'buy': {'mfi-value': 13, 'fastd-value': 41, 'adx-value': 21, 'rsi-value': 29, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower'}, 'sell': {'sell-mfi-value': 99, 'sell-fastd-value': 60, 'sell-adx-value': 81, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.4837436938134452, 145: 0.10853310701097472, 765: 0.0586919200378493, 1536: 0}, # noqa: E501 + 'stoploss': {'stoploss': -0.14613268022709905}}, # noqa: E501 'results_metrics': {'trade_count': 318, 'avg_profit': -0.39833954716981146, 'total_profit': -0.06339929, 'profit': -126.67197600000004, 'duration': 3140.377358490566}, # noqa: E501 'results_explanation': ' 318 trades. Avg profit -0.40%. Total profit -0.06339929 BTC (-126.67Σ%). Avg duration 3140.4 min.', # noqa: E501 'total_profit': -0.06339929, diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index aa42950e2..7b1e9ddaa 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -517,9 +517,9 @@ def test_validate_pairs_restricted(default_conf, mocker, caplog): mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency') Exchange(default_conf) - assert log_has(f"Pair XRP/BTC is restricted for some users on this exchange." - f"Please check if you are impacted by this restriction " - f"on the exchange and eventually remove XRP/BTC from your whitelist.", caplog) + assert log_has("Pair XRP/BTC is restricted for some users on this exchange." + "Please check if you are impacted by this restriction " + "on the exchange and eventually remove XRP/BTC from your whitelist.", caplog) def test_validate_pairs_stakecompatibility(default_conf, mocker, caplog): diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index 093cbf966..019914720 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -555,7 +555,7 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir) """ Buy every xth candle - sell every other xth -2 (hold on to pairs a bit) """ - if metadata['pair'] in('ETH/BTC', 'LTC/BTC'): + if metadata['pair'] in ('ETH/BTC', 'LTC/BTC'): multi = 20 else: multi = 18 diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index cc8b9aa37..90e047954 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -820,7 +820,7 @@ def test_continue_hyperopt(mocker, default_conf, caplog): Hyperopt(default_conf) assert unlinkmock.call_count == 0 - assert log_has(f"Continuing on previous hyperopt results.", caplog) + assert log_has("Continuing on previous hyperopt results.", caplog) def test_print_json_spaces_all(mocker, default_conf, caplog, capsys) -> None: diff --git a/tests/rpc/test_rpc.py b/tests/rpc/test_rpc.py index 1c3a43e4b..63691dfb4 100644 --- a/tests/rpc/test_rpc.py +++ b/tests/rpc/test_rpc.py @@ -83,7 +83,7 @@ def test_rpc_trade_status(default_conf, ticker, fee, mocker) -> None: } == results[0] mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate', - MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available"))) + MagicMock(side_effect=DependencyException("Pair 'ETH/BTC' not available"))) results = rpc._rpc_trade_status() assert isnan(results[0]['current_profit']) assert isnan(results[0]['current_rate']) @@ -167,7 +167,7 @@ def test_rpc_status_table(default_conf, ticker, fee, mocker) -> None: assert '-0.41% (-0.06)' == result[0][3] mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate', - MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available"))) + MagicMock(side_effect=DependencyException("Pair 'ETH/BTC' not available"))) result, headers = rpc._rpc_status_table(default_conf['stake_currency'], 'USD') assert 'instantly' == result[0][2] assert 'ETH/BTC' in result[0][1] @@ -319,7 +319,7 @@ def test_rpc_trade_statistics(default_conf, ticker, ticker_sell_up, fee, # Test non-available pair mocker.patch('freqtrade.freqtradebot.FreqtradeBot.get_sell_rate', - MagicMock(side_effect=DependencyException(f"Pair 'ETH/BTC' not available"))) + MagicMock(side_effect=DependencyException("Pair 'ETH/BTC' not available"))) stats = rpc._rpc_trade_statistics(stake_currency, fiat_display_currency) assert stats['trade_count'] == 2 assert stats['first_trade_date'] == 'just now' diff --git a/tests/test_configuration.py b/tests/test_configuration.py index c89f1381e..edcbe4516 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -73,7 +73,7 @@ def test_load_config_file_error(default_conf, mocker, caplog) -> None: mocker.patch('freqtrade.configuration.load_config.open', mocker.mock_open(read_data=filedata)) mocker.patch.object(Path, "read_text", MagicMock(return_value=filedata)) - with pytest.raises(OperationalException, match=f".*Please verify the following segment.*"): + with pytest.raises(OperationalException, match=r".*Please verify the following segment.*"): load_config_file('somefile') diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index a1358abdc..9d9d133cc 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3153,10 +3153,8 @@ def test_trailing_stop_loss(default_conf, limit_buy_order, fee, caplog, mocker) caplog.set_level(logging.DEBUG) # Sell as trailing-stop is reached assert freqtrade.handle_trade(trade) is True - assert log_has( - f"ETH/BTC - HIT STOP: current price at 0.000012, " - f"stoploss is 0.000015, " - f"initial stoploss was at 0.000010, trade opened at 0.000011", caplog) + assert log_has("ETH/BTC - HIT STOP: current price at 0.000012, stoploss is 0.000015, " + "initial stoploss was at 0.000010, trade opened at 0.000011", caplog) assert trade.sell_reason == SellType.TRAILING_STOP_LOSS.value @@ -3199,8 +3197,8 @@ def test_trailing_stop_loss_positive(default_conf, limit_buy_order, fee, })) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - assert log_has(f"ETH/BTC - Using positive stoploss: 0.01 offset: 0 profit: 0.2666%", caplog) - assert log_has(f"ETH/BTC - Adjusting stoploss...", caplog) + assert log_has("ETH/BTC - Using positive stoploss: 0.01 offset: 0 profit: 0.2666%", caplog) + assert log_has("ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', @@ -3256,9 +3254,8 @@ def test_trailing_stop_loss_offset(default_conf, limit_buy_order, fee, })) # stop-loss not reached, adjusted stoploss assert freqtrade.handle_trade(trade) is False - assert log_has(f"ETH/BTC - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", - caplog) - assert log_has(f"ETH/BTC - Adjusting stoploss...", caplog) + assert log_has("ETH/BTC - Using positive stoploss: 0.01 offset: 0.011 profit: 0.2666%", caplog) + assert log_has("ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000138501 mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', @@ -3322,7 +3319,7 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, # stop-loss should not be adjusted as offset is not reached yet assert freqtrade.handle_trade(trade) is False - assert not log_has(f"ETH/BTC - Adjusting stoploss...", caplog) + assert not log_has("ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000098910 # price rises above the offset (rises 12% when the offset is 5.5%) @@ -3334,9 +3331,8 @@ def test_tsl_only_offset_reached(default_conf, limit_buy_order, fee, })) assert freqtrade.handle_trade(trade) is False - assert log_has(f"ETH/BTC - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", - caplog) - assert log_has(f"ETH/BTC - Adjusting stoploss...", caplog) + assert log_has("ETH/BTC - Using positive stoploss: 0.05 offset: 0.055 profit: 0.1218%", caplog) + assert log_has("ETH/BTC - Adjusting stoploss...", caplog) assert trade.stop_loss == 0.0000117705 From cc28aae5cb02e61e424db23399d8535d280aebfd Mon Sep 17 00:00:00 2001 From: hroff-1902 <47309513+hroff-1902@users.noreply.github.com> Date: Mon, 18 May 2020 12:44:20 +0300 Subject: [PATCH 16/22] Fix the links again --- docs/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 7d99660b8..d9299d21f 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -81,14 +81,14 @@ 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.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `exchange.secret` | API secret to use for the exchange. Only required when you are in production mode.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `exchange.password` | API password to use for the exchange. Only required when you are in production mode and for exchanges that use password for API requests.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String -| `exchange.pair_whitelist` | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Not used by VolumePairList (see [below](#pairlists)).
**Datatype:** List -| `exchange.pair_blacklist` | List of pairs the bot must absolutely avoid for trading and backtesting (see [below](#pairlists)).
**Datatype:** List +| `exchange.pair_whitelist` | List of pairs to use by the bot for trading and to check for potential trades during backtesting. Not used by VolumePairList (see [below](#pairlists-and-pairlist-handlers)).
**Datatype:** List +| `exchange.pair_blacklist` | List of pairs the bot must absolutely avoid for trading and backtesting (see [below](#pairlists-and-pairlist-handlers)).
**Datatype:** List | `exchange.ccxt_config` | Additional CCXT parameters passed to the regular ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.ccxt_async_config` | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation)
**Datatype:** Dict | `exchange.markets_refresh_interval` | The interval in minutes in which markets are reloaded.
*Defaults to `60` minutes.*
**Datatype:** Positive Integer | `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.
*Defaults to `true`.*
**Datatype:** Boolean -| `pairlists` | Define one or more pairlists to be used. [More information below](#pairlists).
*Defaults to `StaticPairList`.*
**Datatype:** List of Dicts +| `pairlists` | Define one or more pairlists to be used. [More information below](#pairlists-and-pairlist-handlers).
*Defaults to `StaticPairList`.*
**Datatype:** List of Dicts | `telegram.enabled` | Enable the usage of Telegram.
**Datatype:** Boolean | `telegram.token` | Your Telegram bot token. Only required if `telegram.enabled` is `true`.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String | `telegram.chat_id` | Your personal Telegram account id. Only required if `telegram.enabled` is `true`.
**Keep it in secret, do not disclose publicly.**
**Datatype:** String From 627c5059f0066ca7bbe6e2c5e3fc0a2ed7e9c8cd Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 18 May 2020 13:54:21 +0300 Subject: [PATCH 17/22] Move create_pair_list to pairlistmanager --- freqtrade/data/common.py | 7 ------- freqtrade/data/dataprovider.py | 8 +------- freqtrade/exchange/exchange.py | 2 +- freqtrade/freqtradebot.py | 2 +- freqtrade/pairlist/pairlistmanager.py | 13 ++++++++++++- freqtrade/strategy/interface.py | 2 +- 6 files changed, 16 insertions(+), 18 deletions(-) delete mode 100644 freqtrade/data/common.py diff --git a/freqtrade/data/common.py b/freqtrade/data/common.py deleted file mode 100644 index 7a61d51ea..000000000 --- a/freqtrade/data/common.py +++ /dev/null @@ -1,7 +0,0 @@ -""" -Common datatypes -""" -from typing import List, Tuple - -# List of pairs with their timeframes -ListPairsWithTimeframes = List[Tuple[str, str]] diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index 602a92358..5668e2437 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -9,10 +9,10 @@ from typing import Any, Dict, List, Optional from pandas import DataFrame -from freqtrade.data.common import ListPairsWithTimeframes from freqtrade.data.history import load_pair_history from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exchange import Exchange +from freqtrade.pairlist.pairlistmanager import ListPairsWithTimeframes from freqtrade.state import RunMode @@ -45,12 +45,6 @@ class DataProvider: """ return list(self._exchange._klines.keys()) - def create_pair_list(self, pairs: List[str], timeframe: str = None) -> ListPairsWithTimeframes: - """ - Create list of pair tuples with (pair, ticker_interval) - """ - return [(pair, timeframe or self._config['ticker_interval']) for pair in pairs] - def ohlcv(self, pair: str, timeframe: str = None, copy: bool = True) -> DataFrame: """ Get candle (OHLCV) data for the given pair as DataFrame diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 43ed65787..858cdecab 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -18,12 +18,12 @@ from ccxt.base.decimal_to_precision import (ROUND_DOWN, ROUND_UP, TICK_SIZE, TRUNCATE, decimal_to_precision) from pandas import DataFrame -from freqtrade.data.common import ListPairsWithTimeframes from freqtrade.data.converter import ohlcv_to_dataframe, trades_dict_to_list from freqtrade.exceptions import (DependencyException, InvalidOrderException, OperationalException, TemporaryError) from freqtrade.exchange.common import BAD_EXCHANGES, retrier, retrier_async from freqtrade.misc import deep_merge_dicts, safe_value_fallback +from freqtrade.pairlist.pairlistmanager import ListPairsWithTimeframes CcxtModuleType = Any diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 6b99e95b6..6ea5ec970 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -145,7 +145,7 @@ class FreqtradeBot: self.active_pair_whitelist = self._refresh_active_whitelist(trades) # Refreshing candles - self.dataprovider.refresh(self.dataprovider.create_pair_list(self.active_pair_whitelist), + self.dataprovider.refresh(self.pairlists.create_pair_list(self.active_pair_whitelist), self.strategy.informative_pairs()) with self._sell_lock: diff --git a/freqtrade/pairlist/pairlistmanager.py b/freqtrade/pairlist/pairlistmanager.py index 5b4c5b602..163836c4d 100644 --- a/freqtrade/pairlist/pairlistmanager.py +++ b/freqtrade/pairlist/pairlistmanager.py @@ -5,7 +5,7 @@ Provides lists as configured in config.json """ import logging -from typing import Dict, List +from typing import Dict, List, Tuple from cachetools import TTLCache, cached @@ -13,9 +13,14 @@ from freqtrade.exceptions import OperationalException from freqtrade.pairlist.IPairList import IPairList from freqtrade.resolvers import PairListResolver + logger = logging.getLogger(__name__) +# List of pairs with their timeframes +ListPairsWithTimeframes = List[Tuple[str, str]] + + class PairListManager(): def __init__(self, exchange, config: dict) -> None: @@ -94,3 +99,9 @@ class PairListManager(): pairlist = IPairList.verify_blacklist(pairlist, self.blacklist, True) self._whitelist = pairlist + + def create_pair_list(self, pairs: List[str], timeframe: str = None) -> ListPairsWithTimeframes: + """ + Create list of pair tuples with (pair, ticker_interval) + """ + return [(pair, timeframe or self._config['ticker_interval']) for pair in pairs] diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 5173265bc..d5d171bec 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -12,10 +12,10 @@ from typing import Dict, NamedTuple, Optional, Tuple import arrow from pandas import DataFrame -from freqtrade.data.common import ListPairsWithTimeframes from freqtrade.data.dataprovider import DataProvider from freqtrade.exceptions import StrategyError from freqtrade.exchange import timeframe_to_minutes +from freqtrade.pairlist.pairlistmanager import ListPairsWithTimeframes from freqtrade.persistence import Trade from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper from freqtrade.wallets import Wallets From 0c8aff98e093eb539802885e3247d4ed5c0f32fb Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 18 May 2020 15:03:36 +0300 Subject: [PATCH 18/22] Make flake happy --- freqtrade/pairlist/pairlistmanager.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/pairlist/pairlistmanager.py b/freqtrade/pairlist/pairlistmanager.py index 9c8f0de1f..5c3a3aaa7 100644 --- a/freqtrade/pairlist/pairlistmanager.py +++ b/freqtrade/pairlist/pairlistmanager.py @@ -116,4 +116,4 @@ class PairListManager(): """ Create list of pair tuples with (pair, ticker_interval) """ - return [(pair, timeframe or self._config['ticker_interval']) for pair in pairs] \ No newline at end of file + return [(pair, timeframe or self._config['ticker_interval']) for pair in pairs] From 8bdd5e71215963cf0fa2e22d5fb5c7bfabf67a85 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 18 May 2020 15:20:51 +0300 Subject: [PATCH 19/22] Minor: correct import of retrier --- freqtrade/exchange/kraken.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/exchange/kraken.py b/freqtrade/exchange/kraken.py index 243f1a6d6..932d82a27 100644 --- a/freqtrade/exchange/kraken.py +++ b/freqtrade/exchange/kraken.py @@ -7,7 +7,7 @@ import ccxt from freqtrade.exceptions import (DependencyException, InvalidOrderException, OperationalException, TemporaryError) from freqtrade.exchange import Exchange -from freqtrade.exchange.exchange import retrier +from freqtrade.exchange.common import retrier logger = logging.getLogger(__name__) From 6951b20aa030ceee5bcd0d6acd6e5679ce9d4aea Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 18 May 2020 17:31:34 +0300 Subject: [PATCH 20/22] Do not throttle with DependencyException in retrier --- freqtrade/exchange/common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index b38ed35a3..a10d41247 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -1,6 +1,6 @@ import logging -from freqtrade.exceptions import DependencyException, TemporaryError +from freqtrade.exceptions import TemporaryError logger = logging.getLogger(__name__) @@ -93,7 +93,7 @@ def retrier_async(f): count = kwargs.pop('count', API_RETRY_COUNT) try: return await f(*args, **kwargs) - except (TemporaryError, DependencyException) as ex: + except TemporaryError as ex: logger.warning('%s() returned exception: "%s"', f.__name__, ex) if count > 0: count -= 1 @@ -111,7 +111,7 @@ def retrier(f): count = kwargs.pop('count', API_RETRY_COUNT) try: return f(*args, **kwargs) - except (TemporaryError, DependencyException) as ex: + except TemporaryError as ex: logger.warning('%s() returned exception: "%s"', f.__name__, ex) if count > 0: count -= 1 From 115586a50f2cc96580ce0fa989b68995fd9d087d Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Mon, 18 May 2020 21:59:50 +0300 Subject: [PATCH 21/22] Introduce freqtrade.typing --- freqtrade/data/dataprovider.py | 2 +- freqtrade/exchange/exchange.py | 2 +- freqtrade/pairlist/pairlistmanager.py | 7 ++----- freqtrade/strategy/interface.py | 2 +- freqtrade/typing.py | 8 ++++++++ 5 files changed, 13 insertions(+), 8 deletions(-) create mode 100644 freqtrade/typing.py diff --git a/freqtrade/data/dataprovider.py b/freqtrade/data/dataprovider.py index 5668e2437..ef03307cc 100644 --- a/freqtrade/data/dataprovider.py +++ b/freqtrade/data/dataprovider.py @@ -12,8 +12,8 @@ from pandas import DataFrame from freqtrade.data.history import load_pair_history from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exchange import Exchange -from freqtrade.pairlist.pairlistmanager import ListPairsWithTimeframes from freqtrade.state import RunMode +from freqtrade.typing import ListPairsWithTimeframes logger = logging.getLogger(__name__) diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 36d1ddca4..c60eb766a 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -23,7 +23,7 @@ from freqtrade.exceptions import (DependencyException, InvalidOrderException, OperationalException, TemporaryError) from freqtrade.exchange.common import BAD_EXCHANGES, retrier, retrier_async from freqtrade.misc import deep_merge_dicts, safe_value_fallback -from freqtrade.pairlist.pairlistmanager import ListPairsWithTimeframes +from freqtrade.typing import ListPairsWithTimeframes CcxtModuleType = Any diff --git a/freqtrade/pairlist/pairlistmanager.py b/freqtrade/pairlist/pairlistmanager.py index 5c3a3aaa7..78a6a9668 100644 --- a/freqtrade/pairlist/pairlistmanager.py +++ b/freqtrade/pairlist/pairlistmanager.py @@ -3,22 +3,19 @@ PairList manager class """ import logging from copy import deepcopy -from typing import Dict, List, Tuple +from typing import Dict, List from cachetools import TTLCache, cached from freqtrade.exceptions import OperationalException from freqtrade.pairlist.IPairList import IPairList from freqtrade.resolvers import PairListResolver +from freqtrade.typing import ListPairsWithTimeframes logger = logging.getLogger(__name__) -# List of pairs with their timeframes -ListPairsWithTimeframes = List[Tuple[str, str]] - - class PairListManager(): def __init__(self, exchange, config: dict) -> None: diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index d5d171bec..8031c7932 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -15,9 +15,9 @@ from pandas import DataFrame from freqtrade.data.dataprovider import DataProvider from freqtrade.exceptions import StrategyError from freqtrade.exchange import timeframe_to_minutes -from freqtrade.pairlist.pairlistmanager import ListPairsWithTimeframes from freqtrade.persistence import Trade from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper +from freqtrade.typing import ListPairsWithTimeframes from freqtrade.wallets import Wallets diff --git a/freqtrade/typing.py b/freqtrade/typing.py new file mode 100644 index 000000000..3cb7cf816 --- /dev/null +++ b/freqtrade/typing.py @@ -0,0 +1,8 @@ +""" +Common Freqtrade types +""" + +from typing import List, Tuple + +# List of pairs with their timeframes +ListPairsWithTimeframes = List[Tuple[str, str]] From 2c6c287c4b30004b05d9e2842c1f741dbc5e8f97 Mon Sep 17 00:00:00 2001 From: hroff-1902 <47309513+hroff-1902@users.noreply.github.com> Date: Mon, 18 May 2020 22:24:38 +0300 Subject: [PATCH 22/22] Address comments made in review --- docs/configuration.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index d9299d21f..87005ac74 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -555,11 +555,11 @@ Pairlist Handlers define the list of pairs (pairlist) that the bot should trade. In your configuration, you can use Static Pairlist (defined by the [`StaticPairList`](#static-pair-list) Pairlist Handler) and Dynamic Pairlist (defined by the [`VolumePairList`](#volume-pair-list) Pairlist Handler). -Additionaly, [`PrecisionFilter`](#precision-filter), [`PriceFilter`](#price-pair-filter) and [`SpreadFilter`](#spread-pair-filter) act as Pairlist Filters, removing low-value pairs. +Additionaly, [`PrecisionFilter`](#precision-filter), [`PriceFilter`](#price-pair-filter) and [`SpreadFilter`](#spread-pair-filter) act as Pairlist Filters, removing certain pairs. -If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading / backtesting / downloading historical data. Pairlist Handlers are executed in the sequence they are configured. You should always configure either `StaticPairList` or `VolumePairList` as the starting Pairlist Handler. +If multiple Pairlist Handlers are used, they are chained and a combination of all Pairlist Handlers forms the resulting pairlist the bot uses for trading and backtesting. Pairlist Handlers are executed in the sequence they are configured. You should always configure either `StaticPairList` or `VolumePairList` as the starting Pairlist Handler. -Inactive markets and blacklisted pairs are always removed from the resulting pairlist. Blacklisted pairs (those in the `pair_blacklist` configuration setting) are also always removed from the resulting pairlist. +Inactive markets are always removed from the resulting pairlist. Explicitly blacklisted pairs (those in the `pair_blacklist` configuration setting) are also always removed from the resulting pairlist. ### Available Pairlist Handlers @@ -588,9 +588,6 @@ It uses configuration from `exchange.pair_whitelist` and `exchange.pair_blacklis `VolumePairList` employs sorting/filtering of pairs by their trading volume. I selects `number_assets` top pairs with sorting based on the `sort_key` (which can only be `quoteVolume`). -!!! Deprecation - Other values for `sort_key` are now deprecated and this setting will be removed in the future versions. - When used in the chain of Pairlist Handlers in a non-leading position (after StaticPairList and other Pairlist Filters), `VolumePairList` considers outputs of previous Pairlist Handlers, adding its sorting/selection of the pairs by the trading volume. When used on the leading position of the chain of Pairlist Handlers, it does not consider `pair_whitelist` configuration setting, but selects the top assets from all available markets (with matching stake-currency) on the exchange.