Merge pull request #12127 from freqtrade/backtest-filename

Backtest filename
This commit is contained in:
Matthias
2025-08-18 06:47:12 +02:00
committed by GitHub
18 changed files with 177 additions and 97 deletions

View File

@@ -46,29 +46,32 @@ ranging from the simplest (0) to the most detailed per pair, per buy and per sel
More options are available by running with the `-h` option. More options are available by running with the `-h` option.
### Using export-filename ### Using backtest-filename
Normally, `backtesting-analysis` uses the latest backtest results, but if you wanted to go By default, `backtesting-analysis` processes the most recent backtest results in the `user_data/backtest_results` directory.
back to a previous backtest output, you need to supply the `--export-filename` option. If you want to analyze results from an earlier backtest, use the `--backtest-filename` option to specify the desired file. This lets you revisit and re-analyze historical backtest outputs at any time by providing the filename of the relevant backtest result:
You can supply the same parameter to `backtest-analysis` with the name of the final backtest
output file. This allows you to keep historical versions of backtest results and re-analyse
them at a later date:
``` bash ``` bash
freqtrade backtesting-analysis -c <config.json> --timeframe <tf> --strategy <strategy_name> --timerange=<timerange> --export=signals --export-filename=user_data/backtest-results/backtest-result-2025-03-05_20-38-34.zip freqtrade backtesting-analysis -c <config.json> --timeframe <tf> --strategy <strategy_name> --timerange <timerange> --export signals --backtest-filename backtest-result-2025-03-05_20-38-34.zip
``` ```
You should see some output similar to below in the logs with the name of the timestamped You should see some output similar to below in the logs with the name of the timestamped
filename that was exported: filename that was exported:
``` ```
2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "/tmp/mystrat_backtest-2022-06-14_16-28-32.json" 2022-06-14 16:28:32,698 - freqtrade.misc - INFO - dumping json to "mystrat_backtest-2022-06-14_16-28-32.json"
``` ```
You can then use that filename in `backtesting-analysis`: You can then use that filename in `backtesting-analysis`:
``` ```
freqtrade backtesting-analysis -c <config.json> --export-filename=/tmp/mystrat_backtest-2022-06-14_16-28-32.json freqtrade backtesting-analysis -c <config.json> --backtest-filename=mystrat_backtest-2022-06-14_16-28-32.json
```
To use a result from a different results directory, you can use `--backtest-directory` to specify the directory
``` bash
freqtrade backtesting-analysis -c <config.json> --backtest-directory custom_results/ --backtest-filename mystrat_backtest-2022-06-14_16-28-32.json
``` ```
### Tuning the buy tags and sell tags to display ### Tuning the buy tags and sell tags to display

View File

@@ -108,7 +108,7 @@ Only use this if you're sure you'll not want to plot or analyze your results fur
Exporting trades to file specifying a custom directory Exporting trades to file specifying a custom directory
```bash ```bash
freqtrade backtesting --strategy backtesting --export trades --export-filename=user_data/custom-backtest-results freqtrade backtesting --strategy backtesting --export trades --backtest-directory=user_data/custom-backtest-results
``` ```
--- ---

View File

