diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index 3c54b0eeb..6858deb69 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -445,6 +445,9 @@ def _calc_drawdown_series(profit_results: pd.DataFrame, *, date_col: str, value_ cumulative_balance = starting_balance + max_drawdown_df['cumulative'] max_balance = starting_balance + max_drawdown_df['high_value'] max_drawdown_df['drawdown_relative'] = ((max_balance - cumulative_balance) / max_balance) + else: + # This is not completely accurate, + max_drawdown_df['drawdown_relative'] = ((max_drawdown_df['high_value'] - max_drawdown_df['cumulative']) / max_drawdown_df['high_value']) return max_drawdown_df diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index 747248be7..3d651c1d9 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -1,6 +1,7 @@ import logging from pathlib import Path from typing import Any, Dict, List, Optional +from numpy import number import pandas as pd @@ -158,12 +159,12 @@ def add_profit(fig, row, data: pd.DataFrame, column: str, name: str) -> make_sub def add_max_drawdown(fig, row, trades: pd.DataFrame, df_comb: pd.DataFrame, - timeframe: str) -> make_subplots: + timeframe: str, starting_balance: number) -> make_subplots: """ Add scatter points indicating max drawdown """ try: - _, highdate, lowdate, _, _, max_drawdown = calculate_max_drawdown(trades) + _, highdate, lowdate, _, _, max_drawdown = calculate_max_drawdown(trades, starting_balance=starting_balance) drawdown = go.Scatter( x=[highdate, lowdate], @@ -188,22 +189,33 @@ def add_max_drawdown(fig, row, trades: pd.DataFrame, df_comb: pd.DataFrame, return fig -def add_underwater(fig, row, trades: pd.DataFrame) -> make_subplots: +def add_underwater(fig, row, trades: pd.DataFrame, starting_balance: number) -> make_subplots: """ - Add underwater plot + Add underwater plots """ try: - underwater = calculate_underwater(trades, value_col="profit_abs") + underwater = calculate_underwater(trades, value_col="profit_abs", starting_balance=starting_balance) - underwater = go.Scatter( + underwater_plot = go.Scatter( x=underwater['date'], y=underwater['drawdown'], name="Underwater Plot", fill='tozeroy', fillcolor='#cc362b', - line={'color': '#cc362b'}, + line={'color': '#cc362b'} ) - fig.add_trace(underwater, row, 1) + + underwater_plot_relative = go.Scatter( + x=underwater['date'], + y=(-underwater['drawdown_relative']), + name="Underwater Plot (%)", + fill='tozeroy', + fillcolor='green', + line={'color': 'green'} + ) + + fig.add_trace(underwater_plot, row, 1) + fig.add_trace(underwater_plot_relative, row+1, 1) except ValueError: logger.warning("No trades found - not plotting underwater plot") return fig @@ -506,7 +518,8 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra def generate_profit_graph(pairs: str, data: Dict[str, pd.DataFrame], - trades: pd.DataFrame, timeframe: str, stake_currency: str) -> go.Figure: + trades: pd.DataFrame, timeframe: str, stake_currency: str, + starting_balance: number) -> go.Figure: # Combine close-values for all pairs, rename columns to "pair" try: df_comb = combine_dataframes_with_mean(data, "close") @@ -530,8 +543,8 @@ def generate_profit_graph(pairs: str, data: Dict[str, pd.DataFrame], name='Avg close price', ) - fig = make_subplots(rows=5, cols=1, shared_xaxes=True, - row_heights=[1, 1, 1, 0.5, 1], + fig = make_subplots(rows=6, cols=1, shared_xaxes=True, + row_heights=[1, 1, 1, 0.5, 0.75, 0.75], vertical_spacing=0.05, subplot_titles=[ "AVG Close Price", @@ -539,6 +552,7 @@ def generate_profit_graph(pairs: str, data: Dict[str, pd.DataFrame], "Profit per pair", "Parallelism", "Underwater", + "Relative Drawdown", ]) fig['layout'].update(title="Freqtrade Profit plot") fig['layout']['yaxis1'].update(title='Price') @@ -546,14 +560,16 @@ def generate_profit_graph(pairs: str, data: Dict[str, pd.DataFrame], fig['layout']['yaxis3'].update(title=f'Profit {stake_currency}') fig['layout']['yaxis4'].update(title='Trade count') fig['layout']['yaxis5'].update(title='Underwater Plot') + fig['layout']['yaxis6'].update(title='Underwater Plot Relative (%)', tickformat=',.2%') fig['layout']['xaxis']['rangeslider'].update(visible=False) fig.update_layout(modebar_add=["v1hovermode", "toggleSpikeLines"]) fig.add_trace(avgclose, 1, 1) fig = add_profit(fig, 2, df_comb, 'cum_profit', 'Profit') - fig = add_max_drawdown(fig, 2, trades, df_comb, timeframe) + fig = add_max_drawdown(fig, 2, trades, df_comb, timeframe, starting_balance) fig = add_parallelism(fig, 4, trades, timeframe) - fig = add_underwater(fig, 5, trades) + # Two rows consumed + fig = add_underwater(fig, 5, trades, starting_balance) for pair in pairs: profit_col = f'cum_profit_{pair}' @@ -668,7 +684,7 @@ def plot_profit(config: Dict[str, Any]) -> None: # this could be useful to gauge the overall market trend fig = generate_profit_graph(plot_elements['pairs'], plot_elements['ohlcv'], trades, config['timeframe'], - config.get('stake_currency', '')) + config.get('stake_currency', ''), config['available_capital']) store_plot_file(fig, filename='freqtrade-profit-plot.html', directory=config['user_data_dir'] / 'plot', auto_open=config.get('plot_auto_open', False)) diff --git a/tests/optimize/test_hyperoptloss.py b/tests/optimize/test_hyperoptloss.py index e3f6daf6c..aac02305e 100644 --- a/tests/optimize/test_hyperoptloss.py +++ b/tests/optimize/test_hyperoptloss.py @@ -85,6 +85,7 @@ def test_loss_calculation_has_limited_profit(hyperopt_conf, hyperopt_results) -> "SharpeHyperOptLoss", "SharpeHyperOptLossDaily", "MaxDrawDownHyperOptLoss", + "MaxDrawDownRelativeHyperOptLoss", "CalmarHyperOptLoss", "ProfitDrawDownHyperOptLoss",