Merge pull request #6165 from freqtrade/drawdown_fixes
Improved drawdown calculation
This commit is contained in:
		| @@ -312,7 +312,7 @@ A backtesting result will look like that: | |||||||
| |                       |                     | | |                       |                     | | ||||||
| | Min balance           | 0.00945123 BTC      | | | Min balance           | 0.00945123 BTC      | | ||||||
| | Max balance           | 0.01846651 BTC      | | | Max balance           | 0.01846651 BTC      | | ||||||
| | Drawdown              | 50.63%              | | | Drawdown (Account)    | 13.33%              | | ||||||
| | Drawdown              | 0.0015 BTC          | | | Drawdown              | 0.0015 BTC          | | ||||||
| | Drawdown high         | 0.0013 BTC          | | | Drawdown high         | 0.0013 BTC          | | ||||||
| | Drawdown low          | -0.0002 BTC         | | | Drawdown low          | -0.0002 BTC         | | ||||||
| @@ -399,7 +399,7 @@ It contains some useful key metrics about performance of your strategy on backte | |||||||
| |                       |                     | | |                       |                     | | ||||||
| | Min balance           | 0.00945123 BTC      | | | Min balance           | 0.00945123 BTC      | | ||||||
| | Max balance           | 0.01846651 BTC      | | | Max balance           | 0.01846651 BTC      | | ||||||
| | Drawdown              | 50.63%              | | | Drawdown (Account)    | 13.33%              | | ||||||
| | Drawdown              | 0.0015 BTC          | | | Drawdown              | 0.0015 BTC          | | ||||||
| | Drawdown high         | 0.0013 BTC          | | | Drawdown high         | 0.0013 BTC          | | ||||||
| | Drawdown low          | -0.0002 BTC         | | | Drawdown low          | -0.0002 BTC         | | ||||||
| @@ -426,7 +426,8 @@ It contains some useful key metrics about performance of your strategy on backte | |||||||
| - `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades. | - `Avg. Duration Winners` / `Avg. Duration Loser`: Average durations for winning and losing trades. | ||||||
| - `Rejected Buy signals`: Buy signals that could not be acted upon due to max_open_trades being reached. | - `Rejected Buy signals`: Buy signals that could not be acted upon due to max_open_trades being reached. | ||||||
| - `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period. | - `Min balance` / `Max balance`: Lowest and Highest Wallet balance during the backtest period. | ||||||
| - `Drawdown`: Maximum drawdown experienced. For example, the value of 50% means that from highest to subsequent lowest point, a 50% drop was experienced). | - `Drawdown (Account)`: Maximum Account Drawdown experienced. Calculated as $(Absolute Drawdown) / (DrawdownHigh + startingBalance)$. | ||||||
|  | - `Drawdown`: Maximum, absolute drawdown experienced. Difference between Drawdown High and Subsequent Low point. | ||||||
| - `Drawdown high` / `Drawdown low`: Profit at the beginning and end of the largest drawdown period. A negative low value means initial capital lost. | - `Drawdown high` / `Drawdown low`: Profit at the beginning and end of the largest drawdown period. A negative low value means initial capital lost. | ||||||
| - `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command). | - `Drawdown Start` / `Drawdown End`: Start and end datetime for this largest drawdown (can also be visualized via the `plot-dataframe` sub-command). | ||||||
| - `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. | - `Market change`: Change of the market during the backtest period. Calculated as average of all pairs changes from the first to the last candle using the "close" column. | ||||||
|   | |||||||
| @@ -19,11 +19,6 @@ logger = logging.getLogger(__name__) | |||||||
| BT_DATA_COLUMNS_OLD = ["pair", "profit_percent", "open_date", "close_date", "index", | BT_DATA_COLUMNS_OLD = ["pair", "profit_percent", "open_date", "close_date", "index", | ||||||
|                        "trade_duration", "open_rate", "close_rate", "open_at_end", "sell_reason"] |                        "trade_duration", "open_rate", "close_rate", "open_at_end", "sell_reason"] | ||||||
|  |  | ||||||
| # Mid-term format, created by BacktestResult Named Tuple |  | ||||||
| BT_DATA_COLUMNS_MID = ['pair', 'profit_percent', 'open_date', 'close_date', 'trade_duration', |  | ||||||
|                        'open_rate', 'close_rate', 'open_at_end', 'sell_reason', 'fee_open', |  | ||||||
|                        'fee_close', 'amount', 'profit_abs', 'profit_ratio'] |  | ||||||
|  |  | ||||||
| # Newest format | # Newest format | ||||||
| BT_DATA_COLUMNS = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date', | BT_DATA_COLUMNS = ['pair', 'stake_amount', 'amount', 'open_date', 'close_date', | ||||||
|                    'open_rate', 'close_rate', |                    'open_rate', 'close_rate', | ||||||
| @@ -392,15 +387,17 @@ def calculate_underwater(trades: pd.DataFrame, *, date_col: str = 'close_date', | |||||||
|  |  | ||||||
|  |  | ||||||
| def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date', | def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date', | ||||||
|                            value_col: str = 'profit_ratio' |                            value_col: str = 'profit_abs', starting_balance: float = 0 | ||||||
|                            ) -> Tuple[float, pd.Timestamp, pd.Timestamp, float, float]: |                            ) -> Tuple[float, pd.Timestamp, pd.Timestamp, float, float, float]: | ||||||
|     """ |     """ | ||||||
|     Calculate max drawdown and the corresponding close dates |     Calculate max drawdown and the corresponding close dates | ||||||
|     :param trades: DataFrame containing trades (requires columns close_date and profit_ratio) |     :param trades: DataFrame containing trades (requires columns close_date and profit_ratio) | ||||||
|     :param date_col: Column in DataFrame to use for dates (defaults to 'close_date') |     :param date_col: Column in DataFrame to use for dates (defaults to 'close_date') | ||||||
|     :param value_col: Column in DataFrame to use for values (defaults to 'profit_ratio') |     :param value_col: Column in DataFrame to use for values (defaults to 'profit_abs') | ||||||
|     :return: Tuple (float, highdate, lowdate, highvalue, lowvalue) with absolute max drawdown, |     :param starting_balance: Portfolio starting balance - properly calculate relative drawdown. | ||||||
|              high and low time and high and low value. |     :return: Tuple (float, highdate, lowdate, highvalue, lowvalue, relative_drawdown) | ||||||
|  |              with absolute max drawdown, high and low time and high and low value, | ||||||
|  |              and the relative account drawdown | ||||||
|     :raise: ValueError if trade-dataframe was found empty. |     :raise: ValueError if trade-dataframe was found empty. | ||||||
|     """ |     """ | ||||||
|     if len(trades) == 0: |     if len(trades) == 0: | ||||||
| @@ -416,7 +413,17 @@ def calculate_max_drawdown(trades: pd.DataFrame, *, date_col: str = 'close_date' | |||||||
|     high_val = max_drawdown_df.loc[max_drawdown_df.iloc[:idxmin] |     high_val = max_drawdown_df.loc[max_drawdown_df.iloc[:idxmin] | ||||||
|                                    ['high_value'].idxmax(), 'cumulative'] |                                    ['high_value'].idxmax(), 'cumulative'] | ||||||
|     low_val = max_drawdown_df.loc[idxmin, 'cumulative'] |     low_val = max_drawdown_df.loc[idxmin, 'cumulative'] | ||||||
|     return abs(min(max_drawdown_df['drawdown'])), high_date, low_date, high_val, low_val |  | ||||||
|  |     max_drawdown_rel = (high_val - low_val) / (high_val + starting_balance) | ||||||
|  |  | ||||||
|  |     return ( | ||||||
|  |         abs(min(max_drawdown_df['drawdown'])), | ||||||
|  |         high_date, | ||||||
|  |         low_date, | ||||||
|  |         high_val, | ||||||
|  |         low_val, | ||||||
|  |         max_drawdown_rel | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
| def calculate_csum(trades: pd.DataFrame, starting_balance: float = 0) -> Tuple[float, float]: | def calculate_csum(trades: pd.DataFrame, starting_balance: float = 0) -> Tuple[float, float]: | ||||||
|   | |||||||
| @@ -47,10 +47,9 @@ class CalmarHyperOptLoss(IHyperOptLoss): | |||||||
|  |  | ||||||
|         # calculate max drawdown |         # calculate max drawdown | ||||||
|         try: |         try: | ||||||
|             _, _, _, high_val, low_val = calculate_max_drawdown( |             _, _, _, _, _, max_drawdown = calculate_max_drawdown( | ||||||
|                 results, value_col="profit_abs" |                 results, value_col="profit_abs" | ||||||
|             ) |             ) | ||||||
|             max_drawdown = (high_val - low_val) / high_val |  | ||||||
|         except ValueError: |         except ValueError: | ||||||
|             max_drawdown = 0 |             max_drawdown = 0 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -308,8 +308,7 @@ class HyperoptTools(): | |||||||
|  |  | ||||||
|         if not has_drawdown: |         if not has_drawdown: | ||||||
|             # Ensure compatibility with older versions of hyperopt results |             # Ensure compatibility with older versions of hyperopt results | ||||||
|             trials['results_metrics.max_drawdown_abs'] = None |             trials['results_metrics.max_drawdown_account'] = None | ||||||
|             trials['results_metrics.max_drawdown'] = None |  | ||||||
|  |  | ||||||
|         # New mode, using backtest result for metrics |         # New mode, using backtest result for metrics | ||||||
|         trials['results_metrics.winsdrawslosses'] = trials.apply( |         trials['results_metrics.winsdrawslosses'] = trials.apply( | ||||||
| @@ -320,12 +319,15 @@ class HyperoptTools(): | |||||||
|                          'results_metrics.winsdrawslosses', |                          'results_metrics.winsdrawslosses', | ||||||
|                          'results_metrics.profit_mean', 'results_metrics.profit_total_abs', |                          'results_metrics.profit_mean', 'results_metrics.profit_total_abs', | ||||||
|                          'results_metrics.profit_total', 'results_metrics.holding_avg', |                          'results_metrics.profit_total', 'results_metrics.holding_avg', | ||||||
|                          'results_metrics.max_drawdown', 'results_metrics.max_drawdown_abs', |                          'results_metrics.max_drawdown', | ||||||
|  |                          'results_metrics.max_drawdown_account', 'results_metrics.max_drawdown_abs', | ||||||
|                          'loss', 'is_initial_point', 'is_best']] |                          'loss', 'is_initial_point', 'is_best']] | ||||||
|  |  | ||||||
|         trials.columns = ['Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', |         trials.columns = [ | ||||||
|                           'Total profit', 'Profit', 'Avg duration', 'Max Drawdown', |             'Best', 'Epoch', 'Trades', ' Win Draw Loss', 'Avg profit', | ||||||
|                           'max_drawdown_abs', 'Objective', 'is_initial_point', 'is_best'] |             'Total profit', 'Profit', 'Avg duration', 'max_drawdown', 'max_drawdown_account', | ||||||
|  |             'max_drawdown_abs', 'Objective', 'is_initial_point', 'is_best' | ||||||
|  |             ] | ||||||
|  |  | ||||||
|         return trials |         return trials | ||||||
|  |  | ||||||
| @@ -341,9 +343,9 @@ class HyperoptTools(): | |||||||
|         tabulate.PRESERVE_WHITESPACE = True |         tabulate.PRESERVE_WHITESPACE = True | ||||||
|         trials = json_normalize(results, max_level=1) |         trials = json_normalize(results, max_level=1) | ||||||
|  |  | ||||||
|         has_drawdown = 'results_metrics.max_drawdown_abs' in trials.columns |         has_account_drawdown = 'results_metrics.max_drawdown_account' in trials.columns | ||||||
|  |  | ||||||
|         trials = HyperoptTools.prepare_trials_columns(trials, has_drawdown) |         trials = HyperoptTools.prepare_trials_columns(trials, has_account_drawdown) | ||||||
|  |  | ||||||
|         trials['is_profit'] = False |         trials['is_profit'] = False | ||||||
|         trials.loc[trials['is_initial_point'], 'Best'] = '*     ' |         trials.loc[trials['is_initial_point'], 'Best'] = '*     ' | ||||||
| @@ -368,19 +370,20 @@ class HyperoptTools(): | |||||||
|  |  | ||||||
|         stake_currency = config['stake_currency'] |         stake_currency = config['stake_currency'] | ||||||
|  |  | ||||||
|         if has_drawdown: |         trials[f"Max Drawdown{' (Acct)' if has_account_drawdown else ''}"] = trials.apply( | ||||||
|             trials['Max Drawdown'] = trials.apply( |             lambda x: "{} {}".format( | ||||||
|                 lambda x: '{} {}'.format( |                 round_coin_value(x['max_drawdown_abs'], stake_currency), | ||||||
|                     round_coin_value(x['max_drawdown_abs'], stake_currency), |                 (f"({x['max_drawdown_account']:,.2%})" | ||||||
|                     f"({x['Max Drawdown']:,.2%})".rjust(10, ' ') |                     if has_account_drawdown | ||||||
|                 ).rjust(25 + len(stake_currency)) |                     else f"({x['max_drawdown']:,.2%})" | ||||||
|                 if x['Max Drawdown'] != 0.0 else '--'.rjust(25 + len(stake_currency)), |                  ).rjust(10, ' ') | ||||||
|                 axis=1 |             ).rjust(25 + len(stake_currency)) | ||||||
|             ) |             if x['max_drawdown'] != 0.0 or x['max_drawdown_account'] != 0.0 | ||||||
|         else: |             else '--'.rjust(25 + len(stake_currency)), | ||||||
|             trials = trials.drop(columns=['Max Drawdown']) |             axis=1 | ||||||
|  |         ) | ||||||
|  |  | ||||||
|         trials = trials.drop(columns=['max_drawdown_abs']) |         trials = trials.drop(columns=['max_drawdown_abs', 'max_drawdown', 'max_drawdown_account']) | ||||||
|  |  | ||||||
|         trials['Profit'] = trials.apply( |         trials['Profit'] = trials.apply( | ||||||
|             lambda x: '{} {}'.format( |             lambda x: '{} {}'.format( | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| import logging | import logging | ||||||
|  | from copy import deepcopy | ||||||
| from datetime import datetime, timedelta, timezone | 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 | ||||||
| @@ -194,29 +195,21 @@ def generate_sell_reason_stats(max_open_trades: int, results: DataFrame) -> List | |||||||
|     return tabular_data |     return tabular_data | ||||||
|  |  | ||||||
|  |  | ||||||
| def generate_strategy_comparison(all_results: Dict) -> List[Dict]: | def generate_strategy_comparison(bt_stats: Dict) -> List[Dict]: | ||||||
|     """ |     """ | ||||||
|     Generate summary per strategy |     Generate summary per strategy | ||||||
|     :param all_results: Dict of <Strategyname: DataFrame> containing results for all strategies |     :param bt_stats: Dict of <Strategyname: DataFrame> containing results for all strategies | ||||||
|     :return: List of Dicts containing the metrics per Strategy |     :return: List of Dicts containing the metrics per Strategy | ||||||
|     """ |     """ | ||||||
|  |  | ||||||
|     tabular_data = [] |     tabular_data = [] | ||||||
|     for strategy, results in all_results.items(): |     for strategy, result in bt_stats.items(): | ||||||
|         tabular_data.append(_generate_result_line( |         tabular_data.append(deepcopy(result['results_per_pair'][-1])) | ||||||
|             results['results'], results['config']['dry_run_wallet'], strategy) |         # Update "key" to strategy (results_per_pair has it as "Total"). | ||||||
|         ) |         tabular_data[-1]['key'] = strategy | ||||||
|         try: |         tabular_data[-1]['max_drawdown_account'] = result['max_drawdown_account'] | ||||||
|             max_drawdown_per, _, _, _, _ = calculate_max_drawdown(results['results'], |         tabular_data[-1]['max_drawdown_abs'] = round_coin_value( | ||||||
|                                                                   value_col='profit_ratio') |             result['max_drawdown_abs'], result['stake_currency'], False) | ||||||
|             max_drawdown_abs, _, _, _, _ = calculate_max_drawdown(results['results'], |  | ||||||
|                                                                   value_col='profit_abs') |  | ||||||
|         except ValueError: |  | ||||||
|             max_drawdown_per = 0 |  | ||||||
|             max_drawdown_abs = 0 |  | ||||||
|         tabular_data[-1]['max_drawdown_per'] = round(max_drawdown_per * 100, 2) |  | ||||||
|         tabular_data[-1]['max_drawdown_abs'] = \ |  | ||||||
|             round_coin_value(max_drawdown_abs, results['config']['stake_currency'], False) |  | ||||||
|     return tabular_data |     return tabular_data | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -462,12 +455,14 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame], | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     try: |     try: | ||||||
|         max_drawdown, _, _, _, _ = calculate_max_drawdown( |         max_drawdown_legacy, _, _, _, _, _ = calculate_max_drawdown( | ||||||
|             results, value_col='profit_ratio') |             results, value_col='profit_ratio') | ||||||
|         drawdown_abs, drawdown_start, drawdown_end, high_val, low_val = calculate_max_drawdown( |         (drawdown_abs, drawdown_start, drawdown_end, high_val, low_val, | ||||||
|             results, value_col='profit_abs') |          max_drawdown) = calculate_max_drawdown( | ||||||
|  |              results, value_col='profit_abs', starting_balance=starting_balance) | ||||||
|         strat_stats.update({ |         strat_stats.update({ | ||||||
|             'max_drawdown': max_drawdown, |             'max_drawdown': max_drawdown_legacy,  # Deprecated - do not use | ||||||
|  |             'max_drawdown_account': max_drawdown, | ||||||
|             'max_drawdown_abs': drawdown_abs, |             'max_drawdown_abs': drawdown_abs, | ||||||
|             'drawdown_start': drawdown_start.strftime(DATETIME_PRINT_FORMAT), |             'drawdown_start': drawdown_start.strftime(DATETIME_PRINT_FORMAT), | ||||||
|             'drawdown_start_ts': drawdown_start.timestamp() * 1000, |             'drawdown_start_ts': drawdown_start.timestamp() * 1000, | ||||||
| @@ -487,6 +482,7 @@ def generate_strategy_stats(btdata: Dict[str, DataFrame], | |||||||
|     except ValueError: |     except ValueError: | ||||||
|         strat_stats.update({ |         strat_stats.update({ | ||||||
|             'max_drawdown': 0.0, |             'max_drawdown': 0.0, | ||||||
|  |             'max_drawdown_account': 0.0, | ||||||
|             'max_drawdown_abs': 0.0, |             'max_drawdown_abs': 0.0, | ||||||
|             'max_drawdown_low': 0.0, |             'max_drawdown_low': 0.0, | ||||||
|             'max_drawdown_high': 0.0, |             'max_drawdown_high': 0.0, | ||||||
| @@ -521,7 +517,7 @@ def generate_backtest_stats(btdata: Dict[str, DataFrame], | |||||||
|                                               min_date, max_date, market_change=market_change) |                                               min_date, max_date, market_change=market_change) | ||||||
|         result['strategy'][strategy] = strat_stats |         result['strategy'][strategy] = strat_stats | ||||||
|  |  | ||||||
|     strategy_results = generate_strategy_comparison(all_results=all_results) |     strategy_results = generate_strategy_comparison(bt_stats=result['strategy']) | ||||||
|  |  | ||||||
|     result['strategy_comparison'] = strategy_results |     result['strategy_comparison'] = strategy_results | ||||||
|  |  | ||||||
| @@ -646,7 +642,7 @@ def text_table_strategy(strategy_results, stake_currency: str) -> str: | |||||||
|     headers.append('Drawdown') |     headers.append('Drawdown') | ||||||
|  |  | ||||||
|     # Align drawdown string on the center two space separator. |     # Align drawdown string on the center two space separator. | ||||||
|     drawdown = [f'{t["max_drawdown_per"]:.2f}' for t in strategy_results] |     drawdown = [f'{t["max_drawdown_account"] * 100:.2f}' for t in strategy_results] | ||||||
|     dd_pad_abs = max([len(t['max_drawdown_abs']) for t in strategy_results]) |     dd_pad_abs = max([len(t['max_drawdown_abs']) for t in strategy_results]) | ||||||
|     dd_pad_per = max([len(dd) for dd in drawdown]) |     dd_pad_per = max([len(dd) for dd in drawdown]) | ||||||
|     drawdown = [f'{t["max_drawdown_abs"]:>{dd_pad_abs}} {stake_currency}  {dd:>{dd_pad_per}}%' |     drawdown = [f'{t["max_drawdown_abs"]:>{dd_pad_abs}} {stake_currency}  {dd:>{dd_pad_per}}%' | ||||||
| @@ -716,7 +712,10 @@ def text_table_add_metrics(strat_results: Dict) -> str: | |||||||
|             ('Max balance', round_coin_value(strat_results['csum_max'], |             ('Max balance', round_coin_value(strat_results['csum_max'], | ||||||
|                                              strat_results['stake_currency'])), |                                              strat_results['stake_currency'])), | ||||||
|  |  | ||||||
|             ('Drawdown', f"{strat_results['max_drawdown']:.2%}"), |             # Compatibility to show old hyperopt results | ||||||
|  |             ('Drawdown (Account)', f"{strat_results['max_drawdown_account']:.2%}") | ||||||
|  |             if 'max_drawdown_account' in strat_results else ( | ||||||
|  |                 'Drawdown', f"{strat_results['max_drawdown']:.2%}"), | ||||||
|             ('Drawdown', round_coin_value(strat_results['max_drawdown_abs'], |             ('Drawdown', round_coin_value(strat_results['max_drawdown_abs'], | ||||||
|                                           strat_results['stake_currency'])), |                                           strat_results['stake_currency'])), | ||||||
|             ('Drawdown high', round_coin_value(strat_results['max_drawdown_high'], |             ('Drawdown high', round_coin_value(strat_results['max_drawdown_high'], | ||||||
|   | |||||||
| @@ -161,7 +161,7 @@ def add_max_drawdown(fig, row, trades: pd.DataFrame, df_comb: pd.DataFrame, | |||||||
|     Add scatter points indicating max drawdown |     Add scatter points indicating max drawdown | ||||||
|     """ |     """ | ||||||
|     try: |     try: | ||||||
|         max_drawdown, highdate, lowdate, _, _ = calculate_max_drawdown(trades) |         _, highdate, lowdate, _, _, max_drawdown = calculate_max_drawdown(trades) | ||||||
|  |  | ||||||
|         drawdown = go.Scatter( |         drawdown = go.Scatter( | ||||||
|             x=[highdate, lowdate], |             x=[highdate, lowdate], | ||||||
|   | |||||||
| @@ -55,7 +55,8 @@ class MaxDrawdown(IProtection): | |||||||
|  |  | ||||||
|         # Drawdown is always positive |         # Drawdown is always positive | ||||||
|         try: |         try: | ||||||
|             drawdown, _, _, _, _ = calculate_max_drawdown(trades_df, value_col='close_profit') |             # TODO: This should use absolute profit calculation, considering account balance. | ||||||
|  |             drawdown, _, _, _, _, _ = calculate_max_drawdown(trades_df, value_col='close_profit') | ||||||
|         except ValueError: |         except ValueError: | ||||||
|             return False, None, None |             return False, None, None | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2020,7 +2020,7 @@ def saved_hyperopt_results(): | |||||||
|             'params_dict': { |             'params_dict': { | ||||||
|                 'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1190, 'roi_t2': 541, 'roi_t3': 408, 'roi_p1': 0.026035863879169705, 'roi_p2': 0.12508730043628782, 'roi_p3': 0.27766427921605896, 'stoploss': -0.2562930402099556},  # noqa: E501 |                 'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1190, 'roi_t2': 541, 'roi_t3': 408, 'roi_p1': 0.026035863879169705, 'roi_p2': 0.12508730043628782, 'roi_p3': 0.27766427921605896, 'stoploss': -0.2562930402099556},  # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper'}, 'roi': {0: 0.4287874435315165, 408: 0.15112316431545753, 949: 0.026035863879169705, 2139: 0}, 'stoploss': {'stoploss': -0.2562930402099556}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 15, 'fastd-value': 20, 'adx-value': 25, 'rsi-value': 28, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 88, 'sell-fastd-value': 97, 'sell-adx-value': 51, 'sell-rsi-value': 67, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper'}, 'roi': {0: 0.4287874435315165, 408: 0.15112316431545753, 949: 0.026035863879169705, 2139: 0}, 'stoploss': {'stoploss': -0.2562930402099556}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 2, 'wins': 0, 'draws': 0, 'losses': 2, 'profit_mean': -0.01254995, 'profit_median': -0.012222, 'profit_total': -0.00125625, 'profit_total_abs': -2.50999, 'holding_avg': timedelta(minutes=3930.0), 'stake_currency': 'BTC', 'strategy_name': 'SampleStrategy'},  # noqa: E501 |             'results_metrics': {'total_trades': 2, 'wins': 0, 'draws': 0, 'losses': 2, 'profit_mean': -0.01254995, 'profit_median': -0.012222, 'profit_total': -0.00125625,  'profit_total_abs': -2.50999, 'max_drawdown': 0.23, 'max_drawdown_abs': -0.00125625,  'holding_avg': timedelta(minutes=3930.0), 'stake_currency': 'BTC', 'strategy_name': 'SampleStrategy'},  # noqa: E501 | ||||||
|             'results_explanation': '     2 trades. Avg profit  -1.25%. Total profit -0.00125625 BTC (  -2.51Σ%). Avg duration 3930.0 min.',  # noqa: E501 |             'results_explanation': '     2 trades. Avg profit  -1.25%. Total profit -0.00125625 BTC (  -2.51Σ%). Avg duration 3930.0 min.',  # noqa: E501 | ||||||
|             'total_profit': -0.00125625, |             'total_profit': -0.00125625, | ||||||
|             'current_epoch': 1, |             'current_epoch': 1, | ||||||
| @@ -2036,7 +2036,7 @@ def saved_hyperopt_results(): | |||||||
|                 'sell': {'sell-mfi-value': 96, 'sell-fastd-value': 68, 'sell-adx-value': 63, 'sell-rsi-value': 81, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal'},  # noqa: E501 |                 'sell': {'sell-mfi-value': 96, 'sell-fastd-value': 68, 'sell-adx-value': 63, 'sell-rsi-value': 81, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal'},  # noqa: E501 | ||||||
|                 'roi': {0: 0.4449309386008759, 140: 0.11955965746663, 823: 0.06403981740598495, 1157: 0},  # noqa: E501 |                 'roi': {0: 0.4449309386008759, 140: 0.11955965746663, 823: 0.06403981740598495, 1157: 0},  # noqa: E501 | ||||||
|                 'stoploss': {'stoploss': -0.338070047333259}}, |                 'stoploss': {'stoploss': -0.338070047333259}}, | ||||||
|             'results_metrics': {'total_trades': 1, 'wins': 0, 'draws': 0, 'losses': 1, 'profit_mean': 0.012357, 'profit_median': -0.012222, 'profit_total': 6.185e-05, 'profit_total_abs': 0.12357, 'holding_avg': timedelta(minutes=1200.0)},  # noqa: E501 |             'results_metrics': {'total_trades': 1, 'wins': 0, 'draws': 0, 'losses': 1, 'profit_mean': 0.012357, 'profit_median': -0.012222, 'profit_total': 6.185e-05, 'profit_total_abs': 0.12357, 'max_drawdown': 0.23, 'max_drawdown_abs': -0.00125625, 'holding_avg': timedelta(minutes=1200.0)},  # noqa: E501 | ||||||
|             'results_explanation': '     1 trades. Avg profit   0.12%. Total profit  0.00006185 BTC (   0.12Σ%). Avg duration 1200.0 min.',  # noqa: E501 |             'results_explanation': '     1 trades. Avg profit   0.12%. Total profit  0.00006185 BTC (   0.12Σ%). Avg duration 1200.0 min.',  # noqa: E501 | ||||||
|             'total_profit': 6.185e-05, |             'total_profit': 6.185e-05, | ||||||
|             'current_epoch': 2, |             'current_epoch': 2, | ||||||
| @@ -2046,7 +2046,7 @@ def saved_hyperopt_results(): | |||||||
|             'loss': 14.241196856510731, |             'loss': 14.241196856510731, | ||||||
|             'params_dict': {'mfi-value': 25, 'fastd-value': 16, 'adx-value': 29, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 98, 'sell-fastd-value': 72, 'sell-adx-value': 51, 'sell-rsi-value': 82, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 889, 'roi_t2': 533, 'roi_t3': 263, 'roi_p1': 0.04759065393663096, 'roi_p2': 0.1488819964638463, 'roi_p3': 0.4102801822104605, 'stoploss': -0.05394588767607611},  # noqa: E501 |             'params_dict': {'mfi-value': 25, 'fastd-value': 16, 'adx-value': 29, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 98, 'sell-fastd-value': 72, 'sell-adx-value': 51, 'sell-rsi-value': 82, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 889, 'roi_t2': 533, 'roi_t3': 263, 'roi_p1': 0.04759065393663096, 'roi_p2': 0.1488819964638463, 'roi_p3': 0.4102801822104605, 'stoploss': -0.05394588767607611},  # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 25, 'fastd-value': 16, 'adx-value': 29, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 98, 'sell-fastd-value': 72, 'sell-adx-value': 51, 'sell-rsi-value': 82, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.6067528326109377, 263: 0.19647265040047726, 796: 0.04759065393663096, 1685: 0}, 'stoploss': {'stoploss': -0.05394588767607611}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 25, 'fastd-value': 16, 'adx-value': 29, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 98, 'sell-fastd-value': 72, 'sell-adx-value': 51, 'sell-rsi-value': 82, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.6067528326109377, 263: 0.19647265040047726, 796: 0.04759065393663096, 1685: 0}, 'stoploss': {'stoploss': -0.05394588767607611}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 621, 'wins': 320, 'draws': 0, 'losses': 301, 'profit_mean': -0.043883302093397747, 'profit_median': -0.012222, 'profit_total': -0.13639474, 'profit_total_abs': -272.515306, 'holding_avg': timedelta(minutes=1691.207729468599)},  # noqa: E501 |             'results_metrics': {'total_trades': 621, 'wins': 320, 'draws': 0, 'losses': 301, 'profit_mean': -0.043883302093397747, 'profit_median': -0.012222, 'profit_total': -0.13639474, 'profit_total_abs': -272.515306, 'max_drawdown': 0.25, 'max_drawdown_abs': -272.515306, 'holding_avg': timedelta(minutes=1691.207729468599)},  # noqa: E501 | ||||||
|             'results_explanation': '   621 trades. Avg profit  -0.44%. Total profit -0.13639474 BTC (-272.52Σ%). Avg duration 1691.2 min.',  # noqa: E501 |             'results_explanation': '   621 trades. Avg profit  -0.44%. Total profit -0.13639474 BTC (-272.52Σ%). Avg duration 1691.2 min.',  # noqa: E501 | ||||||
|             'total_profit': -0.13639474, |             'total_profit': -0.13639474, | ||||||
|             'current_epoch': 3, |             'current_epoch': 3, | ||||||
| @@ -2063,7 +2063,7 @@ def saved_hyperopt_results(): | |||||||
|             'loss': 0.22195522184191518, |             'loss': 0.22195522184191518, | ||||||
|             'params_dict': {'mfi-value': 17, 'fastd-value': 21, 'adx-value': 38, 'rsi-value': 33, 'mfi-enabled': True, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': False, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 87, 'sell-fastd-value': 82, 'sell-adx-value': 78, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 1269, 'roi_t2': 601, 'roi_t3': 444, 'roi_p1': 0.07280999507931168, 'roi_p2': 0.08946698095898986, 'roi_p3': 0.1454876733325284, 'stoploss': -0.18181041180901014},   # noqa: E501 |             'params_dict': {'mfi-value': 17, 'fastd-value': 21, 'adx-value': 38, 'rsi-value': 33, 'mfi-enabled': True, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': False, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 87, 'sell-fastd-value': 82, 'sell-adx-value': 78, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 1269, 'roi_t2': 601, 'roi_t3': 444, 'roi_p1': 0.07280999507931168, 'roi_p2': 0.08946698095898986, 'roi_p3': 0.1454876733325284, 'stoploss': -0.18181041180901014},   # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 17, 'fastd-value': 21, 'adx-value': 38, 'rsi-value': 33, 'mfi-enabled': True, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': False, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 87, 'sell-fastd-value': 82, 'sell-adx-value': 78, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.3077646493708299, 444: 0.16227697603830155, 1045: 0.07280999507931168, 2314: 0}, 'stoploss': {'stoploss': -0.18181041180901014}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 17, 'fastd-value': 21, 'adx-value': 38, 'rsi-value': 33, 'mfi-enabled': True, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': False, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 87, 'sell-fastd-value': 82, 'sell-adx-value': 78, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.3077646493708299, 444: 0.16227697603830155, 1045: 0.07280999507931168, 2314: 0}, 'stoploss': {'stoploss': -0.18181041180901014}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 14, 'wins': 6, 'draws': 0, 'losses': 8, 'profit_mean': -0.003539515, 'profit_median': -0.012222, 'profit_total': -0.002480140000000001, 'profit_total_abs': -4.955321, 'holding_avg': timedelta(minutes=3402.8571428571427)},  # noqa: E501 |             'results_metrics': {'total_trades': 14, 'wins': 6, 'draws': 0, 'losses': 8, 'profit_mean': -0.003539515, 'profit_median': -0.012222, 'profit_total': -0.002480140000000001, 'profit_total_abs': -4.955321, 'max_drawdown': 0.34, 'max_drawdown_abs': -4.955321, 'holding_avg': timedelta(minutes=3402.8571428571427)},  # noqa: E501 | ||||||
|             'results_explanation': '    14 trades. Avg profit  -0.35%. Total profit -0.00248014 BTC (  -4.96Σ%). Avg duration 3402.9 min.',  # noqa: E501 |             'results_explanation': '    14 trades. Avg profit  -0.35%. Total profit -0.00248014 BTC (  -4.96Σ%). Avg duration 3402.9 min.',  # noqa: E501 | ||||||
|             'total_profit': -0.002480140000000001, |             'total_profit': -0.002480140000000001, | ||||||
|             'current_epoch': 5, |             'current_epoch': 5, | ||||||
| @@ -2073,7 +2073,7 @@ def saved_hyperopt_results(): | |||||||
|             'loss': 0.545315889154162, |             'loss': 0.545315889154162, | ||||||
|             'params_dict': {'mfi-value': 22, 'fastd-value': 43, 'adx-value': 46, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'bb_lower', 'sell-mfi-value': 87, 'sell-fastd-value': 65, 'sell-adx-value': 94, 'sell-rsi-value': 63, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 319, 'roi_t2': 556, 'roi_t3': 216, 'roi_p1': 0.06251955472249589, 'roi_p2': 0.11659519602202795, 'roi_p3': 0.0953744132197762, 'stoploss': -0.024551752215582423},  # noqa: E501 |             'params_dict': {'mfi-value': 22, 'fastd-value': 43, 'adx-value': 46, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'bb_lower', 'sell-mfi-value': 87, 'sell-fastd-value': 65, 'sell-adx-value': 94, 'sell-rsi-value': 63, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 319, 'roi_t2': 556, 'roi_t3': 216, 'roi_p1': 0.06251955472249589, 'roi_p2': 0.11659519602202795, 'roi_p3': 0.0953744132197762, 'stoploss': -0.024551752215582423},  # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 22, 'fastd-value': 43, 'adx-value': 46, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'bb_lower'}, 'sell': {'sell-mfi-value': 87, 'sell-fastd-value': 65, 'sell-adx-value': 94, 'sell-rsi-value': 63, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.2744891639643, 216: 0.17911475074452382, 772: 0.06251955472249589, 1091: 0}, 'stoploss': {'stoploss': -0.024551752215582423}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 22, 'fastd-value': 43, 'adx-value': 46, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'bb_lower'}, 'sell': {'sell-mfi-value': 87, 'sell-fastd-value': 65, 'sell-adx-value': 94, 'sell-rsi-value': 63, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.2744891639643, 216: 0.17911475074452382, 772: 0.06251955472249589, 1091: 0}, 'stoploss': {'stoploss': -0.024551752215582423}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 39, 'wins': 20, 'draws': 0, 'losses': 19, 'profit_mean': -0.0021400679487179478, 'profit_median': -0.012222, 'profit_total': -0.0041773, 'profit_total_abs': -8.346264999999997, 'holding_avg': timedelta(minutes=636.9230769230769)},  # noqa: E501 |             'results_metrics': {'total_trades': 39, 'wins': 20, 'draws': 0, 'losses': 19, 'profit_mean': -0.0021400679487179478, 'profit_median': -0.012222, 'profit_total': -0.0041773, 'profit_total_abs': -8.346264999999997, 'max_drawdown': 0.45, 'max_drawdown_abs': -4.955321, 'holding_avg': timedelta(minutes=636.9230769230769)},  # noqa: E501 | ||||||
|             'results_explanation': '    39 trades. Avg profit  -0.21%. Total profit -0.00417730 BTC (  -8.35Σ%). Avg duration 636.9 min.',  # noqa: E501 |             'results_explanation': '    39 trades. Avg profit  -0.21%. Total profit -0.00417730 BTC (  -8.35Σ%). Avg duration 636.9 min.',  # noqa: E501 | ||||||
|             'total_profit': -0.0041773, |             'total_profit': -0.0041773, | ||||||
|             'current_epoch': 6, |             'current_epoch': 6, | ||||||
| @@ -2085,7 +2085,7 @@ def saved_hyperopt_results(): | |||||||
|             'params_details': { |             'params_details': { | ||||||
|                 'buy': {'mfi-value': 13, 'fastd-value': 41, 'adx-value': 21, 'rsi-value': 29, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower'}, 'sell': {'sell-mfi-value': 99, 'sell-fastd-value': 60, 'sell-adx-value': 81, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.4837436938134452, 145: 0.10853310701097472, 765: 0.0586919200378493, 1536: 0},  # noqa: E501 |                 'buy': {'mfi-value': 13, 'fastd-value': 41, 'adx-value': 21, 'rsi-value': 29, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower'}, 'sell': {'sell-mfi-value': 99, 'sell-fastd-value': 60, 'sell-adx-value': 81, 'sell-rsi-value': 69, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': False, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.4837436938134452, 145: 0.10853310701097472, 765: 0.0586919200378493, 1536: 0},  # noqa: E501 | ||||||
|                 'stoploss': {'stoploss': -0.14613268022709905}},  # noqa: E501 |                 'stoploss': {'stoploss': -0.14613268022709905}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 318, 'wins': 100, 'draws': 0, 'losses': 218, 'profit_mean': -0.0039833954716981146, 'profit_median': -0.012222, 'profit_total': -0.06339929, 'profit_total_abs': -126.67197600000004, 'holding_avg': timedelta(minutes=3140.377358490566)},  # noqa: E501 |             'results_metrics': {'total_trades': 318, 'wins': 100, 'draws': 0, 'losses': 218, 'profit_mean': -0.0039833954716981146, 'profit_median': -0.012222, 'profit_total': -0.06339929, 'profit_total_abs': -126.67197600000004, 'max_drawdown': 0.50, 'max_drawdown_abs': -200.955321, 'holding_avg': timedelta(minutes=3140.377358490566)},  # noqa: E501 | ||||||
|             'results_explanation': '   318 trades. Avg profit  -0.40%. Total profit -0.06339929 BTC (-126.67Σ%). Avg duration 3140.4 min.',  # noqa: E501 |             'results_explanation': '   318 trades. Avg profit  -0.40%. Total profit -0.06339929 BTC (-126.67Σ%). Avg duration 3140.4 min.',  # noqa: E501 | ||||||
|             'total_profit': -0.06339929, |             'total_profit': -0.06339929, | ||||||
|             'current_epoch': 7, |             'current_epoch': 7, | ||||||
| @@ -2095,7 +2095,7 @@ def saved_hyperopt_results(): | |||||||
|             'loss': 20.0,  # noqa: E501 |             'loss': 20.0,  # noqa: E501 | ||||||
|             'params_dict': {'mfi-value': 24, 'fastd-value': 43, 'adx-value': 33, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'sar_reversal', 'sell-mfi-value': 89, 'sell-fastd-value': 74, 'sell-adx-value': 70, 'sell-rsi-value': 70, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': False, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal', 'roi_t1': 1149, 'roi_t2': 375, 'roi_t3': 289, 'roi_p1': 0.05571820757172588, 'roi_p2': 0.0606240398618907, 'roi_p3': 0.1729012220156157, 'stoploss': -0.1588514289110401},  # noqa: E501 |             'params_dict': {'mfi-value': 24, 'fastd-value': 43, 'adx-value': 33, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'sar_reversal', 'sell-mfi-value': 89, 'sell-fastd-value': 74, 'sell-adx-value': 70, 'sell-rsi-value': 70, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': False, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal', 'roi_t1': 1149, 'roi_t2': 375, 'roi_t3': 289, 'roi_p1': 0.05571820757172588, 'roi_p2': 0.0606240398618907, 'roi_p3': 0.1729012220156157, 'stoploss': -0.1588514289110401},  # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 24, 'fastd-value': 43, 'adx-value': 33, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'sar_reversal'}, 'sell': {'sell-mfi-value': 89, 'sell-fastd-value': 74, 'sell-adx-value': 70, 'sell-rsi-value': 70, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': False, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal'}, 'roi': {0: 0.2892434694492323, 289: 0.11634224743361658, 664: 0.05571820757172588, 1813: 0}, 'stoploss': {'stoploss': -0.1588514289110401}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 24, 'fastd-value': 43, 'adx-value': 33, 'rsi-value': 20, 'mfi-enabled': False, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': True, 'trigger': 'sar_reversal'}, 'sell': {'sell-mfi-value': 89, 'sell-fastd-value': 74, 'sell-adx-value': 70, 'sell-rsi-value': 70, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': False, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal'}, 'roi': {0: 0.2892434694492323, 289: 0.11634224743361658, 664: 0.05571820757172588, 1813: 0}, 'stoploss': {'stoploss': -0.1588514289110401}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 1, 'wins': 0, 'draws': 1, 'losses': 0, 'profit_mean': 0.0, 'profit_median': 0.0, 'profit_total': 0.0, 'profit_total_abs': 0.0, 'holding_avg': timedelta(minutes=5340.0)},  # noqa: E501 |             'results_metrics': {'total_trades': 1, 'wins': 0, 'draws': 1, 'losses': 0, 'profit_mean': 0.0, 'profit_median': 0.0, 'profit_total': 0.0, 'profit_total_abs': 0.0, 'max_drawdown': 0.0, 'max_drawdown_abs': 0.52, 'holding_avg': timedelta(minutes=5340.0)},  # noqa: E501 | ||||||
|             'results_explanation': '     1 trades. Avg profit   0.00%. Total profit  0.00000000 BTC (   0.00Σ%). Avg duration 5340.0 min.',  # noqa: E501 |             'results_explanation': '     1 trades. Avg profit   0.00%. Total profit  0.00000000 BTC (   0.00Σ%). Avg duration 5340.0 min.',  # noqa: E501 | ||||||
|             'total_profit': 0.0, |             'total_profit': 0.0, | ||||||
|             'current_epoch': 8, |             'current_epoch': 8, | ||||||
| @@ -2105,7 +2105,7 @@ def saved_hyperopt_results(): | |||||||
|             'loss': 2.4731817780991223, |             'loss': 2.4731817780991223, | ||||||
|             'params_dict': {'mfi-value': 22, 'fastd-value': 20, 'adx-value': 29, 'rsi-value': 40, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'sar_reversal', 'sell-mfi-value': 97, 'sell-fastd-value': 65, 'sell-adx-value': 81, 'sell-rsi-value': 64, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1012, 'roi_t2': 584, 'roi_t3': 422, 'roi_p1': 0.036764323603472565, 'roi_p2': 0.10335480573205287, 'roi_p3': 0.10322347377503042, 'stoploss': -0.2780610808108503},  # noqa: E501 |             'params_dict': {'mfi-value': 22, 'fastd-value': 20, 'adx-value': 29, 'rsi-value': 40, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'sar_reversal', 'sell-mfi-value': 97, 'sell-fastd-value': 65, 'sell-adx-value': 81, 'sell-rsi-value': 64, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1012, 'roi_t2': 584, 'roi_t3': 422, 'roi_p1': 0.036764323603472565, 'roi_p2': 0.10335480573205287, 'roi_p3': 0.10322347377503042, 'stoploss': -0.2780610808108503},  # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 22, 'fastd-value': 20, 'adx-value': 29, 'rsi-value': 40, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'sar_reversal'}, 'sell': {'sell-mfi-value': 97, 'sell-fastd-value': 65, 'sell-adx-value': 81, 'sell-rsi-value': 64, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper'}, 'roi': {0: 0.2433426031105559, 422: 0.14011912933552545, 1006: 0.036764323603472565, 2018: 0}, 'stoploss': {'stoploss': -0.2780610808108503}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 22, 'fastd-value': 20, 'adx-value': 29, 'rsi-value': 40, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'sar_reversal'}, 'sell': {'sell-mfi-value': 97, 'sell-fastd-value': 65, 'sell-adx-value': 81, 'sell-rsi-value': 64, 'sell-mfi-enabled': True, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper'}, 'roi': {0: 0.2433426031105559, 422: 0.14011912933552545, 1006: 0.036764323603472565, 2018: 0}, 'stoploss': {'stoploss': -0.2780610808108503}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 229, 'wins': 150, 'draws': 0, 'losses': 79, 'profit_mean': -0.0038433433624454144, 'profit_median': -0.012222, 'profit_total': -0.044050070000000004, 'profit_total_abs': -88.01256299999999, 'holding_avg': timedelta(minutes=6505.676855895196)},  # noqa: E501 |             'results_metrics': {'total_trades': 229, 'wins': 150, 'draws': 0, 'losses': 79, 'profit_mean': -0.0038433433624454144, 'profit_median': -0.012222, 'profit_total': -0.044050070000000004, 'profit_total_abs': -88.01256299999999, 'max_drawdown': 0.41, 'max_drawdown_abs': -150.955321, 'holding_avg': timedelta(minutes=6505.676855895196)},  # noqa: E501 | ||||||
|             'results_explanation': '   229 trades. Avg profit  -0.38%. Total profit -0.04405007 BTC ( -88.01Σ%). Avg duration 6505.7 min.',  # noqa: E501 |             'results_explanation': '   229 trades. Avg profit  -0.38%. Total profit -0.04405007 BTC ( -88.01Σ%). Avg duration 6505.7 min.',  # noqa: E501 | ||||||
|             'total_profit': -0.044050070000000004,  # noqa: E501 |             'total_profit': -0.044050070000000004,  # noqa: E501 | ||||||
|             'current_epoch': 9, |             'current_epoch': 9, | ||||||
| @@ -2115,7 +2115,7 @@ def saved_hyperopt_results(): | |||||||
|             'loss': -0.2604606005845212,  # noqa: E501 |             'loss': -0.2604606005845212,  # noqa: E501 | ||||||
|             'params_dict': {'mfi-value': 23, 'fastd-value': 24, 'adx-value': 22, 'rsi-value': 24, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 97, 'sell-fastd-value': 70, 'sell-adx-value': 64, 'sell-rsi-value': 80, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal', 'roi_t1': 792, 'roi_t2': 464, 'roi_t3': 215, 'roi_p1': 0.04594053535385903, 'roi_p2': 0.09623192684243963, 'roi_p3': 0.04428219070850663, 'stoploss': -0.16992287161634415},  # noqa: E501 |             'params_dict': {'mfi-value': 23, 'fastd-value': 24, 'adx-value': 22, 'rsi-value': 24, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': True, 'trigger': 'macd_cross_signal', 'sell-mfi-value': 97, 'sell-fastd-value': 70, 'sell-adx-value': 64, 'sell-rsi-value': 80, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal', 'roi_t1': 792, 'roi_t2': 464, 'roi_t3': 215, 'roi_p1': 0.04594053535385903, 'roi_p2': 0.09623192684243963, 'roi_p3': 0.04428219070850663, 'stoploss': -0.16992287161634415},  # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 23, 'fastd-value': 24, 'adx-value': 22, 'rsi-value': 24, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': True, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 97, 'sell-fastd-value': 70, 'sell-adx-value': 64, 'sell-rsi-value': 80, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal'}, 'roi': {0: 0.18645465290480528, 215: 0.14217246219629864, 679: 0.04594053535385903, 1471: 0}, 'stoploss': {'stoploss': -0.16992287161634415}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 23, 'fastd-value': 24, 'adx-value': 22, 'rsi-value': 24, 'mfi-enabled': False, 'fastd-enabled': False, 'adx-enabled': False, 'rsi-enabled': True, 'trigger': 'macd_cross_signal'}, 'sell': {'sell-mfi-value': 97, 'sell-fastd-value': 70, 'sell-adx-value': 64, 'sell-rsi-value': 80, 'sell-mfi-enabled': False, 'sell-fastd-enabled': True, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-sar_reversal'}, 'roi': {0: 0.18645465290480528, 215: 0.14217246219629864, 679: 0.04594053535385903, 1471: 0}, 'stoploss': {'stoploss': -0.16992287161634415}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 4, 'wins': 0, 'draws': 0, 'losses': 4, 'profit_mean': 0.001080385, 'profit_median': -0.012222, 'profit_total': 0.00021629, 'profit_total_abs': 0.432154, 'holding_avg': timedelta(minutes=2850.0)},  # noqa: E501 |             'results_metrics': {'total_trades': 4, 'wins': 0, 'draws': 0, 'losses': 4, 'profit_mean': 0.001080385, 'profit_median': -0.012222, 'profit_total': 0.00021629, 'profit_total_abs': 0.432154, 'max_drawdown': 0.13, 'max_drawdown_abs': -4.955321, 'holding_avg': timedelta(minutes=2850.0)},  # noqa: E501 | ||||||
|             'results_explanation': '     4 trades. Avg profit   0.11%. Total profit  0.00021629 BTC (   0.43Σ%). Avg duration 2850.0 min.',  # noqa: E501 |             'results_explanation': '     4 trades. Avg profit   0.11%. Total profit  0.00021629 BTC (   0.43Σ%). Avg duration 2850.0 min.',  # noqa: E501 | ||||||
|             'total_profit': 0.00021629, |             'total_profit': 0.00021629, | ||||||
|             'current_epoch': 10, |             'current_epoch': 10, | ||||||
| @@ -2126,7 +2126,7 @@ def saved_hyperopt_results(): | |||||||
|             'params_dict': {'mfi-value': 20, 'fastd-value': 32, 'adx-value': 49, 'rsi-value': 23, 'mfi-enabled': True, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower', 'sell-mfi-value': 75, 'sell-fastd-value': 56, 'sell-adx-value': 61, 'sell-rsi-value': 62, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 579, 'roi_t2': 614, 'roi_t3': 273, 'roi_p1': 0.05307643172744114, 'roi_p2': 0.1352282078262871, 'roi_p3': 0.1913307406325751, 'stoploss': -0.25728526022513887},  # noqa: E501 |             'params_dict': {'mfi-value': 20, 'fastd-value': 32, 'adx-value': 49, 'rsi-value': 23, 'mfi-enabled': True, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower', 'sell-mfi-value': 75, 'sell-fastd-value': 56, 'sell-adx-value': 61, 'sell-rsi-value': 62, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal', 'roi_t1': 579, 'roi_t2': 614, 'roi_t3': 273, 'roi_p1': 0.05307643172744114, 'roi_p2': 0.1352282078262871, 'roi_p3': 0.1913307406325751, 'stoploss': -0.25728526022513887},  # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 20, 'fastd-value': 32, 'adx-value': 49, 'rsi-value': 23, 'mfi-enabled': True, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower'}, 'sell': {'sell-mfi-value': 75, 'sell-fastd-value': 56, 'sell-adx-value': 61, 'sell-rsi-value': 62, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.3796353801863034, 273: 0.18830463955372825, 887: 0.05307643172744114, 1466: 0}, 'stoploss': {'stoploss': -0.25728526022513887}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 20, 'fastd-value': 32, 'adx-value': 49, 'rsi-value': 23, 'mfi-enabled': True, 'fastd-enabled': True, 'adx-enabled': False, 'rsi-enabled': False, 'trigger': 'bb_lower'}, 'sell': {'sell-mfi-value': 75, 'sell-fastd-value': 56, 'sell-adx-value': 61, 'sell-rsi-value': 62, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-macd_cross_signal'}, 'roi': {0: 0.3796353801863034, 273: 0.18830463955372825, 887: 0.05307643172744114, 1466: 0}, 'stoploss': {'stoploss': -0.25728526022513887}},  # noqa: E501 | ||||||
|             # New Hyperopt mode! |             # New Hyperopt mode! | ||||||
|             'results_metrics': {'total_trades': 117, 'wins': 67, 'draws': 0, 'losses': 50, 'profit_mean': -0.012698609145299145, 'profit_median': -0.012222, 'profit_total': -0.07436117, 'profit_total_abs': -148.573727, 'holding_avg': timedelta(minutes=4282.5641025641025)},  # noqa: E501 |             'results_metrics': {'total_trades': 117, 'wins': 67, 'draws': 0, 'losses': 50, 'profit_mean': -0.012698609145299145, 'profit_median': -0.012222, 'profit_total': -0.07436117, 'profit_total_abs': -148.573727, 'max_drawdown': 0.52, 'max_drawdown_abs': -224.955321, 'holding_avg': timedelta(minutes=4282.5641025641025)},  # noqa: E501 | ||||||
|             'results_explanation': '   117 trades. Avg profit  -1.27%. Total profit -0.07436117 BTC (-148.57Σ%). Avg duration 4282.6 min.',  # noqa: E501 |             'results_explanation': '   117 trades. Avg profit  -1.27%. Total profit -0.07436117 BTC (-148.57Σ%). Avg duration 4282.6 min.',  # noqa: E501 | ||||||
|             'total_profit': -0.07436117, |             'total_profit': -0.07436117, | ||||||
|             'current_epoch': 11, |             'current_epoch': 11, | ||||||
| @@ -2136,7 +2136,7 @@ def saved_hyperopt_results(): | |||||||
|             'loss': 100000, |             'loss': 100000, | ||||||
|             'params_dict': {'mfi-value': 10, 'fastd-value': 36, 'adx-value': 31, 'rsi-value': 22, 'mfi-enabled': True, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': False, 'trigger': 'sar_reversal', 'sell-mfi-value': 80, 'sell-fastd-value': 71, 'sell-adx-value': 60, 'sell-rsi-value': 85, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1156, 'roi_t2': 581, 'roi_t3': 408, 'roi_p1': 0.06860454019988212, 'roi_p2': 0.12473718444931989, 'roi_p3': 0.2896360635226823, 'stoploss': -0.30889015124682806},  # noqa: E501 |             'params_dict': {'mfi-value': 10, 'fastd-value': 36, 'adx-value': 31, 'rsi-value': 22, 'mfi-enabled': True, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': False, 'trigger': 'sar_reversal', 'sell-mfi-value': 80, 'sell-fastd-value': 71, 'sell-adx-value': 60, 'sell-rsi-value': 85, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper', 'roi_t1': 1156, 'roi_t2': 581, 'roi_t3': 408, 'roi_p1': 0.06860454019988212, 'roi_p2': 0.12473718444931989, 'roi_p3': 0.2896360635226823, 'stoploss': -0.30889015124682806},  # noqa: E501 | ||||||
|             'params_details': {'buy': {'mfi-value': 10, 'fastd-value': 36, 'adx-value': 31, 'rsi-value': 22, 'mfi-enabled': True, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': False, 'trigger': 'sar_reversal'}, 'sell': {'sell-mfi-value': 80, 'sell-fastd-value': 71, 'sell-adx-value': 60, 'sell-rsi-value': 85, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper'}, 'roi': {0: 0.4829777881718843, 408: 0.19334172464920202, 989: 0.06860454019988212, 2145: 0}, 'stoploss': {'stoploss': -0.30889015124682806}},  # noqa: E501 |             'params_details': {'buy': {'mfi-value': 10, 'fastd-value': 36, 'adx-value': 31, 'rsi-value': 22, 'mfi-enabled': True, 'fastd-enabled': True, 'adx-enabled': True, 'rsi-enabled': False, 'trigger': 'sar_reversal'}, 'sell': {'sell-mfi-value': 80, 'sell-fastd-value': 71, 'sell-adx-value': 60, 'sell-rsi-value': 85, 'sell-mfi-enabled': False, 'sell-fastd-enabled': False, 'sell-adx-enabled': True, 'sell-rsi-enabled': True, 'sell-trigger': 'sell-bb_upper'}, 'roi': {0: 0.4829777881718843, 408: 0.19334172464920202, 989: 0.06860454019988212, 2145: 0}, 'stoploss': {'stoploss': -0.30889015124682806}},  # noqa: E501 | ||||||
|             'results_metrics': {'total_trades': 0, 'wins': 0, 'draws': 0, 'losses': 0, 'profit_mean': None, 'profit_median': None, 'profit_total': 0, 'profit_total_abs': 0.0, 'holding_avg': timedelta()},  # noqa: E501 |             'results_metrics': {'total_trades': 0, 'wins': 0, 'draws': 0, 'losses': 0, 'profit_mean': None, 'profit_median': None, 'profit_total': 0, 'profit_total_abs': 0.0, 'max_drawdown': 0.0, 'max_drawdown_abs': 0.0, 'holding_avg': timedelta()},  # noqa: E501 | ||||||
|             'results_explanation': '     0 trades. Avg profit    nan%. Total profit  0.00000000 BTC (   0.00Σ%). Avg duration   nan min.',  # noqa: E501 |             'results_explanation': '     0 trades. Avg profit    nan%. Total profit  0.00000000 BTC (   0.00Σ%). Avg duration   nan min.',  # noqa: E501 | ||||||
|             'total_profit': 0, |             'total_profit': 0, | ||||||
|             'current_epoch': 12, |             'current_epoch': 12, | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ from pandas import DataFrame, DateOffset, Timestamp, to_datetime | |||||||
|  |  | ||||||
| from freqtrade.configuration import TimeRange | from freqtrade.configuration import TimeRange | ||||||
| from freqtrade.constants import LAST_BT_RESULT_FN | from freqtrade.constants import LAST_BT_RESULT_FN | ||||||
| from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, BT_DATA_COLUMNS_MID, BT_DATA_COLUMNS_OLD, | from freqtrade.data.btanalysis import (BT_DATA_COLUMNS, BT_DATA_COLUMNS_OLD, | ||||||
|                                        analyze_trade_parallelism, calculate_csum, |                                        analyze_trade_parallelism, calculate_csum, | ||||||
|                                        calculate_market_change, calculate_max_drawdown, |                                        calculate_market_change, calculate_max_drawdown, | ||||||
|                                        calculate_underwater, combine_dataframes_with_mean, |                                        calculate_underwater, combine_dataframes_with_mean, | ||||||
| @@ -72,7 +72,7 @@ def test_load_backtest_data_new_format(testdatadir): | |||||||
|     filename = testdatadir / "backtest-result_new.json" |     filename = testdatadir / "backtest-result_new.json" | ||||||
|     bt_data = load_backtest_data(filename) |     bt_data = load_backtest_data(filename) | ||||||
|     assert isinstance(bt_data, DataFrame) |     assert isinstance(bt_data, DataFrame) | ||||||
|     assert set(bt_data.columns) == set(BT_DATA_COLUMNS_MID) |     assert set(bt_data.columns) == set(BT_DATA_COLUMNS + ['close_timestamp', 'open_timestamp']) | ||||||
|     assert len(bt_data) == 179 |     assert len(bt_data) == 179 | ||||||
|  |  | ||||||
|     # Test loading from string (must yield same result) |     # Test loading from string (must yield same result) | ||||||
| @@ -96,7 +96,7 @@ def test_load_backtest_data_multi(testdatadir): | |||||||
|     for strategy in ('StrategyTestV2', 'TestStrategy'): |     for strategy in ('StrategyTestV2', 'TestStrategy'): | ||||||
|         bt_data = load_backtest_data(filename, strategy=strategy) |         bt_data = load_backtest_data(filename, strategy=strategy) | ||||||
|         assert isinstance(bt_data, DataFrame) |         assert isinstance(bt_data, DataFrame) | ||||||
|         assert set(bt_data.columns) == set(BT_DATA_COLUMNS_MID) |         assert set(bt_data.columns) == set(BT_DATA_COLUMNS + ['close_timestamp', 'open_timestamp']) | ||||||
|         assert len(bt_data) == 179 |         assert len(bt_data) == 179 | ||||||
|  |  | ||||||
|         # Test loading from string (must yield same result) |         # Test loading from string (must yield same result) | ||||||
| @@ -280,23 +280,24 @@ def test_create_cum_profit1(testdatadir): | |||||||
|  |  | ||||||
|  |  | ||||||
| def test_calculate_max_drawdown(testdatadir): | def test_calculate_max_drawdown(testdatadir): | ||||||
|     filename = testdatadir / "backtest-result_test.json" |     filename = testdatadir / "backtest-result_new.json" | ||||||
|     bt_data = load_backtest_data(filename) |     bt_data = load_backtest_data(filename) | ||||||
|     drawdown, hdate, lowdate, hval, lval = calculate_max_drawdown(bt_data) |     _, hdate, lowdate, hval, lval, drawdown = calculate_max_drawdown( | ||||||
|  |         bt_data, value_col="profit_abs") | ||||||
|     assert isinstance(drawdown, float) |     assert isinstance(drawdown, float) | ||||||
|     assert pytest.approx(drawdown) == 0.21142322 |     assert pytest.approx(drawdown) == 0.12071099 | ||||||
|     assert isinstance(hdate, Timestamp) |     assert isinstance(hdate, Timestamp) | ||||||
|     assert isinstance(lowdate, Timestamp) |     assert isinstance(lowdate, Timestamp) | ||||||
|     assert isinstance(hval, float) |     assert isinstance(hval, float) | ||||||
|     assert isinstance(lval, float) |     assert isinstance(lval, float) | ||||||
|     assert hdate == Timestamp('2018-01-24 14:25:00', tz='UTC') |     assert hdate == Timestamp('2018-01-25 01:30:00', tz='UTC') | ||||||
|     assert lowdate == Timestamp('2018-01-30 04:45:00', tz='UTC') |     assert lowdate == Timestamp('2018-01-25 03:50:00', tz='UTC') | ||||||
|  |  | ||||||
|     underwater = calculate_underwater(bt_data) |     underwater = calculate_underwater(bt_data) | ||||||
|     assert isinstance(underwater, DataFrame) |     assert isinstance(underwater, DataFrame) | ||||||
|  |  | ||||||
|     with pytest.raises(ValueError, match='Trade dataframe empty.'): |     with pytest.raises(ValueError, match='Trade dataframe empty.'): | ||||||
|         drawdown, hdate, lowdate, hval, lval = calculate_max_drawdown(DataFrame()) |         calculate_max_drawdown(DataFrame()) | ||||||
|  |  | ||||||
|     with pytest.raises(ValueError, match='Trade dataframe empty.'): |     with pytest.raises(ValueError, match='Trade dataframe empty.'): | ||||||
|         calculate_underwater(DataFrame()) |         calculate_underwater(DataFrame()) | ||||||
| @@ -331,12 +332,13 @@ def test_calculate_max_drawdown2(): | |||||||
|     # sort by profit and reset index |     # sort by profit and reset index | ||||||
|     df = df.sort_values('profit').reset_index(drop=True) |     df = df.sort_values('profit').reset_index(drop=True) | ||||||
|     df1 = df.copy() |     df1 = df.copy() | ||||||
|     drawdown, hdate, ldate, hval, lval = calculate_max_drawdown( |     drawdown, hdate, ldate, hval, lval, drawdown_rel = calculate_max_drawdown( | ||||||
|         df, date_col='open_date', value_col='profit') |         df, date_col='open_date', value_col='profit') | ||||||
|     # Ensure df has not been altered. |     # Ensure df has not been altered. | ||||||
|     assert df.equals(df1) |     assert df.equals(df1) | ||||||
|  |  | ||||||
|     assert isinstance(drawdown, float) |     assert isinstance(drawdown, float) | ||||||
|  |     assert isinstance(drawdown_rel, float) | ||||||
|     # High must be before low |     # High must be before low | ||||||
|     assert hdate < ldate |     assert hdate < ldate | ||||||
|     # High value must be higher than low value |     # High value must be higher than low value | ||||||
|   | |||||||
| @@ -1,4 +1,3 @@ | |||||||
| import datetime |  | ||||||
| import re | import re | ||||||
| from datetime import timedelta | from datetime import timedelta | ||||||
| from pathlib import Path | from pathlib import Path | ||||||
| @@ -103,7 +102,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): | |||||||
|     assert strat_stats['backtest_end'] == max_date.strftime(DATETIME_PRINT_FORMAT) |     assert strat_stats['backtest_end'] == max_date.strftime(DATETIME_PRINT_FORMAT) | ||||||
|     assert strat_stats['total_trades'] == len(results['DefStrat']['results']) |     assert strat_stats['total_trades'] == len(results['DefStrat']['results']) | ||||||
|     # Above sample had no loosing trade |     # Above sample had no loosing trade | ||||||
|     assert strat_stats['max_drawdown'] == 0.0 |     assert strat_stats['max_drawdown_account'] == 0.0 | ||||||
|  |  | ||||||
|     # Retry with losing trade |     # Retry with losing trade | ||||||
|     results = {'DefStrat': { |     results = {'DefStrat': { | ||||||
| @@ -143,7 +142,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): | |||||||
|     assert 'strategy_comparison' in stats |     assert 'strategy_comparison' in stats | ||||||
|     strat_stats = stats['strategy']['DefStrat'] |     strat_stats = stats['strategy']['DefStrat'] | ||||||
|  |  | ||||||
|     assert strat_stats['max_drawdown'] == 0.013803 |     assert pytest.approx(strat_stats['max_drawdown_account']) == 1.399999e-08 | ||||||
|     assert strat_stats['drawdown_start'] == '2017-11-14 22:10:00' |     assert strat_stats['drawdown_start'] == '2017-11-14 22:10:00' | ||||||
|     assert strat_stats['drawdown_end'] == '2017-11-14 22:43:00' |     assert strat_stats['drawdown_end'] == '2017-11-14 22:43:00' | ||||||
|     assert strat_stats['drawdown_end_ts'] == 1510699380000 |     assert strat_stats['drawdown_end_ts'] == 1510699380000 | ||||||
| @@ -165,7 +164,7 @@ def test_generate_backtest_stats(default_conf, testdatadir, tmpdir): | |||||||
|     filename1 = Path(tmpdir / last_fn) |     filename1 = Path(tmpdir / last_fn) | ||||||
|     assert filename1.is_file() |     assert filename1.is_file() | ||||||
|     content = filename1.read_text() |     content = filename1.read_text() | ||||||
|     assert 'max_drawdown' in content |     assert 'max_drawdown_account' in content | ||||||
|     assert 'strategy' in content |     assert 'strategy' in content | ||||||
|     assert 'pairlist' in content |     assert 'pairlist' in content | ||||||
|  |  | ||||||
| @@ -227,9 +226,9 @@ def test_generate_daily_stats(testdatadir): | |||||||
|     assert isinstance(res, dict) |     assert isinstance(res, dict) | ||||||
|     assert round(res['backtest_best_day'], 4) == 0.1796 |     assert round(res['backtest_best_day'], 4) == 0.1796 | ||||||
|     assert round(res['backtest_worst_day'], 4) == -0.1468 |     assert round(res['backtest_worst_day'], 4) == -0.1468 | ||||||
|     assert res['winning_days'] == 14 |     assert res['winning_days'] == 19 | ||||||
|     assert res['draw_days'] == 4 |     assert res['draw_days'] == 0 | ||||||
|     assert res['losing_days'] == 3 |     assert res['losing_days'] == 2 | ||||||
|  |  | ||||||
|     # Select empty dataframe! |     # Select empty dataframe! | ||||||
|     res = generate_daily_stats(bt_data.loc[bt_data['open_date'] == '2000-01-01', :]) |     res = generate_daily_stats(bt_data.loc[bt_data['open_date'] == '2000-01-01', :]) | ||||||
| @@ -324,51 +323,25 @@ def test_generate_sell_reason_stats(): | |||||||
|     assert stop_result['profit_mean_pct'] == round(stop_result['profit_mean'] * 100, 2) |     assert stop_result['profit_mean_pct'] == round(stop_result['profit_mean'] * 100, 2) | ||||||
|  |  | ||||||
|  |  | ||||||
| def test_text_table_strategy(default_conf): | def test_text_table_strategy(testdatadir): | ||||||
|     default_conf['max_open_trades'] = 2 |     filename = testdatadir / "backtest-result_multistrat.json" | ||||||
|     default_conf['dry_run_wallet'] = 3 |     bt_res_data = load_backtest_stats(filename) | ||||||
|     results = {} |  | ||||||
|     date = datetime.datetime(year=2020, month=1, day=1, hour=12, minute=30) |     bt_res_data_comparison = bt_res_data.pop('strategy_comparison') | ||||||
|     delta = datetime.timedelta(days=1) |  | ||||||
|     results['TestStrategy1'] = {'results': pd.DataFrame( |  | ||||||
|         { |  | ||||||
|             'pair': ['ETH/BTC', 'ETH/BTC', 'ETH/BTC'], |  | ||||||
|             'close_date': [date, date + delta, date + delta * 2], |  | ||||||
|             'profit_ratio': [0.1, 0.2, 0.3], |  | ||||||
|             'profit_abs': [0.2, 0.4, 0.5], |  | ||||||
|             'trade_duration': [10, 30, 10], |  | ||||||
|             'wins': [2, 0, 0], |  | ||||||
|             'draws': [0, 0, 0], |  | ||||||
|             'losses': [0, 0, 1], |  | ||||||
|             'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] |  | ||||||
|         } |  | ||||||
|     ), 'config': default_conf} |  | ||||||
|     results['TestStrategy2'] = {'results': pd.DataFrame( |  | ||||||
|         { |  | ||||||
|             'pair': ['LTC/BTC', 'LTC/BTC', 'LTC/BTC'], |  | ||||||
|             'close_date': [date, date + delta, date + delta * 2], |  | ||||||
|             'profit_ratio': [0.4, 0.2, 0.3], |  | ||||||
|             'profit_abs': [0.4, 0.4, 0.5], |  | ||||||
|             'trade_duration': [15, 30, 15], |  | ||||||
|             'wins': [4, 1, 0], |  | ||||||
|             'draws': [0, 0, 0], |  | ||||||
|             'losses': [0, 0, 1], |  | ||||||
|             'sell_reason': [SellType.ROI, SellType.ROI, SellType.STOP_LOSS] |  | ||||||
|         } |  | ||||||
|     ), 'config': default_conf} |  | ||||||
|  |  | ||||||
|     result_str = ( |     result_str = ( | ||||||
|         '|      Strategy |   Buys |   Avg Profit % |   Cum Profit % |   Tot Profit BTC |' |         '|       Strategy |   Buys |   Avg Profit % |   Cum Profit % |   Tot Profit BTC |' | ||||||
|         '   Tot Profit % |   Avg Duration |   Win  Draw  Loss  Win% |              Drawdown |\n' |         '   Tot Profit % |   Avg Duration |   Win  Draw  Loss  Win% |              Drawdown |\n' | ||||||
|         '|---------------+--------+----------------+----------------+------------------+' |         '|----------------+--------+----------------+----------------+------------------+' | ||||||
|         '----------------+----------------+-------------------------+-----------------------|\n' |         '----------------+----------------+-------------------------+-----------------------|\n' | ||||||
|         '| TestStrategy1 |      3 |          20.00 |          60.00 |       1.10000000 |' |         '| StrategyTestV2 |    179 |           0.08 |          14.39 |       0.02608550 |' | ||||||
|         '          36.67 |        0:17:00 |     3     0     0   100 | 0.00000000 BTC  0.00% |\n' |         '         260.85 |        3:40:00 |   170     0     9  95.0 | 0.00308222 BTC  8.67% |\n' | ||||||
|         '| TestStrategy2 |      3 |          30.00 |          90.00 |       1.30000000 |' |         '|   TestStrategy |    179 |           0.08 |          14.39 |       0.02608550 |' | ||||||
|         '          43.33 |        0:20:00 |     3     0     0   100 | 0.00000000 BTC  0.00% |' |         '         260.85 |        3:40:00 |   170     0     9  95.0 | 0.00308222 BTC  8.67% |' | ||||||
|     ) |     ) | ||||||
|  |  | ||||||
|     strategy_results = generate_strategy_comparison(all_results=results) |     strategy_results = generate_strategy_comparison(bt_stats=bt_res_data['strategy']) | ||||||
|  |     assert strategy_results == bt_res_data_comparison | ||||||
|     assert text_table_strategy(strategy_results, 'BTC') == result_str |     assert text_table_strategy(strategy_results, 'BTC') == result_str | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -343,7 +343,7 @@ def test_generate_profit_graph(testdatadir): | |||||||
|  |  | ||||||
|     profit = find_trace_in_fig_data(figure.data, "Profit") |     profit = find_trace_in_fig_data(figure.data, "Profit") | ||||||
|     assert isinstance(profit, go.Scatter) |     assert isinstance(profit, go.Scatter) | ||||||
|     drawdown = find_trace_in_fig_data(figure.data, "Max drawdown 10.45%") |     drawdown = find_trace_in_fig_data(figure.data, "Max drawdown 35.69%") | ||||||
|     assert isinstance(drawdown, go.Scatter) |     assert isinstance(drawdown, go.Scatter) | ||||||
|     parallel = find_trace_in_fig_data(figure.data, "Parallel trades") |     parallel = find_trace_in_fig_data(figure.data, "Parallel trades") | ||||||
|     assert isinstance(parallel, go.Scatter) |     assert isinstance(parallel, go.Scatter) | ||||||
|   | |||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								tests/testdata/backtest-result_new.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								tests/testdata/backtest-result_new.json
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Reference in New Issue
	
	Block a user