Extract signals generation from backtesting class

This commit is contained in:
Matthias 2023-04-28 16:14:16 +02:00
parent 6e395ad7c9
commit 023c155a25
2 changed files with 48 additions and 45 deletions

View File

@ -9,7 +9,6 @@ from copy import deepcopy
from datetime import datetime, timedelta, timezone from datetime import datetime, timedelta, timezone
from typing import Any, Dict, List, Optional, Tuple from typing import Any, Dict, List, Optional, Tuple
import pandas as pd
from numpy import nan from numpy import nan
from pandas import DataFrame from pandas import DataFrame
@ -28,7 +27,9 @@ from freqtrade.exchange import (amount_to_contract_precision, price_to_precision
from freqtrade.mixins import LoggingMixin from freqtrade.mixins import LoggingMixin
from freqtrade.optimize.backtest_caching import get_strategy_run_id from freqtrade.optimize.backtest_caching import get_strategy_run_id
from freqtrade.optimize.bt_progress import BTProgress from freqtrade.optimize.bt_progress import BTProgress
from freqtrade.optimize.optimize_reports import (generate_backtest_stats, show_backtest_results, from freqtrade.optimize.optimize_reports import (generate_backtest_stats, generate_rejected_signals,
generate_trade_signal_candles,
show_backtest_results,
store_backtest_analysis_results, store_backtest_analysis_results,
store_backtest_stats) store_backtest_stats)
from freqtrade.persistence import LocalTrade, Order, PairLocks, Trade from freqtrade.persistence import LocalTrade, Order, PairLocks, Trade
@ -1296,53 +1297,13 @@ class Backtesting:
if (self.config.get('export', 'none') == 'signals' and if (self.config.get('export', 'none') == 'signals' and
self.dataprovider.runmode == RunMode.BACKTEST): self.dataprovider.runmode == RunMode.BACKTEST):
self.processed_dfs[strategy_name] = self._generate_trade_signal_candles( self.processed_dfs[strategy_name] = generate_trade_signal_candles(
preprocessed_tmp, results) preprocessed_tmp, results)
self.rejected_df[strategy_name] = self._generate_rejected_signals( self.rejected_df[strategy_name] = generate_rejected_signals(
preprocessed_tmp, self.rejected_dict) preprocessed_tmp, self.rejected_dict)
return min_date, max_date return min_date, max_date
def _generate_trade_signal_candles(self, preprocessed_df: Dict[str, pd.DataFrame],
bt_results: Dict[str, Any]) -> pd.DataFrame:
signal_candles_only = {}
for pair in preprocessed_df.keys():
signal_candles_only_df = DataFrame()
pairdf = preprocessed_df[pair]
resdf = bt_results['results']
pairresults = resdf.loc[(resdf["pair"] == pair)]
if pairdf.shape[0] > 0:
for t, v in pairresults.open_date.items():
allinds = pairdf.loc[(pairdf['date'] < v)]
signal_inds = allinds.iloc[[-1]]
signal_candles_only_df = pd.concat([
signal_candles_only_df.infer_objects(),
signal_inds.infer_objects()])
signal_candles_only[pair] = signal_candles_only_df
return signal_candles_only
def _generate_rejected_signals(self, preprocessed_df: Dict[str, DataFrame],
rejected_dict: Dict[str, DataFrame]) -> Dict[str, DataFrame]:
rejected_candles_only = {}
for pair, signals in rejected_dict.items():
rejected_signals_only_df = DataFrame()
pairdf = preprocessed_df[pair]
for t in signals:
data_df_row = pairdf.loc[(pairdf['date'] == t[0])].copy()
data_df_row['pair'] = pair
data_df_row['enter_tag'] = t[1]
rejected_signals_only_df = pd.concat([
rejected_signals_only_df.infer_objects(),
data_df_row.infer_objects()])
rejected_candles_only[pair] = rejected_signals_only_df
return rejected_candles_only
def _get_min_cached_backtest_date(self): def _get_min_cached_backtest_date(self):
min_backtest_date = None min_backtest_date = None
backtest_cache_age = self.config.get('backtest_cache', constants.BACKTEST_CACHE_DEFAULT) backtest_cache_age = self.config.get('backtest_cache', constants.BACKTEST_CACHE_DEFAULT)

View File

@ -4,7 +4,7 @@ from datetime import datetime, timedelta, timezone
from pathlib import Path from pathlib import Path
from typing import Any, Dict, List, Union from typing import Any, Dict, List, Union
from pandas import DataFrame, to_datetime from pandas import DataFrame, concat, to_datetime
from tabulate import tabulate from tabulate import tabulate
from freqtrade.constants import (BACKTEST_BREAKDOWNS, DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN, from freqtrade.constants import (BACKTEST_BREAKDOWNS, DATETIME_PRINT_FORMAT, LAST_BT_RESULT_FN,
@ -78,6 +78,48 @@ def store_backtest_analysis_results(
_store_backtest_analysis_data(recordfilename, trades, dtappendix, "rejected") _store_backtest_analysis_data(recordfilename, trades, dtappendix, "rejected")
def generate_trade_signal_candles(preprocessed_df: Dict[str, DataFrame],
bt_results: Dict[str, Any]) -> DataFrame:
signal_candles_only = {}
for pair in preprocessed_df.keys():
signal_candles_only_df = DataFrame()
pairdf = preprocessed_df[pair]
resdf = bt_results['results']
pairresults = resdf.loc[(resdf["pair"] == pair)]
if pairdf.shape[0] > 0:
for t, v in pairresults.open_date.items():
allinds = pairdf.loc[(pairdf['date'] < v)]
signal_inds = allinds.iloc[[-1]]
signal_candles_only_df = concat([
signal_candles_only_df.infer_objects(),
signal_inds.infer_objects()])
signal_candles_only[pair] = signal_candles_only_df
return signal_candles_only
def generate_rejected_signals(preprocessed_df: Dict[str, DataFrame],
rejected_dict: Dict[str, DataFrame]) -> Dict[str, DataFrame]:
rejected_candles_only = {}
for pair, signals in rejected_dict.items():
rejected_signals_only_df = DataFrame()
pairdf = preprocessed_df[pair]
for t in signals:
data_df_row = pairdf.loc[(pairdf['date'] == t[0])].copy()
data_df_row['pair'] = pair
data_df_row['enter_tag'] = t[1]
rejected_signals_only_df = concat([
rejected_signals_only_df.infer_objects(),
data_df_row.infer_objects()])
rejected_candles_only[pair] = rejected_signals_only_df
return rejected_candles_only
def _get_line_floatfmt(stake_currency: str) -> List[str]: def _get_line_floatfmt(stake_currency: str) -> List[str]:
""" """
Generate floatformat (goes in line with _generate_result_line()) Generate floatformat (goes in line with _generate_result_line())