diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index cb5806f75..c11776fab 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -56,35 +56,7 @@ def init_plotscript(config): } -def _add_indicators_list(fig, row, indicators: List[str], data: pd.DataFrame) -> make_subplots: - """ - Generate all the indicator selected by the user for a specific row - :param fig: Plot figure to append to - :param row: row number for this plot - :param indicators: List of indicators present in the dataframe - :param data: candlestick DataFrame - """ - for indicator in indicators: - if indicator in data: - scatter = go.Scatter( - x=data['date'], - y=data[indicator].values, - mode='lines', - name=indicator - ) - fig.add_trace(scatter, row, 1) - else: - logger.info( - 'Indicator "%s" ignored. Reason: This indicator is not found ' - 'in your strategy.', - indicator - ) - - return fig - - -def _add_indicators_dict(fig, row, indicators: Dict[str, Dict], - data: pd.DataFrame) -> make_subplots: +def add_indicators(fig, row, indicators: Dict[str, Dict], data: pd.DataFrame) -> make_subplots: """ Generate all the indicators selected by the user for a specific row, based on the configuration :param fig: Plot figure to append to @@ -94,7 +66,7 @@ def _add_indicators_dict(fig, row, indicators: Dict[str, Dict], :param data: candlestick DataFrame """ for indicator, conf in indicators.items(): - print(conf) + logger.debug(f"indicator {indicator} with config {conf}") if indicator in data: kwargs = {'x': data['date'], 'y': data[indicator].values, @@ -117,21 +89,6 @@ def _add_indicators_dict(fig, row, indicators: Dict[str, Dict], return fig -def add_indicators(fig, row, indicators: IndicatorType, data: pd.DataFrame) -> make_subplots: - """ - Generate all the indicator selected by the user for a specific row - :param fig: Plot figure to append to - :param row: row number for this plot - :param indicators: List of indicators present in the dataframe, Or Dict of Indicators - with configuration options. Dict key must correspond to dataframe column. - :param data: candlestick DataFrame - """ - if isinstance(indicators, list): - return _add_indicators_list(fig, row, indicators, data) - else: - return _add_indicators_dict(fig, row, indicators, data) - - def add_profit(fig, row, data: pd.DataFrame, column: str, name: str) -> make_subplots: """ Add profit-plot @@ -194,9 +151,39 @@ def plot_trades(fig, trades: pd.DataFrame) -> make_subplots: return fig -def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFrame = None, - indicators1: IndicatorType = [], - indicators2: IndicatorType = [],) -> go.Figure: +def create_plotconfig(indicators1: List[str], indicators2: List[str], plot_config: Dict[str, Dict]) -> Dict[str, Dict]: + """ + Combines indicators 1 and indicators 2 into plot_config if necessary + :param indicators1: List containing Main plot indicators + :param indicators2: List containing Sub plot indicators + :param plot_config: Dict of Dicts containing advanced plot configuration + :return: plot_config - eventually with indicators 1 and 2 + """ + + if not plot_config: + # If no indicators and no plot-config given, use defaults. + if not indicators1: + indicators1 = ['sma', 'ema3', 'ema5'] + if not indicators2: + indicators1 = ['macd', 'macdsignal'] + + # Create subplot configuration if plot_config is not available. + plot_config = { + 'main_plot': {ind: {} for ind in indicators1}, + 'subplots': {'Other': {ind: {} for ind in indicators2}}, + } + if 'main_plot' not in plot_config: + plot_config['main_plot'] = {} + + if 'subplots' not in plot_config: + plot_config['subplots'] = {} + + +def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFrame = None, *, + indicators1: List[str] = [], + indicators2: List[str] = [], + plot_config: Dict[str, Dict] = {}, + ) -> go.Figure: """ Generate the graph from the data generated by Backtesting or from DB Volume will always be ploted in row2, so Row 1 and 3 are to our disposal for custom indicators @@ -205,21 +192,26 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra :param trades: All trades created :param indicators1: List containing Main plot indicators :param indicators2: List containing Sub plot indicators - :return: None + :param plot_config: Dict of Dicts containing advanced plot configuration + :return: Plotly figure """ + plot_config = create_plotconfig(indicators1, indicators2) + rows = 2 + len(plot_config['subplots']) + row_widths = [1 for _ in plot_config['subplots']] # Define the graph fig = make_subplots( - rows=3, + rows=rows, cols=1, shared_xaxes=True, - row_width=[1, 1, 4], + row_width=row_widths + [1, 4], vertical_spacing=0.0001, ) fig['layout'].update(title=pair) fig['layout']['yaxis1'].update(title='Price') fig['layout']['yaxis2'].update(title='Volume') - fig['layout']['yaxis3'].update(title='Other') + for i, name in enumerate(plot_config['subplots']): + fig['layout'][f'yaxis{3 + i}'].update(title=name) fig['layout']['xaxis']['rangeslider'].update(visible=False) # Common information @@ -289,12 +281,13 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra ) fig.add_trace(bb_lower, 1, 1) fig.add_trace(bb_upper, 1, 1) - if 'bb_upperband' in indicators1 and 'bb_lowerband' in indicators1: - indicators1.remove('bb_upperband') - indicators1.remove('bb_lowerband') + if ('bb_upperband' in plot_config['main_plot'] + and 'bb_lowerband' in plot_config['main_plot']): + del plot_config['main_plot']['bb_upperband'] + del plot_config['main_plot']['bb_lowerband'] # Add indicators to main plot - fig = add_indicators(fig=fig, row=1, indicators=indicators1, data=data) + fig = add_indicators(fig=fig, row=1, indicators=plot_config['main_plot'], data=data) fig = plot_trades(fig, trades) @@ -309,7 +302,10 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra fig.add_trace(volume, 2, 1) # Add indicators to separate row - fig = add_indicators(fig=fig, row=3, indicators=indicators2, data=data) + for i, name in enumerate(plot_config['subplots']): + fig = add_indicators(fig=fig, row=3 + i, + indicators=plot_config['subplots'][name], + data=data) return fig @@ -380,17 +376,6 @@ def store_plot_file(fig, filename: str, directory: Path, auto_open: bool = False logger.info(f"Stored plot as {_filename}") -def _get_plot_indicators(config, strategy): - - if hasattr(strategy, 'plot_config'): - indicators1 = strategy.plot_config['main_plot'] - indicators2 = strategy.plot_config['subplots'] - else: - indicators1 = config.get("indicators1") - indicators2 = config.get("indicators2") - return indicators1, indicators2 - - def load_and_plot_trades(config: Dict[str, Any]): """ From configuration provided @@ -417,14 +402,13 @@ def load_and_plot_trades(config: Dict[str, Any]): trades_pair = trades.loc[trades['pair'] == pair] trades_pair = extract_trades_of_period(dataframe, trades_pair) - indicators1, indicators2 = _get_plot_indicators(config, strategy) - fig = generate_candlestick_graph( pair=pair, data=dataframe, trades=trades_pair, - indicators1=indicators1, - indicators2=indicators2, + indicators1=config["indicators1"], + indicators2=config["indicators2"], + plot_config=strategy.plot_config if hasattr(strategy, 'plot_config') else {} ) store_plot_file(fig, filename=generate_plot_filename(pair, config['ticker_interval']),