From 9b233764153adcf939e72fc45d8a0c54bd865093 Mon Sep 17 00:00:00 2001 From: hroff-1902 Date: Sat, 5 Oct 2019 13:29:59 +0300 Subject: [PATCH] Move experimental settings to ask_strategy --- config.json.example | 10 ++++------ config_binance.json.example | 10 ++++------ config_full.json.example | 10 ++++------ config_kraken.json.example | 6 +++++- docs/configuration.md | 12 ++++++------ freqtrade/constants.py | 8 ++++++-- freqtrade/freqtradebot.py | 8 +++++--- freqtrade/optimize/hyperopt.py | 8 ++++---- freqtrade/resolvers/strategy_resolver.py | 20 ++++++++++---------- freqtrade/strategy/interface.py | 8 ++++---- tests/config_test_comments.json | 5 ----- tests/optimize/test_backtest_detail.py | 2 +- tests/optimize/test_backtesting.py | 17 +++++++++++------ tests/strategy/test_strategy.py | 20 ++++++++++---------- tests/test_freqtradebot.py | 19 ++++++++----------- 15 files changed, 82 insertions(+), 81 deletions(-) diff --git a/config.json.example b/config.json.example index 94084434a..419019030 100644 --- a/config.json.example +++ b/config.json.example @@ -22,7 +22,10 @@ "ask_strategy":{ "use_order_book": false, "order_book_min": 1, - "order_book_max": 9 + "order_book_max": 9, + "use_sell_signal": true, + "sell_profit_only": false, + "ignore_roi_if_buy_signal": false }, "exchange": { "name": "bittrex", @@ -49,11 +52,6 @@ "DOGE/BTC" ] }, - "experimental": { - "use_sell_signal": false, - "sell_profit_only": false, - "ignore_roi_if_buy_signal": false - }, "edge": { "enabled": false, "process_throttle_secs": 3600, diff --git a/config_binance.json.example b/config_binance.json.example index 1d492fc3c..58817a78e 100644 --- a/config_binance.json.example +++ b/config_binance.json.example @@ -22,7 +22,10 @@ "ask_strategy":{ "use_order_book": false, "order_book_min": 1, - "order_book_max": 9 + "order_book_max": 9, + "use_sell_signal": true, + "sell_profit_only": false, + "ignore_roi_if_buy_signal": false }, "exchange": { "name": "binance", @@ -51,11 +54,6 @@ "BNB/BTC" ] }, - "experimental": { - "use_sell_signal": false, - "sell_profit_only": false, - "ignore_roi_if_buy_signal": false - }, "edge": { "enabled": false, "process_throttle_secs": 3600, diff --git a/config_full.json.example b/config_full.json.example index 957967042..c6b229ea3 100644 --- a/config_full.json.example +++ b/config_full.json.example @@ -33,7 +33,10 @@ "ask_strategy":{ "use_order_book": false, "order_book_min": 1, - "order_book_max": 9 + "order_book_max": 9, + "use_sell_signal": true, + "sell_profit_only": false, + "ignore_roi_if_buy_signal": false }, "order_types": { "buy": "limit", @@ -100,11 +103,6 @@ "max_trade_duration_minute": 1440, "remove_pumps": false }, - "experimental": { - "use_sell_signal": false, - "sell_profit_only": false, - "ignore_roi_if_buy_signal": false - }, "telegram": { "enabled": true, "token": "your_telegram_token", diff --git a/config_kraken.json.example b/config_kraken.json.example index ea3677b2d..51aa9a8e9 100644 --- a/config_kraken.json.example +++ b/config_kraken.json.example @@ -22,7 +22,11 @@ "ask_strategy":{ "use_order_book": false, "order_book_min": 1, - "order_book_max": 9 + "order_book_max": 9, + "use_sell_signal": true, + "sell_profit_only": false, + "ignore_roi_if_buy_signal": false + }, "exchange": { "name": "kraken", diff --git a/docs/configuration.md b/docs/configuration.md index 0d902766a..a31650f78 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -65,6 +65,9 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `ask_strategy.use_order_book` | false | Allows selling of open traded pair using the rates in Order Book Asks. | `ask_strategy.order_book_min` | 0 | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. | `ask_strategy.order_book_max` | 0 | Bot will scan from the top min to max Order Book Asks searching for a profitable rate. +| `ask_strategy.use_sell_signal` | true | Use your strategy sell signals in addition to the `minimal_roi`. [Strategy Override](#parameters-in-the-strategy). +| `ask_strategy.sell_profit_only` | false | Wait until you have made a positive profit before taking a sell decision. [Strategy Override](#parameters-in-the-strategy). +| `ask_strategy.ignore_roi_if_buy_signal` | false | Do not sell if the buy-signal is still active. This setting takes preference over `minimal_roi` and `use_sell_signal`. [Strategy Override](#parameters-in-the-strategy). | `order_types` | None | Configure order-types depending on the action (`"buy"`, `"sell"`, `"stoploss"`, `"stoploss_on_exchange"`). [More information below](#understand-order_types). [Strategy Override](#parameters-in-the-strategy). | `order_time_in_force` | None | Configure time in force for buy and sell orders. [More information below](#understand-order_time_in_force). [Strategy Override](#parameters-in-the-strategy). | `exchange.name` | | **Required.** Name of the exchange class to use. [List below](#user-content-what-values-for-exchangename). @@ -78,9 +81,6 @@ Mandatory parameters are marked as **Required**, which means that they are requi | `exchange.ccxt_async_config` | None | Additional CCXT parameters passed to the async ccxt instance. Parameters may differ from exchange to exchange and are documented in the [ccxt documentation](https://ccxt.readthedocs.io/en/latest/manual.html#instantiation) | `exchange.markets_refresh_interval` | 60 | The interval in minutes in which markets are reloaded. | `edge` | false | Please refer to [edge configuration document](edge.md) for detailed explanation. -| `experimental.use_sell_signal` | false | Use your sell strategy in addition of the `minimal_roi`. [Strategy Override](#parameters-in-the-strategy). -| `experimental.sell_profit_only` | false | Waits until you have made a positive profit before taking a sell decision. [Strategy Override](#parameters-in-the-strategy). -| `experimental.ignore_roi_if_buy_signal` | false | Does not sell if the buy-signal is still active. Takes preference over `minimal_roi` and `use_sell_signal`. [Strategy Override](#parameters-in-the-strategy). | `experimental.block_bad_exchanges` | true | Block exchanges known to not work with freqtrade. Leave on default unless you want to test if that exchange works now. | `pairlist.method` | StaticPairList | Use static or dynamic volume-based pairlist. [More information below](#dynamic-pairlists). | `pairlist.config` | None | Additional configuration for dynamic pairlists. [More information below](#dynamic-pairlists). @@ -116,9 +116,9 @@ Values set in the configuration file always overwrite values set in the strategy * `process_only_new_candles` * `order_types` * `order_time_in_force` -* `use_sell_signal` (experimental) -* `sell_profit_only` (experimental) -* `ignore_roi_if_buy_signal` (experimental) +* `use_sell_signal` (ask_strategy) +* `sell_profit_only` (ask_strategy) +* `ignore_roi_if_buy_signal` (ask_strategy) ### Understand stake_amount diff --git a/freqtrade/constants.py b/freqtrade/constants.py index abf43b24d..697bc280f 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -114,7 +114,10 @@ CONF_SCHEMA = { 'properties': { 'use_order_book': {'type': 'boolean'}, 'order_book_min': {'type': 'number', 'minimum': 1}, - 'order_book_max': {'type': 'number', 'minimum': 1, 'maximum': 50} + 'order_book_max': {'type': 'number', 'minimum': 1, 'maximum': 50}, + 'use_sell_signal': {'type': 'boolean'}, + 'sell_profit_only': {'type': 'boolean'}, + 'ignore_roi_if_buy_signal': {'type': 'boolean'} } }, 'order_types': { @@ -144,7 +147,8 @@ CONF_SCHEMA = { 'properties': { 'use_sell_signal': {'type': 'boolean'}, 'sell_profit_only': {'type': 'boolean'}, - 'ignore_roi_if_buy_signal_true': {'type': 'boolean'} + 'ignore_roi_if_buy_signal': {'type': 'boolean'}, + 'block_bad_exchanges': {'type': 'boolean'} } }, 'pairlist': { diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 3f7eab27a..9a2f2cdc4 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -580,13 +580,15 @@ class FreqtradeBot: logger.debug('Handling %s ...', trade) (buy, sell) = (False, False) - experimental = self.config.get('experimental', {}) - if experimental.get('use_sell_signal') or experimental.get('ignore_roi_if_buy_signal'): + + config_ask_strategy = self.config.get('ask_strategy', {}) + + if (config_ask_strategy.get('use_sell_signal', True) or + config_ask_strategy.get('ignore_roi_if_buy_signal')): (buy, sell) = self.strategy.get_signal( trade.pair, self.strategy.ticker_interval, self.dataprovider.ohlcv(trade.pair, self.strategy.ticker_interval)) - config_ask_strategy = self.config.get('ask_strategy', {}) if config_ask_strategy.get('use_order_book', False): logger.info('Using order book for selling...') # logger.debug('Order book %s',orderBook) diff --git a/freqtrade/optimize/hyperopt.py b/freqtrade/optimize/hyperopt.py index a70ff8142..07258a048 100644 --- a/freqtrade/optimize/hyperopt.py +++ b/freqtrade/optimize/hyperopt.py @@ -98,10 +98,10 @@ class Hyperopt: self.position_stacking = self.config.get('position_stacking', False) if self.has_space('sell'): - # Make sure experimental is enabled - if 'experimental' not in self.config: - self.config['experimental'] = {} - self.config['experimental']['use_sell_signal'] = True + # Make sure use_sell_signal is enabled + if 'ask_strategy' not in self.config: + self.config['ask_strategy'] = {} + self.config['ask_strategy']['use_sell_signal'] = True @staticmethod def get_lock_filename(config) -> str: diff --git a/freqtrade/resolvers/strategy_resolver.py b/freqtrade/resolvers/strategy_resolver.py index ca7e1165b..43197e5bc 100644 --- a/freqtrade/resolvers/strategy_resolver.py +++ b/freqtrade/resolvers/strategy_resolver.py @@ -38,13 +38,13 @@ class StrategyResolver(IResolver): config=config, extra_dir=config.get('strategy_path')) - # make sure experimental dict is available - if 'experimental' not in config: - config['experimental'] = {} + # make sure ask_strategy dict is available + if 'ask_strategy' not in config: + config['ask_strategy'] = {} # Set attributes # Check if we need to override configuration - # (Attribute name, default, experimental) + # (Attribute name, default, ask_strategy) attributes = [("minimal_roi", {"0": 10.0}, False), ("ticker_interval", None, False), ("stoploss", None, False), @@ -57,20 +57,20 @@ class StrategyResolver(IResolver): ("order_time_in_force", None, False), ("stake_currency", None, False), ("stake_amount", None, False), - ("use_sell_signal", False, True), + ("use_sell_signal", True, True), ("sell_profit_only", False, True), ("ignore_roi_if_buy_signal", False, True), ] - for attribute, default, experimental in attributes: - if experimental: - self._override_attribute_helper(config['experimental'], attribute, default) + for attribute, default, ask_strategy in attributes: + if ask_strategy: + self._override_attribute_helper(config['ask_strategy'], attribute, default) else: self._override_attribute_helper(config, attribute, default) # Loop this list again to have output combined for attribute, _, exp in attributes: - if exp and attribute in config['experimental']: - logger.info("Strategy using %s: %s", attribute, config['experimental'][attribute]) + if exp and attribute in config['ask_strategy']: + logger.info("Strategy using %s: %s", attribute, config['ask_strategy'][attribute]) elif attribute in config: logger.info("Strategy using %s: %s", attribute, config[attribute]) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 17246ecf7..b35ebabbb 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -309,9 +309,9 @@ class IStrategy(ABC): # Set current rate to high for backtesting sell current_rate = high or rate current_profit = trade.calc_profit_percent(current_rate) - experimental = self.config.get('experimental', {}) + config_ask_strategy = self.config.get('ask_strategy', {}) - if buy and experimental.get('ignore_roi_if_buy_signal', False): + if buy and config_ask_strategy.get('ignore_roi_if_buy_signal', False): # This one is noisy, commented out # logger.debug(f"{trade.pair} - Buy signal still active. sell_flag=False") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) @@ -322,7 +322,7 @@ class IStrategy(ABC): f"sell_type=SellType.ROI") return SellCheckTuple(sell_flag=True, sell_type=SellType.ROI) - if experimental.get('sell_profit_only', False): + if config_ask_strategy.get('sell_profit_only', False): # This one is noisy, commented out # logger.debug(f"{trade.pair} - Checking if trade is profitable...") if trade.calc_profit(rate=rate) <= 0: @@ -330,7 +330,7 @@ class IStrategy(ABC): # logger.debug(f"{trade.pair} - Trade is not profitable. sell_flag=False") return SellCheckTuple(sell_flag=False, sell_type=SellType.NONE) - if sell and not buy and experimental.get('use_sell_signal', False): + if sell and not buy and config_ask_strategy.get('use_sell_signal', True): logger.debug(f"{trade.pair} - Sell signal received. sell_flag=True, " f"sell_type=SellType.SELL_SIGNAL") return SellCheckTuple(sell_flag=True, sell_type=SellType.SELL_SIGNAL) diff --git a/tests/config_test_comments.json b/tests/config_test_comments.json index 85becc3e8..8af39d6ba 100644 --- a/tests/config_test_comments.json +++ b/tests/config_test_comments.json @@ -103,11 +103,6 @@ "max_trade_duration_minute": 1440, "remove_pumps": false }, - "experimental": { - "use_sell_signal": false, - "sell_profit_only": false, - "ignore_roi_if_buy_signal": false - }, "telegram": { // We can now comment out some settings // "enabled": true, diff --git a/tests/optimize/test_backtest_detail.py b/tests/optimize/test_backtest_detail.py index d8a4190e2..a85dc99c3 100644 --- a/tests/optimize/test_backtest_detail.py +++ b/tests/optimize/test_backtest_detail.py @@ -285,7 +285,7 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None: if data.trailing_stop_positive: default_conf["trailing_stop_positive"] = data.trailing_stop_positive default_conf["trailing_stop_positive_offset"] = data.trailing_stop_positive_offset - default_conf["experimental"] = {"use_sell_signal": data.use_sell_signal} + default_conf["ask_strategy"] = {"use_sell_signal": data.use_sell_signal} mocker.patch("freqtrade.exchange.Exchange.get_fee", MagicMock(return_value=0.0)) patch_exchange(mocker) diff --git a/tests/optimize/test_backtesting.py b/tests/optimize/test_backtesting.py index fa40809d8..589896c39 100644 --- a/tests/optimize/test_backtesting.py +++ b/tests/optimize/test_backtesting.py @@ -507,6 +507,7 @@ def test_backtesting_start_no_data(default_conf, mocker, caplog, testdatadir) -> def test_backtest(default_conf, fee, mocker, testdatadir) -> None: + default_conf['ask_strategy']['use_sell_signal'] = False mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) patch_exchange(mocker) backtesting = Backtesting(default_conf) @@ -561,6 +562,7 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None: def test_backtest_1min_ticker_interval(default_conf, fee, mocker, testdatadir) -> None: + default_conf['ask_strategy']['use_sell_signal'] = False mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) patch_exchange(mocker) backtesting = Backtesting(default_conf) @@ -603,8 +605,9 @@ def test_backtest_pricecontours(default_conf, fee, mocker, testdatadir) -> None: # TODO: Evaluate usefullness of this, the patterns and buy-signls are unrealistic mocker.patch('freqtrade.exchange.Exchange.get_fee', fee) tests = [['raise', 19], ['lower', 0], ['sine', 35]] - # We need to enable sell-signal - otherwise it sells on ROI!! - default_conf['experimental'] = {"use_sell_signal": True} + # use_sell_signal is True by default now, it will sell on the sell signal instead of ROI, + # which is what we need here +# default_conf['ask_strategy'] = {"use_sell_signal": True} for [contour, numres] in tests: simple_backtest(default_conf, contour, numres, mocker, testdatadir) @@ -645,8 +648,9 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir): mocker.patch('freqtrade.optimize.backtesting.file_dump_json', MagicMock()) backtest_conf = _make_backtest_conf(mocker, conf=default_conf, pair='UNITTEST/BTC', datadir=testdatadir) - # We need to enable sell-signal - otherwise it sells on ROI!! - default_conf['experimental'] = {"use_sell_signal": True} + # use_sell_signal is True by default now, it will sell on the sell signal instead of ROI, + # which is what we need here +# default_conf['ask_strategy'] = {"use_sell_signal": True} default_conf['ticker_interval'] = '1m' backtesting = Backtesting(default_conf) backtesting.strategy.advise_buy = _trend_alternate # Override @@ -687,8 +691,9 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir) # Remove data for one pair from the beginning of the data data[pair] = data[pair][tres:].reset_index() - # We need to enable sell-signal - otherwise it sells on ROI!! - default_conf['experimental'] = {"use_sell_signal": True} + # use_sell_signal is True by default now, it will sell on the sell signal instead of ROI, + # which is what we need here +# default_conf['ask_strategy'] = {"use_sell_signal": True} default_conf['ticker_interval'] = '5m' backtesting = Backtesting(default_conf) diff --git a/tests/strategy/test_strategy.py b/tests/strategy/test_strategy.py index 6992d1aa5..88e29b40e 100644 --- a/tests/strategy/test_strategy.py +++ b/tests/strategy/test_strategy.py @@ -256,23 +256,23 @@ def test_strategy_override_use_sell_signal(caplog, default_conf): 'strategy': 'DefaultStrategy', }) resolver = StrategyResolver(default_conf) - assert not resolver.strategy.use_sell_signal + assert resolver.strategy.use_sell_signal assert isinstance(resolver.strategy.use_sell_signal, bool) # must be inserted to configuration - assert 'use_sell_signal' in default_conf['experimental'] - assert not default_conf['experimental']['use_sell_signal'] + assert 'use_sell_signal' in default_conf['ask_strategy'] + assert default_conf['ask_strategy']['use_sell_signal'] default_conf.update({ 'strategy': 'DefaultStrategy', - 'experimental': { - 'use_sell_signal': True, + 'ask_strategy': { + 'use_sell_signal': False, }, }) resolver = StrategyResolver(default_conf) - assert resolver.strategy.use_sell_signal + assert not resolver.strategy.use_sell_signal assert isinstance(resolver.strategy.use_sell_signal, bool) - assert log_has("Override strategy 'use_sell_signal' with value in config file: True.", caplog) + assert log_has("Override strategy 'use_sell_signal' with value in config file: False.", caplog) def test_strategy_override_use_sell_profit_only(caplog, default_conf): @@ -284,12 +284,12 @@ def test_strategy_override_use_sell_profit_only(caplog, default_conf): assert not resolver.strategy.sell_profit_only assert isinstance(resolver.strategy.sell_profit_only, bool) # must be inserted to configuration - assert 'sell_profit_only' in default_conf['experimental'] - assert not default_conf['experimental']['sell_profit_only'] + assert 'sell_profit_only' in default_conf['ask_strategy'] + assert not default_conf['ask_strategy']['sell_profit_only'] default_conf.update({ 'strategy': 'DefaultStrategy', - 'experimental': { + 'ask_strategy': { 'sell_profit_only': True, }, }) diff --git a/tests/test_freqtradebot.py b/tests/test_freqtradebot.py index ee28f2e58..a9c85b4c3 100644 --- a/tests/test_freqtradebot.py +++ b/tests/test_freqtradebot.py @@ -1768,8 +1768,6 @@ def test_handle_trade(default_conf, limit_buy_order, limit_sell_order, def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, fee, markets, mocker) -> None: - default_conf.update({'experimental': {'use_sell_signal': True}}) - patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -1824,7 +1822,6 @@ def test_handle_overlpapping_signals(default_conf, ticker, limit_buy_order, def test_handle_trade_roi(default_conf, ticker, limit_buy_order, fee, mocker, markets, caplog) -> None: caplog.set_level(logging.DEBUG) - default_conf.update({'experimental': {'use_sell_signal': True}}) patch_RPCManager(mocker) patch_exchange(mocker) @@ -1856,10 +1853,10 @@ def test_handle_trade_roi(default_conf, ticker, limit_buy_order, caplog) -def test_handle_trade_experimental( +def test_handle_trade_use_sell_signal( default_conf, ticker, limit_buy_order, fee, mocker, markets, caplog) -> None: + # use_sell_signal is True buy default caplog.set_level(logging.DEBUG) - default_conf.update({'experimental': {'use_sell_signal': True}}) patch_RPCManager(mocker) patch_exchange(mocker) mocker.patch.multiple( @@ -2600,7 +2597,7 @@ def test_sell_profit_only_enable_profit(default_conf, limit_buy_order, get_fee=fee, markets=PropertyMock(return_value=markets) ) - default_conf['experimental'] = { + default_conf['ask_strategy'] = { 'use_sell_signal': True, 'sell_profit_only': True, } @@ -2632,7 +2629,7 @@ def test_sell_profit_only_disable_profit(default_conf, limit_buy_order, get_fee=fee, markets=PropertyMock(return_value=markets) ) - default_conf['experimental'] = { + default_conf['ask_strategy'] = { 'use_sell_signal': True, 'sell_profit_only': False, } @@ -2662,7 +2659,7 @@ def test_sell_profit_only_enable_loss(default_conf, limit_buy_order, fee, market get_fee=fee, markets=PropertyMock(return_value=markets) ) - default_conf['experimental'] = { + default_conf['ask_strategy'] = { 'use_sell_signal': True, 'sell_profit_only': True, } @@ -2692,7 +2689,7 @@ def test_sell_profit_only_disable_loss(default_conf, limit_buy_order, fee, marke get_fee=fee, markets=PropertyMock(return_value=markets) ) - default_conf['experimental'] = { + default_conf['ask_strategy'] = { 'use_sell_signal': True, 'sell_profit_only': False, } @@ -2761,7 +2758,7 @@ def test_ignore_roi_if_buy_signal(default_conf, limit_buy_order, fee, markets, m get_fee=fee, markets=PropertyMock(return_value=markets) ) - default_conf['experimental'] = { + default_conf['ask_strategy'] = { 'ignore_roi_if_buy_signal': True } freqtrade = FreqtradeBot(default_conf) @@ -3029,7 +3026,7 @@ def test_disable_ignore_roi_if_buy_signal(default_conf, limit_buy_order, get_fee=fee, markets=PropertyMock(return_value=markets) ) - default_conf['experimental'] = { + default_conf['ask_strategy'] = { 'ignore_roi_if_buy_signal': False } freqtrade = FreqtradeBot(default_conf)