extract backtesting abort functionality

This commit is contained in:
Matthias 2021-07-06 06:28:47 +02:00
parent 5474d5ee64
commit 005da97183
4 changed files with 33 additions and 9 deletions

View File

@ -189,6 +189,15 @@ class Backtesting:
self.rejected_trades = 0 self.rejected_trades = 0
self.dataprovider.clear_cache() self.dataprovider.clear_cache()
def check_abort(self):
"""
Check if abort was requested, raise DependencyException if that's the case
Only applies to Interactive backtest mode (webserver mode)
"""
if self.abort:
self.abort = False
raise DependencyException("Stop requested")
def _get_ohlcv_as_lists(self, processed: Dict[str, DataFrame]) -> Dict[str, Tuple]: def _get_ohlcv_as_lists(self, processed: Dict[str, DataFrame]) -> Dict[str, Tuple]:
""" """
Helper function to convert a processed dataframes into lists for performance reasons. Helper function to convert a processed dataframes into lists for performance reasons.
@ -203,8 +212,7 @@ class Backtesting:
# Create dict with data # Create dict with data
for pair, pair_data in processed.items(): for pair, pair_data in processed.items():
if self.abort: self.check_abort()
raise DependencyException("Stop requested")
self.progress.increment() self.progress.increment()
if not pair_data.empty: if not pair_data.empty:
pair_data.loc[:, 'buy'] = 0 # cleanup if buy_signal is exist pair_data.loc[:, 'buy'] = 0 # cleanup if buy_signal is exist
@ -422,8 +430,7 @@ class Backtesting:
# Loop timerange and get candle for each pair at that point in time # Loop timerange and get candle for each pair at that point in time
while tmp <= end_date: while tmp <= end_date:
open_trade_count_start = open_trade_count open_trade_count_start = open_trade_count
if self.abort: self.check_abort()
raise DependencyException("Stop requested")
for i, pair in enumerate(data): for i, pair in enumerate(data):
row_index = indexes[pair] row_index = indexes[pair]
try: try:

View File

@ -52,8 +52,8 @@ async def api_start_backtest(bt_settings: BacktestRequest, background_tasks: Bac
# TODO: Investigate if enabling protections can be dynamically ingested from here... # TODO: Investigate if enabling protections can be dynamically ingested from here...
from freqtrade.optimize.backtesting import Backtesting from freqtrade.optimize.backtesting import Backtesting
ApiServer._bt = Backtesting(btconfig) ApiServer._bt = Backtesting(btconfig)
# Reset data if backtesting is reloaded
# Only reload data if timeframe or timerange changed.
if (not ApiServer._backtestdata or not ApiServer._bt_timerange if (not ApiServer._backtestdata or not ApiServer._bt_timerange
or lastconfig.get('timerange') != btconfig['timerange'] or lastconfig.get('timerange') != btconfig['timerange']
or lastconfig.get('timeframe') != strat.timeframe): or lastconfig.get('timeframe') != strat.timeframe):

View File

@ -346,6 +346,20 @@ def test_data_to_dataframe_bt(default_conf, mocker, testdatadir) -> None:
assert processed['UNITTEST/BTC'].equals(processed2['UNITTEST/BTC']) assert processed['UNITTEST/BTC'].equals(processed2['UNITTEST/BTC'])
def test_backtest_abort(default_conf, mocker, testdatadir) -> None:
patch_exchange(mocker)
backtesting = Backtesting(default_conf)
backtesting.check_abort()
backtesting.abort = True
with pytest.raises(DependencyException, match="Stop requested"):
backtesting.check_abort()
# abort flag resets
assert backtesting.abort is False
assert backtesting.progress.progress == 0
def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None: def test_backtesting_start(default_conf, mocker, testdatadir, caplog) -> None:
def get_timerange(input1): def get_timerange(input1):
return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59) return Arrow(2017, 11, 14, 21, 17), Arrow(2017, 11, 14, 22, 59)

View File

@ -1252,10 +1252,6 @@ def test_api_backtesting(botclient, mocker, fee):
assert not result['running'] assert not result['running']
assert result['status_msg'] == 'Backtest reset' assert result['status_msg'] == 'Backtest reset'
# bt_mock = mocker.patch('freqtrade.optimize.backtesting.Backtesting.backtest_one_strategy',
# return_value=(1, 2))
# stats_mock = mocker.patch('freqtrade.optimize.optimize_reports.generate_backtest_stats')
# bt_mock.load_bt_data = MagicMock(return_value=(xxx, 'asdfadf'))
# start backtesting # start backtesting
data = { data = {
"strategy": "DefaultStrategy", "strategy": "DefaultStrategy",
@ -1285,6 +1281,13 @@ def test_api_backtesting(botclient, mocker, fee):
assert result['progress'] == 1 assert result['progress'] == 1
assert result['backtest_result'] assert result['backtest_result']
rc = client_get(client, f"{BASE_URI}/backtest/abort")
assert_response(rc)
result = rc.json()
assert result['status'] == 'not_running'
assert not result['running']
assert result['status_msg'] == 'Backtest ended'
# Delete backtesting to avoid leakage since the backtest-object may stick around. # Delete backtesting to avoid leakage since the backtest-object may stick around.
rc = client_delete(client, f"{BASE_URI}/backtest") rc = client_delete(client, f"{BASE_URI}/backtest")
assert_response(rc) assert_response(rc)