diff --git a/freqtrade/configuration/configuration.py b/freqtrade/configuration/configuration.py index defb76b4b..c763d791a 100644 --- a/freqtrade/configuration/configuration.py +++ b/freqtrade/configuration/configuration.py @@ -300,9 +300,10 @@ class Configuration: self._args_to_config(config, argname='hyperoptexportfilename', logstring='Using hyperopt file: {}') - if self.args["lookahead_analysis_exportfilename"] is not None: - self._args_to_config(config, argname='lookahead_analysis_exportfilename', - logstring='saving lookahead analysis results into {} ...') + if self.args.get('lookahead_analysis_exportfilename'): + if self.args["lookahead_analysis_exportfilename"] is not None: + self._args_to_config(config, argname='lookahead_analysis_exportfilename', + logstring='saving lookahead analysis results into {} ...') self._args_to_config(config, argname='epochs', logstring='Parameter --epochs detected ... ' diff --git a/tests/strategy/strats/strategy_test_v3_with_lookahead_bias.py b/tests/strategy/strats/strategy_test_v3_with_lookahead_bias.py new file mode 100644 index 000000000..6cf894586 --- /dev/null +++ b/tests/strategy/strats/strategy_test_v3_with_lookahead_bias.py @@ -0,0 +1,50 @@ +# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement +from pandas import DataFrame +from technical.indicators import ichimoku + +from freqtrade.strategy import IStrategy + + +class strategy_test_v3_with_lookahead_bias(IStrategy): + INTERFACE_VERSION = 3 + + # Minimal ROI designed for the strategy + minimal_roi = { + "40": 0.0, + "30": 0.01, + "20": 0.02, + "0": 0.04 + } + + # Optimal stoploss designed for the strategy + stoploss = -0.10 + + # Optimal timeframe for the strategy + timeframe = '5m' + + # Number of candles the strategy requires before producing valid signals + startup_candle_count: int = 20 + + def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + # bias is introduced here + ichi = ichimoku(dataframe, + conversion_line_period=20, + base_line_periods=60, + laggin_span=120, + displacement=30) + dataframe['chikou_span'] = ichi['chikou_span'] + + return dataframe + + def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + dataframe['close'].shift(-10) > dataframe['close'], + 'enter_long'] = 1 + + return dataframe + + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: + dataframe.loc[ + dataframe['close'].shift(-10) > dataframe['close'], 'exit'] = 1 + + return dataframe diff --git a/tests/test_lookahead_analysis.py b/tests/test_lookahead_analysis.py new file mode 100644 index 000000000..24290798b --- /dev/null +++ b/tests/test_lookahead_analysis.py @@ -0,0 +1,69 @@ +# pragma pylint: disable=missing-docstring, W0212, line-too-long, C0103, unused-argument + +from unittest.mock import PropertyMock + +import numpy as np + +import freqtrade.commands.arguments +import freqtrade.optimize.lookahead_analysis +from freqtrade.configuration import TimeRange +from freqtrade.data import history +from freqtrade.data.converter import clean_ohlcv_dataframe +from freqtrade.data.history import get_timerange +from tests.conftest import patch_exchange + + +def trim_dictlist(dict_list, num): + new = {} + for pair, pair_data in dict_list.items(): + new[pair] = pair_data[num:].reset_index() + return new + + +def load_data_test(what, testdatadir): + timerange = TimeRange.parse_timerange('1510694220-1510700340') + data = history.load_pair_history(pair='UNITTEST/BTC', datadir=testdatadir, + timeframe='1m', timerange=timerange, + drop_incomplete=False, + fill_up_missing=False) + + base = 0.001 + if what == 'raise': + data.loc[:, 'open'] = data.index * base + data.loc[:, 'high'] = data.index * base + 0.0001 + data.loc[:, 'low'] = data.index * base - 0.0001 + data.loc[:, 'close'] = data.index * base + + if what == 'lower': + data.loc[:, 'open'] = 1 - data.index * base + data.loc[:, 'high'] = 1 - data.index * base + 0.0001 + data.loc[:, 'low'] = 1 - data.index * base - 0.0001 + data.loc[:, 'close'] = 1 - data.index * base + + if what == 'sine': + hz = 0.1 # frequency + data.loc[:, 'open'] = np.sin(data.index * hz) / 1000 + base + data.loc[:, 'high'] = np.sin(data.index * hz) / 1000 + base + 0.0001 + data.loc[:, 'low'] = np.sin(data.index * hz) / 1000 + base - 0.0001 + data.loc[:, 'close'] = np.sin(data.index * hz) / 1000 + base + + return {'UNITTEST/BTC': clean_ohlcv_dataframe(data, timeframe='1m', pair='UNITTEST/BTC', + fill_missing=True, drop_incomplete=True)} + + +def test_biased_strategy(default_conf, mocker, caplog) -> None: + + mocker.patch('freqtrade.data.history.get_timerange', get_timerange) + patch_exchange(mocker) + mocker.patch('freqtrade.plugins.pairlistmanager.PairListManager.whitelist', + PropertyMock(return_value=['UNITTEST/BTC'])) + + default_conf['timeframe'] = '5m' + default_conf['timerange'] = '-1510694220' + default_conf['strategy'] = 'strategy_test_v3_with_lookahead_bias' + default_conf['strategy_path'] = 'tests/strategy/strats' + + strategy_obj = {} + strategy_obj['name'] = "strategy_test_v3_with_lookahead_bias" + freqtrade.optimize.lookahead_analysis.LookaheadAnalysis(default_conf, strategy_obj, {}) + pass