diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 1725a7d13..f29f599a6 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -149,8 +149,8 @@ class Backtesting: # To avoid using data from future, we use buy/sell signals shifted # from the previous candle - df_analyzed.loc[:, 'buy'] = df_analyzed['buy'].shift(1) - df_analyzed.loc[:, 'sell'] = df_analyzed['sell'].shift(1) + df_analyzed.loc[:, 'buy'] = df_analyzed.loc[:, 'buy'].shift(1) + df_analyzed.loc[:, 'sell'] = df_analyzed.loc[:, 'sell'].shift(1) df_analyzed.drop(df_analyzed.head(1).index, inplace=True) diff --git a/freqtrade/strategy/interface.py b/freqtrade/strategy/interface.py index 89a38bf54..c6f711b74 100644 --- a/freqtrade/strategy/interface.py +++ b/freqtrade/strategy/interface.py @@ -467,8 +467,11 @@ class IStrategy(ABC): """ Creates a dataframe and populates indicators for given candle (OHLCV) data Used by optimize operations only, not during dry / live runs. + Using .copy() to get a fresh copy of the dataframe for every strategy run. + Has positive effects on memory usage for whatever reason - also when + using only one strategy. """ - return {pair: self.advise_indicators(pair_data, {'pair': pair}) + return {pair: self.advise_indicators(pair_data.copy(), {'pair': pair}) for pair, pair_data in data.items()} def advise_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/tests/strategy/test_interface.py b/tests/strategy/test_interface.py index 8bc399f42..1c31aeb6a 100644 --- a/tests/strategy/test_interface.py +++ b/tests/strategy/test_interface.py @@ -168,6 +168,19 @@ def test_ohlcvdata_to_dataframe(default_conf, testdatadir) -> None: assert len(processed['UNITTEST/BTC']) == 102 # partial candle was removed +def test_ohlcvdata_to_dataframe_copy(mocker, default_conf, testdatadir) -> None: + default_conf.update({'strategy': 'DefaultStrategy'}) + strategy = StrategyResolver.load_strategy(default_conf) + aimock = mocker.patch('freqtrade.strategy.interface.IStrategy.advise_indicators') + timerange = TimeRange.parse_timerange('1510694220-1510700340') + data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], timerange=timerange, + fill_up_missing=True) + strategy.ohlcvdata_to_dataframe(data) + assert aimock.call_count == 1 + # Ensure that a copy of the dataframe is passed to advice_indicators + assert aimock.call_args_list[0][0][0] is not data + + def test_min_roi_reached(default_conf, fee) -> None: # Use list to confirm sequence does not matter