mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 18:23:55 +00:00
Merge pull request #2801 from freqtrade/backtest_arguments_2
Backtest arguments instead of dictionary
This commit is contained in:
commit
a97bb10877
|
@ -279,30 +279,28 @@ class Backtesting:
|
|||
return bt_res
|
||||
return None
|
||||
|
||||
def backtest(self, args: Dict) -> DataFrame:
|
||||
def backtest(self, processed: Dict, stake_amount: float,
|
||||
start_date, end_date,
|
||||
max_open_trades: int = 0, position_stacking: bool = False) -> DataFrame:
|
||||
"""
|
||||
Implements backtesting functionality
|
||||
Implement backtesting functionality
|
||||
|
||||
NOTE: This method is used by Hyperopt at each iteration. Please keep it optimized.
|
||||
Of course try to not have ugly code. By some accessor are sometime slower than functions.
|
||||
Avoid, logging on this method
|
||||
Avoid extensive logging in this method and functions it calls.
|
||||
|
||||
:param args: a dict containing:
|
||||
stake_amount: btc amount to use for each trade
|
||||
processed: a processed dictionary with format {pair, data}
|
||||
max_open_trades: maximum number of concurrent trades (default: 0, disabled)
|
||||
position_stacking: do we allow position stacking? (default: False)
|
||||
:return: DataFrame
|
||||
:param processed: a processed dictionary with format {pair, data}
|
||||
:param stake_amount: amount to use for each trade
|
||||
:param start_date: backtesting timerange start datetime
|
||||
:param end_date: backtesting timerange end datetime
|
||||
:param max_open_trades: maximum number of concurrent trades, <= 0 means unlimited
|
||||
:param position_stacking: do we allow position stacking?
|
||||
:return: DataFrame with trades (results of backtesting)
|
||||
"""
|
||||
# Arguments are long and noisy, so this is commented out.
|
||||
# Uncomment if you need to debug the backtest() method.
|
||||
# logger.debug(f"Start backtest, args: {args}")
|
||||
processed = args['processed']
|
||||
stake_amount = args['stake_amount']
|
||||
max_open_trades = args.get('max_open_trades', 0)
|
||||
position_stacking = args.get('position_stacking', False)
|
||||
start_date = args['start_date']
|
||||
end_date = args['end_date']
|
||||
logger.debug(f"Run backtest, stake_amount: {stake_amount}, "
|
||||
f"start_date: {start_date}, end_date: {end_date}, "
|
||||
f"max_open_trades: {max_open_trades}, position_stacking: {position_stacking}"
|
||||
)
|
||||
trades = []
|
||||
trade_count_lock: Dict = {}
|
||||
|
||||
|
@ -369,18 +367,21 @@ class Backtesting:
|
|||
|
||||
def start(self) -> None:
|
||||
"""
|
||||
Run a backtesting end-to-end
|
||||
Run backtesting end-to-end
|
||||
:return: None
|
||||
"""
|
||||
data: Dict[str, Any] = {}
|
||||
|
||||
logger.info('Using stake_currency: %s ...', self.config['stake_currency'])
|
||||
logger.info('Using stake_amount: %s ...', self.config['stake_amount'])
|
||||
|
||||
# Use max_open_trades in backtesting, except --disable-max-market-positions is set
|
||||
if self.config.get('use_max_market_positions', True):
|
||||
max_open_trades = self.config['max_open_trades']
|
||||
else:
|
||||
logger.info('Ignoring max_open_trades (--disable-max-market-positions was used) ...')
|
||||
max_open_trades = 0
|
||||
position_stacking = self.config.get('position_stacking', False)
|
||||
|
||||
data, timerange = self.load_bt_data()
|
||||
|
||||
|
@ -403,14 +404,12 @@ class Backtesting:
|
|||
)
|
||||
# Execute backtest and print results
|
||||
all_results[self.strategy.get_strategy_name()] = self.backtest(
|
||||
{
|
||||
'stake_amount': self.config.get('stake_amount'),
|
||||
'processed': preprocessed,
|
||||
'max_open_trades': max_open_trades,
|
||||
'position_stacking': self.config.get('position_stacking', False),
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
}
|
||||
processed=preprocessed,
|
||||
stake_amount=self.config['stake_amount'],
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=max_open_trades,
|
||||
position_stacking=position_stacking,
|
||||
)
|
||||
|
||||
for strategy, results in all_results.items():
|
||||
|
|
|
@ -372,14 +372,12 @@ class Hyperopt:
|
|||
min_date, max_date = get_timerange(processed)
|
||||
|
||||
backtesting_results = self.backtesting.backtest(
|
||||
{
|
||||
'stake_amount': self.config['stake_amount'],
|
||||
'processed': processed,
|
||||
'max_open_trades': self.max_open_trades,
|
||||
'position_stacking': self.position_stacking,
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
}
|
||||
processed=processed,
|
||||
stake_amount=self.config['stake_amount'],
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=self.max_open_trades,
|
||||
position_stacking=self.position_stacking,
|
||||
)
|
||||
return self._get_results_dict(backtesting_results, min_date, max_date,
|
||||
params_dict, params_details)
|
||||
|
|
|
@ -382,13 +382,11 @@ def test_backtest_results(default_conf, fee, mocker, caplog, data) -> None:
|
|||
data_processed = {pair: frame.copy()}
|
||||
min_date, max_date = get_timerange({pair: frame})
|
||||
results = backtesting.backtest(
|
||||
{
|
||||
'stake_amount': default_conf['stake_amount'],
|
||||
'processed': data_processed,
|
||||
'max_open_trades': 10,
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
}
|
||||
processed=data_processed,
|
||||
stake_amount=default_conf['stake_amount'],
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=10,
|
||||
)
|
||||
|
||||
assert len(results) == len(data.trades)
|
||||
|
|
|
@ -103,14 +103,12 @@ def simple_backtest(config, contour, num_results, mocker, testdatadir) -> None:
|
|||
min_date, max_date = get_timerange(processed)
|
||||
assert isinstance(processed, dict)
|
||||
results = backtesting.backtest(
|
||||
{
|
||||
'stake_amount': config['stake_amount'],
|
||||
'processed': processed,
|
||||
'max_open_trades': 1,
|
||||
'position_stacking': False,
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
}
|
||||
processed=processed,
|
||||
stake_amount=config['stake_amount'],
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=1,
|
||||
position_stacking=False,
|
||||
)
|
||||
# results :: <class 'pandas.core.frame.DataFrame'>
|
||||
assert len(results) == num_results
|
||||
|
@ -132,7 +130,7 @@ def _load_pair_as_ticks(pair, tickfreq):
|
|||
|
||||
|
||||
# FIX: fixturize this?
|
||||
def _make_backtest_conf(mocker, datadir, conf=None, pair='UNITTEST/BTC', record=None):
|
||||
def _make_backtest_conf(mocker, datadir, conf=None, pair='UNITTEST/BTC'):
|
||||
data = history.load_data(datadir=datadir, timeframe='1m', pairs=[pair])
|
||||
data = trim_dictlist(data, -201)
|
||||
patch_exchange(mocker)
|
||||
|
@ -140,13 +138,12 @@ def _make_backtest_conf(mocker, datadir, conf=None, pair='UNITTEST/BTC', record=
|
|||
processed = backtesting.strategy.tickerdata_to_dataframe(data)
|
||||
min_date, max_date = get_timerange(processed)
|
||||
return {
|
||||
'stake_amount': conf['stake_amount'],
|
||||
'processed': processed,
|
||||
'max_open_trades': 10,
|
||||
'position_stacking': False,
|
||||
'record': record,
|
||||
'stake_amount': conf['stake_amount'],
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
'max_open_trades': 10,
|
||||
'position_stacking': False,
|
||||
}
|
||||
|
||||
|
||||
|
@ -422,14 +419,12 @@ def test_backtest(default_conf, fee, mocker, testdatadir) -> None:
|
|||
data_processed = backtesting.strategy.tickerdata_to_dataframe(data)
|
||||
min_date, max_date = get_timerange(data_processed)
|
||||
results = backtesting.backtest(
|
||||
{
|
||||
'stake_amount': default_conf['stake_amount'],
|
||||
'processed': data_processed,
|
||||
'max_open_trades': 10,
|
||||
'position_stacking': False,
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
}
|
||||
processed=data_processed,
|
||||
stake_amount=default_conf['stake_amount'],
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=10,
|
||||
position_stacking=False,
|
||||
)
|
||||
assert not results.empty
|
||||
assert len(results) == 2
|
||||
|
@ -478,14 +473,12 @@ def test_backtest_1min_ticker_interval(default_conf, fee, mocker, testdatadir) -
|
|||
processed = backtesting.strategy.tickerdata_to_dataframe(data)
|
||||
min_date, max_date = get_timerange(processed)
|
||||
results = backtesting.backtest(
|
||||
{
|
||||
'stake_amount': default_conf['stake_amount'],
|
||||
'processed': processed,
|
||||
'max_open_trades': 1,
|
||||
'position_stacking': False,
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
}
|
||||
processed=processed,
|
||||
stake_amount=default_conf['stake_amount'],
|
||||
start_date=min_date,
|
||||
end_date=max_date,
|
||||
max_open_trades=1,
|
||||
position_stacking=False,
|
||||
)
|
||||
assert not results.empty
|
||||
assert len(results) == 1
|
||||
|
@ -525,7 +518,7 @@ def test_backtest_clash_buy_sell(mocker, default_conf, testdatadir):
|
|||
backtesting = Backtesting(default_conf)
|
||||
backtesting.strategy.advise_buy = fun # Override
|
||||
backtesting.strategy.advise_sell = fun # Override
|
||||
results = backtesting.backtest(backtest_conf)
|
||||
results = backtesting.backtest(**backtest_conf)
|
||||
assert results.empty
|
||||
|
||||
|
||||
|
@ -540,7 +533,7 @@ def test_backtest_only_sell(mocker, default_conf, testdatadir):
|
|||
backtesting = Backtesting(default_conf)
|
||||
backtesting.strategy.advise_buy = fun # Override
|
||||
backtesting.strategy.advise_sell = fun # Override
|
||||
results = backtesting.backtest(backtest_conf)
|
||||
results = backtesting.backtest(**backtest_conf)
|
||||
assert results.empty
|
||||
|
||||
|
||||
|
@ -553,7 +546,7 @@ def test_backtest_alternate_buy_sell(default_conf, fee, mocker, testdatadir):
|
|||
backtesting = Backtesting(default_conf)
|
||||
backtesting.strategy.advise_buy = _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)
|
||||
# 200 candles in backtest data
|
||||
# won't buy on first (shifted by 1)
|
||||
|
@ -598,15 +591,15 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
|
|||
data_processed = backtesting.strategy.tickerdata_to_dataframe(data)
|
||||
min_date, max_date = get_timerange(data_processed)
|
||||
backtest_conf = {
|
||||
'stake_amount': default_conf['stake_amount'],
|
||||
'processed': data_processed,
|
||||
'max_open_trades': 3,
|
||||
'position_stacking': False,
|
||||
'stake_amount': default_conf['stake_amount'],
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
'max_open_trades': 3,
|
||||
'position_stacking': False,
|
||||
}
|
||||
|
||||
results = backtesting.backtest(backtest_conf)
|
||||
results = backtesting.backtest(**backtest_conf)
|
||||
|
||||
# Make sure we have parallel trades
|
||||
assert len(evaluate_result_multi(results, '5m', 2)) > 0
|
||||
|
@ -614,14 +607,14 @@ def test_backtest_multi_pair(default_conf, fee, mocker, tres, pair, testdatadir)
|
|||
assert len(evaluate_result_multi(results, '5m', 3)) == 0
|
||||
|
||||
backtest_conf = {
|
||||
'stake_amount': default_conf['stake_amount'],
|
||||
'processed': data_processed,
|
||||
'max_open_trades': 1,
|
||||
'position_stacking': False,
|
||||
'stake_amount': default_conf['stake_amount'],
|
||||
'start_date': min_date,
|
||||
'end_date': max_date,
|
||||
'max_open_trades': 1,
|
||||
'position_stacking': False,
|
||||
}
|
||||
results = backtesting.backtest(backtest_conf)
|
||||
results = backtesting.backtest(**backtest_conf)
|
||||
assert len(evaluate_result_multi(results, '5m', 1)) == 0
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user