@@ -3,6 +3,7 @@ usage: freqtrade backtesting-analysis [-h] [-v] [--no-color] [--logfile FILE]
[-V] [-c PATH] [-d PATH] [-V] [-c PATH] [-d PATH]
[--userdir PATH] [--userdir PATH]
[--backtest-filename PATH] [--backtest-filename PATH]
[--backtest-directory PATH]
[--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]] [--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]]
[--enter-reason-list ENTER_REASON_LIST [ENTER_REASON_LIST ...]] [--enter-reason-list ENTER_REASON_LIST [ENTER_REASON_LIST ...]]
[--exit-reason-list EXIT_REASON_LIST [EXIT_REASON_LIST ...]] [--exit-reason-list EXIT_REASON_LIST [EXIT_REASON_LIST ...]]
@@ -16,7 +17,13 @@ options:
-h, --help show this help message and exit -h, --help show this help message and exit
--backtest-filename PATH, --export-filename PATH --backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example: Use this filename for backtest results.Example:
`--backtest-filename=user_data/backtest_results/` `--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--backtest-directory PATH, --export-directory PATH
Directory to use for backtest results. Example:
`--export-directory=user_data/backtest_results/`.
--analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...] --analysis-groups {0,1,2,3,4,5} [{0,1,2,3,4,5} ...]
grouping output - 0: simple wins/losses by enter tag, grouping output - 0: simple wins/losses by enter tag,
1: by enter_tag, 2: by enter_tag and exit_tag, 3: by 1: by enter_tag, 2: by enter_tag and exit_tag, 3: by

View File

@@ -2,6 +2,7 @@
usage: freqtrade backtesting-show [-h] [-v] [--no-color] [--logfile FILE] [-V] usage: freqtrade backtesting-show [-h] [-v] [--no-color] [--logfile FILE] [-V]
[-c PATH] [-d PATH] [--userdir PATH] [-c PATH] [-d PATH] [--userdir PATH]
[--backtest-filename PATH] [--backtest-filename PATH]
[--backtest-directory PATH]
[--show-pair-list] [--show-pair-list]
[--breakdown {day,week,month,year} [{day,week,month,year} ...]] [--breakdown {day,week,month,year} [{day,week,month,year} ...]]
@@ -9,7 +10,13 @@ options:
-h, --help show this help message and exit -h, --help show this help message and exit
--backtest-filename PATH, --export-filename PATH --backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example: Use this filename for backtest results.Example:
`--backtest-filename=user_data/backtest_results/` `--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--backtest-directory PATH, --export-directory PATH
Directory to use for backtest results. Example:
`--export-directory=user_data/backtest_results/`.
--show-pair-list Show backtesting pairlist sorted by profit. --show-pair-list Show backtesting pairlist sorted by profit.
--breakdown {day,week,month,year} [{day,week,month,year} ...] --breakdown {day,week,month,year} [{day,week,month,year} ...]
Show backtesting breakdown per [day, week, month, Show backtesting breakdown per [day, week, month,

View File

@@ -15,6 +15,7 @@ usage: freqtrade backtesting [-h] [-v] [--no-color] [--logfile FILE] [-V]
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]] [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
[--export {none,trades,signals}] [--export {none,trades,signals}]
[--backtest-filename PATH] [--backtest-filename PATH]
[--backtest-directory PATH]
[--breakdown {day,week,month,year} [{day,week,month,year} ...]] [--breakdown {day,week,month,year} [{day,week,month,year} ...]]
[--cache {none,day,week,month}] [--cache {none,day,week,month}]
[--freqai-backtest-live-models] [--notes TEXT] [--freqai-backtest-live-models] [--notes TEXT]
@@ -63,7 +64,13 @@ options:
Export backtest results (default: trades). Export backtest results (default: trades).
--backtest-filename PATH, --export-filename PATH --backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example: Use this filename for backtest results.Example:
`--backtest-filename=user_data/backtest_results/` `--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--backtest-directory PATH, --export-directory PATH
Directory to use for backtest results. Example:
`--export-directory=user_data/backtest_results/`.
--breakdown {day,week,month,year} [{day,week,month,year} ...] --breakdown {day,week,month,year} [{day,week,month,year} ...]
Show backtesting breakdown per [day, week, month, Show backtesting breakdown per [day, week, month,
year]. year].

View File

@@ -16,6 +16,7 @@ usage: freqtrade lookahead-analysis [-h] [-v] [--no-color] [--logfile FILE]
[--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]] [--strategy-list STRATEGY_LIST [STRATEGY_LIST ...]]
[--export {none,trades,signals}] [--export {none,trades,signals}]
[--backtest-filename PATH] [--backtest-filename PATH]
[--backtest-directory PATH]
[--freqai-backtest-live-models] [--freqai-backtest-live-models]
[--minimum-trade-amount INT] [--minimum-trade-amount INT]
[--targeted-trade-amount INT] [--targeted-trade-amount INT]
@@ -62,7 +63,13 @@ options:
Export backtest results (default: trades). Export backtest results (default: trades).
--backtest-filename PATH, --export-filename PATH --backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example: Use this filename for backtest results.Example:
`--backtest-filename=user_data/backtest_results/` `--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--backtest-directory PATH, --export-directory PATH
Directory to use for backtest results. Example:
`--export-directory=user_data/backtest_results/`.
--freqai-backtest-live-models --freqai-backtest-live-models
Run backtest with ready models. Run backtest with ready models.
--minimum-trade-amount INT --minimum-trade-amount INT

View File

@@ -40,7 +40,10 @@ options:
Export backtest results (default: trades). Export backtest results (default: trades).
--backtest-filename PATH, --export-filename PATH --backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example: Use this filename for backtest results.Example:
`--backtest-filename=user_data/backtest_results/` `--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--timerange TIMERANGE --timerange TIMERANGE
Specify what timerange of data to use. Specify what timerange of data to use.
-i TIMEFRAME, --timeframe TIMEFRAME -i TIMEFRAME, --timeframe TIMEFRAME

View File

@@ -21,7 +21,10 @@ options:
Export backtest results (default: trades). Export backtest results (default: trades).
--backtest-filename PATH, --export-filename PATH --backtest-filename PATH, --export-filename PATH
Use this filename for backtest results.Example: Use this filename for backtest results.Example:
`--backtest-filename=user_data/backtest_results/` `--backtest-
filename=backtest_results_2020-09-27_16-20-48.json`.
Assumes either `user_data/backtest_results/` or
`--export-directory` as base directory.
--db-url PATH Override trades database URL, this is useful in custom --db-url PATH Override trades database URL, this is useful in custom
deployments (default: `sqlite:///tradesv3.sqlite` for deployments (default: `sqlite:///tradesv3.sqlite` for
Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for Live Run mode, `sqlite:///tradesv3.dryrun.sqlite` for

View File

@@ -54,6 +54,7 @@ ARGS_BACKTEST = [
"strategy_list", "strategy_list",
"export", "export",
"exportfilename", "exportfilename",
"exportdirectory",
"backtest_breakdown", "backtest_breakdown",
"backtest_cache", "backtest_cache",
"freqai_backtest_live_models", "freqai_backtest_live_models",
@@ -94,7 +95,12 @@ ARGS_LIST_FREQAIMODELS = ["freqaimodel_path", "print_one_column"]
ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column"] ARGS_LIST_HYPEROPTS = ["hyperopt_path", "print_one_column"]
ARGS_BACKTEST_SHOW = ["exportfilename", "backtest_show_pair_list", "backtest_breakdown"] ARGS_BACKTEST_SHOW = [
"exportfilename",
"exportdirectory",
"backtest_show_pair_list",
"backtest_breakdown",
]
ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all", "trading_mode", "dex_exchanges"] ARGS_LIST_EXCHANGES = ["print_one_column", "list_exchanges_all", "trading_mode", "dex_exchanges"]
@@ -233,6 +239,7 @@ ARGS_HYPEROPT_SHOW = [
ARGS_ANALYZE_ENTRIES_EXITS = [ ARGS_ANALYZE_ENTRIES_EXITS = [
"exportfilename", "exportfilename",
"exportdirectory",
"analysis_groups", "analysis_groups",
"enter_reason_list", "enter_reason_list",
"exit_reason_list", "exit_reason_list",

View File

@@ -199,21 +199,29 @@ AVAILABLE_CLI_OPTIONS = {
"(so `backtest-data.json` becomes `backtest-data-SampleStrategy.json`", "(so `backtest-data.json` becomes `backtest-data-SampleStrategy.json`",
nargs="+", nargs="+",
), ),
"export": Arg(
"--export",
help="Export backtest results (default: trades).",
choices=constants.EXPORT_OPTIONS,
),
"backtest_notes": Arg( "backtest_notes": Arg(
"--notes", "--notes",
help="Add notes to the backtest results.", help="Add notes to the backtest results.",
metavar="TEXT", metavar="TEXT",
), ),
"export": Arg(
"--export",
help="Export backtest results (default: trades).",
choices=constants.EXPORT_OPTIONS,
),
"exportdirectory": Arg(
"--backtest-directory",
"--export-directory",
help="Directory to use for backtest results. "
"Example: `--export-directory=user_data/backtest_results/`. ",
metavar="PATH",
),
"exportfilename": Arg( "exportfilename": Arg(
"--backtest-filename", "--backtest-filename",
"--export-filename", "--export-filename",
help="Use this filename for backtest results." help="Use this filename for backtest results."
"Example: `--backtest-filename=user_data/backtest_results/`", "Example: `--backtest-filename=backtest_results_2020-09-27_16-20-48.json`. "
"Assumes either `user_data/backtest_results/` or `--export-directory` as base directory.",
metavar="PATH", metavar="PATH",
), ),
"disableparamexport": Arg( "disableparamexport": Arg(

View File

@@ -72,7 +72,7 @@ def start_backtesting_show(args: dict[str, Any]) -> None:
from freqtrade.data.btanalysis import load_backtest_stats from freqtrade.data.btanalysis import load_backtest_stats
from freqtrade.optimize.optimize_reports import show_backtest_results, show_sorted_pairlist from freqtrade.optimize.optimize_reports import show_backtest_results, show_sorted_pairlist
results = load_backtest_stats(config["exportfilename"]) results = load_backtest_stats(config["exportdirectory"], config["exportfilename"])
show_backtest_results(config, results) show_backtest_results(config, results)
show_sorted_pairlist(config, results) show_sorted_pairlist(config, results)

View File

@@ -209,13 +209,28 @@ class Configuration:
config.update({"datadir": create_datadir(config, self.args.get("datadir"))}) config.update({"datadir": create_datadir(config, self.args.get("datadir"))})
logger.info("Using data directory: %s ...", config.get("datadir")) logger.info("Using data directory: %s ...", config.get("datadir"))
self._args_to_config(
config, argname="exportdirectory", logstring="Using {} as backtest directory ..."
)
if self.args.get("exportfilename"): if self.args.get("exportfilename"):
self._args_to_config( self._args_to_config(
config, argname="exportfilename", logstring="Storing backtest results to {} ..." config, argname="exportfilename", logstring="Storing backtest results to {} ..."
) )
config["exportfilename"] = Path(config["exportfilename"]) config["exportfilename"] = Path(config["exportfilename"])
else: if config.get("exportdirectory") and Path(config["exportdirectory"]).is_dir():
config["exportfilename"] = config["user_data_dir"] / "backtest_results" logger.warning(
"DEPRECATED: Using `--export-filename` with directories is deprecated, "
"use `--backtest-directory` instead."
)
if config.get("exportdirectory") is None:
# Fallback - assign export-directory directly.
config["exportdirectory"] = config["exportfilename"]
if not config.get("exportdirectory"):
config["exportdirectory"] = config["user_data_dir"] / "backtest_results"
if not config.get("exportfilename"):
config["exportfilename"] = None
config["exportdirectory"] = Path(config["exportdirectory"])
if self.args.get("show_sensitive"): if self.args.get("show_sensitive"):
logger.warning( logger.warning(

View File

@@ -155,33 +155,55 @@ def load_backtest_metadata(filename: Path | str) -> dict[str, Any]:
raise OperationalException("Unexpected error while loading backtest metadata.") from e raise OperationalException("Unexpected error while loading backtest metadata.") from e
def load_backtest_stats(filename: Path | str) -> BacktestResultType: def _normalize_filename(file_or_directory: Path | str, filename: Path | str | None) -> Path:
"""
Normalize the filename by ensuring it is a Path object.
:param file_or_directory: The directory or file to normalize.
:param filename: The filename to normalize.
:return: A Path object representing the normalized filename.
"""
if isinstance(file_or_directory, str):
file_or_directory = Path(file_or_directory)
if file_or_directory.is_dir():
if not filename:
filename = get_latest_backtest_filename(file_or_directory)
if Path(filename).is_file():
fn = Path(filename)
else:
fn = file_or_directory / filename
else:
fn = file_or_directory
return fn
def load_backtest_stats(
file_or_directory: Path | str, filename: Path | str | None = None
) -> BacktestResultType:
""" """
Load backtest statistics file. Load backtest statistics file.
:param filename: pathlib.Path object, or string pointing to the file. :param file_or_directory: pathlib.Path object, or string pointing to the directory,
or absolute/relative path to the backtest results file.
:param filename: Optional filename to load from (if different from the main filename).
Only valid when loading from a directory.
:return: a dictionary containing the resulting file. :return: a dictionary containing the resulting file.
""" """
if isinstance(filename, str): fn = _normalize_filename(file_or_directory, filename)
filename = Path(filename)
if filename.is_dir():
filename = filename / get_latest_backtest_filename(filename)
if not filename.is_file():
raise ValueError(f"File {filename} does not exist.")
logger.info(f"Loading backtest result from {filename}")
if filename.suffix == ".zip": if not fn.is_file():
raise ValueError(f"File or directory {fn} does not exist.")
logger.info(f"Loading backtest result from {fn}")
if fn.suffix == ".zip":
data = json_load( data = json_load(
StringIO( StringIO(load_file_from_zip(fn, fn.with_suffix(".json").name).decode("utf-8"))
load_file_from_zip(filename, filename.with_suffix(".json").name).decode("utf-8")
)
) )
else: else:
with filename.open() as file: with fn.open() as file:
data = json_load(file) data = json_load(file)
# Legacy list format does not contain metadata. # Legacy list format does not contain metadata.
if isinstance(data, dict): if isinstance(data, dict):
data["metadata"] = load_backtest_metadata(filename) data["metadata"] = load_backtest_metadata(fn)
return data return data
@@ -362,16 +384,21 @@ def _load_backtest_data_df_compatibility(df: pd.DataFrame) -> pd.DataFrame:
return df return df
def load_backtest_data(filename: Path | str, strategy: str | None = None) -> pd.DataFrame: def load_backtest_data(
file_or_directory: Path | str, strategy: str | None = None, filename: Path | str | None = None
) -> pd.DataFrame:
""" """
Load backtest data file. Load backtest data file, returns a dataframe with the individual trades.
:param filename: pathlib.Path object, or string pointing to a file or directory :param file_or_directory: pathlib.Path object, or string pointing to the directory,
or absolute/relative path to the backtest results file.
:param strategy: Strategy to load - mainly relevant for multi-strategy backtests :param strategy: Strategy to load - mainly relevant for multi-strategy backtests
Can also serve as protection to load the correct result. Can also serve as protection to load the correct result.
:param filename: Optional filename to load from (if different from the main filename).
Only valid when loading from a directory.
:return: a dataframe with the analysis results :return: a dataframe with the analysis results
:raise: ValueError if loading goes wrong. :raise: ValueError if loading goes wrong.
""" """
data = load_backtest_stats(filename) data = load_backtest_stats(file_or_directory, filename)
if not isinstance(data, list): if not isinstance(data, list):
# new, nested format # new, nested format
if "strategy" not in data: if "strategy" not in data:
@@ -430,20 +457,23 @@ def load_file_from_zip(zip_path: Path, filename: str) -> bytes:
raise ValueError(f"Bad zip file: {zip_path}.") from None raise ValueError(f"Bad zip file: {zip_path}.") from None
def load_backtest_analysis_data(backtest_dir: Path, name: Literal["signals", "rejected", "exited"]): def load_backtest_analysis_data(
file_or_directory: Path,
name: Literal["signals", "rejected", "exited"],
filename: Path | str | None = None,
):
""" """
Load backtest analysis data either from a pickle file or from within a zip file Load backtest analysis data either from a pickle file or from within a zip file
:param backtest_dir: Directory containing backtest results :param file_or_directory: pathlib.Path object, or string pointing to the directory,
or absolute/relative path to the backtest results file.
:param name: Name of the analysis data to load (signals, rejected, exited) :param name: Name of the analysis data to load (signals, rejected, exited)
:param filename: Optional filename to load from (if different from the main filename).
Only valid when loading from a directory.
:return: Analysis data :return: Analysis data
""" """
import joblib import joblib
if backtest_dir.is_dir(): zip_path = _normalize_filename(file_or_directory, filename)
lbf = Path(get_latest_backtest_filename(backtest_dir))
zip_path = backtest_dir / lbf
else:
zip_path = backtest_dir
if zip_path.suffix == ".zip": if zip_path.suffix == ".zip":
# Load from zip file # Load from zip file
@@ -458,10 +488,10 @@ def load_backtest_analysis_data(backtest_dir: Path, name: Literal["signals", "re
else: else:
# Load from separate pickle file # Load from separate pickle file
if backtest_dir.is_dir(): if file_or_directory.is_dir():
scpf = Path(backtest_dir, f"{zip_path.stem}_{name}.pkl") scpf = Path(file_or_directory, f"{zip_path.stem}_{name}.pkl")
else: else:
scpf = Path(backtest_dir.parent / f"{backtest_dir.stem}_{name}.pkl") scpf = Path(file_or_directory.parent / f"{file_or_directory.stem}_{name}.pkl")
try: try:
with scpf.open("rb") as scp: with scpf.open("rb") as scp:

View File

@@ -330,7 +330,7 @@ def process_entry_exit_reasons(config: Config):
do_rejected = config.get("analysis_rejected", False) do_rejected = config.get("analysis_rejected", False)
to_csv = config.get("analysis_to_csv", False) to_csv = config.get("analysis_to_csv", False)
csv_path = Path( csv_path = Path(
config.get("analysis_csv_path", config["exportfilename"]), # type: ignore[arg-type] config.get("analysis_csv_path", config["exportdirectory"]), # type: ignore[arg-type]
) )
if entry_only is True and exit_only is True: if entry_only is True and exit_only is True:
@@ -344,21 +344,29 @@ def process_entry_exit_reasons(config: Config):
None if config.get("timerange") is None else str(config.get("timerange")) None if config.get("timerange") is None else str(config.get("timerange"))
) )
try: try:
backtest_stats = load_backtest_stats(config["exportfilename"]) backtest_stats = load_backtest_stats(
config["exportdirectory"], config["exportfilename"]
)
except ValueError as e: except ValueError as e:
raise ConfigurationError(e) from e raise ConfigurationError(e) from e
for strategy_name, results in backtest_stats["strategy"].items(): for strategy_name, results in backtest_stats["strategy"].items():
trades = load_backtest_data(config["exportfilename"], strategy_name) trades = load_backtest_data(
config["exportdirectory"], strategy_name, config["exportfilename"]
)
if trades is not None and not trades.empty: if trades is not None and not trades.empty:
signal_candles = load_backtest_analysis_data(config["exportfilename"], "signals") signal_candles = load_backtest_analysis_data(
exit_signals = load_backtest_analysis_data(config["exportfilename"], "exited") config["exportdirectory"], "signals", config["exportfilename"]
)
exit_signals = load_backtest_analysis_data(
config["exportdirectory"], "exited", config["exportfilename"]
)
rej_df = None rej_df = None
if do_rejected: if do_rejected:
rejected_signals_dict = load_backtest_analysis_data( rejected_signals_dict = load_backtest_analysis_data(
config["exportfilename"], "rejected" config["exportdirectory"], "rejected", config["exportfilename"]
) )
rej_df = prepare_results( rej_df = prepare_results(
rejected_signals_dict, rejected_signals_dict,

View File

@@ -64,7 +64,7 @@ def store_backtest_results(
:param market_change_data: Dataframe containing market change data :param market_change_data: Dataframe containing market change data
:param analysis_results: Dictionary containing analysis results :param analysis_results: Dictionary containing analysis results
""" """
recordfilename: Path = config["exportfilename"] recordfilename: Path = config["exportdirectory"]
zip_filename = _generate_filename(recordfilename, dtappendix, ".zip") zip_filename = _generate_filename(recordfilename, dtappendix, ".zip")
base_filename = _generate_filename(recordfilename, dtappendix, "") base_filename = _generate_filename(recordfilename, dtappendix, "")
json_filename = _generate_filename(recordfilename, dtappendix, ".json") json_filename = _generate_filename(recordfilename, dtappendix, ".json")

View File

@@ -1862,8 +1862,10 @@ def test_backtesting_show(mocker, testdatadir, capsys):
sbr = mocker.patch("freqtrade.optimize.optimize_reports.show_backtest_results") sbr = mocker.patch("freqtrade.optimize.optimize_reports.show_backtest_results")
args = [ args = [
"backtesting-show", "backtesting-show",
"--export-directory",
f"{testdatadir / 'backtest_results'}",
"--export-filename", "--export-filename",
f"{testdatadir / 'backtest_results/backtest-result.json'}", "backtest-result.json",
"--show-pair-list", "--show-pair-list",
] ]
pargs = get_args(args) pargs = get_args(args)

View File

@@ -236,7 +236,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmp_path):
filename_last = tmp_path / LAST_BT_RESULT_FN filename_last = tmp_path / LAST_BT_RESULT_FN
_backup_file(filename_last, copy_file=True) _backup_file(filename_last, copy_file=True)
assert not filename.is_file() assert not filename.is_file()
default_conf["exportfilename"] = filename default_conf["exportdirectory"] = filename
store_backtest_results(default_conf, stats, "2022_01_01_15_05_13") store_backtest_results(default_conf, stats, "2022_01_01_15_05_13")
@@ -263,7 +263,7 @@ def test_store_backtest_results(testdatadir, mocker):
zip_mock = mocker.patch("freqtrade.optimize.optimize_reports.bt_storage.ZipFile") zip_mock = mocker.patch("freqtrade.optimize.optimize_reports.bt_storage.ZipFile")
data = {"metadata": {}, "strategy": {}, "strategy_comparison": []} data = {"metadata": {}, "strategy": {}, "strategy_comparison": []}
store_backtest_results( store_backtest_results(
{"exportfilename": testdatadir, "original_config": {}}, data, "2022_01_01_15_05_13" {"exportdirectory": testdatadir, "original_config": {}}, data, "2022_01_01_15_05_13"
) )
assert dump_mock.call_count == 2 assert dump_mock.call_count == 2
@@ -275,7 +275,7 @@ def test_store_backtest_results(testdatadir, mocker):
zip_mock.reset_mock() zip_mock.reset_mock()
filename = testdatadir / "testresult.json" filename = testdatadir / "testresult.json"
store_backtest_results( store_backtest_results(
{"exportfilename": filename, "original_config": {}}, data, "2022_01_01_15_05_13" {"exportdirectory": filename, "original_config": {}}, data, "2022_01_01_15_05_13"
) )
assert dump_mock.call_count == 2 assert dump_mock.call_count == 2
assert zip_mock.call_count == 1 assert zip_mock.call_count == 1
@@ -287,7 +287,7 @@ def test_store_backtest_results(testdatadir, mocker):
def test_store_backtest_results_real(tmp_path, caplog): def test_store_backtest_results_real(tmp_path, caplog):
data = {"metadata": {}, "strategy": {}, "strategy_comparison": []} data = {"metadata": {}, "strategy": {}, "strategy_comparison": []}
config = { config = {
"exportfilename": tmp_path, "exportdirectory": tmp_path,
"original_config": {}, "original_config": {},
} }
store_backtest_results( store_backtest_results(
@@ -356,7 +356,7 @@ def test_write_read_backtest_candles(tmp_path):
bt_results = {"metadata": {}, "strategy": {}, "strategy_comparison": []} bt_results = {"metadata": {}, "strategy": {}, "strategy_comparison": []}
mock_conf = { mock_conf = {
"exportfilename": tmp_path, "exportdirectory": tmp_path,
"export": "signals", "export": "signals",
"runmode": "backtest", "runmode": "backtest",
"original_config": {}, "original_config": {},
@@ -393,33 +393,6 @@ def test_write_read_backtest_candles(tmp_path):
_clean_test_file(stored_file) _clean_test_file(stored_file)
# test file exporting
filename = tmp_path / "testresult"
mock_conf["exportfilename"] = filename
store_backtest_results(mock_conf, bt_results, sample_date, analysis_results=data)
stored_file = tmp_path / f"testresult-{sample_date}.zip"
signals_pkl = f"testresult-{sample_date}_signals.pkl"
rejected_pkl = f"testresult-{sample_date}_rejected.pkl"
exited_pkl = f"testresult-{sample_date}_exited.pkl"
assert not (tmp_path / signals_pkl).is_file()
assert stored_file.is_file()
with ZipFile(stored_file, "r") as zipf:
assert signals_pkl in zipf.namelist()
assert rejected_pkl in zipf.namelist()
assert exited_pkl in zipf.namelist()
with zipf.open(signals_pkl) as scp:
pickled_signal_candles2 = joblib.load(scp)
assert pickled_signal_candles2.keys() == candle_dict.keys()
assert pickled_signal_candles2["DefStrat"].keys() == pickled_signal_candles2["DefStrat"].keys()
assert pickled_signal_candles2["DefStrat"]["UNITTEST/BTC"].equals(
pickled_signal_candles2["DefStrat"]["UNITTEST/BTC"]
)
_clean_test_file(stored_file)
def test_generate_pair_metrics(): def test_generate_pair_metrics():
results = pd.DataFrame( results = pd.DataFrame(

View File

@@ -2802,8 +2802,8 @@ def test_api_backtesting(botclient, mocker, fee, caplog, tmp_path):
ftbot.config["export"] = "trades" ftbot.config["export"] = "trades"
ftbot.config["backtest_cache"] = "day" ftbot.config["backtest_cache"] = "day"
ftbot.config["user_data_dir"] = tmp_path ftbot.config["user_data_dir"] = tmp_path
ftbot.config["exportfilename"] = tmp_path / "backtest_results" ftbot.config["exportdirectory"] = tmp_path / "backtest_results"
ftbot.config["exportfilename"].mkdir() ftbot.config["exportdirectory"].mkdir()
# start backtesting # start backtesting
data = { data = {