diff --git a/build_helpers/install_ta-lib.sh b/build_helpers/install_ta-lib.sh index d12b16364..00c4417ae 100755 --- a/build_helpers/install_ta-lib.sh +++ b/build_helpers/install_ta-lib.sh @@ -11,8 +11,13 @@ 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.sub;hb=HEAD' -o config.sub \ && ./configure --prefix=${INSTALL_LOC}/ \ - && make -j$(nproc) \ - && which sudo && sudo make install || make install + && make + if [ $? -ne 0 ]; then + 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 diff --git a/docs/data-download.md b/docs/data-download.md index 5f605c404..6c7d5312d 100644 --- a/docs/data-download.md +++ b/docs/data-download.md @@ -22,6 +22,7 @@ usage: freqtrade download-data [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [-p PAIRS [PAIRS ...]] [--pairs-file FILE] [--days INT] [--new-pairs-days INT] + [--include-inactive-pairs] [--timerange TIMERANGE] [--dl-trades] [--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} ...]] @@ -38,6 +39,8 @@ optional arguments: --days INT Download data for given number of days. --new-pairs-days INT Download data of new pairs for given number of days. Default: `None`. + --include-inactive-pairs + Also download data from inactive pairs. --timerange TIMERANGE Specify what timerange of data to use. --dl-trades Download trades instead of OHLCV data. The bot will @@ -52,10 +55,10 @@ optional arguments: exchange/pairs/timeframes. --data-format-ohlcv {json,jsongz,hdf5} Storage format for downloaded candle (OHLCV) data. - (default: `None`). + (default: `json`). --data-format-trades {json,jsongz,hdf5} Storage format for downloaded trades data. (default: - `None`). + `jsongz`). Common arguments: -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). +### 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 Freqtrade currently supports 3 data-formats for both OHLCV and trades data: @@ -312,64 +391,6 @@ ETH/BTC 5m, 15m, 30m, 1h, 2h, 4h, 6h, 12h, 1d 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 By default, `download-data` sub-command downloads Candles (OHLCV) data. Some exchanges also provide historic trade-data via their API. diff --git a/docs/developer.md b/docs/developer.md index bd138212b..a6c9ec322 100644 --- a/docs/developer.md +++ b/docs/developer.md @@ -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. -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. diff --git a/docs/hyperopt.md b/docs/hyperopt.md index 45e0d444d..49b4cdda6 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -51,6 +51,7 @@ usage: freqtrade hyperopt [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--print-all] [--no-color] [--print-json] [-j JOBS] [--random-state INT] [--min-trades INT] [--hyperopt-loss NAME] [--disable-param-export] + [--ignore-missing-spaces] optional arguments: -h, --help show this help message and exit @@ -118,6 +119,9 @@ optional arguments: MaxDrawDownHyperOptLoss --disable-param-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: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). diff --git a/docs/includes/pairlists.md b/docs/includes/pairlists.md index b612a4ddf..3d10747d3 100644 --- a/docs/includes/pairlists.md +++ b/docs/includes/pairlists.md @@ -194,17 +194,22 @@ Trade count is used as a tie breaker. 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` 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 without a way to recover. + ```json "pairlists": [ // ... { "method": "PerformanceFilter", - "minutes": 1440 // rolling 24h + "minutes": 1440, // rolling 24h + "min_profit": 0.01 } ], ``` -!!! Note +!!! Warning "Backtesting" `PerformanceFilter` does not support backtesting mode. #### PrecisionFilter diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 9a733d8f7..72d1d0494 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,4 +1,4 @@ -mkdocs==1.2.2 -mkdocs-material==7.3.2 +mkdocs==1.2.3 +mkdocs-material==7.3.4 mdx_truly_sane_lists==1.2 pymdown-extensions==9.0 diff --git a/environment.yml b/environment.yml index f58434c15..84ab5ff6f 100644 --- a/environment.yml +++ b/environment.yml @@ -16,7 +16,6 @@ dependencies: - cachetools - requests - urllib3 - - wrapt - jsonschema - TA-Lib - tabulate @@ -64,7 +63,6 @@ dependencies: - py_find_1st - tables - pytest-random-order - - flake8-type-annotations - ccxt - flake8-tidy-imports - -e . diff --git a/freqtrade/commands/arguments.py b/freqtrade/commands/arguments.py index a02faa736..86d7a1923 100644 --- a/freqtrade/commands/arguments.py +++ b/freqtrade/commands/arguments.py @@ -31,7 +31,8 @@ ARGS_HYPEROPT = ARGS_COMMON_OPTIMIZE + ["hyperopt", "hyperopt_path", "epochs", "spaces", "print_all", "print_colorized", "print_json", "hyperopt_jobs", "hyperopt_random_state", "hyperopt_min_trades", - "hyperopt_loss", "disableparamexport"] + "hyperopt_loss", "disableparamexport", + "hyperopt_ignore_missing_space"] ARGS_EDGE = ARGS_COMMON_OPTIMIZE + ["stoploss_range"] @@ -62,9 +63,9 @@ ARGS_CONVERT_TRADES = ["pairs", "timeframes", "exchange", "dataformat_ohlcv", "d ARGS_LIST_DATA = ["exchange", "dataformat_ohlcv", "pairs"] -ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "new_pairs_days", "timerange", - "download_trades", "exchange", "timeframes", "erase", "dataformat_ohlcv", - "dataformat_trades"] +ARGS_DOWNLOAD_DATA = ["pairs", "pairs_file", "days", "new_pairs_days", "include_inactive", + "timerange", "download_trades", "exchange", "timeframes", + "erase", "dataformat_ohlcv", "dataformat_trades"] ARGS_PLOT_DATAFRAME = ["pairs", "indicators1", "indicators2", "plot_limit", "db_url", "trade_source", "export", "exportfilename", diff --git a/freqtrade/commands/cli_options.py b/freqtrade/commands/cli_options.py index 30a9b0137..b60692c67 100644 --- a/freqtrade/commands/cli_options.py +++ b/freqtrade/commands/cli_options.py @@ -355,6 +355,11 @@ AVAILABLE_CLI_OPTIONS = { type=check_int_positive, 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', help='Download data of new pairs for given number of days. Default: `%(default)s`.', @@ -558,4 +563,10 @@ AVAILABLE_CLI_OPTIONS = { help='Do not print epoch details header.', 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", + ), } diff --git a/freqtrade/commands/data_commands.py b/freqtrade/commands/data_commands.py index ee05e6c69..5dc5fe7ea 100644 --- a/freqtrade/commands/data_commands.py +++ b/freqtrade/commands/data_commands.py @@ -11,6 +11,7 @@ from freqtrade.data.history import (convert_trades_to_ohlcv, refresh_backtest_oh from freqtrade.enums import RunMode from freqtrade.exceptions import OperationalException 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.resolvers import ExchangeResolver @@ -47,11 +48,13 @@ def start_download_data(args: Dict[str, Any]) -> None: # Init exchange 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 if not config['exchange'].get('skip_pair_validation', False): - exchange.validate_pairs(config['pairs']) - expanded_pairs = expand_pairlist(config['pairs'], list(exchange.markets)) - + exchange.validate_pairs(expanded_pairs) logger.info(f"About to download pairs: {expanded_pairs}, " f"intervals: {config['timeframes']} to {config['datadir']}") diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index 94b108f2b..5db3379d2 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -369,6 +369,9 @@ class Configuration: self._args_to_config(config, argname='hyperopt_show_no_header', 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: self._args_to_config(config, argname='pairs', @@ -404,6 +407,9 @@ class Configuration: self._args_to_config(config, argname='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', logstring='Detected --dl-trades: {}') diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index 9549b4054..6397bbacb 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -258,6 +258,7 @@ class Hyperopt: if HyperoptTools.has_space(self.config, 'trailing'): logger.debug("Hyperopt has 'trailing' space") self.trailing_space = self.custom_hyperopt.trailing_space() + self.dimensions = (self.buy_space + self.sell_space + self.protection_space + self.roi_space + self.stoploss_space + self.trailing_space) diff --git a/freqtrade/optimize/hyperopt_auto.py b/freqtrade/optimize/hyperopt_auto.py index c1c769c72..63b4b14e1 100644 --- a/freqtrade/optimize/hyperopt_auto.py +++ b/freqtrade/optimize/hyperopt_auto.py @@ -3,6 +3,7 @@ HyperOptAuto class. This module implements a convenience auto-hyperopt class, which can be used together with strategies that implement IHyperStrategy interface. """ +import logging from contextlib import suppress from typing import Callable, Dict, List @@ -15,12 +16,19 @@ with suppress(ImportError): from freqtrade.optimize.hyperopt_interface import EstimatorType, IHyperOpt -def _format_exception_message(space: str) -> str: - raise OperationalException( - f"The '{space}' space is included into the hyperoptimization " - f"but no parameter for this space was not found in your Strategy. " - f"Please make sure to have parameters for this space enabled for optimization " - f"or remove the '{space}' space from hyperoptimization.") +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): @@ -48,13 +56,16 @@ class HyperOptAuto(IHyperOpt): if attr.optimize: yield attr.get_space(attr_name) - def _get_indicator_space(self, category): + 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)) if len(indicator_space) > 0: return indicator_space else: - _format_exception_message(category) + _format_exception_message( + category, + self.config.get("hyperopt_ignore_missing_space", False)) + return [] def buy_indicator_space(self) -> List['Dimension']: return self._get_indicator_space('buy') diff --git a/freqtrade/plugins/pairlist/PerformanceFilter.py b/freqtrade/plugins/pairlist/PerformanceFilter.py index 301ee57ab..671b6362b 100644 --- a/freqtrade/plugins/pairlist/PerformanceFilter.py +++ b/freqtrade/plugins/pairlist/PerformanceFilter.py @@ -21,6 +21,7 @@ class PerformanceFilter(IPairList): super().__init__(exchange, pairlistmanager, config, pairlistconfig, pairlist_pos) self._minutes = pairlistconfig.get('minutes', 0) + self._min_profit = pairlistconfig.get('min_profit', None) @property def needstickers(self) -> bool: @@ -68,6 +69,14 @@ class PerformanceFilter(IPairList): sorted_df = list_df.merge(performance, on='pair', how='left')\ .fillna(0).sort_values(by=['count', 'pair'], ascending=True)\ .sort_values(by=['profit'], ascending=False) + if self._min_profit is not None: + removed = sorted_df[sorted_df['profit'] < self._min_profit] + for _, row in removed.iterrows(): + self.log_once( + f"Removing pair {row['pair']} since {row['profit']} is " + f"below {self._min_profit}", logger.info) + sorted_df = sorted_df[sorted_df['profit'] >= self._min_profit] + pairlist = sorted_df['pair'].tolist() return pairlist diff --git a/freqtrade/rpc/api_server/deps.py b/freqtrade/rpc/api_server/deps.py index d2459010f..16f9a78c0 100644 --- a/freqtrade/rpc/api_server/deps.py +++ b/freqtrade/rpc/api_server/deps.py @@ -1,5 +1,6 @@ -from typing import Any, Dict, Optional +from typing import Any, Dict, Iterator, Optional +from freqtrade.persistence import Trade from freqtrade.rpc.rpc import RPC, RPCException from .webserver import ApiServer @@ -11,10 +12,12 @@ def get_rpc_optional() -> Optional[RPC]: return None -def get_rpc() -> Optional[RPC]: +def get_rpc() -> Optional[Iterator[RPC]]: _rpc = get_rpc_optional() if _rpc: - return _rpc + Trade.query.session.rollback() + yield _rpc + Trade.query.session.rollback() else: raise RPCException('Bot is not in the correct state') diff --git a/freqtrade/rpc/telegram.py b/freqtrade/rpc/telegram.py index 85a91a10e..0a84b588a 100644 --- a/freqtrade/rpc/telegram.py +++ b/freqtrade/rpc/telegram.py @@ -25,6 +25,7 @@ from freqtrade.constants import DUST_PER_COIN from freqtrade.enums import RPCMessageType from freqtrade.exceptions import OperationalException from freqtrade.misc import chunks, plural, round_coin_value +from freqtrade.persistence import Trade from freqtrade.rpc import RPC, RPCException, RPCHandler @@ -59,7 +60,8 @@ def authorized_only(command_handler: Callable[..., None]) -> Callable[..., Any]: update.message.chat_id ) return wrapper - + # Rollback session to avoid getting data stored in a transaction. + Trade.query.session.rollback() logger.debug( 'Executing handler: %s for chat_id: %s', command_handler.__name__, diff --git a/freqtrade/vendor/qtpylib/indicators.py b/freqtrade/vendor/qtpylib/indicators.py index 4c0fb5b5c..4f14ae13c 100644 --- a/freqtrade/vendor/qtpylib/indicators.py +++ b/freqtrade/vendor/qtpylib/indicators.py @@ -339,11 +339,13 @@ def vwap(bars): (input can be pandas series or numpy array) bars are usually mid [ (h+l)/2 ] or typical [ (h+l+c)/3 ] """ - typical = ((bars['high'] + bars['low'] + bars['close']) / 3).values - volume = bars['volume'].values + raise ValueError("using `qtpylib.vwap` facilitates lookahead bias. Please use " + "`qtpylib.rolling_vwap` instead, which calculates vwap in a rolling manner.") + # typical = ((bars['high'] + bars['low'] + bars['close']) / 3).values + # volume = bars['volume'].values - return pd.Series(index=bars.index, - data=np.cumsum(volume * typical) / np.cumsum(volume)) + # return pd.Series(index=bars.index, + # data=np.cumsum(volume * typical) / np.cumsum(volume)) # --------------------------------------------- diff --git a/mkdocs.yml b/mkdocs.yml index 05156168f..0daf462c2 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -54,8 +54,8 @@ theme: primary: 'blue grey' accent: 'tear' toggle: - icon: material/toggle-switch-off-outline - name: Switch to dark mode + icon: material/toggle-switch + name: Switch to light mode extra_css: - 'stylesheets/ft.extra.css' extra_javascript: diff --git a/requirements-dev.txt b/requirements-dev.txt index 74ebee479..c2b62196c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -4,11 +4,11 @@ -r requirements-hyperopt.txt coveralls==3.2.0 -flake8==4.0.0 +flake8==4.0.1 flake8-tidy-imports==4.5.0 mypy==0.910 pytest==6.2.5 -pytest-asyncio==0.15.1 +pytest-asyncio==0.16.0 pytest-cov==3.0.0 pytest-mock==3.6.1 pytest-random-order==1.0.4 @@ -20,7 +20,7 @@ time-machine==2.4.0 nbconvert==6.2.0 # mypy types -types-cachetools==4.2.2 -types-filelock==3.2.0 -types-requests==2.25.9 -types-tabulate==0.8.2 +types-cachetools==4.2.4 +types-filelock==3.2.1 +types-requests==2.25.11 +types-tabulate==0.8.3 diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index e97e78638..288d3efad 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -5,7 +5,7 @@ scipy==1.7.1 scikit-learn==1.0 scikit-optimize==0.9.0 -filelock==3.3.0 +filelock==3.3.1 joblib==1.1.0 psutil==5.8.0 -progressbar2==3.53.3 +progressbar2==3.55.0 diff --git a/requirements.txt b/requirements.txt index af6ef974e..b10bbabf6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,8 +1,8 @@ numpy==1.21.2 -pandas==1.3.3 +pandas==1.3.4 pandas-ta==0.3.14b -ccxt==1.57.94 +ccxt==1.58.47 # Pin cryptography for now due to rust build errors with piwheels cryptography==35.0.0 aiohttp==3.7.4.post0 @@ -12,7 +12,6 @@ arrow==1.2.0 cachetools==4.2.2 requests==2.26.0 urllib3==1.26.7 -wrapt==1.13.1 jsonschema==4.1.0 TA-Lib==0.4.21 technical==1.3.0 @@ -26,15 +25,15 @@ blosc==1.10.6 py_find_1st==1.1.5 # Load ticker files 30% faster -python-rapidjson==1.4 +python-rapidjson==1.5 # Notify systemd sdnotify==0.3.2 # API Server -fastapi==0.68.1 +fastapi==0.70.0 uvicorn==0.15.0 -pyjwt==2.2.0 +pyjwt==2.3.0 aiofiles==0.7.0 psutil==5.8.0 diff --git a/setup.py b/setup.py index cf381bdd3..b23fa814d 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,6 @@ hyperopt = [ develop = [ 'coveralls', 'flake8', - 'flake8-type-annotations', 'flake8-tidy-imports', 'mypy', 'pytest', @@ -51,7 +50,6 @@ setup( 'cachetools', 'requests', 'urllib3', - 'wrapt', 'jsonschema', 'TA-Lib', 'pandas-ta', diff --git a/setup.sh b/setup.sh index aee7c80b5..1173b59b9 100755 --- a/setup.sh +++ b/setup.sh @@ -30,7 +30,7 @@ function check_installed_python() { check_installed_pip return fi - done + done echo "No usable python found. Please make sure to have python3.7 or newer installed" exit 1 @@ -95,11 +95,19 @@ function install_talib() { return fi - cd build_helpers && ./install_ta-lib.sh && cd .. + cd build_helpers && ./install_ta-lib.sh + + if [ $? -ne 0 ]; then + echo "Quitting. Please fix the above error before continuing." + cd .. + exit 1 + fi; + + cd .. } -function install_mac_newer_python_dependencies() { - +function install_mac_newer_python_dependencies() { + if [ ! $(brew --prefix --installed hdf5 2>/dev/null) ] then echo "-------------------------" @@ -115,7 +123,7 @@ function install_mac_newer_python_dependencies() { echo "Installing c-blosc" echo "-------------------------" brew install c-blosc - fi + fi export CBLOSC_DIR=$(brew --prefix) } @@ -130,7 +138,7 @@ function install_macos() { fi #Gets number after decimal in python version version=$(egrep -o 3.\[0-9\]+ <<< $PYTHON | sed 's/3.//g') - + if [[ $version -ge 9 ]]; then #Checks if python version >= 3.9 install_mac_newer_python_dependencies fi diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index 6a0e741d9..6e717afdf 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -754,6 +754,46 @@ def test_download_data_no_pairs(mocker, caplog): start_download_data(pargs) +def test_download_data_all_pairs(mocker, markets): + + mocker.patch.object(Path, "exists", MagicMock(return_value=False)) + + dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_ohlcv_data', + MagicMock(return_value=["ETH/BTC", "XRP/BTC"])) + patch_exchange(mocker) + mocker.patch( + 'freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets) + ) + args = [ + "download-data", + "--exchange", + "binance", + "--pairs", + ".*/USDT" + ] + pargs = get_args(args) + pargs['config'] = None + start_download_data(pargs) + expected = set(['ETH/USDT', 'XRP/USDT', 'NEO/USDT', 'TKN/USDT']) + assert set(dl_mock.call_args_list[0][1]['pairs']) == expected + assert dl_mock.call_count == 1 + + dl_mock.reset_mock() + args = [ + "download-data", + "--exchange", + "binance", + "--pairs", + ".*/USDT", + "--include-inactive-pairs", + ] + pargs = get_args(args) + pargs['config'] = None + start_download_data(pargs) + expected = set(['ETH/USDT', 'LTC/USDT', 'XRP/USDT', 'NEO/USDT', 'TKN/USDT']) + assert set(dl_mock.call_args_list[0][1]['pairs']) == expected + + def test_download_data_trades(mocker, caplog): dl_mock = mocker.patch('freqtrade.commands.data_commands.refresh_backtest_trades_data', MagicMock(return_value=[])) diff --git a/tests/conftest.py b/tests/conftest.py index 49534c88d..b35a220df 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -226,7 +226,7 @@ def create_mock_trades(fee, use_db: bool = True): add_trade(trade) if use_db: - Trade.query.session.flush() + Trade.commit() def create_mock_trades_usdt(fee, use_db: bool = True): @@ -259,7 +259,7 @@ def create_mock_trades_usdt(fee, use_db: bool = True): add_trade(trade) if use_db: - Trade.query.session.flush() + Trade.commit() @pytest.fixture(autouse=True) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index e4ce29d44..b123fec21 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -702,7 +702,7 @@ def test_simplified_interface_roi_stoploss(mocker, hyperopt_conf, capsys) -> Non assert hasattr(hyperopt, "position_stacking") -def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None: +def test_simplified_interface_all_failed(mocker, hyperopt_conf, caplog) -> None: mocker.patch('freqtrade.optimize.hyperopt.dump', MagicMock()) mocker.patch('freqtrade.optimize.hyperopt.file_dump_json') mocker.patch('freqtrade.optimize.backtesting.Backtesting.load_bt_data', @@ -724,7 +724,13 @@ def test_simplified_interface_all_failed(mocker, hyperopt_conf) -> None: hyperopt.custom_hyperopt.generate_roi_table = MagicMock(return_value={}) with pytest.raises(OperationalException, match=r"The 'protection' space is included into *"): - hyperopt.start() + hyperopt.init_spaces() + + hyperopt.config['hyperopt_ignore_missing_space'] = True + caplog.clear() + hyperopt.init_spaces() + assert log_has_re(r"The 'protection' space is included into *", caplog) + assert hyperopt.protection_space == [] def test_simplified_interface_buy(mocker, hyperopt_conf, capsys) -> None: diff --git a/tests/plugins/test_pairlist.py b/tests/plugins/test_pairlist.py index cf918e2a0..c6246dccb 100644 --- a/tests/plugins/test_pairlist.py +++ b/tests/plugins/test_pairlist.py @@ -665,11 +665,11 @@ def test_PerformanceFilter_error(mocker, whitelist_conf, caplog) -> None: @pytest.mark.usefixtures("init_persistence") -def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee) -> None: +def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee, caplog) -> None: whitelist_conf['exchange']['pair_whitelist'].append('XRP/BTC') whitelist_conf['pairlists'] = [ {"method": "StaticPairList"}, - {"method": "PerformanceFilter", "minutes": 60} + {"method": "PerformanceFilter", "minutes": 60, "min_profit": 0.01} ] mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True)) exchange = get_patched_exchange(mocker, whitelist_conf) @@ -681,7 +681,8 @@ def test_PerformanceFilter_lookback(mocker, whitelist_conf, fee) -> None: with time_machine.travel("2021-09-01 05:00:00 +00:00") as t: create_mock_trades(fee) pm.refresh_pairlist() - assert pm.whitelist == ['XRP/BTC', 'ETH/BTC', 'TKN/BTC'] + assert pm.whitelist == ['XRP/BTC'] + assert log_has_re(r'Removing pair .* since .* is below .*', caplog) # Move to "outside" of lookback window, so original sorting is restored. t.move_to("2021-09-01 07:00:00 +00:00") diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index ac76bbd11..02ed26459 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -95,7 +95,7 @@ def test_api_not_found(botclient): assert rc.json() == {"detail": "Not Found"} -def test_api_ui_fallback(botclient): +def test_api_ui_fallback(botclient, mocker): ftbot, client = botclient rc = client_get(client, "/favicon.ico") @@ -109,9 +109,16 @@ def test_api_ui_fallback(botclient): rc = client_get(client, "/something") assert rc.status_code == 200 - # Test directory traversal + # Test directory traversal without mock rc = client_get(client, '%2F%2F%2Fetc/passwd') assert rc.status_code == 200 + # Allow both fallback or real UI + assert '`freqtrade install-ui`' in rc.text or '' in rc.text + + mocker.patch.object(Path, 'is_file', MagicMock(side_effect=[True, False])) + rc = client_get(client, '%2F%2F%2Fetc/passwd') + assert rc.status_code == 200 + assert '`freqtrade install-ui`' in rc.text @@ -563,7 +570,6 @@ def test_api_trades(botclient, mocker, fee, markets): assert rc.json()['total_trades'] == 0 create_mock_trades(fee) - Trade.query.session.flush() rc = client_get(client, f"{BASE_URI}/trades") assert_response(rc) @@ -590,7 +596,6 @@ def test_api_trade_single(botclient, mocker, fee, ticker, markets): assert rc.json()['detail'] == 'Trade not found.' create_mock_trades(fee) - Trade.query.session.flush() rc = client_get(client, f"{BASE_URI}/trade/3") assert_response(rc) @@ -613,10 +618,11 @@ def test_api_delete_trade(botclient, mocker, fee, markets): assert_response(rc, 502) create_mock_trades(fee) - Trade.query.session.flush() + ftbot.strategy.order_types['stoploss_on_exchange'] = True trades = Trade.query.all() trades[1].stoploss_order_id = '1234' + Trade.commit() assert len(trades) > 2 rc = client_delete(client, f"{BASE_URI}/trades/1") @@ -686,7 +692,6 @@ def test_api_edge_disabled(botclient, mocker, ticker, fee, markets): assert rc.json() == {"error": "Error querying /api/v1/edge: Edge is not enabled."} -@pytest.mark.usefixtures("init_persistence") def test_api_profit(botclient, mocker, ticker, fee, markets): ftbot, client = botclient patch_get_signal(ftbot) @@ -737,7 +742,6 @@ def test_api_profit(botclient, mocker, ticker, fee, markets): } -@pytest.mark.usefixtures("init_persistence") def test_api_stats(botclient, mocker, ticker, fee, markets,): ftbot, client = botclient patch_get_signal(ftbot) @@ -803,7 +807,7 @@ def test_api_performance(botclient, fee): trade.close_profit_abs = trade.calc_profit() Trade.query.session.add(trade) - Trade.query.session.flush() + Trade.commit() rc = client_get(client, f"{BASE_URI}/performance") assert_response(rc) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index f57e35ca1..838a158e0 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -3378,9 +3378,9 @@ def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usd mocker.patch.multiple( 'freqtrade.exchange.Exchange', fetch_ticker=MagicMock(return_value={ - 'bid': 0.00000172, - 'ask': 0.00000173, - 'last': 0.00000172 + 'bid': 2.0, + 'ask': 2.0, + 'last': 2.0 }), create_order=MagicMock(side_effect=[ limit_buy_order_usdt_open, @@ -3408,7 +3408,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf_usdt, limit_buy_order_usd # Test if buy-signal is absent patch_get_signal(freqtrade, value=(False, True, None)) assert freqtrade.handle_trade(trade) is True - assert trade.sell_reason == SellType.SELL_SIGNAL.value + assert trade.sell_reason == SellType.ROI.value def test_get_real_amount_quote(default_conf_usdt, trades_for_order, buy_order_fee, fee, caplog,