From 4599c80e79aeafbdf4ec0508a7dee2f3951af23e Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 07:10:25 +0100 Subject: [PATCH 01/19] Add trailing-stop to strategy --- freqtrade/resolvers/strategy_resolver.py | 27 ++++++++++++++++ freqtrade/strategy/interface.py | 5 +++ freqtrade/tests/strategy/test_strategy.py | 39 +++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index c1d967383..ee00b419b 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -56,6 +56,33 @@ class StrategyResolver(IResolver): else: config['stoploss'] = self.strategy.stoploss + if 'trailing_stop' in config: + self.strategy.trailing_stop = config['trailing_stop'] + logger.info( + "Override strategy 'trailing_stop' with value in config file: %s.", + config['trailing_stop'] + ) + elif hasattr(self.strategy, "trailing_stop"): + config['trailing_stop'] = self.strategy.trailing_stop + + if 'trailing_stop_positive' in config: + self.strategy.trailing_stop_positive = config['trailing_stop_positive'] + logger.info( + "Override strategy 'trailing_stop_positive' with value in config file: %s.", + config['trailing_stop_positive'] + ) + elif hasattr(self.strategy, "trailing_stop_positive"): + config['trailing_stop_positive'] = self.strategy.trailing_stop_positive + + if 'trailing_stop_positive_offset' in config: + self.strategy.trailing_stop_positive_offset = config['trailing_stop_positive_offset'] + logger.info( + "Override strategy 'trailing_stop_positive_offset' with value in config file: %s.", + config['trailing_stop_positive_offset'] + ) + elif hasattr(self.strategy, "trailing_stop_positive_offset"): + config['trailing_stop_positive_offset'] = self.strategy.trailing_stop_positive_offset + if 'ticker_interval' in config: self.strategy.ticker_interval = config['ticker_interval'] logger.info( diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 694430fd6..a6569ec19 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -67,6 +67,11 @@ class IStrategy(ABC): # associated stoploss stoploss: float + # trailing stoploss + trailing_stop: bool = False + trailing_stop_positive: float + trailing_stop_positive_offset: float + # associated ticker interval ticker_interval: str diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index 08d95fc5d..676ffc95b 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -150,6 +150,45 @@ def test_strategy_override_stoploss(caplog): ) in caplog.record_tuples +def test_strategy_override_trailing_stop(caplog): + caplog.set_level(logging.INFO) + config = { + 'strategy': 'DefaultStrategy', + 'trailing_stop': True + } + resolver = StrategyResolver(config) + + assert resolver.strategy.trailing_stop + assert isinstance(resolver.strategy.trailing_stop, bool) + assert ('freqtrade.resolvers.strategy_resolver', + logging.INFO, + "Override strategy 'trailing_stop' with value in config file: True." + ) in caplog.record_tuples + + +def test_strategy_override_trailing_stop_positive(caplog): + caplog.set_level(logging.INFO) + config = { + 'strategy': 'DefaultStrategy', + 'trailing_stop_positive': -0.1, + 'trailing_stop_positive_offset': -0.2 + + } + resolver = StrategyResolver(config) + + assert resolver.strategy.trailing_stop_positive == -0.1 + assert ('freqtrade.resolvers.strategy_resolver', + logging.INFO, + "Override strategy 'trailing_stop_positive' with value in config file: -0.1." + ) in caplog.record_tuples + + assert resolver.strategy.trailing_stop_positive_offset == -0.2 + assert ('freqtrade.resolvers.strategy_resolver', + logging.INFO, + "Override strategy 'trailing_stop_positive' with value in config file: -0.1." + ) in caplog.record_tuples + + def test_strategy_override_ticker_interval(caplog): caplog.set_level(logging.INFO) From 5e234420325469d145f3c79e2d078eac5f1a1c08 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 07:20:38 +0100 Subject: [PATCH 02/19] Simplify StrategyResolver by code deduplication --- freqtrade/resolvers/strategy_resolver.py | 104 +++++----------------- freqtrade/tests/strategy/test_strategy.py | 3 +- 2 files changed, 24 insertions(+), 83 deletions(-) diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index ee00b419b..3be73f982 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -38,87 +38,35 @@ class StrategyResolver(IResolver): self.strategy: IStrategy = self._load_strategy(strategy_name, config=config, extra_dir=config.get('strategy_path')) - # Set attributes # Check if we need to override configuration - if 'minimal_roi' in config: - self.strategy.minimal_roi = config['minimal_roi'] - logger.info("Override strategy 'minimal_roi' with value in config file: %s.", - config['minimal_roi']) - else: - config['minimal_roi'] = self.strategy.minimal_roi + self._override_attribute_helper(config, "minimal_roi") + self._override_attribute_helper(config, "ticker_interval") + self._override_attribute_helper(config, "stoploss") + self._override_attribute_helper(config, "trailing_stop") + self._override_attribute_helper(config, "trailing_stop_positive") + self._override_attribute_helper(config, "trailing_stop_positive_offset") + self._override_attribute_helper(config, "process_only_new_candles") + self._override_attribute_helper(config, "order_types") + self._override_attribute_helper(config, "order_time_in_force") - if 'stoploss' in config: - self.strategy.stoploss = config['stoploss'] - logger.info( - "Override strategy 'stoploss' with value in config file: %s.", config['stoploss'] - ) - else: - config['stoploss'] = self.strategy.stoploss + # Sort and apply type conversions + self.strategy.minimal_roi = OrderedDict(sorted( + {int(key): value for (key, value) in self.strategy.minimal_roi.items()}.items(), + key=lambda t: t[0])) + self.strategy.stoploss = float(self.strategy.stoploss) - if 'trailing_stop' in config: - self.strategy.trailing_stop = config['trailing_stop'] - logger.info( - "Override strategy 'trailing_stop' with value in config file: %s.", - config['trailing_stop'] - ) - elif hasattr(self.strategy, "trailing_stop"): - config['trailing_stop'] = self.strategy.trailing_stop + self._strategy_sanity_validations() - if 'trailing_stop_positive' in config: - self.strategy.trailing_stop_positive = config['trailing_stop_positive'] - logger.info( - "Override strategy 'trailing_stop_positive' with value in config file: %s.", - config['trailing_stop_positive'] - ) - elif hasattr(self.strategy, "trailing_stop_positive"): - config['trailing_stop_positive'] = self.strategy.trailing_stop_positive - - if 'trailing_stop_positive_offset' in config: - self.strategy.trailing_stop_positive_offset = config['trailing_stop_positive_offset'] - logger.info( - "Override strategy 'trailing_stop_positive_offset' with value in config file: %s.", - config['trailing_stop_positive_offset'] - ) - elif hasattr(self.strategy, "trailing_stop_positive_offset"): - config['trailing_stop_positive_offset'] = self.strategy.trailing_stop_positive_offset - - if 'ticker_interval' in config: - self.strategy.ticker_interval = config['ticker_interval'] - logger.info( - "Override strategy 'ticker_interval' with value in config file: %s.", - config['ticker_interval'] - ) - else: - config['ticker_interval'] = self.strategy.ticker_interval - - if 'process_only_new_candles' in config: - self.strategy.process_only_new_candles = config['process_only_new_candles'] - logger.info( - "Override process_only_new_candles 'process_only_new_candles' " - "with value in config file: %s.", config['process_only_new_candles'] - ) - else: - config['process_only_new_candles'] = self.strategy.process_only_new_candles - - if 'order_types' in config: - self.strategy.order_types = config['order_types'] - logger.info( - "Override strategy 'order_types' with value in config file: %s.", - config['order_types'] - ) - else: - config['order_types'] = self.strategy.order_types - - if 'order_time_in_force' in config: - self.strategy.order_time_in_force = config['order_time_in_force'] - logger.info( - "Override strategy 'order_time_in_force' with value in config file: %s.", - config['order_time_in_force'] - ) - else: - config['order_time_in_force'] = self.strategy.order_time_in_force + def _override_attribute_helper(self, config, attribute: str): + if attribute in config: + setattr(self.strategy, attribute, config[attribute]) + logger.info("Override strategy '%s' with value in config file: %s.", + attribute, config[attribute]) + elif hasattr(self.strategy, attribute): + config[attribute] = getattr(self.strategy, attribute) + def _strategy_sanity_validations(self): if not all(k in self.strategy.order_types for k in constants.REQUIRED_ORDERTYPES): raise ImportError(f"Impossible to load Strategy '{self.strategy.__class__.__name__}'. " f"Order-types mapping is incomplete.") @@ -127,12 +75,6 @@ class StrategyResolver(IResolver): raise ImportError(f"Impossible to load Strategy '{self.strategy.__class__.__name__}'. " f"Order-time-in-force mapping is incomplete.") - # Sort and apply type conversions - self.strategy.minimal_roi = OrderedDict(sorted( - {int(key): value for (key, value) in self.strategy.minimal_roi.items()}.items(), - key=lambda t: t[0])) - self.strategy.stoploss = float(self.strategy.stoploss) - def _load_strategy( self, strategy_name: str, config: dict, extra_dir: Optional[str] = None) -> IStrategy: """ diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index 676ffc95b..b2315f381 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -217,8 +217,7 @@ def test_strategy_override_process_only_new_candles(caplog): assert resolver.strategy.process_only_new_candles assert ('freqtrade.resolvers.strategy_resolver', logging.INFO, - "Override process_only_new_candles 'process_only_new_candles' " - "with value in config file: True." + "Override strategy 'process_only_new_candles' with value in config file: True." ) in caplog.record_tuples From a7dc6b18aaeb27f0460af9555c277e83ac5c4be0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 07:22:19 +0100 Subject: [PATCH 03/19] Overridable attributs as list --- freqtrade/resolvers/strategy_resolver.py | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 3be73f982..d3972d0ba 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -40,15 +40,19 @@ class StrategyResolver(IResolver): extra_dir=config.get('strategy_path')) # Set attributes # Check if we need to override configuration - self._override_attribute_helper(config, "minimal_roi") - self._override_attribute_helper(config, "ticker_interval") - self._override_attribute_helper(config, "stoploss") - self._override_attribute_helper(config, "trailing_stop") - self._override_attribute_helper(config, "trailing_stop_positive") - self._override_attribute_helper(config, "trailing_stop_positive_offset") - self._override_attribute_helper(config, "process_only_new_candles") - self._override_attribute_helper(config, "order_types") - self._override_attribute_helper(config, "order_time_in_force") + attributes = ["minimal_roi", + "ticker_interval", + "stoploss", + "trailing_stop", + "trailing_stop_positive", + "trailing_stop_positive_offset", + "process_only_new_candles", + "order_types", + "order_time_in_force" + ] + for attribute in attributes: + self._override_attribute_helper(config, attribute) + # Sort and apply type conversions self.strategy.minimal_roi = OrderedDict(sorted( From 00c5ac56d438162a704a2e32d708014445b825a6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 07:24:15 +0100 Subject: [PATCH 04/19] Print startup strategy summary --- freqtrade/resolvers/strategy_resolver.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index d3972d0ba..35c02599a 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -52,6 +52,9 @@ class StrategyResolver(IResolver): ] for attribute in attributes: self._override_attribute_helper(config, attribute) + if attribute in config: + logger.info("Strategy using %s: %s", attribute, config[attribute]) + # Sort and apply type conversions From cacb9ef3add0bec62dfcf0ce6ceb9cb9a803f2a0 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 07:25:35 +0100 Subject: [PATCH 05/19] Loop twice --- freqtrade/resolvers/strategy_resolver.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 35c02599a..15451a7d9 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -52,6 +52,9 @@ class StrategyResolver(IResolver): ] for attribute in attributes: self._override_attribute_helper(config, attribute) + + # Loop this list again to have output combined + for attribute in attributes: if attribute in config: logger.info("Strategy using %s: %s", attribute, config[attribute]) From f32232ba9602fb85b38a902aa256f0f192a0eb55 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 07:31:03 +0100 Subject: [PATCH 06/19] Add documentation for stoploss in strategy --- docs/configuration.md | 8 ++++---- docs/stoploss.md | 3 +++ freqtrade/resolvers/strategy_resolver.py | 2 -- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index eb58e4925..44db019d0 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -19,10 +19,10 @@ The table below will list all configuration parameters. | `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. | `process_only_new_candles` | false | No | If set to true indicators are processed only once a new candle arrives. If false each loop populates the indicators, this will mean the same candle is processed many times creating system load but can be useful of your strategy depends on tick data not only candle. Can be set either in Configuration or in the strategy. | `minimal_roi` | See below | No | Set the threshold in percent the bot will use to sell a trade. More information below. If set, this parameter will override `minimal_roi` from your strategy file. -| `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. If set, this parameter will override `stoploss` from your strategy file. -| `trailing_stop` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). -| `trailing_stop_positve` | 0 | No | Changes stop-loss once profit has been reached. -| `trailing_stop_positve_offset` | 0 | No | Offset on when to apply `trailing_stop_positive`. Percentage value which should be positive. +| `stoploss` | -0.10 | No | Value of the stoploss in percent used by the bot. More information below. More details in the [stoploss documentation](stoploss.md). +| `trailing_stop` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). More details in the [stoploss documentation](stoploss.md). +| `trailing_stop_positve` | 0 | No | Changes stop-loss once profit has been reached. More details in the [stoploss documentation](stoploss.md). +| `trailing_stop_positve_offset` | 0 | No | Offset on when to apply `trailing_stop_positive`. Percentage value which should be positive. More details in the [stoploss documentation](stoploss.md). | `unfilledtimeout.buy` | 10 | Yes | How long (in minutes) the bot will wait for an unfilled buy order to complete, after which the order will be cancelled. | `unfilledtimeout.sell` | 10 | Yes | How long (in minutes) the bot will wait for an unfilled sell order to complete, after which the order will be cancelled. | `bid_strategy.ask_last_balance` | 0.0 | Yes | Set the bidding price. More information below. diff --git a/docs/stoploss.md b/docs/stoploss.md index f34050a85..0278e7bbb 100644 --- a/docs/stoploss.md +++ b/docs/stoploss.md @@ -6,6 +6,9 @@ At this stage the bot contains the following stoploss support modes: 2. trailing stop loss, defined in the configuration 3. trailing stop loss, custom positive loss, defined in configuration +!!! Note + All stoploss properties can be configured in eihter Strategy or configuration. Configuration values override strategy values. + ## Static Stop Loss This is very simple, basically you define a stop loss of x in your strategy file or alternative in the configuration, which diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index 15451a7d9..0d1c9f9a0 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -58,8 +58,6 @@ class StrategyResolver(IResolver): if attribute in config: logger.info("Strategy using %s: %s", attribute, config[attribute]) - - # Sort and apply type conversions self.strategy.minimal_roi = OrderedDict(sorted( {int(key): value for (key, value) in self.strategy.minimal_roi.items()}.items(), From f7b96d839d644474321f5cca34b79aa28fc8a419 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 09:03:14 +0100 Subject: [PATCH 07/19] Add trailing options to sample-strategy --- user_data/strategies/test_strategy.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/user_data/strategies/test_strategy.py b/user_data/strategies/test_strategy.py index f72677e3d..048b398c7 100644 --- a/user_data/strategies/test_strategy.py +++ b/user_data/strategies/test_strategy.py @@ -42,6 +42,11 @@ class TestStrategy(IStrategy): # This attribute will be overridden if the config file contains "stoploss" stoploss = -0.10 + # trailing stoploss + trailing_stop = False + trailing_stop_positive = 0.01 + trailing_stop_positive_offset = None # Disabled / not configured + # Optimal ticker interval for the strategy ticker_interval = '5m' From dbf8ec6a20ffd5df1d8d7cd0cc0ed9735ada52d9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 19:24:07 +0100 Subject: [PATCH 08/19] Update dockerfile to python 3.7.2 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 24cce0049..ded74bd18 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:3.7.0-slim-stretch +FROM python:3.7.2-slim-stretch RUN apt-get update \ && apt-get -y install curl build-essential \ From 94aa1aaff3e47d320197ac3bd24e521411e844fc Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 19:34:45 +0100 Subject: [PATCH 09/19] fix typo, improve doc sequence --- mkdocs.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/mkdocs.yml b/mkdocs.yml index 07672884a..36428d1c1 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -4,18 +4,18 @@ nav: - Installation: installation.md - Configuration: configuration.md - Start the bot: bot-usage.md - - Optimization: bot-optimization.md + - Stoploss: stoploss.md + - Custom Strategy: bot-optimization.md + - Telegram: telegram-usage.md + - Web Hook: webhook-config.md - Backtesting: backtesting.md - Hyperopt: hyperopt.md - - Stoploss: stoploss.md - - Telegram: telegram-usage.md - - Plotting: plotting.md - Edge positioning: edge.md - - Web Hook: webhook-config.md + - Plotting: plotting.md - FAQ: faq.md - - Contributors guide: developer.md - - SQL Cheatsheeet: sql_cheatsheet.md + - SQL Cheatsheet: sql_cheatsheet.md - Sanbox testing: sandbox-testing.md + - Contributors guide: developer.md theme: name: material logo: 'images/logo.png' @@ -40,4 +40,4 @@ markdown_extensions: - pymdownx.superfences - pymdownx.tasklist: custom_checkbox: true - - pymdownx.tilde \ No newline at end of file + - pymdownx.tilde From 31da42a485396d3440ca97d9de242a3828adc115 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 19:50:46 +0100 Subject: [PATCH 10/19] Show error when no python is found --- setup.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup.sh b/setup.sh index 58aabd507..11a36380c 100755 --- a/setup.sh +++ b/setup.sh @@ -17,6 +17,11 @@ function check_installed_python() { return fi + if [ -z ${PYTHON} ]; then + echo "No usable python found. Please make sure to have python3.6 or python3.7 installed" + exit 1 + fi + } function updateenv () { From 9e5e485d0a090de77200c781d9618e280357433d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 19:51:28 +0100 Subject: [PATCH 11/19] put --upgrade flag to the same location in subsequent requests --- setup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.sh b/setup.sh index 11a36380c..f2ebb7009 100755 --- a/setup.sh +++ b/setup.sh @@ -31,7 +31,7 @@ function updateenv () { source .env/bin/activate echo "pip3 install in-progress. Please wait..." pip3 install --quiet --upgrade pip - pip3 install --quiet -r requirements.txt --upgrade + pip3 install --quiet --upgrade -r requirements.txt pip3 install --quiet -r requirements.txt read -p "Do you want to install dependencies for dev [Y/N]? " From 337ebdeccb02fc75bdd4b0c92ddf02129c84afee Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 19:51:51 +0100 Subject: [PATCH 12/19] Avoid installing ta-lib multiple times --- setup.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/setup.sh b/setup.sh index f2ebb7009..3ab013250 100755 --- a/setup.sh +++ b/setup.sh @@ -50,6 +50,11 @@ function updateenv () { # Install tab lib function install_talib () { + if [ -f /usr/local/lib/libta_lib.a ]; then + echo "ta-lib already installed, skipping" + return + fi + cd build_helpers tar zxvf ta-lib-0.4.0-src.tar.gz cd ta-lib From 01e2dc17b5c506da86373cee27aa98ac7e3bbd2d Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 20:00:10 +0100 Subject: [PATCH 13/19] Remove whitespace in fucntion definition --- setup.sh | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/setup.sh b/setup.sh index 3ab013250..9e969be2b 100755 --- a/setup.sh +++ b/setup.sh @@ -24,7 +24,7 @@ function check_installed_python() { } -function updateenv () { +function updateenv() { echo "-------------------------" echo "Update your virtual env" echo "-------------------------" @@ -49,7 +49,7 @@ function updateenv () { } # Install tab lib -function install_talib () { +function install_talib() { if [ -f /usr/local/lib/libta_lib.a ]; then echo "ta-lib already installed, skipping" return @@ -67,7 +67,7 @@ function install_talib () { } # Install bot MacOS -function install_macos () { +function install_macos() { if [ ! -x "$(command -v brew)" ] then echo "-------------------------" @@ -81,7 +81,7 @@ function install_macos () { } # Install bot Debian_ubuntu -function install_debian () { +function install_debian() { sudo add-apt-repository ppa:jonathonf/python-3.6 sudo apt-get update sudo apt-get install python3.6 python3.6-venv python3.6-dev build-essential autoconf libtool pkg-config make wget git @@ -89,13 +89,13 @@ function install_debian () { } # Upgrade the bot -function update () { +function update() { git pull updateenv } # Reset Develop or Master branch -function reset () { +function reset() { echo "----------------------------" echo "Reset branch and virtual env" echo "----------------------------" @@ -139,7 +139,7 @@ function test_and_fix_python_on_mac() { fi } -function config_generator () { +function config_generator() { echo "Starting to generate config.json" echo @@ -185,7 +185,7 @@ function config_generator () { } -function config () { +function config() { echo "-------------------------" echo "Config file generator" @@ -211,7 +211,7 @@ function config () { echo } -function install () { +function install() { echo "-------------------------" echo "Install mandatory dependencies" echo "-------------------------" @@ -239,7 +239,7 @@ function install () { echo "You can now use the bot by executing 'source .env/bin/activate; python freqtrade/main.py'." } -function plot () { +function plot() { echo " ----------------------------------------- Install dependencies for Plotting scripts @@ -248,7 +248,7 @@ Install dependencies for Plotting scripts pip install plotly --upgrade } -function help () { +function help() { echo "usage:" echo " -i,--install Install freqtrade from scratch" echo " -u,--update Command git pull to update." From f088f43b406613ad1fd9aff7c8db1909129a7c40 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 20:04:54 +0100 Subject: [PATCH 14/19] Install numpy before py_find_1st --- setup.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.sh b/setup.sh index 9e969be2b..55bd746e1 100755 --- a/setup.sh +++ b/setup.sh @@ -30,9 +30,9 @@ function updateenv() { echo "-------------------------" source .env/bin/activate echo "pip3 install in-progress. Please wait..." - pip3 install --quiet --upgrade pip + # Install numpy first to have py_find_1st install clean + pip3 install --quiet --upgrade pip numpy pip3 install --quiet --upgrade -r requirements.txt - pip3 install --quiet -r requirements.txt read -p "Do you want to install dependencies for dev [Y/N]? " if [[ $REPLY =~ ^[Yy]$ ]] From 506237e3b4973e84b7022657b441c6ba0e08d2ca Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 5 Jan 2019 20:06:15 +0100 Subject: [PATCH 15/19] Don't use --quiet on pip install this hides errors from users and complicates debugging in case of problmes --- setup.sh | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/setup.sh b/setup.sh index 55bd746e1..2005f4f82 100755 --- a/setup.sh +++ b/setup.sh @@ -31,14 +31,13 @@ function updateenv() { source .env/bin/activate echo "pip3 install in-progress. Please wait..." # Install numpy first to have py_find_1st install clean - pip3 install --quiet --upgrade pip numpy - pip3 install --quiet --upgrade -r requirements.txt + pip3 install --upgrade pip numpy + pip3 install --upgrade -r requirements.txt read -p "Do you want to install dependencies for dev [Y/N]? " if [[ $REPLY =~ ^[Yy]$ ]] then - pip3 install --quiet -r requirements-dev.txt --upgrade - pip3 install --quiet -r requirements-dev.txt + pip3 install --upgrade -r requirements-dev.txt else echo "Dev dependencies ignored." fi From a07353d3c72b03145b9753ca981e632081489317 Mon Sep 17 00:00:00 2001 From: Misagh Date: Sun, 6 Jan 2019 12:02:57 +0100 Subject: [PATCH 16/19] fixes few wordings --- setup.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/setup.sh b/setup.sh index 2005f4f82..66d449037 100755 --- a/setup.sh +++ b/setup.sh @@ -26,7 +26,7 @@ function check_installed_python() { function updateenv() { echo "-------------------------" - echo "Update your virtual env" + echo "Updating your virtual env" echo "-------------------------" source .env/bin/activate echo "pip3 install in-progress. Please wait..." @@ -34,7 +34,7 @@ function updateenv() { pip3 install --upgrade pip numpy pip3 install --upgrade -r requirements.txt - read -p "Do you want to install dependencies for dev [Y/N]? " + read -p "Do you want to install dependencies for dev [y/N]? " if [[ $REPLY =~ ^[Yy]$ ]] then pip3 install --upgrade -r requirements-dev.txt @@ -70,7 +70,7 @@ function install_macos() { if [ ! -x "$(command -v brew)" ] then echo "-------------------------" - echo "Install Brew" + echo "Installing Brew" echo "-------------------------" /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" fi @@ -96,7 +96,7 @@ function update() { # Reset Develop or Master branch function reset() { echo "----------------------------" - echo "Reset branch and virtual env" + echo "Reseting branch and virtual env" echo "----------------------------" if [ "1" == $(git branch -vv |grep -cE "\* develop|\* master") ] then @@ -142,7 +142,7 @@ function config_generator() { echo "Starting to generate config.json" echo - echo "General configuration" + echo "Generating General configuration" echo "-------------------------" default_max_trades=3 read -p "Max open trades: (Default: $default_max_trades) " max_trades @@ -161,13 +161,13 @@ function config_generator() { fiat_currency=${fiat_currency:-$default_fiat_currency} echo - echo "Exchange config generator" + echo "Generating exchange config " echo "------------------------" read -p "Exchange API key: " api_key read -p "Exchange API Secret: " api_secret echo - echo "Telegram config generator" + echo "Generating Telegram config" echo "-------------------------" read -p "Telegram Token: " token read -p "Telegram Chat_id: " chat_id @@ -187,11 +187,11 @@ function config_generator() { function config() { echo "-------------------------" - echo "Config file generator" + echo "Generating config file" echo "-------------------------" if [ -f config.json ] then - read -p "A config file already exist, do you want to override it [Y/N]? " + read -p "A config file already exist, do you want to override it [y/N]? " if [[ $REPLY =~ ^[Yy]$ ]] then config_generator @@ -212,7 +212,7 @@ function config() { function install() { echo "-------------------------" - echo "Install mandatory dependencies" + echo "Installing mandatory dependencies" echo "-------------------------" if [ "$(uname -s)" == "Darwin" ] @@ -233,7 +233,7 @@ function install() { reset config echo "-------------------------" - echo "Run the bot" + echo "Run the bot !" echo "-------------------------" echo "You can now use the bot by executing 'source .env/bin/activate; python freqtrade/main.py'." } @@ -241,7 +241,7 @@ function install() { function plot() { echo " ----------------------------------------- -Install dependencies for Plotting scripts +Installing dependencies for Plotting scripts ----------------------------------------- " pip install plotly --upgrade From 3f82dd05aa85def6b9e3559b763a767531b2cf95 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 6 Jan 2019 13:33:06 +0100 Subject: [PATCH 17/19] Update ccxt from 1.18.101 to 1.18.102 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 551b85456..b07c450f3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.18.101 +ccxt==1.18.102 SQLAlchemy==1.2.15 python-telegram-bot==11.1.0 arrow==0.12.1 From 13800701ce4612d7198e43da0ffbc8c26e57941b Mon Sep 17 00:00:00 2001 From: Gianluca Puglia Date: Sun, 6 Jan 2019 13:47:36 +0100 Subject: [PATCH 18/19] Fix custom db_url ignored if provided by conf.json --- docs/configuration.md | 2 +- freqtrade/configuration.py | 3 -- freqtrade/tests/test_configuration.py | 40 +++++++++++++++++++++++++-- 3 files changed, 39 insertions(+), 6 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 44db019d0..a7deaa60c 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -223,7 +223,7 @@ creating trades. ```json "dry_run": true, -"db_url": "sqlite///tradesv3.dryrun.sqlite", +"db_url": "sqlite:///tradesv3.dryrun.sqlite", ``` 3. Remove your Exchange API key (change them by fake api credentials) diff --git a/freqtrade/configuration.py b/freqtrade/configuration.py index ddcf99c1d..9fd93629f 100644 --- a/freqtrade/configuration.py +++ b/freqtrade/configuration.py @@ -124,9 +124,6 @@ class Configuration(object): if self.args.db_url and self.args.db_url != constants.DEFAULT_DB_PROD_URL: config.update({'db_url': self.args.db_url}) logger.info('Parameter --db-url detected ...') - else: - # Set default here - config.update({'db_url': constants.DEFAULT_DB_PROD_URL}) if config.get('dry_run', False): logger.info('Dry run is enabled') diff --git a/freqtrade/tests/test_configuration.py b/freqtrade/tests/test_configuration.py index ac322c6fc..f5c887089 100644 --- a/freqtrade/tests/test_configuration.py +++ b/freqtrade/tests/test_configuration.py @@ -73,7 +73,6 @@ def test_load_config_max_open_trades_minus_one(default_conf, mocker, caplog) -> args = Arguments([], '').get_parsed_arg() configuration = Configuration(args) validated_conf = configuration.load_config() - print(validated_conf) assert validated_conf['max_open_trades'] > 999999999 assert validated_conf['max_open_trades'] == float('inf') @@ -125,6 +124,43 @@ def test_load_config_with_params(default_conf, mocker) -> None: assert validated_conf.get('strategy_path') == '/some/path' assert validated_conf.get('db_url') == 'sqlite:///someurl' + # Test conf provided db_url prod + conf = default_conf.copy() + conf["dry_run"] = False + conf["db_url"] = "sqlite:///path/to/db.sqlite" + mocker.patch('freqtrade.configuration.open', mocker.mock_open( + read_data=json.dumps(conf) + )) + + arglist = [ + '--strategy', 'TestStrategy', + '--strategy-path', '/some/path' + ] + args = Arguments(arglist, '').get_parsed_arg() + + configuration = Configuration(args) + validated_conf = configuration.load_config() + assert validated_conf.get('db_url') == "sqlite:///path/to/db.sqlite" + + # Test conf provided db_url dry_run + conf = default_conf.copy() + conf["dry_run"] = True + conf["db_url"] = "sqlite:///path/to/db.sqlite" + mocker.patch('freqtrade.configuration.open', mocker.mock_open( + read_data=json.dumps(conf) + )) + + arglist = [ + '--strategy', 'TestStrategy', + '--strategy-path', '/some/path' + ] + args = Arguments(arglist, '').get_parsed_arg() + + configuration = Configuration(args) + validated_conf = configuration.load_config() + assert validated_conf.get('db_url') == "sqlite:///path/to/db.sqlite" + + # Test args provided db_url prod conf = default_conf.copy() conf["dry_run"] = False del conf["db_url"] @@ -142,7 +178,7 @@ def test_load_config_with_params(default_conf, mocker) -> None: validated_conf = configuration.load_config() assert validated_conf.get('db_url') == DEFAULT_DB_PROD_URL - # Test dry=run with ProdURL + # Test args provided db_url dry_run conf = default_conf.copy() conf["dry_run"] = True conf["db_url"] = DEFAULT_DB_PROD_URL From 87cbff5d0e99f896e92ce2e74203446b3c6fb7cf Mon Sep 17 00:00:00 2001 From: Gianluca Puglia Date: Sun, 6 Jan 2019 13:48:27 +0100 Subject: [PATCH 19/19] Fix warning for max_open_trades when edge is enabled --- freqtrade/edge/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 8ccfc90de..76af703aa 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -59,7 +59,7 @@ class Edge(): # checking max_open_trades. it should be -1 as with Edge # the number of trades is determined by position size - if self.config['max_open_trades'] != -1: + if self.config['max_open_trades'] != float('inf'): logger.critical('max_open_trades should be -1 in config !') if self.config['stake_amount'] != constants.UNLIMITED_STAKE_AMOUNT: