From c38d94df2d226ede89ab71f88dac5169fcd5b628 Mon Sep 17 00:00:00 2001 From: creslin Date: Fri, 3 Aug 2018 07:33:34 +0000 Subject: [PATCH 01/35] Resubmitting - because GIT. This is the last cut that was in #1117 before i closed that PR This PR allows a user to set the flag "ta_on_candle" in their config.json This will change the behaviour of the the bot to only process indicators when there is a new candle to be processed for that pair. The test is made up of "last dataframe row date + pair" is different to last_seen OR ta_on_candle is not True --- docs/configuration.md | 1 + freqtrade/constants.py | 1 + freqtrade/strategy/interface.py | 45 ++++++++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index ff5ce118c..6f03117ba 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -23,6 +23,7 @@ The table below will list all configuration parameters. | `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | No | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes | `fiat_display_currency` | USD | Yes | Fiat currency used to show your profits. More information below. | `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. +| `ta_on_candle` | false | No | if set to true indicators are processed each new candle. If false each bot loop, this will mean the same candle is processed many times creating system load and buy/sell signals. | `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_stoploss` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 87e354455..189b78617 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -53,6 +53,7 @@ CONF_SCHEMA = { }, 'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT}, 'dry_run': {'type': 'boolean'}, + 'ta_on_candle': {'type': 'boolean'}, 'minimal_roi': { 'type': 'object', 'patternProperties': { diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index dfd624393..e68d484de 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -19,6 +19,24 @@ from freqtrade.persistence import Trade logger = logging.getLogger(__name__) +class CandleAnalyzed: + ''' + Maintains candle_row, the last df ['date'], set by analyze_ticker. + This allows analyze_ticker to test if analysed the candle row in dataframe prior. + To not keep testing the same candle data, which is wasteful in CPU and time + ''' + def __init__(self, candle_row=0): + self.candle_row = candle_row + + def get_candle_row(self): + return self._candle_row + + def set_candle_row(self, row): + self._candle_row = row + + candle_row = property(get_candle_row, set_candle_row) + + class SignalType(Enum): """ Enum to distinguish between buy and sell signals @@ -72,6 +90,7 @@ class IStrategy(ABC): def __init__(self, config: dict) -> None: self.config = config + self.r = CandleAnalyzed() @abstractmethod def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: @@ -112,10 +131,30 @@ class IStrategy(ABC): add several TA indicators and buy signal to it :return DataFrame with ticker data and indicator data """ + + # Test if seen this pair and last candle before. dataframe = parse_ticker_dataframe(ticker_history) - dataframe = self.advise_indicators(dataframe, metadata) - dataframe = self.advise_buy(dataframe, metadata) - dataframe = self.advise_sell(dataframe, metadata) + + last_seen = metadata['pair'] + str(dataframe.iloc[-1]['date']) + last_candle_processed = self.r.get_candle_row() + + if last_candle_processed != last_seen or self.config.get('ta_on_candle') is False: + # Defs that only make change on new candle data. + logging.info("TA Analysis Launched") + dataframe = self.advise_indicators(dataframe, metadata) + dataframe = self.advise_buy(dataframe, metadata) + dataframe = self.advise_sell(dataframe, metadata) + + last_seen = metadata['pair'] + str(dataframe.iloc[-1]['date']) + self.r.set_candle_row(last_seen) + else: + dataframe.loc['buy'] = 0 + dataframe.loc['sell'] = 0 + + # Other Defs in strategy that want to be called every loop here + # twitter_sell = self.watch_twitter_feed(dataframe, metadata) + logging.info("Loop Analysis Launched") + return dataframe def get_signal(self, pair: str, interval: str, ticker_hist: List[Dict]) -> Tuple[bool, bool]: From 6b3e8dcc3396753e649e9ecc7e9035810fced686 Mon Sep 17 00:00:00 2001 From: creslin Date: Fri, 3 Aug 2018 08:33:37 +0000 Subject: [PATCH 02/35] holds a dict of each pair last seen. to correctly manage the last seen of a pair. --- freqtrade/strategy/interface.py | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index e68d484de..b44d6997a 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -21,20 +21,20 @@ logger = logging.getLogger(__name__) class CandleAnalyzed: ''' - Maintains candle_row, the last df ['date'], set by analyze_ticker. + Maintains dictionary of the last candle date a pair was processed with This allows analyze_ticker to test if analysed the candle row in dataframe prior. To not keep testing the same candle data, which is wasteful in CPU and time ''' - def __init__(self, candle_row=0): - self.candle_row = candle_row + def __init__(self, last_seen = {}): + self.last_seen = last_seen - def get_candle_row(self): - return self._candle_row + def get_last_seen(self, pair): + return self.last_seen.get(pair) - def set_candle_row(self, row): - self._candle_row = row + def set_last_seen(self, pair, candle_date): + self.last_seen[pair] = candle_date - candle_row = property(get_candle_row, set_candle_row) + candle_row = property(get_last_seen, set_last_seen) class SignalType(Enum): @@ -90,7 +90,7 @@ class IStrategy(ABC): def __init__(self, config: dict) -> None: self.config = config - self.r = CandleAnalyzed() + self.candleSeen = CandleAnalyzed() @abstractmethod def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: @@ -135,18 +135,16 @@ class IStrategy(ABC): # Test if seen this pair and last candle before. dataframe = parse_ticker_dataframe(ticker_history) - last_seen = metadata['pair'] + str(dataframe.iloc[-1]['date']) - last_candle_processed = self.r.get_candle_row() + pair = metadata['pair'] + last_candle_seen = self.candleSeen.get_last_seen(pair) - if last_candle_processed != last_seen or self.config.get('ta_on_candle') is False: + if last_candle_seen != dataframe.iloc[-1]['date'] or self.config.get('ta_on_candle') is False: # Defs that only make change on new candle data. logging.info("TA Analysis Launched") dataframe = self.advise_indicators(dataframe, metadata) dataframe = self.advise_buy(dataframe, metadata) dataframe = self.advise_sell(dataframe, metadata) - - last_seen = metadata['pair'] + str(dataframe.iloc[-1]['date']) - self.r.set_candle_row(last_seen) + self.candleSeen.set_last_seen(pair=pair, candle_date=dataframe.iloc[-1]['date']) else: dataframe.loc['buy'] = 0 dataframe.loc['sell'] = 0 From d2a728cebd381bb7e5c1d7de218ab5ae4f31d418 Mon Sep 17 00:00:00 2001 From: creslin Date: Fri, 3 Aug 2018 08:38:13 +0000 Subject: [PATCH 03/35] flake 8 --- freqtrade/strategy/interface.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index b44d6997a..6035f50bf 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -25,7 +25,7 @@ class CandleAnalyzed: This allows analyze_ticker to test if analysed the candle row in dataframe prior. To not keep testing the same candle data, which is wasteful in CPU and time ''' - def __init__(self, last_seen = {}): + def __init__(self, last_seen={}): self.last_seen = last_seen def get_last_seen(self, pair): @@ -136,9 +136,9 @@ class IStrategy(ABC): dataframe = parse_ticker_dataframe(ticker_history) pair = metadata['pair'] - last_candle_seen = self.candleSeen.get_last_seen(pair) + last_seen = self.candleSeen.get_last_seen(pair) - if last_candle_seen != dataframe.iloc[-1]['date'] or self.config.get('ta_on_candle') is False: + if last_seen != dataframe.iloc[-1]['date'] or self.config.get('ta_on_candle') is False: # Defs that only make change on new candle data. logging.info("TA Analysis Launched") dataframe = self.advise_indicators(dataframe, metadata) From 1fef384bbae17b18e7d4842d47581a1cef7dae4f Mon Sep 17 00:00:00 2001 From: creslin Date: Fri, 3 Aug 2018 08:40:16 +0000 Subject: [PATCH 04/35] flake 8 --- freqtrade/strategy/interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 6035f50bf..a17fdb625 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -135,7 +135,7 @@ class IStrategy(ABC): # Test if seen this pair and last candle before. dataframe = parse_ticker_dataframe(ticker_history) - pair = metadata['pair'] + pair = metadata.get('pair') last_seen = self.candleSeen.get_last_seen(pair) if last_seen != dataframe.iloc[-1]['date'] or self.config.get('ta_on_candle') is False: From 71b0e15182cf4bd45f816df0d3c1196f066cc2d9 Mon Sep 17 00:00:00 2001 From: creslin Date: Fri, 3 Aug 2018 08:45:24 +0000 Subject: [PATCH 05/35] updated configuration.md --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index 6f03117ba..4c43975d7 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -23,7 +23,7 @@ The table below will list all configuration parameters. | `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | No | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes | `fiat_display_currency` | USD | Yes | Fiat currency used to show your profits. More information below. | `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. -| `ta_on_candle` | false | No | if set to true indicators are processed each new candle. If false each bot loop, this will mean the same candle is processed many times creating system load and buy/sell signals. +| `ta_on_candle` | false | No | if set to true indicators are processed each new candle. If false each bot loop, 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. | `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_stoploss` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). From 10ab6c7ffa54442c2d90e0b95653adb0be776bdc Mon Sep 17 00:00:00 2001 From: creslin Date: Fri, 3 Aug 2018 09:14:16 +0000 Subject: [PATCH 06/35] Removed unneeded property code --- freqtrade/strategy/interface.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index a17fdb625..5e0837767 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -34,8 +34,6 @@ class CandleAnalyzed: def set_last_seen(self, pair, candle_date): self.last_seen[pair] = candle_date - candle_row = property(get_last_seen, set_last_seen) - class SignalType(Enum): """ From d1306a21778d9ad15928bbd4449152d3f890b213 Mon Sep 17 00:00:00 2001 From: Matthias Date: Mon, 6 Aug 2018 19:15:30 +0200 Subject: [PATCH 07/35] Fix failing tests when metadata in `analyze_ticker` is actually used --- freqtrade/tests/test_dataframe.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/tests/test_dataframe.py b/freqtrade/tests/test_dataframe.py index ce144e118..dc030d630 100644 --- a/freqtrade/tests/test_dataframe.py +++ b/freqtrade/tests/test_dataframe.py @@ -14,7 +14,7 @@ def load_dataframe_pair(pairs, strategy): assert isinstance(pairs[0], str) dataframe = ld[pairs[0]] - dataframe = strategy.analyze_ticker(dataframe, pairs[0]) + dataframe = strategy.analyze_ticker(dataframe, {'pair': pairs[0]}) return dataframe From 98730939d4a3b0607774b8668d771505c6b1c287 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 13:02:41 +0200 Subject: [PATCH 08/35] Refactor to use a plain dict * check config-setting first - avoids any call to "candle_seen" eventually --- freqtrade/strategy/interface.py | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 5e0837767..0f03cddb3 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -19,22 +19,6 @@ from freqtrade.persistence import Trade logger = logging.getLogger(__name__) -class CandleAnalyzed: - ''' - Maintains dictionary of the last candle date a pair was processed with - This allows analyze_ticker to test if analysed the candle row in dataframe prior. - To not keep testing the same candle data, which is wasteful in CPU and time - ''' - def __init__(self, last_seen={}): - self.last_seen = last_seen - - def get_last_seen(self, pair): - return self.last_seen.get(pair) - - def set_last_seen(self, pair, candle_date): - self.last_seen[pair] = candle_date - - class SignalType(Enum): """ Enum to distinguish between buy and sell signals @@ -86,9 +70,11 @@ class IStrategy(ABC): # associated ticker interval ticker_interval: str + # Dict to determine if analysis is necessary + candle_seen: Dict[str, datetime] = {} + def __init__(self, config: dict) -> None: self.config = config - self.candleSeen = CandleAnalyzed() @abstractmethod def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: @@ -133,23 +119,23 @@ class IStrategy(ABC): # Test if seen this pair and last candle before. dataframe = parse_ticker_dataframe(ticker_history) - pair = metadata.get('pair') - last_seen = self.candleSeen.get_last_seen(pair) + pair = str(metadata.get('pair')) - if last_seen != dataframe.iloc[-1]['date'] or self.config.get('ta_on_candle') is False: + if (not self.config.get('ta_on_candle') or + self.candle_seen.get(pair, None) != dataframe.iloc[-1]['date']): # Defs that only make change on new candle data. - logging.info("TA Analysis Launched") + logging.debug("TA Analysis Launched") dataframe = self.advise_indicators(dataframe, metadata) dataframe = self.advise_buy(dataframe, metadata) dataframe = self.advise_sell(dataframe, metadata) - self.candleSeen.set_last_seen(pair=pair, candle_date=dataframe.iloc[-1]['date']) + self.candle_seen[pair] = dataframe.iloc[-1]['date'] else: dataframe.loc['buy'] = 0 dataframe.loc['sell'] = 0 # Other Defs in strategy that want to be called every loop here # twitter_sell = self.watch_twitter_feed(dataframe, metadata) - logging.info("Loop Analysis Launched") + logging.debug("Loop Analysis Launched") return dataframe From 029d61b8c5a3fdcfc0d352dc04bbd1d3ad46f79c Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 13:12:12 +0200 Subject: [PATCH 09/35] Add ta_on_candle descripton to support strategy --- docs/configuration.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 4c43975d7..64e75c51e 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -22,8 +22,8 @@ The table below will list all configuration parameters. | `stake_amount` | 0.05 | Yes | Amount of crypto-currency your bot will use for each trade. Per default, the bot will use (0.05 BTC x 3) = 0.15 BTC in total will be always engaged. Set it to 'unlimited' to allow the bot to use all avaliable balance. | `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | No | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes | `fiat_display_currency` | USD | Yes | Fiat currency used to show your profits. More information below. -| `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. -| `ta_on_candle` | false | No | if set to true indicators are processed each new candle. If false each bot loop, 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. +| `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. +| `ta_on_candle` | 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_stoploss` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). From c4e43039f20accf285d201bd6e93177d768697d1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 19:24:00 +0200 Subject: [PATCH 10/35] Allow control from strategy --- freqtrade/strategy/interface.py | 6 +++++- freqtrade/strategy/resolver.py | 9 +++++++++ user_data/strategies/test_strategy.py | 3 +++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 0f03cddb3..494f65547 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -70,6 +70,9 @@ class IStrategy(ABC): # associated ticker interval ticker_interval: str + # run "populate_indicators" only for new candle + ta_on_candle: bool = False + # Dict to determine if analysis is necessary candle_seen: Dict[str, datetime] = {} @@ -121,7 +124,8 @@ class IStrategy(ABC): pair = str(metadata.get('pair')) - if (not self.config.get('ta_on_candle') or + # always run if ta_on_candle is set to true + if (not self.ta_on_candle or self.candle_seen.get(pair, None) != dataframe.iloc[-1]['date']): # Defs that only make change on new candle data. logging.debug("TA Analysis Launched") diff --git a/freqtrade/strategy/resolver.py b/freqtrade/strategy/resolver.py index 7aeec300e..1a15ba63f 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -65,6 +65,15 @@ class StrategyResolver(object): else: config['ticker_interval'] = self.strategy.ticker_interval + if 'ta_on_candle' in config: + self.strategy.ta_on_candle = config['ta_on_candle'] + logger.info( + "Override ta_on_candle \'ta_on_candle\' with value in config file: %s.", + config['ta_on_candle'] + ) + else: + config['ta_on_candle'] = self.strategy.ta_on_candle + # Sort and apply type conversions self.strategy.minimal_roi = OrderedDict(sorted( {int(key): value for (key, value) in self.strategy.minimal_roi.items()}.items(), diff --git a/user_data/strategies/test_strategy.py b/user_data/strategies/test_strategy.py index 80c238d92..7c3892b77 100644 --- a/user_data/strategies/test_strategy.py +++ b/user_data/strategies/test_strategy.py @@ -45,6 +45,9 @@ class TestStrategy(IStrategy): # Optimal ticker interval for the strategy ticker_interval = '5m' + # run "populate_indicators" only for new candle + ta_on_candle = False + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ Adds several different TA indicators to the given DataFrame From e36067afd35c00799965b3f0aeb14a1ebc7576f6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 19:53:47 +0200 Subject: [PATCH 11/35] refactor candle_seen to private --- freqtrade/strategy/interface.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 494f65547..f8965d440 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -74,10 +74,11 @@ class IStrategy(ABC): ta_on_candle: bool = False # Dict to determine if analysis is necessary - candle_seen: Dict[str, datetime] = {} + _candle_seen: Dict[str, datetime] = {} def __init__(self, config: dict) -> None: self.config = config + self._candle_seen = {} @abstractmethod def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: @@ -126,16 +127,16 @@ class IStrategy(ABC): # always run if ta_on_candle is set to true if (not self.ta_on_candle or - self.candle_seen.get(pair, None) != dataframe.iloc[-1]['date']): + self._candle_seen.get(pair, None) != dataframe.iloc[-1]['date']): # Defs that only make change on new candle data. logging.debug("TA Analysis Launched") dataframe = self.advise_indicators(dataframe, metadata) dataframe = self.advise_buy(dataframe, metadata) dataframe = self.advise_sell(dataframe, metadata) - self.candle_seen[pair] = dataframe.iloc[-1]['date'] + self._candle_seen[pair] = dataframe.iloc[-1]['date'] else: - dataframe.loc['buy'] = 0 - dataframe.loc['sell'] = 0 + dataframe['buy'] = 0 + dataframe['sell'] = 0 # Other Defs in strategy that want to be called every loop here # twitter_sell = self.watch_twitter_feed(dataframe, metadata) From 4ece5d6d7ac9f20c3f868dc5569e12a9e709bdcc Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 20:02:24 +0200 Subject: [PATCH 12/35] Add tests for ta_on_candle --- freqtrade/tests/strategy/test_interface.py | 57 ++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/freqtrade/tests/strategy/test_interface.py b/freqtrade/tests/strategy/test_interface.py index ec4ab0fd4..45f650938 100644 --- a/freqtrade/tests/strategy/test_interface.py +++ b/freqtrade/tests/strategy/test_interface.py @@ -105,3 +105,60 @@ def test_tickerdata_to_dataframe(default_conf) -> None: tickerlist = {'UNITTEST/BTC': tick} data = strategy.tickerdata_to_dataframe(tickerlist) assert len(data['UNITTEST/BTC']) == 99 # partial candle was removed + + +def test_analyze_ticker_default(ticker_history, mocker) -> None: + + ind_mock = MagicMock(side_effect=lambda x, meta: x) + buy_mock = MagicMock(side_effect=lambda x, meta: x) + sell_mock = MagicMock(side_effect=lambda x, meta: x) + mocker.patch.multiple( + 'freqtrade.strategy.interface.IStrategy', + advise_indicators=ind_mock, + advise_buy=buy_mock, + advise_sell=sell_mock, + + ) + strategy = DefaultStrategy({}) + ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) + assert ind_mock.call_count == 1 + assert buy_mock.call_count == 1 + assert buy_mock.call_count == 1 + + ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) + # No analysis happens as ta_on_candle is true + assert ind_mock.call_count == 2 + assert buy_mock.call_count == 2 + assert buy_mock.call_count == 2 + + +def test_analyze_ticker_only_once(ticker_history, mocker) -> None: + + ind_mock = MagicMock(side_effect=lambda x, meta: x) + buy_mock = MagicMock(side_effect=lambda x, meta: x) + sell_mock = MagicMock(side_effect=lambda x, meta: x) + mocker.patch.multiple( + 'freqtrade.strategy.interface.IStrategy', + advise_indicators=ind_mock, + advise_buy=buy_mock, + advise_sell=sell_mock, + + ) + strategy = DefaultStrategy({}) + strategy.ta_on_candle = True + + ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) + assert ind_mock.call_count == 1 + assert buy_mock.call_count == 1 + assert buy_mock.call_count == 1 + + ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) + # No analysis happens as ta_on_candle is true + assert ind_mock.call_count == 1 + assert buy_mock.call_count == 1 + assert buy_mock.call_count == 1 + # only skipped analyze adds buy and sell columns, otherwise it's all mocked + assert 'buy' in ret + assert 'sell' in ret + assert ret['buy'].sum() == 0 + assert ret['sell'].sum() == 0 From df960241bd7e627c1aeec356c62e4b6f7322c882 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 20:07:01 +0200 Subject: [PATCH 13/35] Add log-message for skipped candle and tests --- freqtrade/tests/strategy/test_interface.py | 23 ++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/freqtrade/tests/strategy/test_interface.py b/freqtrade/tests/strategy/test_interface.py index 45f650938..75deecda2 100644 --- a/freqtrade/tests/strategy/test_interface.py +++ b/freqtrade/tests/strategy/test_interface.py @@ -107,8 +107,8 @@ def test_tickerdata_to_dataframe(default_conf) -> None: assert len(data['UNITTEST/BTC']) == 99 # partial candle was removed -def test_analyze_ticker_default(ticker_history, mocker) -> None: - +def test_analyze_ticker_default(ticker_history, mocker, caplog) -> None: + caplog.set_level(logging.DEBUG) ind_mock = MagicMock(side_effect=lambda x, meta: x) buy_mock = MagicMock(side_effect=lambda x, meta: x) sell_mock = MagicMock(side_effect=lambda x, meta: x) @@ -125,15 +125,23 @@ def test_analyze_ticker_default(ticker_history, mocker) -> None: assert buy_mock.call_count == 1 assert buy_mock.call_count == 1 + assert log_has('TA Analysis Launched', caplog.record_tuples) + assert not log_has('Skippinig TA Analysis for already analyzed candle', + caplog.record_tuples) + caplog.clear() + ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) # No analysis happens as ta_on_candle is true assert ind_mock.call_count == 2 assert buy_mock.call_count == 2 assert buy_mock.call_count == 2 + assert log_has('TA Analysis Launched', caplog.record_tuples) + assert not log_has('Skippinig TA Analysis for already analyzed candle', + caplog.record_tuples) -def test_analyze_ticker_only_once(ticker_history, mocker) -> None: - +def test_analyze_ticker_skip_analyze(ticker_history, mocker, caplog) -> None: + caplog.set_level(logging.DEBUG) ind_mock = MagicMock(side_effect=lambda x, meta: x) buy_mock = MagicMock(side_effect=lambda x, meta: x) sell_mock = MagicMock(side_effect=lambda x, meta: x) @@ -151,6 +159,10 @@ def test_analyze_ticker_only_once(ticker_history, mocker) -> None: assert ind_mock.call_count == 1 assert buy_mock.call_count == 1 assert buy_mock.call_count == 1 + assert log_has('TA Analysis Launched', caplog.record_tuples) + assert not log_has('Skippinig TA Analysis for already analyzed candle', + caplog.record_tuples) + caplog.clear() ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) # No analysis happens as ta_on_candle is true @@ -162,3 +174,6 @@ def test_analyze_ticker_only_once(ticker_history, mocker) -> None: assert 'sell' in ret assert ret['buy'].sum() == 0 assert ret['sell'].sum() == 0 + assert not log_has('TA Analysis Launched', caplog.record_tuples) + assert log_has('Skippinig TA Analysis for already analyzed candle', + caplog.record_tuples) From 3b2f161573712c4823e591fe41d6e9e0ce758aea Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 20:12:45 +0200 Subject: [PATCH 14/35] Add test for ta_on_candle override --- freqtrade/strategy/interface.py | 1 + freqtrade/tests/strategy/test_strategy.py | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index f8965d440..3957139d2 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -135,6 +135,7 @@ class IStrategy(ABC): dataframe = self.advise_sell(dataframe, metadata) self._candle_seen[pair] = dataframe.iloc[-1]['date'] else: + logging.debug("Skippinig TA Analysis for already analyzed candle") dataframe['buy'] = 0 dataframe['sell'] = 0 diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index 0cbd9f22c..d45715a69 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -130,7 +130,7 @@ def test_strategy_override_minimal_roi(caplog): assert resolver.strategy.minimal_roi[0] == 0.5 assert ('freqtrade.strategy.resolver', logging.INFO, - 'Override strategy \'minimal_roi\' with value in config file.' + "Override strategy 'minimal_roi' with value in config file." ) in caplog.record_tuples @@ -145,7 +145,7 @@ def test_strategy_override_stoploss(caplog): assert resolver.strategy.stoploss == -0.5 assert ('freqtrade.strategy.resolver', logging.INFO, - 'Override strategy \'stoploss\' with value in config file: -0.5.' + "Override strategy 'stoploss' with value in config file: -0.5." ) in caplog.record_tuples @@ -161,10 +161,25 @@ def test_strategy_override_ticker_interval(caplog): assert resolver.strategy.ticker_interval == 60 assert ('freqtrade.strategy.resolver', logging.INFO, - 'Override strategy \'ticker_interval\' with value in config file: 60.' + "Override strategy 'ticker_interval' with value in config file: 60." ) in caplog.record_tuples +def test_strategy_override_ta_on_candle(caplog): + caplog.set_level(logging.INFO) + + config = { + 'strategy': 'DefaultStrategy', + 'ta_on_candle': True + } + resolver = StrategyResolver(config) + + assert resolver.strategy.ta_on_candle == True + assert ('freqtrade.strategy.resolver', + logging.INFO, + "Override ta_on_candle 'ta_on_candle' with value in config file: True." + ) in caplog.record_tuples + def test_deprecate_populate_indicators(result): default_location = path.join(path.dirname(path.realpath(__file__))) resolver = StrategyResolver({'strategy': 'TestStrategyLegacy', From b008649d790e74f81b114ef82c36b05da4045648 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 20:13:07 +0200 Subject: [PATCH 15/35] Remove unnecessary quote escaping --- freqtrade/strategy/resolver.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/strategy/resolver.py b/freqtrade/strategy/resolver.py index 1a15ba63f..75fb99d69 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -44,14 +44,14 @@ class StrategyResolver(object): # 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.") + logger.info("Override strategy 'minimal_roi' with value in config file.") else: config['minimal_roi'] = self.strategy.minimal_roi if 'stoploss' in config: self.strategy.stoploss = config['stoploss'] logger.info( - "Override strategy \'stoploss\' with value in config file: %s.", config['stoploss'] + "Override strategy 'stoploss' with value in config file: %s.", config['stoploss'] ) else: config['stoploss'] = self.strategy.stoploss @@ -59,7 +59,7 @@ class StrategyResolver(object): if 'ticker_interval' in config: self.strategy.ticker_interval = config['ticker_interval'] logger.info( - "Override strategy \'ticker_interval\' with value in config file: %s.", + "Override strategy 'ticker_interval' with value in config file: %s.", config['ticker_interval'] ) else: @@ -68,7 +68,7 @@ class StrategyResolver(object): if 'ta_on_candle' in config: self.strategy.ta_on_candle = config['ta_on_candle'] logger.info( - "Override ta_on_candle \'ta_on_candle\' with value in config file: %s.", + "Override ta_on_candle 'ta_on_candle' with value in config file: %s.", config['ta_on_candle'] ) else: From 56768f1a617c4fca5c648ffcbe95b3e53b7d7f9c Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 9 Aug 2018 20:17:55 +0200 Subject: [PATCH 16/35] Flake8 in tests ... --- freqtrade/tests/strategy/test_interface.py | 4 ++-- freqtrade/tests/strategy/test_strategy.py | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/freqtrade/tests/strategy/test_interface.py b/freqtrade/tests/strategy/test_interface.py index 75deecda2..e96dfb024 100644 --- a/freqtrade/tests/strategy/test_interface.py +++ b/freqtrade/tests/strategy/test_interface.py @@ -120,7 +120,7 @@ def test_analyze_ticker_default(ticker_history, mocker, caplog) -> None: ) strategy = DefaultStrategy({}) - ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) + strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) assert ind_mock.call_count == 1 assert buy_mock.call_count == 1 assert buy_mock.call_count == 1 @@ -130,7 +130,7 @@ def test_analyze_ticker_default(ticker_history, mocker, caplog) -> None: caplog.record_tuples) caplog.clear() - ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) + strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) # No analysis happens as ta_on_candle is true assert ind_mock.call_count == 2 assert buy_mock.call_count == 2 diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index d45715a69..14b1ef1bd 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -174,12 +174,13 @@ def test_strategy_override_ta_on_candle(caplog): } resolver = StrategyResolver(config) - assert resolver.strategy.ta_on_candle == True + assert resolver.strategy.ta_on_candle assert ('freqtrade.strategy.resolver', logging.INFO, "Override ta_on_candle 'ta_on_candle' with value in config file: True." ) in caplog.record_tuples + def test_deprecate_populate_indicators(result): default_location = path.join(path.dirname(path.realpath(__file__))) resolver = StrategyResolver({'strategy': 'TestStrategyLegacy', From c5efcace4747999c72c02f6218e86e263c7bca20 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Aug 2018 12:49:39 +0200 Subject: [PATCH 17/35] change pip3.6 to pip3 --- docs/installation.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 4de05c121..7d0076673 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -335,11 +335,11 @@ cp config.json.example config.json #### 2. Setup your Python virtual environment (virtualenv) ```bash -python3.6 -m venv .env +python3 -m venv .env source .env/bin/activate -pip3.6 install --upgrade pip -pip3.6 install -r requirements.txt -pip3.6 install -e . +pip3 install --upgrade pip +pip3 install -r requirements.txt +pip3 install -e . ``` #### 3. Run the Bot From 1a9c085f10793ccb21ca676f80bce9b161bb0181 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sun, 26 Aug 2018 20:09:12 +0200 Subject: [PATCH 18/35] Restructure install documentation --- docs/installation.md | 151 ++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 87 deletions(-) diff --git a/docs/installation.md b/docs/installation.md index 7d0076673..525c6f187 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -8,7 +8,6 @@ To understand how to set up the bot please read the [Bot Configuration](https:// * [Table of Contents](#table-of-contents) * [Easy Installation - Linux Script](#easy-installation---linux-script) -* [Manual installation](#manual-installation) * [Automatic Installation - Docker](#automatic-installation---docker) * [Custom Linux MacOS Installation](#custom-installation) - [Requirements](#requirements) @@ -56,34 +55,6 @@ Reset parameter will hard reset your branch (only if you are on `master` or `dev Config parameter is a `config.json` configurator. This script will ask you questions to setup your bot and create your `config.json`. -## Manual installation - Linux/MacOS - -The following steps are made for Linux/MacOS environment - -### 1. Clone the repo - -```bash -git clone git@github.com:freqtrade/freqtrade.git -git checkout develop -cd freqtrade -``` - -### 2. Create the config file - -Switch `"dry_run": true,` - -```bash -cp config.json.example config.json -vi config.json -``` - -### 3. Build your docker image and run it - -```bash -docker build -t freqtrade . -docker run --rm -v /etc/localtime:/etc/localtime:ro -v `pwd`/config.json:/freqtrade/config.json -it freqtrade -``` - ------ ## Automatic Installation - Docker @@ -196,7 +167,7 @@ docker run -d \ freqtrade --db-url sqlite:///tradesv3.sqlite ``` -NOTE: db-url defaults to `sqlite:///tradesv3.sqlite` but it defaults to `sqlite://` if `dry_run=True` is being used. +*Note*: db-url defaults to `sqlite:///tradesv3.sqlite` but it defaults to `sqlite://` if `dry_run=True` is being used. To override this behaviour use a custom db-url value: i.e.: `--db-url sqlite:///tradesv3.dryrun.sqlite` ### 6. Monitor your Docker instance @@ -211,14 +182,15 @@ docker stop freqtrade docker start freqtrade ``` -You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. +For more information on how to operate Docker, please refer to the [official Docker documentation](https://docs.docker.com/). + +*Note*: You do not need to rebuild the image for configuration changes, it will suffice to edit `config.json` and restart the container. ### 7. Backtest with docker The following assumes that the above steps (1-4) have been completed successfully. Also, backtest-data should be available at `~/.freqtrade/user_data/`. - ``` bash docker run -d \ --name freqtrade \ @@ -238,12 +210,13 @@ Head over to the [Backtesting Documentation](https://github.com/freqtrade/freqtr ## Custom Installation We've included/collected install instructions for Ubuntu 16.04, MacOS, and Windows. These are guidelines and your success may vary with other distros. +OS Specific steps are listed first, the [common](#common) section below is necessary for all systems. ### Requirements Click each one for install guide: -* [Python 3.6.x](http://docs.python-guide.org/en/latest/starting/installation/), note the bot was not tested on Python >= 3.7.x +* [Python >= 3.6.x](http://docs.python-guide.org/en/latest/starting/installation/) * [pip](https://pip.pypa.io/en/stable/installing/) * [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) * [virtualenv](https://virtualenv.pypa.io/en/stable/installation/) (Recommended) @@ -251,7 +224,7 @@ Click each one for install guide: ### Linux - Ubuntu 16.04 -#### 1. Install Python 3.6, Git, and wget +#### Install Python 3.6, Git, and wget ```bash sudo add-apt-repository ppa:jonathonf/python-3.6 @@ -259,7 +232,17 @@ 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 ``` -#### 2. Install TA-Lib +### MacOS + +#### Install Python 3.6, git, wget and ta-lib + +```bash +brew install python3 git wget +``` + +### common + +#### 1. Install TA-Lib Official webpage: https://mrjbq7.github.io/ta-lib/install.html @@ -275,15 +258,60 @@ cd .. rm -rf ./ta-lib* ``` +*Note*: An already downloaded version of ta-lib is included in the repository, as the sourceforge.net source seems to have problems frequently. + +#### 2. Setup your Python virtual environment (virtualenv) + +*Note*: This step is optional but strongly recommended to keep your system organized + +```bash +python3 -m venv .env +source .env/bin/activate +``` + #### 3. Install FreqTrade Clone the git repository: ```bash git clone https://github.com/freqtrade/freqtrade.git + ``` -#### 4. Configure `freqtrade` as a `systemd` service +Optionally checkout the stable/master branch: + +```bash +git checkout master +``` + +#### 4. Initialize the configuration + +```bash +cd freqtrade +cp config.json.example config.json +``` + +> *To edit the config please refer to [Bot Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md).* + +#### 5. Install python dependencies + +``` bash +pip3 install --upgrade pip +pip3 install -r requirements.txt +pip3 install -e . +``` + +#### 6. Run the Bot + +If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins. + +```bash +python3.6 ./freqtrade/main.py -c config.json +``` + +*Note*: If you run the bot on a server, you should consider using [Docker](#automatic-installation---docker) a terminal multiplexer like `screen` or [`tmux`](https://en.wikipedia.org/wiki/Tmux) to avoid that the bot is stopped on logout. + +#### 7. [Optional] Configure `freqtrade` as a `systemd` service From the freqtrade repo... copy `freqtrade.service` to your systemd user directory (usually `~/.config/systemd/user`) and update `WorkingDirectory` and `ExecStart` to match your setup. @@ -299,57 +327,6 @@ For this to be persistent (run when user is logged out) you'll need to enable `l sudo loginctl enable-linger "$USER" ``` -### MacOS - -#### 1. Install Python 3.6, git, wget and ta-lib - -```bash -brew install python3 git wget ta-lib -``` - -#### 2. Install FreqTrade - -Clone the git repository: - -```bash -git clone https://github.com/freqtrade/freqtrade.git -``` - -Optionally checkout the develop branch: - -```bash -git checkout develop -``` - -### Setup Config and virtual env - -#### 1. Initialize the configuration - -```bash -cd freqtrade -cp config.json.example config.json -``` - -> *To edit the config please refer to [Bot Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md).* - -#### 2. Setup your Python virtual environment (virtualenv) - -```bash -python3 -m venv .env -source .env/bin/activate -pip3 install --upgrade pip -pip3 install -r requirements.txt -pip3 install -e . -``` - -#### 3. Run the Bot - -If this is the first time you run the bot, ensure you are running it in Dry-run `"dry_run": true,` otherwise it will start to buy and sell coins. - -```bash -python3.6 ./freqtrade/main.py -c config.json -``` - ------ ## Windows From 9bce6c5f4837c2651ccb06d28fdb78de87b7b11b Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Aug 2018 19:30:26 +0200 Subject: [PATCH 19/35] Add error-section for windows --- docs/installation.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/installation.md b/docs/installation.md index 525c6f187..820383ff6 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -346,7 +346,7 @@ git clone https://github.com/freqtrade/freqtrade.git copy paste `config.json` to ``\path\freqtrade-develop\freqtrade` -#### install ta-lib +#### Install ta-lib Install ta-lib according to the [ta-lib documentation](https://github.com/mrjbq7/ta-lib#windows). @@ -367,5 +367,17 @@ REM >pip install TA_Lib‑0.4.17‑cp36‑cp36m‑win32.whl > Thanks [Owdr](https://github.com/Owdr) for the commands. Source: [Issue #222](https://github.com/freqtrade/freqtrade/issues/222) +#### Error during installation under Windows + +``` bash +error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools +``` + +Unfortunately, many packages requiring compilation don't provide a pre-build wheel. It is therefore mandatory to have a C/C++ compiler installed and available for your python environment to use. + +The easiest way is to download install Microsoft Visual Studio Community [here](https://visualstudio.microsoft.com/downloads/) and make sure to install "Common Tools for Visual C++" to enable building c code on Windows. Unfortunately, this is a heavy download / dependency (~4Gb) so you might want to consider WSL or docker first. + +--- + Now you have an environment ready, the next step is [Bot Configuration](https://github.com/freqtrade/freqtrade/blob/develop/docs/configuration.md)... From c9ee528050cd5d964e50021ad9592d0f74cc2b88 Mon Sep 17 00:00:00 2001 From: Matthias Date: Tue, 28 Aug 2018 22:06:46 +0200 Subject: [PATCH 20/35] Add section about raspberry / conda to install.md --- docs/installation.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/installation.md b/docs/installation.md index 820383ff6..0fecfcf78 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -232,6 +232,23 @@ 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 ``` +#### Raspberry Pi / Raspbian + +Before installing FreqTrade on a Raspberry Pi running the official Raspbian Image, make sure you have at least Python 3.6 installed. The default image only provides Python 3.5. Probably the easiest way to get a recent version of python is [miniconda](https://repo.continuum.io/miniconda/). + +The following assumes that miniconda3 is installed and available in your environment, and is installed. +It's recommended to use (mini)conda for this as installation/compilation of `scipy` and `pandas` takes a long time. + +``` bash +conda config --add channels rpi +conda install python=3.6 +conda create -n freqtrade python=3.6 +conda install scipy pandas + +pip install -r requirements.txt +pip install -e . +``` + ### MacOS #### Install Python 3.6, git, wget and ta-lib From a1bd30aa605228510349c2ec97671eb28af282de Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 29 Aug 2018 19:59:25 +0200 Subject: [PATCH 21/35] Fix documentation string --- docs/configuration.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 757310957..3866effd2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -25,9 +25,9 @@ The table below will list all configuration parameters. | `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. | `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_stoploss` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). -| `trailing_stoploss_positve` | 0 | No | Changes stop-loss once profit has been reached. -| `trailing_stoploss_positve_offset` | 0 | No | Offset on when to apply `trailing_stoploss_positive`. Percentage value which should be positive. +| `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. | `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. From 35c5d4f5804b211b97889301e93cd872c35b1fba Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 30 Aug 2018 14:28:07 +0200 Subject: [PATCH 22/35] Update ccxt from 1.17.205 to 1.17.210 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fe64ea684..fcffbf887 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.205 +ccxt==1.17.210 SQLAlchemy==1.2.11 python-telegram-bot==10.1.0 arrow==0.12.1 From 3ed97fe5e880dd0cb3ffcad238a9e0fa9f340b20 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 30 Aug 2018 14:28:08 +0200 Subject: [PATCH 23/35] Update python-telegram-bot from 10.1.0 to 11.0.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fcffbf887..0e0685487 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ ccxt==1.17.210 SQLAlchemy==1.2.11 -python-telegram-bot==10.1.0 +python-telegram-bot==11.0.0 arrow==0.12.1 cachetools==2.1.0 requests==2.19.1 From 9560cb80566efb3414ed0bbbc7da5a93318f345f Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 30 Aug 2018 14:28:10 +0200 Subject: [PATCH 24/35] Update pytest from 3.7.3 to 3.7.4 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 0e0685487..3a605a663 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ scipy==1.1.0 jsonschema==2.6.0 numpy==1.15.1 TA-Lib==0.4.17 -pytest==3.7.3 +pytest==3.7.4 pytest-mock==1.10.0 pytest-cov==2.5.1 tabulate==0.8.2 From fa5c8e4bb11519ec3302beed5324b7c85ba19635 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sat, 1 Sep 2018 14:28:06 +0200 Subject: [PATCH 25/35] Update ccxt from 1.17.210 to 1.17.216 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3a605a663..5cb061855 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.210 +ccxt==1.17.216 SQLAlchemy==1.2.11 python-telegram-bot==11.0.0 arrow==0.12.1 From cb46aeb73cc277a2883c75ba3feadeb7ad2c132b Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Sep 2018 19:50:45 +0200 Subject: [PATCH 26/35] rename variable to be more expressive --- freqtrade/strategy/interface.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 3957139d2..a9838a5cb 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -74,11 +74,11 @@ class IStrategy(ABC): ta_on_candle: bool = False # Dict to determine if analysis is necessary - _candle_seen: Dict[str, datetime] = {} + _last_candle_seen_per_pair: Dict[str, datetime] = {} def __init__(self, config: dict) -> None: self.config = config - self._candle_seen = {} + self._last_candle_seen_per_pair = {} @abstractmethod def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: @@ -119,7 +119,6 @@ class IStrategy(ABC): add several TA indicators and buy signal to it :return DataFrame with ticker data and indicator data """ - # Test if seen this pair and last candle before. dataframe = parse_ticker_dataframe(ticker_history) @@ -127,13 +126,13 @@ class IStrategy(ABC): # always run if ta_on_candle is set to true if (not self.ta_on_candle or - self._candle_seen.get(pair, None) != dataframe.iloc[-1]['date']): + self._last_candle_seen_per_pair.get(pair, None) != dataframe.iloc[-1]['date']): # Defs that only make change on new candle data. logging.debug("TA Analysis Launched") dataframe = self.advise_indicators(dataframe, metadata) dataframe = self.advise_buy(dataframe, metadata) dataframe = self.advise_sell(dataframe, metadata) - self._candle_seen[pair] = dataframe.iloc[-1]['date'] + self._last_candle_seen_per_pair[pair] = dataframe.iloc[-1]['date'] else: logging.debug("Skippinig TA Analysis for already analyzed candle") dataframe['buy'] = 0 From d35d3bb38cf9de50b0d6d2a234297d6c8b892cee Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Sep 2018 19:52:40 +0200 Subject: [PATCH 27/35] rename ta_on_candle to process_only_new_candles be more expressive --- docs/configuration.md | 2 +- freqtrade/constants.py | 2 +- freqtrade/strategy/interface.py | 6 +++--- freqtrade/strategy/resolver.py | 10 +++++----- freqtrade/tests/strategy/test_interface.py | 6 +++--- freqtrade/tests/strategy/test_strategy.py | 9 +++++---- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index 64e75c51e..1d5fc0922 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -23,7 +23,7 @@ The table below will list all configuration parameters. | `ticker_interval` | [1m, 5m, 30m, 1h, 1d] | No | The ticker interval to use (1min, 5 min, 30 min, 1 hour or 1 day). Default is 5 minutes | `fiat_display_currency` | USD | Yes | Fiat currency used to show your profits. More information below. | `dry_run` | true | Yes | Define if the bot must be in Dry-run or production mode. -| `ta_on_candle` | 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. +| `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_stoploss` | false | No | Enables trailing stop-loss (based on `stoploss` in either configuration or strategy file). diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 189b78617..92b090432 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -53,7 +53,7 @@ CONF_SCHEMA = { }, 'fiat_display_currency': {'type': 'string', 'enum': SUPPORTED_FIAT}, 'dry_run': {'type': 'boolean'}, - 'ta_on_candle': {'type': 'boolean'}, + 'process_only_new_candles': {'type': 'boolean'}, 'minimal_roi': { 'type': 'object', 'patternProperties': { diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index a9838a5cb..05ede129e 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -71,7 +71,7 @@ class IStrategy(ABC): ticker_interval: str # run "populate_indicators" only for new candle - ta_on_candle: bool = False + process_only_new_candles: bool = False # Dict to determine if analysis is necessary _last_candle_seen_per_pair: Dict[str, datetime] = {} @@ -124,8 +124,8 @@ class IStrategy(ABC): pair = str(metadata.get('pair')) - # always run if ta_on_candle is set to true - if (not self.ta_on_candle or + # always run if process_only_new_candles is set to true + if (not self.process_only_new_candles or self._last_candle_seen_per_pair.get(pair, None) != dataframe.iloc[-1]['date']): # Defs that only make change on new candle data. logging.debug("TA Analysis Launched") diff --git a/freqtrade/strategy/resolver.py b/freqtrade/strategy/resolver.py index 75fb99d69..35aee8d20 100644 --- a/freqtrade/strategy/resolver.py +++ b/freqtrade/strategy/resolver.py @@ -65,14 +65,14 @@ class StrategyResolver(object): else: config['ticker_interval'] = self.strategy.ticker_interval - if 'ta_on_candle' in config: - self.strategy.ta_on_candle = config['ta_on_candle'] + if 'process_only_new_candles' in config: + self.strategy.process_only_new_candles = config['process_only_new_candles'] logger.info( - "Override ta_on_candle 'ta_on_candle' with value in config file: %s.", - config['ta_on_candle'] + "Override process_only_new_candles 'process_only_new_candles' " + "with value in config file: %s.", config['process_only_new_candles'] ) else: - config['ta_on_candle'] = self.strategy.ta_on_candle + config['process_only_new_candles'] = self.strategy.process_only_new_candles # Sort and apply type conversions self.strategy.minimal_roi = OrderedDict(sorted( diff --git a/freqtrade/tests/strategy/test_interface.py b/freqtrade/tests/strategy/test_interface.py index e96dfb024..5afffd87f 100644 --- a/freqtrade/tests/strategy/test_interface.py +++ b/freqtrade/tests/strategy/test_interface.py @@ -131,7 +131,7 @@ def test_analyze_ticker_default(ticker_history, mocker, caplog) -> None: caplog.clear() strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) - # No analysis happens as ta_on_candle is true + # No analysis happens as process_only_new_candles is true assert ind_mock.call_count == 2 assert buy_mock.call_count == 2 assert buy_mock.call_count == 2 @@ -153,7 +153,7 @@ def test_analyze_ticker_skip_analyze(ticker_history, mocker, caplog) -> None: ) strategy = DefaultStrategy({}) - strategy.ta_on_candle = True + strategy.process_only_new_candles = True ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) assert ind_mock.call_count == 1 @@ -165,7 +165,7 @@ def test_analyze_ticker_skip_analyze(ticker_history, mocker, caplog) -> None: caplog.clear() ret = strategy.analyze_ticker(ticker_history, {'pair': 'ETH/BTC'}) - # No analysis happens as ta_on_candle is true + # No analysis happens as process_only_new_candles is true assert ind_mock.call_count == 1 assert buy_mock.call_count == 1 assert buy_mock.call_count == 1 diff --git a/freqtrade/tests/strategy/test_strategy.py b/freqtrade/tests/strategy/test_strategy.py index 14b1ef1bd..8a6e7e617 100644 --- a/freqtrade/tests/strategy/test_strategy.py +++ b/freqtrade/tests/strategy/test_strategy.py @@ -165,19 +165,20 @@ def test_strategy_override_ticker_interval(caplog): ) in caplog.record_tuples -def test_strategy_override_ta_on_candle(caplog): +def test_strategy_override_process_only_new_candles(caplog): caplog.set_level(logging.INFO) config = { 'strategy': 'DefaultStrategy', - 'ta_on_candle': True + 'process_only_new_candles': True } resolver = StrategyResolver(config) - assert resolver.strategy.ta_on_candle + assert resolver.strategy.process_only_new_candles assert ('freqtrade.strategy.resolver', logging.INFO, - "Override ta_on_candle 'ta_on_candle' with value in config file: True." + "Override process_only_new_candles 'process_only_new_candles' " + "with value in config file: True." ) in caplog.record_tuples From 2ec5a536aadf63006e734b8989fbefa904a95945 Mon Sep 17 00:00:00 2001 From: Matthias Date: Sat, 1 Sep 2018 19:53:49 +0200 Subject: [PATCH 28/35] Fix comment location --- freqtrade/strategy/interface.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 05ede129e..6d865f4bc 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -119,11 +119,12 @@ class IStrategy(ABC): add several TA indicators and buy signal to it :return DataFrame with ticker data and indicator data """ - # Test if seen this pair and last candle before. + dataframe = parse_ticker_dataframe(ticker_history) pair = str(metadata.get('pair')) + # Test if seen this pair and last candle before. # always run if process_only_new_candles is set to true if (not self.process_only_new_candles or self._last_candle_seen_per_pair.get(pair, None) != dataframe.iloc[-1]['date']): From adfd8c7f5c29f9294b4b8ba9933af69e227d19c0 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 2 Sep 2018 14:28:06 +0200 Subject: [PATCH 29/35] Update ccxt from 1.17.216 to 1.17.222 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 5cb061855..fbbba7c60 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.216 +ccxt==1.17.222 SQLAlchemy==1.2.11 python-telegram-bot==11.0.0 arrow==0.12.1 From 3831f198e9e75e7258ac24a74392cb5f0510f71f Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Sun, 2 Sep 2018 14:28:07 +0200 Subject: [PATCH 30/35] Update python-telegram-bot from 11.0.0 to 11.1.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index fbbba7c60..38baf322b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,6 @@ ccxt==1.17.222 SQLAlchemy==1.2.11 -python-telegram-bot==11.0.0 +python-telegram-bot==11.1.0 arrow==0.12.1 cachetools==2.1.0 requests==2.19.1 From 754027efedf2c3a996c4480e50a10d93535b7b9b Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Mon, 3 Sep 2018 14:28:07 +0200 Subject: [PATCH 31/35] Update ccxt from 1.17.222 to 1.17.223 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 38baf322b..56ff17113 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.222 +ccxt==1.17.223 SQLAlchemy==1.2.11 python-telegram-bot==11.1.0 arrow==0.12.1 From d62f97dc3bc56896109c5fa711fc23bbc86c650a Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 4 Sep 2018 14:28:06 +0200 Subject: [PATCH 32/35] Update ccxt from 1.17.223 to 1.17.229 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 56ff17113..062c36e98 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.223 +ccxt==1.17.229 SQLAlchemy==1.2.11 python-telegram-bot==11.1.0 arrow==0.12.1 From 27ffce4c3f2c4c7e30f5c0766a427436003c7b01 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Tue, 4 Sep 2018 14:28:08 +0200 Subject: [PATCH 33/35] Update pytest-cov from 2.5.1 to 2.6.0 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 062c36e98..dfcce9ee4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -14,7 +14,7 @@ numpy==1.15.1 TA-Lib==0.4.17 pytest==3.7.4 pytest-mock==1.10.0 -pytest-cov==2.5.1 +pytest-cov==2.6.0 tabulate==0.8.2 coinmarketcap==5.0.3 From a748c0794e4832c7c7f0d7bf6bb501479188afbf Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Wed, 5 Sep 2018 14:28:06 +0200 Subject: [PATCH 34/35] Update ccxt from 1.17.229 to 1.17.231 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index dfcce9ee4..447478f2e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.229 +ccxt==1.17.231 SQLAlchemy==1.2.11 python-telegram-bot==11.1.0 arrow==0.12.1 From 4f583d61c801de09c8778f1512ab69a4598d71e5 Mon Sep 17 00:00:00 2001 From: pyup-bot Date: Thu, 6 Sep 2018 14:28:06 +0200 Subject: [PATCH 35/35] Update ccxt from 1.17.231 to 1.17.233 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 447478f2e..2346f0e25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -ccxt==1.17.231 +ccxt==1.17.233 SQLAlchemy==1.2.11 python-telegram-bot==11.1.0 arrow==0.12.1