From 0b01fcf0477b0eb78b8f0d1eb1f2d0c7b5e76dcd Mon Sep 17 00:00:00 2001 From: zx <54022220+ediziks@users.noreply.github.com> Date: Sun, 6 Feb 2022 15:40:54 +0100 Subject: [PATCH 1/7] Add ProfitDrawdownHyperoptLoss method --- docs/hyperopt.md | 3 +- freqtrade/constants.py | 2 +- .../optimize/hyperopt_loss_profit_drawdown.py | 29 +++++++++++++++++++ tests/optimize/test_hyperoptloss.py | 3 +- 4 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 freqtrade/optimize/hyperopt_loss_profit_drawdown.py diff --git a/docs/hyperopt.md b/docs/hyperopt.md index b7b6cb772..27d5a8761 100644 --- a/docs/hyperopt.md +++ b/docs/hyperopt.md @@ -116,7 +116,7 @@ optional arguments: ShortTradeDurHyperOptLoss, OnlyProfitHyperOptLoss, SharpeHyperOptLoss, SharpeHyperOptLossDaily, SortinoHyperOptLoss, SortinoHyperOptLossDaily, - CalmarHyperOptLoss, MaxDrawDownHyperOptLoss + CalmarHyperOptLoss, MaxDrawDownHyperOptLoss, ProfitDrawDownHyperOptLoss --disable-param-export Disable automatic hyperopt parameter export. --ignore-missing-spaces, --ignore-unparameterized-spaces @@ -525,6 +525,7 @@ Currently, the following loss functions are builtin: * `SortinoHyperOptLossDaily` - optimizes Sortino Ratio calculated on **daily** trade returns relative to **downside** standard deviation. * `MaxDrawDownHyperOptLoss` - Optimizes Maximum drawdown. * `CalmarHyperOptLoss` - Optimizes Calmar Ratio calculated on trade returns relative to max drawdown. +* `ProfitDrawDownHyperOptLoss` - Optimizes by max Profit & min Drawdown objective. `DRAWDOWN_MULT` variable within the hyperoptloss file can be adjusted to be stricter or more flexible on drawdown purposes. Creation of a custom loss function is covered in the [Advanced Hyperopt](advanced-hyperopt.md) part of the documentation. diff --git a/freqtrade/constants.py b/freqtrade/constants.py index d94e8d850..e7782b6d2 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -26,7 +26,7 @@ HYPEROPT_LOSS_BUILTIN = ['ShortTradeDurHyperOptLoss', 'OnlyProfitHyperOptLoss', 'SharpeHyperOptLoss', 'SharpeHyperOptLossDaily', 'SortinoHyperOptLoss', 'SortinoHyperOptLossDaily', 'CalmarHyperOptLoss', - 'MaxDrawDownHyperOptLoss'] + 'MaxDrawDownHyperOptLoss', 'ProfitDrawDownHyperOptLoss'] AVAILABLE_PAIRLISTS = ['StaticPairList', 'VolumePairList', 'AgeFilter', 'OffsetFilter', 'PerformanceFilter', 'PrecisionFilter', 'PriceFilter', 'RangeStabilityFilter', diff --git a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py new file mode 100644 index 000000000..8bb8cd9d4 --- /dev/null +++ b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py @@ -0,0 +1,29 @@ +""" +ProfitDrawDownHyperOptLoss + +This module defines the alternative HyperOptLoss class based on Profit & +Drawdown objective which can be used for Hyperoptimization. + +Possible to change `DRAWDOWN_MULT` to penalize drawdown objective for +individual needs. +""" +from pandas import DataFrame +from freqtrade.optimize.hyperopt import IHyperOptLoss +from freqtrade.data.btanalysis import calculate_max_drawdown + +# higher numbers penalize drawdowns more severely +DRAWDOWN_MULT = 0.075 + + +class ProfitDrawDownHyperOptLoss(IHyperOptLoss): + @staticmethod + def hyperopt_loss_function(results: DataFrame, trade_count: int, *args, **kwargs) -> float: + total_profit = results["profit_abs"].sum() + + # from freqtrade.optimize.optimize_reports.generate_strategy_stats() + try: + _, _, _, _, max_drawdown_per = calculate_max_drawdown(results, value_col="profit_ratio") + except ValueError: + max_drawdown_per = 0 + + return -1 * (total_profit * (1 - max_drawdown_per * DRAWDOWN_MULT)) diff --git a/tests/optimize/test_hyperoptloss.py b/tests/optimize/test_hyperoptloss.py index e4a2eec2e..e3f6daf6c 100644 --- a/tests/optimize/test_hyperoptloss.py +++ b/tests/optimize/test_hyperoptloss.py @@ -86,6 +86,7 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) -> "SharpeHyperOptLossDaily", "MaxDrawDownHyperOptLoss", "CalmarHyperOptLoss", + "ProfitDrawDownHyperOptLoss", ]) def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunction) -> None: @@ -106,7 +107,7 @@ def test_loss_functions_better_profits(default_conf, hyperopt_results, lossfunct config=default_conf, processed=None, backtest_stats={'profit_total': hyperopt_results['profit_abs'].sum()} - ) + ) over = hl.hyperopt_loss_function( results_over, trade_count=len(results_over), From 6b5f63d4d61e40764fa3e6d92ec482fa570229ef Mon Sep 17 00:00:00 2001 From: zx <54022220+ediziks@users.noreply.github.com> Date: Sun, 6 Feb 2022 16:20:25 +0100 Subject: [PATCH 2/7] change profit_ratio by profit_abs --- freqtrade/optimize/hyperopt_loss_profit_drawdown.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py index 8bb8cd9d4..104bacd2a 100644 --- a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py +++ b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py @@ -22,8 +22,8 @@ class ProfitDrawDownHyperOptLoss(IHyperOptLoss): # from freqtrade.optimize.optimize_reports.generate_strategy_stats() try: - _, _, _, _, max_drawdown_per = calculate_max_drawdown(results, value_col="profit_ratio") + profit_abs, _, _, _, _ = calculate_max_drawdown(results, value_col="profit_ratio") except ValueError: - max_drawdown_per = 0 + profit_abs = 0 - return -1 * (total_profit * (1 - max_drawdown_per * DRAWDOWN_MULT)) + return -1 * (total_profit * (1 - profit_abs * DRAWDOWN_MULT)) From 7d3b80fbde373208cfd340f707ea6fdd0b35b4ce Mon Sep 17 00:00:00 2001 From: zx <54022220+ediziks@users.noreply.github.com> Date: Sun, 6 Feb 2022 17:13:09 +0100 Subject: [PATCH 3/7] isort fix and leftover cleaning --- .DS_Store | Bin 0 -> 10244 bytes .../optimize/hyperopt_loss_profit_drawdown.py | 7 ++++--- 2 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..a67fb52e74d3dc023db3b44f1beea46a3926f230 GIT binary patch literal 10244 zcmeHM&1w`u5Uz=3)!mtN_0CQ<2SKF8*@Z45sjj; zJb4_if``Ys^*tl5=O$zXd!iM}XoI$Bnb!NXwL=+D29yD1Kp9X5{sso{o6XPYxRv@= z29yD1AZLKjhZv1z;$+WCb9CTkN&v_Ty3K>nr~`~m>}29(&q`y8Ic@b2In&6M7?Cx{ zc+BdMiIY7mtvN;3oFeBraurHsyu&Uw>J%kb>RTC52KpJ`+I@m%s6i?1i28j4J)5oO z+`>xM?pVX>yK?PzR;$%pSshx~j=izn&+l&^WYIXJMQ6=N6k~dvAT!j&jl-6Ywleu( z${+Kw{kY$Hbn=VAmfNC@Ur zGFZ#UL-dC6@H%$r8SYf*hK^;||t3^6_CHIV4XzlGxxYtFftLn15IDZo*2I3$B-o?ifle9ZUX zdiC*oe%{y^y1wtCapCuDf~jeYR*`!tJ;C1I#7c&Hyr z1vJ}+hd?91KAE5UeAeaj1Skh+NjwRh(b4?GmsobISLJAcW6I^EXCGiF&=CG#FR}kI zoRVGMlQ?4<$V=S+%T>PgwOA{_bKc=8m@mLpqABpX;({)5dVQ0)C?QQ-a|1-edA;_vi>wijpMzsFt`wCf4ntRrux|g-?zf%AI E2BFcLxBvhE literal 0 HcmV?d00001 diff --git a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py index 104bacd2a..6df605c82 100644 --- a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py +++ b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py @@ -8,8 +8,10 @@ Possible to change `DRAWDOWN_MULT` to penalize drawdown objective for individual needs. """ from pandas import DataFrame -from freqtrade.optimize.hyperopt import IHyperOptLoss + from freqtrade.data.btanalysis import calculate_max_drawdown +from freqtrade.optimize.hyperopt import IHyperOptLoss + # higher numbers penalize drawdowns more severely DRAWDOWN_MULT = 0.075 @@ -20,9 +22,8 @@ class ProfitDrawDownHyperOptLoss(IHyperOptLoss): def hyperopt_loss_function(results: DataFrame, trade_count: int, *args, **kwargs) -> float: total_profit = results["profit_abs"].sum() - # from freqtrade.optimize.optimize_reports.generate_strategy_stats() try: - profit_abs, _, _, _, _ = calculate_max_drawdown(results, value_col="profit_ratio") + profit_abs, _, _, _, _ = calculate_max_drawdown(results, value_col="profit_abs") except ValueError: profit_abs = 0 From 2893d0b50db94d7aa6f98e29674e57468b476dc2 Mon Sep 17 00:00:00 2001 From: zx <54022220+ediziks@users.noreply.github.com> Date: Mon, 7 Feb 2022 06:22:27 +0100 Subject: [PATCH 4/7] proper var name --- freqtrade/optimize/hyperopt_loss_profit_drawdown.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py index 6df605c82..957663827 100644 --- a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py +++ b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py @@ -14,7 +14,7 @@ from freqtrade.optimize.hyperopt import IHyperOptLoss # higher numbers penalize drawdowns more severely -DRAWDOWN_MULT = 0.075 +DRAWDOWN_MULT = 0.01 class ProfitDrawDownHyperOptLoss(IHyperOptLoss): @@ -23,8 +23,8 @@ class ProfitDrawDownHyperOptLoss(IHyperOptLoss): total_profit = results["profit_abs"].sum() try: - profit_abs, _, _, _, _ = calculate_max_drawdown(results, value_col="profit_abs") + max_drawdown_abs, _, _, _, _ = calculate_max_drawdown(results, value_col="profit_abs") except ValueError: - profit_abs = 0 + max_drawdown_abs = 0 - return -1 * (total_profit * (1 - profit_abs * DRAWDOWN_MULT)) + return -1 * (total_profit * (1 - max_drawdown_abs * DRAWDOWN_MULT)) From 8cdb6e0774dbbfe2e869d589d5a2a17d2e94da6b Mon Sep 17 00:00:00 2001 From: zx <54022220+ediziks@users.noreply.github.com> Date: Mon, 7 Feb 2022 06:31:16 +0100 Subject: [PATCH 5/7] DRAWDOWN_MULT back to a higher value as built-in for safer HOs first --- freqtrade/optimize/hyperopt_loss_profit_drawdown.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py index 957663827..2bba58333 100644 --- a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py +++ b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py @@ -14,7 +14,7 @@ from freqtrade.optimize.hyperopt import IHyperOptLoss # higher numbers penalize drawdowns more severely -DRAWDOWN_MULT = 0.01 +DRAWDOWN_MULT = 0.075 class ProfitDrawDownHyperOptLoss(IHyperOptLoss): From 7811a36ae91f564287b5dade852a599e2a6b103b Mon Sep 17 00:00:00 2001 From: zx <54022220+ediziks@users.noreply.github.com> Date: Mon, 7 Feb 2022 07:44:13 +0100 Subject: [PATCH 6/7] max_drawdown_abs calc fix & .DS_Store deletition --- .DS_Store | Bin 10244 -> 0 bytes .../optimize/hyperopt_loss_profit_drawdown.py | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index a67fb52e74d3dc023db3b44f1beea46a3926f230..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10244 zcmeHM&1w`u5Uz=3)!mtN_0CQ<2SKF8*@Z45sjj; zJb4_if``Ys^*tl5=O$zXd!iM}XoI$Bnb!NXwL=+D29yD1Kp9X5{sso{o6XPYxRv@= z29yD1AZLKjhZv1z;$+WCb9CTkN&v_Ty3K>nr~`~m>}29(&q`y8Ic@b2In&6M7?Cx{ zc+BdMiIY7mtvN;3oFeBraurHsyu&Uw>J%kb>RTC52KpJ`+I@m%s6i?1i28j4J)5oO z+`>xM?pVX>yK?PzR;$%pSshx~j=izn&+l&^WYIXJMQ6=N6k~dvAT!j&jl-6Ywleu( z${+Kw{kY$Hbn=VAmfNC@Ur zGFZ#UL-dC6@H%$r8SYf*hK^;||t3^6_CHIV4XzlGxxYtFftLn15IDZo*2I3$B-o?ifle9ZUX zdiC*oe%{y^y1wtCapCuDf~jeYR*`!tJ;C1I#7c&Hyr z1vJ}+hd?91KAE5UeAeaj1Skh+NjwRh(b4?GmsobISLJAcW6I^EXCGiF&=CG#FR}kI zoRVGMlQ?4<$V=S+%T>PgwOA{_bKc=8m@mLpqABpX;({)5dVQ0)C?QQ-a|1-edA;_vi>wijpMzsFt`wCf4ntRrux|g-?zf%AI E2BFcLxBvhE diff --git a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py index 2bba58333..90240e80f 100644 --- a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py +++ b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py @@ -23,7 +23,8 @@ class ProfitDrawDownHyperOptLoss(IHyperOptLoss): total_profit = results["profit_abs"].sum() try: - max_drawdown_abs, _, _, _, _ = calculate_max_drawdown(results, value_col="profit_abs") + _, _, _, _, _, max_drawdown_abs = calculate_max_drawdown(results, value_col="profit_abs") + # max_drawdown_abs = calculate_max_drawdown(results, value_col="profit_abs")[5] except ValueError: max_drawdown_abs = 0 From 4bce64b4271803429f31d03d5bdbe4502b1203e0 Mon Sep 17 00:00:00 2001 From: zx <54022220+ediziks@users.noreply.github.com> Date: Mon, 7 Feb 2022 14:12:07 +0100 Subject: [PATCH 7/7] commented method deletition --- freqtrade/optimize/hyperopt_loss_profit_drawdown.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py index 90240e80f..5bd12ff52 100644 --- a/freqtrade/optimize/hyperopt_loss_profit_drawdown.py +++ b/freqtrade/optimize/hyperopt_loss_profit_drawdown.py @@ -23,8 +23,7 @@ class ProfitDrawDownHyperOptLoss(IHyperOptLoss): total_profit = results["profit_abs"].sum() try: - _, _, _, _, _, max_drawdown_abs = calculate_max_drawdown(results, value_col="profit_abs") - # max_drawdown_abs = calculate_max_drawdown(results, value_col="profit_abs")[5] + max_drawdown_abs = calculate_max_drawdown(results, value_col="profit_abs")[5] except ValueError: max_drawdown_abs = 0