Merge pull request #2275 from hroff-1902/backtest-cleanup3
minor: Cleanup in backtesting
This commit is contained in:
commit
c625058f41
@ -217,7 +217,7 @@ class Configuration:
|
|||||||
deprecated_msg='-r/--refresh-pairs-cached will be removed soon.')
|
deprecated_msg='-r/--refresh-pairs-cached will be removed soon.')
|
||||||
|
|
||||||
self._args_to_config(config, argname='strategy_list',
|
self._args_to_config(config, argname='strategy_list',
|
||||||
logstring='Using strategy list of {} Strategies', logfun=len)
|
logstring='Using strategy list of {} strategies', logfun=len)
|
||||||
|
|
||||||
self._args_to_config(config, argname='ticker_interval',
|
self._args_to_config(config, argname='ticker_interval',
|
||||||
logstring='Overriding ticker interval with Command line argument')
|
logstring='Overriding ticker interval with Command line argument')
|
||||||
@ -238,7 +238,7 @@ class Configuration:
|
|||||||
|
|
||||||
# Hyperopt section
|
# Hyperopt section
|
||||||
self._args_to_config(config, argname='hyperopt',
|
self._args_to_config(config, argname='hyperopt',
|
||||||
logstring='Using Hyperopt file {}')
|
logstring='Using Hyperopt class name: {}')
|
||||||
|
|
||||||
self._args_to_config(config, argname='hyperopt_path',
|
self._args_to_config(config, argname='hyperopt_path',
|
||||||
logstring='Using additional Hyperopt lookup path: {}')
|
logstring='Using additional Hyperopt lookup path: {}')
|
||||||
@ -276,7 +276,7 @@ class Configuration:
|
|||||||
logstring='Hyperopt continue: {}')
|
logstring='Hyperopt continue: {}')
|
||||||
|
|
||||||
self._args_to_config(config, argname='hyperopt_loss',
|
self._args_to_config(config, argname='hyperopt_loss',
|
||||||
logstring='Using loss function: {}')
|
logstring='Using Hyperopt loss class name: {}')
|
||||||
|
|
||||||
def _process_plot_options(self, config: Dict[str, Any]) -> None:
|
def _process_plot_options(self, config: Dict[str, Any]) -> None:
|
||||||
|
|
||||||
|
@ -95,8 +95,6 @@ class Backtesting:
|
|||||||
Load strategy into backtesting
|
Load strategy into backtesting
|
||||||
"""
|
"""
|
||||||
self.strategy = strategy
|
self.strategy = strategy
|
||||||
self.advise_buy = strategy.advise_buy
|
|
||||||
self.advise_sell = strategy.advise_sell
|
|
||||||
# Set stoploss_on_exchange to false for backtesting,
|
# Set stoploss_on_exchange to false for backtesting,
|
||||||
# since a "perfect" stoploss-sell is assumed anyway
|
# since a "perfect" stoploss-sell is assumed anyway
|
||||||
# And the regular "stoploss" function would not apply to that case
|
# And the regular "stoploss" function would not apply to that case
|
||||||
@ -219,8 +217,8 @@ class Backtesting:
|
|||||||
for pair, pair_data in processed.items():
|
for pair, pair_data in processed.items():
|
||||||
pair_data['buy'], pair_data['sell'] = 0, 0 # cleanup from previous run
|
pair_data['buy'], pair_data['sell'] = 0, 0 # cleanup from previous run
|
||||||
|
|
||||||
ticker_data = self.advise_sell(
|
ticker_data = self.strategy.advise_sell(
|
||||||
self.advise_buy(pair_data, {'pair': pair}), {'pair': pair})[headers].copy()
|
self.strategy.advise_buy(pair_data, {'pair': pair}), {'pair': pair})[headers].copy()
|
||||||
|
|
||||||
# to avoid using data from future, we buy/sell with signal from previous candle
|
# to avoid using data from future, we buy/sell with signal from previous candle
|
||||||
ticker_data.loc[:, 'buy'] = ticker_data['buy'].shift(1)
|
ticker_data.loc[:, 'buy'] = ticker_data['buy'].shift(1)
|
||||||
|
@ -49,10 +49,11 @@ class Hyperopt:
|
|||||||
"""
|
"""
|
||||||
def __init__(self, config: Dict[str, Any]) -> None:
|
def __init__(self, config: Dict[str, Any]) -> None:
|
||||||
self.config = config
|
self.config = config
|
||||||
self.backtesting = Backtesting(self.config)
|
|
||||||
|
|
||||||
self.custom_hyperopt = HyperOptResolver(self.config).hyperopt
|
self.custom_hyperopt = HyperOptResolver(self.config).hyperopt
|
||||||
|
|
||||||
|
self.backtesting = Backtesting(self.config)
|
||||||
|
|
||||||
self.custom_hyperoptloss = HyperOptLossResolver(self.config).hyperoptloss
|
self.custom_hyperoptloss = HyperOptLossResolver(self.config).hyperoptloss
|
||||||
self.calculate_loss = self.custom_hyperoptloss.hyperopt_loss_function
|
self.calculate_loss = self.custom_hyperoptloss.hyperopt_loss_function
|
||||||
|
|
||||||
@ -77,9 +78,11 @@ class Hyperopt:
|
|||||||
self.backtesting.strategy.advise_indicators = \
|
self.backtesting.strategy.advise_indicators = \
|
||||||
self.custom_hyperopt.populate_indicators # type: ignore
|
self.custom_hyperopt.populate_indicators # type: ignore
|
||||||
if hasattr(self.custom_hyperopt, 'populate_buy_trend'):
|
if hasattr(self.custom_hyperopt, 'populate_buy_trend'):
|
||||||
self.backtesting.advise_buy = self.custom_hyperopt.populate_buy_trend # type: ignore
|
self.backtesting.strategy.advise_buy = \
|
||||||
|
self.custom_hyperopt.populate_buy_trend # type: ignore
|
||||||
if hasattr(self.custom_hyperopt, 'populate_sell_trend'):
|
if hasattr(self.custom_hyperopt, 'populate_sell_trend'):
|
||||||
self.backtesting.advise_sell = self.custom_hyperopt.populate_sell_trend # type: ignore
|
self.backtesting.strategy.advise_sell = \
|
||||||
|
self.custom_hyperopt.populate_sell_trend # type: ignore
|
||||||
|
|
||||||
# Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set
|
# Use max_open_trades for hyperopt as well, except --disable-max-market-positions is set
|
||||||
if self.config.get('use_max_market_positions', True):
|
if self.config.get('use_max_market_positions', True):
|
||||||
@ -259,13 +262,16 @@ class Hyperopt:
|
|||||||
"""
|
"""
|
||||||
params = self.get_args(_params)
|
params = self.get_args(_params)
|
||||||
if self.has_space('roi'):
|
if self.has_space('roi'):
|
||||||
self.backtesting.strategy.minimal_roi = self.custom_hyperopt.generate_roi_table(params)
|
self.backtesting.strategy.minimal_roi = \
|
||||||
|
self.custom_hyperopt.generate_roi_table(params)
|
||||||
|
|
||||||
if self.has_space('buy'):
|
if self.has_space('buy'):
|
||||||
self.backtesting.advise_buy = self.custom_hyperopt.buy_strategy_generator(params)
|
self.backtesting.strategy.advise_buy = \
|
||||||
|
self.custom_hyperopt.buy_strategy_generator(params)
|
||||||
|
|
||||||
if self.has_space('sell'):
|
if self.has_space('sell'):
|
||||||
self.backtesting.advise_sell = self.custom_hyperopt.sell_strategy_generator(params)
|
self.backtesting.strategy.advise_sell = \
|
||||||
|
self.custom_hyperopt.sell_strategy_generator(params)
|
||||||
|
|
||||||
if self.has_space('stoploss'):
|
if self.has_space('stoploss'):
|
||||||
self.backtesting.strategy.stoploss = params['stoploss']
|
self.backtesting.strategy.stoploss = params['stoploss']
|
||||||
|
@ -38,11 +38,11 @@ class HyperOptResolver(IResolver):
|
|||||||
IHyperOpt.ticker_interval = str(config['ticker_interval'])
|
IHyperOpt.ticker_interval = str(config['ticker_interval'])
|
||||||
|
|
||||||
if not hasattr(self.hyperopt, 'populate_buy_trend'):
|
if not hasattr(self.hyperopt, 'populate_buy_trend'):
|
||||||
logger.warning("Custom Hyperopt does not provide populate_buy_trend. "
|
logger.warning("Hyperopt class does not provide populate_buy_trend() method. "
|
||||||
"Using populate_buy_trend from DefaultStrategy.")
|
"Using populate_buy_trend from the strategy.")
|
||||||
if not hasattr(self.hyperopt, 'populate_sell_trend'):
|
if not hasattr(self.hyperopt, 'populate_sell_trend'):
|
||||||
logger.warning("Custom Hyperopt does not provide populate_sell_trend. "
|
logger.warning("Hyperopt class does not provide populate_sell_trend() method. "
|
||||||
"Using populate_sell_trend from DefaultStrategy.")
|
"Using populate_sell_trend from the strategy.")
|
||||||
|
|
||||||
def _load_hyperopt(
|
def _load_hyperopt(
|
||||||
self, hyperopt_name: str, config: Dict, extra_dir: Optional[str] = None) -> IHyperOpt:
|
self, hyperopt_name: str, config: Dict, extra_dir: Optional[str] = None) -> IHyperOpt:
|
||||||
|
@ -291,8 +291,8 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
|
|||||||
patch_exchange(mocker)
|
patch_exchange(mocker)
|
||||||
frame = _build_backtest_dataframe(data.data)
|
frame = _build_backtest_dataframe(data.data)
|
||||||
backtesting = Backtesting(default_conf)
|
backtesting = Backtesting(default_conf)
|
||||||
backtesting.advise_buy = lambda a, m: frame
|
backtesting.strategy.advise_buy = lambda a, m: frame
|
||||||
backtesting.advise_sell = lambda a, m: frame
|
backtesting.strategy.advise_sell = lambda a, m: frame
|
||||||
caplog.set_level(logging.DEBUG)
|
caplog.set_level(logging.DEBUG)
|
||||||
|
|
||||||
pair = "UNITTEST/BTC"
|
pair = "UNITTEST/BTC"
|
||||||
|
@ -313,8 +313,8 @@ def test_backtesting_init(mocker, default_conf, order_types) -> None:
|
|||||||
assert backtesting.config == default_conf
|
assert backtesting.config == default_conf
|
||||||
assert backtesting.ticker_interval == '5m'
|
assert backtesting.ticker_interval == '5m'
|
||||||
assert callable(backtesting.strategy.tickerdata_to_dataframe)
|
assert callable(backtesting.strategy.tickerdata_to_dataframe)
|
||||||
assert callable(backtesting.advise_buy)
|
assert callable(backtesting.strategy.advise_buy)
|
||||||
assert callable(backtesting.advise_sell)
|
assert callable(backtesting.strategy.advise_sell)
|
||||||
assert isinstance(backtesting.strategy.dp, DataProvider)
|
assert isinstance(backtesting.strategy.dp, DataProvider)
|
||||||
get_fee.assert_called()
|
get_fee.assert_called()
|
||||||
assert backtesting.fee == 0.5
|
assert backtesting.fee == 0.5
|
||||||
@ -627,8 +627,8 @@ def test_backtest_clash_buy_sell(mocker, default_conf, testdatadir):
|
|||||||
|
|
||||||
backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir)
|
backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir)
|
||||||
backtesting = Backtesting(default_conf)
|
backtesting = Backtesting(default_conf)
|
||||||
backtesting.advise_buy = fun # Override
|
backtesting.strategy.advise_buy = fun # Override
|
||||||
backtesting.advise_sell = fun # Override
|
backtesting.strategy.advise_sell = fun # Override
|
||||||
results = backtesting.backtest(backtest_conf)
|
results = backtesting.backtest(backtest_conf)
|
||||||
assert results.empty
|
assert results.empty
|
||||||
|
|
||||||
@ -642,8 +642,8 @@ def test_backtest_only_sell(mocker, default_conf, testdatadir):
|
|||||||
|
|
||||||
backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir)
|
backtest_conf = _make_backtest_conf(mocker, conf=default_conf, datadir=testdatadir)
|
||||||
backtesting = Backtesting(default_conf)
|
backtesting = Backtesting(default_conf)
|
||||||
backtesting.advise_buy = fun # Override
|
backtesting.strategy.advise_buy = fun # Override
|
||||||
backtesting.advise_sell = fun # Override
|
backtesting.strategy.advise_sell = fun # Override
|
||||||
results = backtesting.backtest(backtest_conf)
|
results = backtesting.backtest(backtest_conf)
|
||||||
assert results.empty
|
assert results.empty
|
||||||
|
|
||||||
@ -657,8 +657,8 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir):
|
|||||||
default_conf['experimental'] = {"use_sell_signal": True}
|
default_conf['experimental'] = {"use_sell_signal": True}
|
||||||
default_conf['ticker_interval'] = '1m'
|
default_conf['ticker_interval'] = '1m'
|
||||||
backtesting = Backtesting(default_conf)
|
backtesting = Backtesting(default_conf)
|
||||||
backtesting.advise_buy = _trend_alternate # Override
|
backtesting.strategy.advise_buy = _trend_alternate # Override
|
||||||
backtesting.advise_sell = _trend_alternate # Override
|
backtesting.strategy.advise_sell = _trend_alternate # Override
|
||||||
results = backtesting.backtest(backtest_conf)
|
results = backtesting.backtest(backtest_conf)
|
||||||
backtesting._store_backtest_result("test_.json", results)
|
backtesting._store_backtest_result("test_.json", results)
|
||||||
# 200 candles in backtest data
|
# 200 candles in backtest data
|
||||||
@ -700,8 +700,8 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
|
|||||||
default_conf['ticker_interval'] = '5m'
|
default_conf['ticker_interval'] = '5m'
|
||||||
|
|
||||||
backtesting = Backtesting(default_conf)
|
backtesting = Backtesting(default_conf)
|
||||||
backtesting.advise_buy = _trend_alternate_hold # Override
|
backtesting.strategy.advise_buy = _trend_alternate_hold # Override
|
||||||
backtesting.advise_sell = _trend_alternate_hold # Override
|
backtesting.strategy.advise_sell = _trend_alternate_hold # Override
|
||||||
|
|
||||||
data_processed = backtesting.strategy.tickerdata_to_dataframe(data)
|
data_processed = backtesting.strategy.tickerdata_to_dataframe(data)
|
||||||
min_date, max_date = get_timeframe(data_processed)
|
min_date, max_date = get_timeframe(data_processed)
|
||||||
|
@ -166,10 +166,10 @@ def test_hyperoptresolver(mocker, default_conf, caplog) -> None:
|
|||||||
x = HyperOptResolver(default_conf, ).hyperopt
|
x = HyperOptResolver(default_conf, ).hyperopt
|
||||||
assert not hasattr(x, 'populate_buy_trend')
|
assert not hasattr(x, 'populate_buy_trend')
|
||||||
assert not hasattr(x, 'populate_sell_trend')
|
assert not hasattr(x, 'populate_sell_trend')
|
||||||
assert log_has("Custom Hyperopt does not provide populate_sell_trend. "
|
assert log_has("Hyperopt class does not provide populate_sell_trend() method. "
|
||||||
"Using populate_sell_trend from DefaultStrategy.", caplog)
|
"Using populate_sell_trend from the strategy.", caplog)
|
||||||
assert log_has("Custom Hyperopt does not provide populate_buy_trend. "
|
assert log_has("Hyperopt class does not provide populate_buy_trend() method. "
|
||||||
"Using populate_buy_trend from DefaultStrategy.", caplog)
|
"Using populate_buy_trend from the strategy.", caplog)
|
||||||
assert hasattr(x, "ticker_interval")
|
assert hasattr(x, "ticker_interval")
|
||||||
|
|
||||||
|
|
||||||
@ -415,8 +415,8 @@ def test_start_calls_optimizer(mocker, default_conf, caplog, capsys) -> None:
|
|||||||
assert dumper.called
|
assert dumper.called
|
||||||
# Should be called twice, once for tickerdata, once to save evaluations
|
# Should be called twice, once for tickerdata, once to save evaluations
|
||||||
assert dumper.call_count == 2
|
assert dumper.call_count == 2
|
||||||
assert hasattr(hyperopt.backtesting, "advise_sell")
|
assert hasattr(hyperopt.backtesting.strategy, "advise_sell")
|
||||||
assert hasattr(hyperopt.backtesting, "advise_buy")
|
assert hasattr(hyperopt.backtesting.strategy, "advise_buy")
|
||||||
assert hasattr(hyperopt, "max_open_trades")
|
assert hasattr(hyperopt, "max_open_trades")
|
||||||
assert hyperopt.max_open_trades == default_conf['max_open_trades']
|
assert hyperopt.max_open_trades == default_conf['max_open_trades']
|
||||||
assert hasattr(hyperopt, "position_stacking")
|
assert hasattr(hyperopt, "position_stacking")
|
||||||
@ -709,8 +709,8 @@ def test_simplified_interface_roi_stoploss(mocker, default_conf, caplog, capsys)
|
|||||||
assert dumper.called
|
assert dumper.called
|
||||||
# Should be called twice, once for tickerdata, once to save evaluations
|
# Should be called twice, once for tickerdata, once to save evaluations
|
||||||
assert dumper.call_count == 2
|
assert dumper.call_count == 2
|
||||||
assert hasattr(hyperopt.backtesting, "advise_sell")
|
assert hasattr(hyperopt.backtesting.strategy, "advise_sell")
|
||||||
assert hasattr(hyperopt.backtesting, "advise_buy")
|
assert hasattr(hyperopt.backtesting.strategy, "advise_buy")
|
||||||
assert hasattr(hyperopt, "max_open_trades")
|
assert hasattr(hyperopt, "max_open_trades")
|
||||||
assert hyperopt.max_open_trades == default_conf['max_open_trades']
|
assert hyperopt.max_open_trades == default_conf['max_open_trades']
|
||||||
assert hasattr(hyperopt, "position_stacking")
|
assert hasattr(hyperopt, "position_stacking")
|
||||||
@ -783,8 +783,8 @@ def test_simplified_interface_buy(mocker, default_conf, caplog, capsys) -> None:
|
|||||||
assert dumper.called
|
assert dumper.called
|
||||||
# Should be called twice, once for tickerdata, once to save evaluations
|
# Should be called twice, once for tickerdata, once to save evaluations
|
||||||
assert dumper.call_count == 2
|
assert dumper.call_count == 2
|
||||||
assert hasattr(hyperopt.backtesting, "advise_sell")
|
assert hasattr(hyperopt.backtesting.strategy, "advise_sell")
|
||||||
assert hasattr(hyperopt.backtesting, "advise_buy")
|
assert hasattr(hyperopt.backtesting.strategy, "advise_buy")
|
||||||
assert hasattr(hyperopt, "max_open_trades")
|
assert hasattr(hyperopt, "max_open_trades")
|
||||||
assert hyperopt.max_open_trades == default_conf['max_open_trades']
|
assert hyperopt.max_open_trades == default_conf['max_open_trades']
|
||||||
assert hasattr(hyperopt, "position_stacking")
|
assert hasattr(hyperopt, "position_stacking")
|
||||||
@ -828,8 +828,8 @@ def test_simplified_interface_sell(mocker, default_conf, caplog, capsys) -> None
|
|||||||
assert dumper.called
|
assert dumper.called
|
||||||
# Should be called twice, once for tickerdata, once to save evaluations
|
# Should be called twice, once for tickerdata, once to save evaluations
|
||||||
assert dumper.call_count == 2
|
assert dumper.call_count == 2
|
||||||
assert hasattr(hyperopt.backtesting, "advise_sell")
|
assert hasattr(hyperopt.backtesting.strategy, "advise_sell")
|
||||||
assert hasattr(hyperopt.backtesting, "advise_buy")
|
assert hasattr(hyperopt.backtesting.strategy, "advise_buy")
|
||||||
assert hasattr(hyperopt, "max_open_trades")
|
assert hasattr(hyperopt, "max_open_trades")
|
||||||
assert hyperopt.max_open_trades == default_conf['max_open_trades']
|
assert hyperopt.max_open_trades == default_conf['max_open_trades']
|
||||||
assert hasattr(hyperopt, "position_stacking")
|
assert hasattr(hyperopt, "position_stacking")
|
||||||
|
@ -440,7 +440,7 @@ def test_setup_configuration_with_stratlist(mocker, default_conf, caplog) -> Non
|
|||||||
caplog)
|
caplog)
|
||||||
|
|
||||||
assert 'strategy_list' in config
|
assert 'strategy_list' in config
|
||||||
assert log_has('Using strategy list of 2 Strategies', caplog)
|
assert log_has('Using strategy list of 2 strategies', caplog)
|
||||||
|
|
||||||
assert 'position_stacking' not in config
|
assert 'position_stacking' not in config
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user