diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 912b906d7..a2f6567dc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -90,7 +90,7 @@ jobs: - name: Backtesting (multi) run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade new-strategy -s AwesomeStrategy freqtrade new-strategy -s AwesomeStrategyMin --template minimal @@ -98,7 +98,7 @@ jobs: - name: Hyperopt run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade hyperopt --datadir tests/testdata -e 6 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all @@ -200,14 +200,14 @@ jobs: - name: Backtesting run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade new-strategy -s AwesomeStrategyAdv --template advanced freqtrade backtesting --datadir tests/testdata --strategy AwesomeStrategyAdv - name: Hyperopt run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all @@ -275,13 +275,13 @@ jobs: - name: Backtesting run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade backtesting --datadir tests/testdata --strategy SampleStrategy - name: Hyperopt run: | - cp config_examples/config_bittrex.example.json config.json + cp tests/testdata/config.tests.json config.json freqtrade create-userdir --userdir user_data freqtrade hyperopt --datadir tests/testdata -e 5 --strategy SampleStrategy --hyperopt-loss SharpeHyperOptLossDaily --print-all diff --git a/Dockerfile b/Dockerfile index e2adf65f9..38f9ca788 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.11.6-slim-bullseye as base +FROM python:3.11.6-slim-bookworm as base # Setup env ENV LANG C.UTF-8 diff --git a/README.md b/README.md index 0cacfe703..4ed144f93 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ hesitate to read the source code and understand the mechanism of this bot. Please read the [exchange specific notes](docs/exchanges.md) to learn about eventual, special configurations needed for each exchange. - [X] [Binance](https://www.binance.com/) -- [X] [Bittrex](https://bittrex.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) - [X] [Huobi](http://huobi.com/) - [X] [Kraken](https://kraken.com/) diff --git a/build_helpers/publish_docker_arm64.sh b/build_helpers/publish_docker_arm64.sh index 8f0de2cc9..71fc01509 100755 --- a/build_helpers/publish_docker_arm64.sh +++ b/build_helpers/publish_docker_arm64.sh @@ -54,7 +54,7 @@ docker tag freqtrade:$TAG_FREQAI_ARM ${CACHE_IMAGE}:$TAG_FREQAI_ARM docker tag freqtrade:$TAG_FREQAI_RL_ARM ${CACHE_IMAGE}:$TAG_FREQAI_RL_ARM # Run backtest -docker run --rm -v $(pwd)/config_examples/config_bittrex.example.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG_ARM} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3 +docker run --rm -v $(pwd)/tests/testdata/config.tests.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG_ARM} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3 if [ $? -ne 0 ]; then echo "failed running backtest" diff --git a/build_helpers/publish_docker_multi.sh b/build_helpers/publish_docker_multi.sh index 72b20ac5d..34dc1faa3 100755 --- a/build_helpers/publish_docker_multi.sh +++ b/build_helpers/publish_docker_multi.sh @@ -67,7 +67,7 @@ docker tag freqtrade:$TAG_FREQAI ${CACHE_IMAGE}:$TAG_FREQAI docker tag freqtrade:$TAG_FREQAI_RL ${CACHE_IMAGE}:$TAG_FREQAI_RL # Run backtest -docker run --rm -v $(pwd)/config_examples/config_bittrex.example.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3 +docker run --rm -v $(pwd)/tests/testdata/config.tests.json:/freqtrade/config.json:ro -v $(pwd)/tests:/tests freqtrade:${TAG} backtesting --datadir /tests/testdata --strategy-path /tests/strategy/strats/ --strategy StrategyTestV3 if [ $? -ne 0 ]; then echo "failed running backtest" diff --git a/config_examples/config_binance.example.json b/config_examples/config_binance.example.json index 7968bdedc..3a2cea530 100644 --- a/config_examples/config_binance.example.json +++ b/config_examples/config_binance.example.json @@ -1,6 +1,6 @@ { "max_open_trades": 3, - "stake_currency": "BTC", + "stake_currency": "USDT", "stake_amount": 0.05, "tradable_balance_ratio": 0.99, "fiat_display_currency": "USD", @@ -36,21 +36,21 @@ "ccxt_async_config": { }, "pair_whitelist": [ - "ALGO/BTC", - "ATOM/BTC", - "BAT/BTC", - "BCH/BTC", - "BRD/BTC", - "EOS/BTC", - "ETH/BTC", - "IOTA/BTC", - "LINK/BTC", - "LTC/BTC", - "NEO/BTC", - "NXS/BTC", - "XMR/BTC", - "XRP/BTC", - "XTZ/BTC" + "ALGO/USDT", + "ATOM/USDT", + "BAT/USDT", + "BCH/USDT", + "BRD/USDT", + "EOS/USDT", + "ETH/USDT", + "IOTA/USDT", + "LINK/USDT", + "LTC/USDT", + "NEO/USDT", + "NXS/USDT", + "XMR/USDT", + "XRP/USDT", + "XTZ/USDT" ], "pair_blacklist": [ "BNB/.*" diff --git a/docker/Dockerfile.armhf b/docker/Dockerfile.armhf index c17c0adbe..c8efa4232 100644 --- a/docker/Dockerfile.armhf +++ b/docker/Dockerfile.armhf @@ -1,4 +1,4 @@ -FROM python:3.9.16-slim-bullseye as base +FROM python:3.11.6-slim-bookworm as base # Setup env ENV LANG C.UTF-8 @@ -11,7 +11,7 @@ ENV FT_APP_ENV="docker" # Prepare environment RUN mkdir /freqtrade \ && apt-get update \ - && apt-get -y install sudo libatlas3-base libopenblas-base curl sqlite3 libhdf5-dev libutf8proc-dev libsnappy-dev \ + && apt-get -y install sudo libatlas3-base libopenblas-dev curl sqlite3 libhdf5-dev libutf8proc-dev libsnappy-dev \ && apt-get clean \ && useradd -u 1000 -G sudo -U -m ftuser \ && chown ftuser:ftuser /freqtrade \ @@ -24,7 +24,7 @@ WORKDIR /freqtrade # Install dependencies FROM base as python-deps RUN apt-get update \ - && apt-get -y install build-essential libssl-dev libffi-dev libopenblas-dev libgfortran5 pkg-config cmake gcc \ + && apt-get -y install build-essential libssl-dev libffi-dev libgfortran5 pkg-config cmake gcc \ && apt-get clean \ && echo "[global]\nextra-index-url=https://www.piwheels.org/simple" > /etc/pip.conf diff --git a/docs/backtesting.md b/docs/backtesting.md index 41498fb00..d13b00a38 100644 --- a/docs/backtesting.md +++ b/docs/backtesting.md @@ -170,11 +170,11 @@ freqtrade backtesting --strategy AwesomeStrategy --dry-run-wallet 1000 Using a different on-disk historical candle (OHLCV) data source -Assume you downloaded the history data from the Bittrex exchange and kept it in the `user_data/data/bittrex-20180101` directory. +Assume you downloaded the history data from the Binance exchange and kept it in the `user_data/data/binance-20180101` directory. You can then use this data for backtesting as follows: ```bash -freqtrade backtesting --strategy AwesomeStrategy --datadir user_data/data/bittrex-20180101 +freqtrade backtesting --strategy AwesomeStrategy --datadir user_data/data/binance-20180101 ``` --- diff --git a/docs/configuration.md b/docs/configuration.md index 7303f78c7..313e3e456 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -594,7 +594,7 @@ creating trades on the exchange. ```json "exchange": { - "name": "bittrex", + "name": "binance", "key": "key", "secret": "secret", ... @@ -644,7 +644,7 @@ API Keys are usually only required for live trading (trading for real money, bot ```json { "exchange": { - "name": "bittrex", + "name": "binance", "key": "af8ddd35195e9dc500b9a6f799f6f5c93d89193b", "secret": "08a9dc6db3d7b53e1acebd9275677f4b0a04f1a5", //"password": "", // Optional, not needed by all exchanges) diff --git a/docs/freqai-parameter-table.md b/docs/freqai-parameter-table.md index 95687c7ab..905ea479a 100644 --- a/docs/freqai-parameter-table.md +++ b/docs/freqai-parameter-table.md @@ -74,7 +74,6 @@ Mandatory parameters are marked as **Required** and have to be set in one of the | | **Reinforcement Learning Parameters within the `freqai.rl_config` sub dictionary** | `rl_config` | A dictionary containing the control parameters for a Reinforcement Learning model.
**Datatype:** Dictionary. | `train_cycles` | Training time steps will be set based on the `train_cycles * number of training data points.
**Datatype:** Integer. -| `cpu_count` | Number of processors to dedicate to the Reinforcement Learning training process.
**Datatype:** int. | `max_trade_duration_candles`| Guides the agent training to keep trades below desired length. Example usage shown in `prediction_models/ReinforcementLearner.py` within the customizable `calculate_reward()` function.
**Datatype:** int. | `model_type` | Model string from stable_baselines3 or SBcontrib. Available strings include: `'TRPO', 'ARS', 'RecurrentPPO', 'MaskablePPO', 'PPO', 'A2C', 'DQN'`. User should ensure that `model_training_parameters` match those available to the corresponding stable_baselines3 model by visiting their documentaiton. [PPO doc](https://stable-baselines3.readthedocs.io/en/master/modules/ppo.html) (external website)
**Datatype:** string. | `policy_type` | One of the available policy types from stable_baselines3
**Datatype:** string. diff --git a/docs/index.md b/docs/index.md index 190e7e3c3..dd80db958 100644 --- a/docs/index.md +++ b/docs/index.md @@ -40,7 +40,6 @@ Freqtrade is a free and open source crypto trading bot written in Python. It is Please read the [exchange specific notes](exchanges.md) to learn about eventual, special configurations needed for each exchange. - [X] [Binance](https://www.binance.com/) -- [X] [Bittrex](https://bittrex.com/) - [X] [Gate.io](https://www.gate.io/ref/6266643) - [X] [Huobi](http://huobi.com/) - [X] [Kraken](https://kraken.com/) diff --git a/docs/requirements-docs.txt b/docs/requirements-docs.txt index 8269c02da..31e04a74f 100644 --- a/docs/requirements-docs.txt +++ b/docs/requirements-docs.txt @@ -1,6 +1,6 @@ markdown==3.5.1 mkdocs==1.5.3 -mkdocs-material==9.4.8 +mkdocs-material==9.4.10 mdx_truly_sane_lists==1.3 pymdown-extensions==10.4 jinja2==3.1.2 diff --git a/docs/utils.md b/docs/utils.md index 65ab50b9e..ac0d341bd 100644 --- a/docs/utils.md +++ b/docs/utils.md @@ -427,25 +427,33 @@ zb True missing opt: fetchMyTrades Use the `list-timeframes` subcommand to see the list of timeframes available for the exchange. ``` -usage: freqtrade list-timeframes [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [--exchange EXCHANGE] [-1] +usage: freqtrade list-timeframes [-h] [-v] [--logfile FILE] [-V] [-c PATH] + [-d PATH] [--userdir PATH] + [--exchange EXCHANGE] [-1] -optional arguments: +options: -h, --help show this help message and exit - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no config is provided. + --exchange EXCHANGE Exchange name. Only valid if no config is provided. -1, --one-column Print output in one column. Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. + --logfile FILE, --log-file FILE + Log to the file specified. Special values are: + 'syslog', 'journald'. See the documentation for more + details. -V, --version show program's version number and exit -c PATH, --config PATH - Specify configuration file (default: `config.json`). Multiple --config options may be used. Can be set to `-` - to read config from stdin. - -d PATH, --datadir PATH + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. + -d PATH, --datadir PATH, --data-dir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. + ``` * Example: see the timeframes for the 'binance' exchange, set in the configuration file: @@ -479,20 +487,17 @@ usage: freqtrade list-markets [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [--exchange EXCHANGE] [--print-list] [--print-json] [-1] [--print-csv] [--base BASE_CURRENCY [BASE_CURRENCY ...]] - [--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]] [-a] - [--trading-mode {spot,margin,futures}] - + [--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]] + [-a] [--trading-mode {spot,margin,futures}] usage: freqtrade list-pairs [-h] [-v] [--logfile FILE] [-V] [-c PATH] [-d PATH] [--userdir PATH] [--exchange EXCHANGE] [--print-list] [--print-json] [-1] [--print-csv] [--base BASE_CURRENCY [BASE_CURRENCY ...]] [--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]] [-a] [--trading-mode {spot,margin,futures}] - -optional arguments: +options: -h, --help show this help message and exit - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no - config is provided. + --exchange EXCHANGE Exchange name. Only valid if no config is provided. --print-list Print list of pairs or market symbols. By default data is printed in the tabular format. --print-json Print list of pairs or market symbols in JSON format. @@ -504,20 +509,22 @@ optional arguments: Specify quote currency(-ies). Space-separated list. -a, --all Print all pairs or market symbols. By default only active ones are shown. - --trading-mode {spot,margin,futures} + --trading-mode {spot,margin,futures}, --tradingmode {spot,margin,futures} Select Trading mode Common arguments: -v, --verbose Verbose mode (-vv for more, -vvv to get all messages). - --logfile FILE Log to the file specified. Special values are: + --logfile FILE, --log-file FILE + Log to the file specified. Special values are: 'syslog', 'journald'. See the documentation for more details. -V, --version show program's version number and exit -c PATH, --config PATH - Specify configuration file (default: `config.json`). - Multiple --config options may be used. Can be set to - `-` to read config from stdin. - -d PATH, --datadir PATH + Specify configuration file (default: + `userdir/config.json` or `config.json` whichever + exists). Multiple --config options may be used. Can be + set to `-` to read config from stdin. + -d PATH, --datadir PATH, --data-dir PATH Path to directory with historical backtesting data. --userdir PATH, --user-data-dir PATH Path to userdata directory. @@ -532,7 +539,7 @@ Pairs/markets are sorted by its symbol string in the printed output. ### Examples * Print the list of active pairs with quote currency USD on exchange, specified in the default -configuration file (i.e. pairs on the "Bittrex" exchange) in JSON format: +configuration file (i.e. pairs on the "Binance" exchange) in JSON format: ``` $ freqtrade list-pairs --quote USD --print-json @@ -564,7 +571,7 @@ usage: freqtrade test-pairlist [-h] [--userdir PATH] [-v] [-c PATH] [--quote QUOTE_CURRENCY [QUOTE_CURRENCY ...]] [-1] [--print-json] [--exchange EXCHANGE] -optional arguments: +options: -h, --help show this help message and exit --userdir PATH, --user-data-dir PATH Path to userdata directory. @@ -578,8 +585,7 @@ optional arguments: Specify quote currency(-ies). Space-separated list. -1, --one-column Print output in one column. --print-json Print list of pairs or market symbols in JSON format. - --exchange EXCHANGE Exchange name (default: `bittrex`). Only valid if no - config is provided. + --exchange EXCHANGE Exchange name. Only valid if no config is provided. ``` diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py index 6692ad59a..2dff87a7d 100644 --- a/freqtrade/commands/build_config_commands.py +++ b/freqtrade/commands/build_config_commands.py @@ -108,7 +108,6 @@ def ask_user_config() -> Dict[str, Any]: "choices": [ "binance", "binanceus", - "bittrex", "gate", "huobi", "kraken", diff --git a/freqtrade/exchange/common.py b/freqtrade/exchange/common.py index 10dfdf178..36bed9b20 100644 --- a/freqtrade/exchange/common.py +++ b/freqtrade/exchange/common.py @@ -52,7 +52,6 @@ MAP_EXCHANGE_CHILDCLASS = { SUPPORTED_EXCHANGES = [ 'binance', - 'bittrex', 'gate', 'huobi', 'kraken', diff --git a/freqtrade/exchange/exchange.py b/freqtrade/exchange/exchange.py index 603c161cf..5d0bc704f 100644 --- a/freqtrade/exchange/exchange.py +++ b/freqtrade/exchange/exchange.py @@ -486,11 +486,14 @@ class Exchange: except ccxt.BaseError: logger.exception('Unable to initialize markets.') - def reload_markets(self) -> None: + def reload_markets(self, force: bool = False) -> None: """Reload markets both sync and async if refresh interval has passed """ # Check whether markets have to be reloaded - if (self._last_markets_refresh > 0) and ( - self._last_markets_refresh + self.markets_refresh_interval > dt_ts()): + if ( + not force + and self._last_markets_refresh > 0 + and (self._last_markets_refresh + self.markets_refresh_interval > dt_ts()) + ): return None logger.debug("Performing scheduled market reload..") try: @@ -1228,16 +1231,16 @@ class Exchange: return order except ccxt.InsufficientFunds as e: raise InsufficientFundsError( - f'Insufficient funds to create {ordertype} sell order on market {pair}. ' - f'Tried to sell amount {amount} at rate {limit_rate}. ' - f'Message: {e}') from e - except ccxt.InvalidOrder as e: + f'Insufficient funds to create {ordertype} {side} order on market {pair}. ' + f'Tried to {side} amount {amount} at rate {limit_rate} with ' + f'stop-price {stop_price_norm}. Message: {e}') from e + except (ccxt.InvalidOrder, ccxt.BadRequest) as e: # Errors: # `Order would trigger immediately.` raise InvalidOrderException( - f'Could not create {ordertype} sell order on market {pair}. ' - f'Tried to sell amount {amount} at rate {limit_rate}. ' - f'Message: {e}') from e + f'Could not create {ordertype} {side} order on market {pair}. ' + f'Tried to {side} amount {amount} at rate {limit_rate} with ' + f'stop-price {stop_price_norm}. Message: {e}') from e except ccxt.DDoSProtection as e: raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: @@ -1496,8 +1499,9 @@ class Exchange: @retrier def fetch_bids_asks(self, symbols: Optional[List[str]] = None, cached: bool = False) -> Dict: """ + :param symbols: List of symbols to fetch :param cached: Allow cached result - :return: fetch_tickers result + :return: fetch_bids_asks result """ if not self.exchange_has('fetchBidsAsks'): return {} @@ -1546,6 +1550,12 @@ class Exchange: raise OperationalException( f'Exchange {self._api.name} does not support fetching tickers in batch. ' f'Message: {e}') from e + except ccxt.BadSymbol as e: + logger.warning(f"Could not load tickers due to {e.__class__.__name__}. Message: {e} ." + "Reloading markets.") + self.reload_markets(True) + # Re-raise exception to repeat the call. + raise TemporaryError from e except ccxt.DDoSProtection as e: raise DDosProtection(e) from e except (ccxt.NetworkError, ccxt.ExchangeError) as e: diff --git a/freqtrade/freqai/tensorboard/TensorboardCallback.py b/freqtrade/freqai/tensorboard/TensorboardCallback.py index 2be917616..b8a351498 100644 --- a/freqtrade/freqai/tensorboard/TensorboardCallback.py +++ b/freqtrade/freqai/tensorboard/TensorboardCallback.py @@ -3,7 +3,6 @@ from typing import Any, Dict, Type, Union from stable_baselines3.common.callbacks import BaseCallback from stable_baselines3.common.logger import HParam -from stable_baselines3.common.vec_env import VecEnv from freqtrade.freqai.RL.BaseEnvironment import BaseActions @@ -13,13 +12,9 @@ class TensorboardCallback(BaseCallback): Custom callback for plotting additional values in tensorboard and episodic summary reports. """ - # Override training_env type to fix type errors - training_env: Union[VecEnv, None] = None - def __init__(self, verbose=1, actions: Type[Enum] = BaseActions): super().__init__(verbose) self.model: Any = None - self.logger: Any = None self.actions: Type[Enum] = actions def _on_training_start(self) -> None: @@ -47,8 +42,6 @@ class TensorboardCallback(BaseCallback): def _on_step(self) -> bool: local_info = self.locals["infos"][0] - if self.training_env is None: - return True if hasattr(self.training_env, 'envs'): tensorboard_metrics = self.training_env.envs[0].unwrapped.tensorboard_metrics diff --git a/freqtrade/optimize/hyperopt_auto.py b/freqtrade/optimize/hyperopt_auto.py index 13c036a28..a3e2ef058 100644 --- a/freqtrade/optimize/hyperopt_auto.py +++ b/freqtrade/optimize/hyperopt_auto.py @@ -21,7 +21,7 @@ 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. " + f"but no parameter for this space was found in your Strategy. " ) if ignore_missing_space: logger.warning(msg + "This space will be ignored.") diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 241ef70f5..3f721f1e8 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -1066,7 +1066,10 @@ class LocalTrade: exit_amount = o.safe_amount_after_fee prof = self.calculate_profit(exit_rate, exit_amount, float(avg_price)) close_profit_abs += prof.profit_abs - close_profit = prof.profit_ratio + if total_stake > 0: + # This needs to be calculated based on the last occuring exit to be aligned + # with realized_profit. + close_profit = (close_profit_abs / total_stake) * self.leverage else: total_stake = total_stake + self._calc_open_trade_value(tmp_amount, price) max_stake_amount += (tmp_amount * price) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 9ed7bbc46..e0aa2437a 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -21,6 +21,7 @@ from freqtrade.misc import pair_to_filename from freqtrade.plugins.pairlist.pairlist_helpers import expand_pairlist from freqtrade.resolvers import ExchangeResolver, StrategyResolver from freqtrade.strategy import IStrategy +from freqtrade.strategy.strategy_wrapper import strategy_safe_wrapper logger = logging.getLogger(__name__) @@ -636,7 +637,7 @@ def load_and_plot_trades(config: Config): exchange = ExchangeResolver.load_exchange(config) IStrategy.dp = DataProvider(config, exchange) strategy.ft_bot_start() - strategy.bot_loop_start(datetime.now(timezone.utc)) + strategy_safe_wrapper(strategy.bot_loop_start)(current_time=datetime.now(timezone.utc)) plot_elements = init_plotscript(config, list(exchange.markets), strategy.startup_candle_count) timerange = plot_elements['timerange'] trades = plot_elements['trades'] diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index e64570b9e..8be1f0336 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -290,9 +290,6 @@ class FreqaiExampleStrategy(IStrategy): return df - def get_ticker_indicator(self): - return int(self.config["timeframe"][:-1]) - def confirm_trade_entry( self, pair: str, diff --git a/requirements-dev.txt b/requirements-dev.txt index 4bda09e2d..44cf0982d 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -7,7 +7,7 @@ -r docs/requirements-docs.txt coveralls==3.3.1 -ruff==0.1.5 +ruff==0.1.6 mypy==1.7.0 pre-commit==3.5.0 pytest==7.4.3 diff --git a/requirements-freqai-rl.txt b/requirements-freqai-rl.txt index c2cca5427..fba25d409 100644 --- a/requirements-freqai-rl.txt +++ b/requirements-freqai-rl.txt @@ -5,7 +5,7 @@ torch==2.0.1 #until these branches will be released we can use this gymnasium==0.29.1 -stable_baselines3==2.1.0 +stable_baselines3==2.2.1 sb3_contrib>=2.0.0a9 # Progress bar for stable-baselines3 and sb3-contrib tqdm==4.66.1 diff --git a/requirements-hyperopt.txt b/requirements-hyperopt.txt index d1931eec1..b4bca9751 100644 --- a/requirements-hyperopt.txt +++ b/requirements-hyperopt.txt @@ -2,7 +2,7 @@ -r requirements.txt # Required for hyperopt -scipy==1.11.3 +scipy==1.11.4 scikit-learn==1.1.3 scikit-optimize==0.9.0 filelock==3.13.1 diff --git a/requirements.txt b/requirements.txt index 63ae316a6..e3f2b4bbb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,9 +2,9 @@ numpy==1.26.2 pandas==2.1.3 pandas-ta==0.3.14b -ccxt==4.1.52 +ccxt==4.1.57 cryptography==41.0.5 -aiohttp==3.8.6 +aiohttp==3.9.0 SQLAlchemy==2.0.23 python-telegram-bot==20.6 # can't be hard-pinned due to telegram-bot pinning httpx with ~ @@ -12,17 +12,16 @@ httpx>=0.24.1 arrow==1.3.0 cachetools==5.3.2 requests==2.31.0 -urllib3==2.0.7 -jsonschema==4.19.2 +urllib3==2.1.0 +jsonschema==4.20.0 TA-Lib==0.4.28 technical==1.4.0 tabulate==0.9.0 pycoingecko==3.1.0 jinja2==3.1.2 tables==3.9.1 -blosc==1.11.1 joblib==1.3.2 -rich==13.6.0 +rich==13.7.0 pyarrow==14.0.1; platform_machine != 'armv7l' # find first, C search in arrays @@ -38,7 +37,7 @@ sdnotify==0.3.2 # API Server fastapi==0.104.1 -pydantic==2.4.2 +pydantic==2.5.1 uvicorn==0.24.0.post1 pyjwt==2.8.0 aiofiles==23.2.1 diff --git a/tests/exchange/test_exchange.py b/tests/exchange/test_exchange.py index e2b3cc102..ad993cb6d 100644 --- a/tests/exchange/test_exchange.py +++ b/tests/exchange/test_exchange.py @@ -1851,7 +1851,7 @@ def test_fetch_bids_asks(default_conf, mocker): @pytest.mark.parametrize("exchange_name", EXCHANGES) -def test_get_tickers(default_conf, mocker, exchange_name): +def test_get_tickers(default_conf, mocker, exchange_name, caplog): api_mock = MagicMock() tick = {'ETH/BTC': { 'symbol': 'ETH/BTC', @@ -1900,6 +1900,14 @@ def test_get_tickers(default_conf, mocker, exchange_name): exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) exchange.get_tickers() + caplog.clear() + api_mock.fetch_tickers = MagicMock(side_effect=[ccxt.BadSymbol("SomeSymbol"), []]) + exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) + x = exchange.get_tickers() + assert x == [] + assert log_has_re(r'Could not load tickers due to BadSymbol\..*SomeSymbol', caplog) + caplog.clear() + api_mock.fetch_tickers = MagicMock(return_value={}) exchange = get_patched_exchange(mocker, default_conf, api_mock, id=exchange_name) exchange.get_tickers() diff --git a/tests/exchange/test_exchange_utils.py b/tests/exchange/test_exchange_utils.py index 377514468..8ae4039c7 100644 --- a/tests/exchange/test_exchange_utils.py +++ b/tests/exchange/test_exchange_utils.py @@ -18,7 +18,7 @@ from tests.conftest import log_has_re def test_check_exchange(default_conf, caplog) -> None: # Test an officially supported by Freqtrade team exchange default_conf['runmode'] = RunMode.DRY_RUN - default_conf.get('exchange').update({'name': 'BITTREX'}) + default_conf.get('exchange').update({'name': 'BINANCE'}) assert check_exchange(default_conf) assert log_has_re(r"Exchange .* is officially supported by the Freqtrade development team\.", caplog) diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py index b858aa33c..67f776c7e 100644 --- a/tests/optimize/test_hyperopt.py +++ b/tests/optimize/test_hyperopt.py @@ -310,6 +310,8 @@ def test_start_calls_optimizer(mocker, hyperopt_conf, capsys) -> None: 'freqtrade.optimize.hyperopt.get_timerange', MagicMock(return_value=(datetime(2017, 12, 10), datetime(2017, 12, 13))) ) + # Dummy-reduce points to ensure scikit-learn is forced to generate new values + mocker.patch('freqtrade.optimize.hyperopt.INITIAL_POINTS', 2) parallel = mocker.patch( 'freqtrade.optimize.hyperopt.Hyperopt.run_optimizer_parallel', @@ -860,6 +862,8 @@ def test_simplified_interface_failed(mocker, hyperopt_conf, space) -> None: def test_in_strategy_auto_hyperopt(mocker, hyperopt_conf, tmp_path, fee) -> None: patch_exchange(mocker) mocker.patch(f'{EXMS}.get_fee', fee) + # Dummy-reduce points to ensure scikit-learn is forced to generate new values + mocker.patch('freqtrade.optimize.hyperopt.INITIAL_POINTS', 2) (tmp_path / 'hyperopt_results').mkdir(parents=True) # No hyperopt needed hyperopt_conf.update({ @@ -904,6 +908,8 @@ def test_in_strategy_auto_hyperopt_with_parallel(mocker, hyperopt_conf, tmp_path mocker.patch(f'{EXMS}.markets', PropertyMock(return_value=get_markets())) (tmp_path / 'hyperopt_results').mkdir(parents=True) + # Dummy-reduce points to ensure scikit-learn is forced to generate new values + mocker.patch('freqtrade.optimize.hyperopt.INITIAL_POINTS', 2) # No hyperopt needed hyperopt_conf.update({ 'strategy': 'HyperoptableStrategy', diff --git a/tests/persistence/test_persistence.py b/tests/persistence/test_persistence.py index 0fc8c7f47..5829f8b71 100644 --- a/tests/persistence/test_persistence.py +++ b/tests/persistence/test_persistence.py @@ -2676,9 +2676,9 @@ def test_order_to_ccxt(limit_buy_order_open, limit_sell_order_usdt_open): 'orders': [ (('buy', 100, 10), (100.0, 10.0, 1000.0, 0.0, None, None)), (('buy', 100, 15), (200.0, 12.5, 2500.0, 0.0, None, None)), - (('sell', 50, 12), (150.0, 12.5, 1875.0, -25.0, -25.0, -0.04)), - (('sell', 100, 20), (50.0, 12.5, 625.0, 725.0, 750.0, 0.60)), - (('sell', 50, 5), (50.0, 12.5, 625.0, 350.0, -375.0, -0.60)), + (('sell', 50, 12), (150.0, 12.5, 1875.0, -25.0, -25.0, -0.01)), + (('sell', 100, 20), (50.0, 12.5, 625.0, 725.0, 750.0, 0.29)), + (('sell', 50, 5), (50.0, 12.5, 625.0, 350.0, -375.0, 0.14)), ], 'end_profit': 350.0, 'end_profit_ratio': 0.14, @@ -2688,9 +2688,9 @@ def test_order_to_ccxt(limit_buy_order_open, limit_sell_order_usdt_open): 'orders': [ (('buy', 100, 10), (100.0, 10.0, 1000.0, 0.0, None, None)), (('buy', 100, 15), (200.0, 12.5, 2500.0, 0.0, None, None)), - (('sell', 50, 12), (150.0, 12.5, 1875.0, -28.0625, -28.0625, -0.044788)), - (('sell', 100, 20), (50.0, 12.5, 625.0, 713.8125, 741.875, 0.59201995)), - (('sell', 50, 5), (50.0, 12.5, 625.0, 336.625, -377.1875, -0.60199501)), + (('sell', 50, 12), (150.0, 12.5, 1875.0, -28.0625, -28.0625, -0.011197)), + (('sell', 100, 20), (50.0, 12.5, 625.0, 713.8125, 741.875, 0.2848129)), + (('sell', 50, 5), (50.0, 12.5, 625.0, 336.625, -377.1875, 0.1343142)), ], 'end_profit': 336.625, 'end_profit_ratio': 0.1343142, @@ -2700,10 +2700,10 @@ def test_order_to_ccxt(limit_buy_order_open, limit_sell_order_usdt_open): 'orders': [ (('buy', 100, 3), (100.0, 3.0, 300.0, 0.0, None, None)), (('buy', 100, 7), (200.0, 5.0, 1000.0, 0.0, None, None)), - (('sell', 100, 11), (100.0, 5.0, 500.0, 596.0, 596.0, 1.189027)), - (('buy', 150, 15), (250.0, 11.0, 2750.0, 596.0, 596.0, 1.189027)), - (('sell', 100, 19), (150.0, 11.0, 1650.0, 1388.5, 792.5, 0.7186579)), - (('sell', 150, 23), (150.0, 11.0, 1650.0, 3175.75, 1787.25, 1.08048062)), + (('sell', 100, 11), (100.0, 5.0, 500.0, 596.0, 596.0, 0.5945137)), + (('buy', 150, 15), (250.0, 11.0, 2750.0, 596.0, 596.0, 0.5945137)), + (('sell', 100, 19), (150.0, 11.0, 1650.0, 1388.5, 792.5, 0.4261653)), + (('sell', 150, 23), (150.0, 11.0, 1650.0, 3175.75, 1787.25, 0.9747170)), ], 'end_profit': 3175.75, 'end_profit_ratio': 0.9747170, @@ -2714,10 +2714,10 @@ def test_order_to_ccxt(limit_buy_order_open, limit_sell_order_usdt_open): 'orders': [ (('buy', 100, 3), (100.0, 3.0, 300.0, 0.0, None, None)), (('buy', 100, 7), (200.0, 5.0, 1000.0, 0.0, None, None)), - (('sell', 100, 11), (100.0, 5.0, 500.0, 600.0, 600.0, 1.2)), - (('buy', 150, 15), (250.0, 11.0, 2750.0, 600.0, 600.0, 1.2)), - (('sell', 100, 19), (150.0, 11.0, 1650.0, 1400.0, 800.0, 0.72727273)), - (('sell', 150, 23), (150.0, 11.0, 1650.0, 3200.0, 1800.0, 1.09090909)), + (('sell', 100, 11), (100.0, 5.0, 500.0, 600.0, 600.0, 0.6)), + (('buy', 150, 15), (250.0, 11.0, 2750.0, 600.0, 600.0, 0.6)), + (('sell', 100, 19), (150.0, 11.0, 1650.0, 1400.0, 800.0, 0.43076923)), + (('sell', 150, 23), (150.0, 11.0, 1650.0, 3200.0, 1800.0, 0.98461538)), ], 'end_profit': 3200.0, 'end_profit_ratio': 0.98461538, @@ -2727,10 +2727,10 @@ def test_order_to_ccxt(limit_buy_order_open, limit_sell_order_usdt_open): 'orders': [ (('buy', 100, 8), (100.0, 8.0, 800.0, 0.0, None, None)), (('buy', 100, 9), (200.0, 8.5, 1700.0, 0.0, None, None)), - (('sell', 100, 10), (100.0, 8.5, 850.0, 150.0, 150.0, 0.17647059)), - (('buy', 150, 11), (250.0, 10, 2500.0, 150.0, 150.0, 0.17647059)), - (('sell', 100, 12), (150.0, 10.0, 1500.0, 350.0, 200.0, 0.2)), - (('sell', 150, 14), (150.0, 10.0, 1500.0, 950.0, 600.0, 0.40)), + (('sell', 100, 10), (100.0, 8.5, 850.0, 150.0, 150.0, 0.08823529)), + (('buy', 150, 11), (250.0, 10, 2500.0, 150.0, 150.0, 0.08823529)), + (('sell', 100, 12), (150.0, 10.0, 1500.0, 350.0, 200.0, 0.1044776)), + (('sell', 150, 14), (150.0, 10.0, 1500.0, 950.0, 600.0, 0.283582)), ], 'end_profit': 950.0, 'end_profit_ratio': 0.283582, diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index 40d77ce6c..c9cb86cc0 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -6569,16 +6569,16 @@ def test_position_adjust2(mocker, default_conf_usdt, fee) -> None: # tuple 2 - amount, open_rate, stake_amount, cumulative_profit, realized_profit, rel_profit (('buy', 100, 10), (100.0, 10.0, 1000.0, 0.0, None, None)), (('buy', 100, 15), (200.0, 12.5, 2500.0, 0.0, None, None)), - (('sell', 50, 12), (150.0, 12.5, 1875.0, -28.0625, -28.0625, -0.044788)), - (('sell', 100, 20), (50.0, 12.5, 625.0, 713.8125, 741.875, 0.59201995)), + (('sell', 50, 12), (150.0, 12.5, 1875.0, -28.0625, -28.0625, -0.011197)), + (('sell', 100, 20), (50.0, 12.5, 625.0, 713.8125, 741.875, 0.2848129)), (('sell', 50, 5), (50.0, 12.5, 625.0, 336.625, 336.625, 0.1343142)), # final profit (sum) ), ( (('buy', 100, 3), (100.0, 3.0, 300.0, 0.0, None, None)), (('buy', 100, 7), (200.0, 5.0, 1000.0, 0.0, None, None)), - (('sell', 100, 11), (100.0, 5.0, 500.0, 596.0, 596.0, 1.189027)), - (('buy', 150, 15), (250.0, 11.0, 2750.0, 596.0, 596.0, 1.189027)), - (('sell', 100, 19), (150.0, 11.0, 1650.0, 1388.5, 792.5, 0.7186579)), + (('sell', 100, 11), (100.0, 5.0, 500.0, 596.0, 596.0, 0.5945137)), + (('buy', 150, 15), (250.0, 11.0, 2750.0, 596.0, 596.0, 0.5945137)), + (('sell', 100, 19), (150.0, 11.0, 1650.0, 1388.5, 792.5, 0.4261653)), (('sell', 150, 23), (150.0, 11.0, 1650.0, 3175.75, 3175.75, 0.9747170)), # final profit ) ]) diff --git a/tests/test_integration.py b/tests/test_integration.py index ee1d4bbb3..12647f6e2 100644 --- a/tests/test_integration.py +++ b/tests/test_integration.py @@ -1,3 +1,4 @@ +import time from unittest.mock import MagicMock import pytest @@ -440,6 +441,7 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, leverage, fee, mocker) assert trade.open_rate == 1.99 assert trade.orders[-1].price == 1.96 assert trade.orders[-1].cost == 120 * leverage + time.sleep(0.1) # Replace new order with diff. order at a lower price freqtrade.strategy.adjust_entry_price = MagicMock(return_value=1.95) diff --git a/tests/testdata/config.tests.json b/tests/testdata/config.tests.json new file mode 100644 index 000000000..fdfa97350 --- /dev/null +++ b/tests/testdata/config.tests.json @@ -0,0 +1,74 @@ +{ + "max_open_trades": 3, + "stake_currency": "BTC", + "stake_amount": 0.05, + "tradable_balance_ratio": 0.99, + "fiat_display_currency": "USD", + "timeframe": "5m", + "dry_run": true, + "cancel_open_orders_on_exit": false, + "unfilledtimeout": { + "entry": 5, + "exit": 5, + "exit_timeout_count": 0, + "unit": "minutes" + }, + "entry_pricing": { + "price_side": "same", + "use_order_book": true, + "order_book_top": 1, + "price_last_balance": 0.0, + "check_depth_of_market": { + "enabled": false, + "bids_to_ask_delta": 1 + } + }, + "exit_pricing":{ + "price_side": "same", + "use_order_book": true, + "order_book_top": 1 + }, + "exchange": { + "name": "gate", + "key": "your_exchange_key", + "secret": "your_exchange_secret", + "ccxt_config": {}, + "ccxt_async_config": {}, + "pair_whitelist": [ + "ETH/BTC", + "LTC/BTC", + "ETC/BTC", + "XLM/BTC", + "XRP/BTC", + "ADA/BTC", + "DOT/BTC" + ], + "pair_blacklist": [ + "DOGE/BTC" + ] + }, + "pairlists": [ + {"method": "StaticPairList"} + ], + "telegram": { + "enabled": false, + "token": "your_telegram_token", + "chat_id": "your_telegram_chat_id" + }, + "api_server": { + "enabled": false, + "listen_ip_address": "127.0.0.1", + "listen_port": 8080, + "verbosity": "error", + "jwt_secret_key": "somethingrandom", + "CORS_origins": [], + "username": "freqtrader", + "password": "SuperSecurePassword" + }, + "bot_name": "freqtrade", + "initial_state": "running", + "force_entry_enable": false, + "internals": { + "process_throttle_secs": 5 + } +}