diff --git a/freqtrade/commands/hyperopt_commands.py b/freqtrade/commands/hyperopt_commands.py index e072e12cb..d8b00f369 100755 --- a/freqtrade/commands/hyperopt_commands.py +++ b/freqtrade/commands/hyperopt_commands.py @@ -197,8 +197,12 @@ def _hyperopt_filter_epochs_duration(epochs: List, filteroptions: dict) -> List: return x['results_metrics']['duration'] else: # New mode - avg = x['results_metrics']['holding_avg'] - return avg.total_seconds() // 60 + if 'holding_avg_s' in x['results_metrics']: + avg = x['results_metrics']['holding_avg_s'] + return avg // 60 + raise OperationalException( + "Holding-average not available. Please omit the filter on average time, " + "or rerun hyperopt with this version") if filteroptions['filter_min_avg_time'] is not None: epochs = _hyperopt_filter_epochs_trade(epochs, 0) diff --git a/freqtrade/optimize/optimize_reports.py b/freqtrade/optimize/optimize_reports.py index 5822fc627..84e052ac4 100644 --- a/freqtrade/optimize/optimize_reports.py +++ b/freqtrade/optimize/optimize_reports.py @@ -232,16 +232,23 @@ def generate_trading_stats(results: DataFrame) -> Dict[str, Any]: zero_duration_trades = len(results.loc[(results['trade_duration'] == 0) & (results['sell_reason'] == 'trailing_stop_loss')]) + holding_avg = (timedelta(minutes=round(results['trade_duration'].mean())) + if not results.empty else timedelta()) + winner_holding_avg = (timedelta(minutes=round(winning_trades['trade_duration'].mean())) + if not winning_trades.empty else timedelta()) + loser_holding_avg = (timedelta(minutes=round(losing_trades['trade_duration'].mean())) + if not losing_trades.empty else timedelta()) + return { 'wins': len(winning_trades), 'losses': len(losing_trades), 'draws': len(draw_trades), - 'holding_avg': (timedelta(minutes=round(results['trade_duration'].mean())) - if not results.empty else timedelta()), - 'winner_holding_avg': (timedelta(minutes=round(winning_trades['trade_duration'].mean())) - if not winning_trades.empty else timedelta()), - 'loser_holding_avg': (timedelta(minutes=round(losing_trades['trade_duration'].mean())) - if not losing_trades.empty else timedelta()), + 'holding_avg': holding_avg, + 'holding_avg_s': holding_avg.total_seconds(), + 'winner_holding_avg': winner_holding_avg, + 'winner_holding_avg_s': winner_holding_avg.total_seconds(), + 'loser_holding_avg': loser_holding_avg, + 'loser_holding_avg_s': loser_holding_avg.total_seconds(), 'zero_duration_trades': zero_duration_trades, } diff --git a/tests/commands/test_commands.py b/tests/commands/test_commands.py index f47fc46c1..71ae0ed78 100644 --- a/tests/commands/test_commands.py +++ b/tests/commands/test_commands.py @@ -921,10 +921,10 @@ def test_start_test_pairlist(mocker, caplog, tickers, default_conf, capsys): def test_hyperopt_list(mocker, capsys, caplog, saved_hyperopt_results, saved_hyperopt_results_legacy, tmpdir): csv_file = Path(tmpdir) / "test.csv" - for _ in (saved_hyperopt_results, saved_hyperopt_results_legacy): + for res in (saved_hyperopt_results, saved_hyperopt_results_legacy): mocker.patch( 'freqtrade.optimize.hyperopt_tools.HyperoptTools.load_previous_results', - MagicMock(return_value=saved_hyperopt_results_legacy) + MagicMock(return_value=res) ) args = [ @@ -1148,9 +1148,10 @@ def test_hyperopt_list(mocker, capsys, caplog, saved_hyperopt_results, start_hyperopt_list(pargs) captured = capsys.readouterr() log_has("CSV file created: test_file.csv", caplog) - assert ('Best,1,2,-1.25%,-1.2222,-0.00125625,,-2.51,"3,930.0 m",0.43662' - in csv_file.read_text()) assert csv_file.is_file() + line = csv_file.read_text() + assert ('Best,1,2,-1.25%,-1.2222,-0.00125625,,-2.51,"3,930.0 m",0.43662' in line + or "Best,1,2,-1.25%,-1.2222,-0.00125625,,-2.51,2 days 17:30:00,0.43662" in line) csv_file.unlink() diff --git a/tests/conftest.py b/tests/conftest.py index ef2bd0613..43a98647f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1913,7 +1913,7 @@ def saved_hyperopt_results_legacy(): @pytest.fixture def saved_hyperopt_results(): - return [ + hyperopt_res = [ { 'loss': 0.4366182531161519, 'params_dict': { @@ -2042,3 +2042,9 @@ def saved_hyperopt_results(): 'is_best': False } ] + + for res in hyperopt_res: + res['results_metrics']['holding_avg_s'] = res['results_metrics']['holding_avg' + ].total_seconds() + + return hyperopt_res