def plot(self, name=None, trace_kwargs={}, fig=None, **layout_kwargs): # pragma: no cover """Plot Series as a line. Args: name (str): Name of the trace. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. Example: ```py df['a'].vbt.plot() ``` ![](/vectorbt/docs/img/sr_plot.png)""" if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) if name is None: name = self._obj.name scatter = go.Scatter(x=self.index, y=self._obj.values, mode='lines', name=str(name), showlegend=name is not None) scatter.update(**trace_kwargs) fig.add_trace(scatter) return fig
def plot(self, column=None, plot_close=True, close_trace_kwargs=None, ma_trace_kwargs=None, row=None, col=None, fig=None, **layout_kwargs): # pragma: no cover """Plot `MA.ma` against `MA.close`. Args: column (str): Name of the column to plot. plot_close (bool): Whether to plot `MA.close`. close_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MA.close`. ma_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MA.ma`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.MA.run(price['Close'], 10).plot() ``` ![](/vectorbt/docs/img/MA.png) """ from vectorbt.settings import color_schema self_col = self.select_series(column=column) if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) if close_trace_kwargs is None: close_trace_kwargs = {} if ma_trace_kwargs is None: ma_trace_kwargs = {} close_trace_kwargs = merge_dicts( dict(name='Close', line_color=color_schema['blue']), close_trace_kwargs) ma_trace_kwargs = merge_dicts(dict(name='MA'), ma_trace_kwargs) if plot_close: fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, row=row, col=col, fig=fig) fig = self_col.ma.vbt.plot(trace_kwargs=ma_trace_kwargs, row=row, col=col, fig=fig) return fig
def plot(self, name=None, trace_kwargs=None, row=None, col=None, yref='y', fig=None, **layout_kwargs): # pragma: no cover """Plot Series as a line. Args: name (str): Name of the signals. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. row (int): Row position. col (int): Column position. yref (str): Y coordinate axis. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> sig['a'].vbt.signals.plot() ``` ![](/vectorbt/docs/img/signals_sr_plot.png) """ if trace_kwargs is None: trace_kwargs = {} # Set up figure if fig is None: fig = CustomFigureWidget() default_layout = dict() default_layout['yaxis' + yref[1:]] = dict(tickmode='array', tickvals=[0, 1], ticktext=['false', 'true']) fig.update_layout(**default_layout) fig.update_layout(**layout_kwargs) if name is None: if 'name' in trace_kwargs: name = trace_kwargs.pop('name') else: name = self._obj.name if name is not None: name = str(name) scatter = go.Scatter(x=self.wrapper.index, y=self._obj.values, mode='lines', name=name, showlegend=name is not None) scatter.update(**trace_kwargs) fig.add_trace(scatter, row=row, col=col) return fig
def plot_as_markers(self, ts, name=None, trace_kwargs={}, fig=None, **layout_kwargs): # pragma: no cover """Plot Series as markers. Args: ts (pandas.Series): Time series to plot markers on. !!! note Doesn't plot `ts`. name (str): Name of the signals. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. Example: ```py ts = pd.Series([1, 2, 3, 2, 1], index=sig.index) fig = ts.vbt.plot() sig['b'].vbt.signals.plot_as_entry_markers(ts, fig=fig) (~sig['b']).vbt.signals.plot_as_exit_markers(ts, fig=fig) ``` ![](/vectorbt/docs/img/signals_plot_as_markers.png)""" checks.assert_type(ts, pd.Series) checks.assert_same_index(self._obj, ts) if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) if name is None: name = self._obj.name # Plot markers scatter = go.Scatter( x=ts.index[self._obj], y=ts[self._obj], mode='markers', marker=dict(symbol='circle', color=contrast_color_schema['blue'], size=7, line=dict(width=1, color=adjust_lightness( contrast_color_schema['blue']))), name=str(name), showlegend=name is not None) scatter.update(**trace_kwargs) fig.add_trace(scatter) return fig
def plot(self, column=None, tr_trace_kwargs=None, atr_trace_kwargs=None, row=None, col=None, fig=None, **layout_kwargs): # pragma: no cover """Plot `ATR.tr` and `ATR.atr`. Args: column (str): Name of the column to plot. tr_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `ATR.tr`. atr_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `ATR.atr`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.ATR.run(price['High'], price['Low'], price['Close'], 10).plot() ``` ![](/vectorbt/docs/img/ATR.png) """ self_col = self.select_series(column=column) if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) if tr_trace_kwargs is None: tr_trace_kwargs = {} if atr_trace_kwargs is None: atr_trace_kwargs = {} tr_trace_kwargs = merge_dicts(dict(name='TR'), tr_trace_kwargs) atr_trace_kwargs = merge_dicts(dict(name='ATR'), atr_trace_kwargs) fig = self_col.tr.vbt.plot(trace_kwargs=tr_trace_kwargs, row=row, col=col, fig=fig) fig = self_col.atr.vbt.plot(trace_kwargs=atr_trace_kwargs, row=row, col=col, fig=fig) return fig
def create_scatter(data=None, trace_names=None, x_labels=None, trace_kwargs={}, fig=None, **layout_kwargs): """Create a scatter plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be of shape (`x_labels`, `trace_names`). trace_names (str or list of str): Trace names, corresponding to columns in pandas. x_labels (array_like): X-axis labels, corresponding to index in pandas. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. Example: ```py import vectorbt as vbt vbt.plotting.create_scatter( data=[[1, 2], [3, 4]], trace_names=['a', 'b'], x_labels=['x', 'y'] ) ``` ![](/vectorbt/docs/img/create_scatter.png) """ if data is None: if trace_names is None: raise ValueError("At least trace_names must be passed") if trace_names is None: data = reshape_fns.to_2d(data) trace_names = [None] * data.shape[1] if isinstance(trace_names, str): trace_names = [trace_names] if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): scatter = go.Scatter( x=x_labels, name=trace_name, showlegend=trace_name is not None ) scatter.update(**(trace_kwargs[i] if isinstance(trace_kwargs, (list, tuple)) else trace_kwargs)) fig.add_trace(scatter) if data is not None: trace_idx = np.arange(len(fig.data) - len(trace_names), len(fig.data)) update_scatter_data(fig, data, trace_idx=trace_idx) return fig
def create_hist(data=None, trace_names=None, horizontal=False, trace_kwargs={}, fig=None, **layout_kwargs): """Create a histogram plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be of shape (any, `trace_names`). trace_names (str or list of str): Trace names, corresponding to columns in pandas. horizontal (bool): Plot horizontally. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Histogram`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. Example: ```py import vectorbt as vbt vbt.plotting.create_hist( data=[[1, 2], [3, 4], [2, 1]], trace_names=['a', 'b'] ) ``` ![](/vectorbt/docs/img/create_hist.png) """ if data is None: if trace_names is None: raise ValueError("At least trace_names must be passed") if trace_names is None: data = reshape_fns.to_2d(data) trace_names = [None] * data.shape[1] if isinstance(trace_names, str): trace_names = [trace_names] if fig is None: fig = CustomFigureWidget() fig.update_layout(barmode='overlay') fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): hist = go.Histogram( opacity=0.75 if len(trace_names) > 1 else 1, name=trace_name, showlegend=trace_name is not None ) hist.update(**(trace_kwargs[i] if isinstance(trace_kwargs, (list, tuple)) else trace_kwargs)) fig.add_trace(hist) if data is not None: trace_idx = np.arange(len(fig.data) - len(trace_names), len(fig.data)) update_hist_data(fig, data, horizontal=horizontal, trace_idx=trace_idx) return fig
def create_heatmap(data=None, x_labels=None, y_labels=None, horizontal=False, trace_kwargs={}, fig=None, **layout_kwargs): """Create a heatmap plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be of shape (`y_labels`, `x_labels`). x_labels (array_like): X-axis labels, corresponding to columns in pandas. y_labels (array_like): Y-axis labels, corresponding to index in pandas. horizontal (bool): Plot horizontally. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Heatmap`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. Example: ```py import vectorbt as vbt vbt.plotting.create_heatmap( data=[[1, 2], [3, 4]], x_labels=['a', 'b'], y_labels=['x', 'y'] ) ``` ![](/vectorbt/docs/img/create_heatmap.png) """ if data is None: if x_labels is None or y_labels is None: raise ValueError("At least x_labels and y_labels must be passed") if fig is None: fig = CustomFigureWidget() fig.update_layout(width=600, height=450) fig.update_layout(**layout_kwargs) heatmap = go.Heatmap( hoverongaps=False, colorscale='Plasma' ) if horizontal: heatmap.y = x_labels heatmap.x = y_labels else: heatmap.x = x_labels heatmap.y = y_labels heatmap.update(**trace_kwargs) fig.add_trace(heatmap) if data is not None: update_heatmap_data(fig, data, horizontal=horizontal, trace_idx=len(fig.data) - 1) return fig
def plot(self, plot_type=go.Ohlc, ohlc_kwargs=None, entry_trace_kwargs=None, exit_trace_kwargs=None, row=None, col=None, fig=None, **layout_kwargs): # pragma: no cover if self.wrapper.ndim > 1: raise TypeError("Select a column first. Use indexing.") if fig is None: fig = CustomFigureWidget() fig.update_layout(showlegend=True, xaxis_rangeslider_visible=False, xaxis_showgrid=True, yaxis_showgrid=True) fig.update_layout(**layout_kwargs) if ohlc_kwargs is None: ohlc_kwargs = {} # Plot OHLC ohlc = plot_type(x=self.wrapper.index, open=self.open, high=self.high, low=self.low, close=self.close, name='OHLC', increasing_line_color='#1b9e76', decreasing_line_color='#d95f02', opacity=0.7) ohlc.update(**ohlc_kwargs) fig.add_trace(ohlc, row=row, col=col) # Plot entry and exit markers base_cls.plot(self, entry_y=self.open, exit_y=self.hit_price, exit_types=self.stop_type_readable, entry_trace_kwargs=entry_trace_kwargs, exit_trace_kwargs=exit_trace_kwargs, row=row, col=col, fig=fig) return fig
def plot(self, column=None, obv_trace_kwargs=None, row=None, col=None, fig=None, **layout_kwargs): # pragma: no cover """Plot `OBV.obv`. Args: column (str): Name of the column to plot. obv_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `OBV.obv`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```py >>> vbt.OBV.run(price['Close'], price['Volume']).plot() ``` ![](/vectorbt/docs/img/OBV.png) """ self_col = self.select_series(column=column) if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) if obv_trace_kwargs is None: obv_trace_kwargs = {} obv_trace_kwargs = merge_dicts(dict(name='OBV'), obv_trace_kwargs) fig = self_col.obv.vbt.plot(trace_kwargs=obv_trace_kwargs, row=row, col=col, fig=fig) return fig
def plot(self, name=None, trace_kwargs={}, fig=None, **layout_kwargs): # pragma: no cover """Plot Series as a line. Args: name (str): Name of the signals. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. Example: ```python-repl >>> signals['a'].vbt.signals.plot() ``` ![](/vectorbt/docs/img/signals_sr_plot.png)""" # Set up figure if fig is None: fig = CustomFigureWidget() fig.update_layout( yaxis=dict( tickmode='array', tickvals=[0, 1], ticktext=['false', 'true'] ) ) fig.update_layout(**layout_kwargs) if name is None: name = self._obj.name scatter = go.Scatter( x=self.index, y=self._obj.values, mode='lines', name=str(name), showlegend=name is not None ) scatter.update(**trace_kwargs) fig.add_trace(scatter) return fig
def create_indicator(value=None, label=None, value_range=None, cmap_name='Spectral', trace_kwargs={}, fig=None, **layout_kwargs): """Create an indicator plot. Args: value (int or float): The value to be displayed. label (str): The label to be displayed. value_range (list or tuple of 2 values): The value range of the gauge. cmap_name (str): A matplotlib-compatible colormap name. See the [list of available colormaps](https://matplotlib.org/tutorials/colors/colormaps.html). trace_kwargs (dict): Keyword arguments passed to the `plotly.graph_objects.Indicator`. **layout_kwargs: Keyword arguments for layout. Example: ```py import vectorbt as vbt vbt.plotting.create_indicator( value=2, value_range=(1, 3), label='My Indicator' ) ``` ![](/vectorbt/docs/img/create_indicator.png) """ if fig is None: fig = CustomFigureWidget() fig.update_layout(width=500, height=300) fig.update_layout(**layout_kwargs) indicator = go.Indicator( domain=dict(x=[0, 1], y=[0, 1]), mode="gauge+number+delta", title=dict(text=label) ) indicator.update(**trace_kwargs) fig.add_trace(indicator) if value is not None: update_indicator_data(fig, value, value_range=value_range, cmap_name=cmap_name, trace_idx=len(fig.data) - 1) return fig
def plot_as_markers(self, y=None, name=None, trace_kwargs=None, row=None, col=None, fig=None, **layout_kwargs): # pragma: no cover """Plot Series as markers. Args: y (array_like): Y-axis values to plot markers on. !!! note Doesn't plot `y`. name (str): Name of the signals. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> ts = pd.Series([1, 2, 3, 2, 1], index=sig.index) >>> fig = ts.vbt.plot() >>> sig['b'].vbt.signals.plot_as_entry_markers(y=ts, fig=fig) >>> (~sig['b']).vbt.signals.plot_as_exit_markers(y=ts, fig=fig) ``` ![](/vectorbt/docs/img/signals_plot_as_markers.png) """ from vectorbt.settings import contrast_color_schema if trace_kwargs is None: trace_kwargs = {} if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) if name is None: if 'name' in trace_kwargs: name = trace_kwargs.pop('name') else: name = self._obj.name if name is not None: name = str(name) # Plot markers _y = 1 if y is None else y scatter = go.Scatter( x=self.wrapper.index, y=np.where(self._obj, _y, np.nan), mode='markers', marker=dict( symbol='circle', color=contrast_color_schema['blue'], size=7, line=dict( width=1, color=adjust_lightness(contrast_color_schema['blue']) ) ), name=name, showlegend=name is not None ) scatter.update(**trace_kwargs) fig.add_trace(scatter, row=row, col=col) return fig
def plot_cum_returns(self, benchmark_rets=None, start_value=1, fill_to_benchmark=False, main_kwargs=None, benchmark_kwargs=None, hline_shape_kwargs=None, row=None, col=None, xref='x', yref='y', fig=None, **layout_kwargs): # pragma: no cover """Plot cumulative returns. Args: benchmark_rets (array_like): Benchmark return to compare returns against. Will broadcast per element. start_value (float): The starting returns. fill_to_benchmark (bool): Whether to fill between main and benchmark, or between main and `start_value`. main_kwargs (dict): Keyword arguments passed to `vectorbt.generic.accessors.Generic_SRAccessor.plot` for main. benchmark_kwargs (dict): Keyword arguments passed to `vectorbt.generic.accessors.Generic_SRAccessor.plot` for benchmark. hline_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for `start_value` line. row (int): Row position. col (int): Column position. xref (str): X coordinate axis. yref (str): Y coordinate axis. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import pandas as pd >>> import numpy as np >>> np.random.seed(0) >>> rets = pd.Series(np.random.uniform(-0.05, 0.05, size=100)) >>> benchmark_rets = pd.Series(np.random.uniform(-0.05, 0.05, size=100)) >>> rets.vbt.returns.plot_cum_returns(benchmark_rets=benchmark_rets) ``` ![](/vectorbt/docs/img/plot_cum_returns.png) """ from vectorbt.settings import color_schema if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) x_domain = [0, 1] xaxis = 'xaxis' + xref[1:] if xaxis in fig.layout: if 'domain' in fig.layout[xaxis]: if fig.layout[xaxis]['domain'] is not None: x_domain = fig.layout[xaxis]['domain'] fill_to_benchmark = fill_to_benchmark and benchmark_rets is not None if benchmark_rets is not None: # Plot benchmark benchmark_rets = reshape_fns.broadcast_to(benchmark_rets, self._obj) if benchmark_kwargs is None: benchmark_kwargs = {} benchmark_kwargs = merge_dicts( dict(trace_kwargs=dict(line_color=color_schema['gray'], name='Benchmark')), benchmark_kwargs) benchmark_cumrets = benchmark_rets.vbt.returns.cumulative( start_value=start_value) benchmark_cumrets.vbt.plot(**benchmark_kwargs, row=row, col=col, fig=fig) else: benchmark_cumrets = None # Plot main if main_kwargs is None: main_kwargs = {} main_kwargs = merge_dicts( dict(trace_kwargs=dict(line_color=color_schema['purple'], ), other_trace_kwargs='hidden'), main_kwargs) cumrets = self.cumulative(start_value=start_value) if fill_to_benchmark: cumrets.vbt.plot_against(benchmark_cumrets, **main_kwargs, row=row, col=col, fig=fig) else: cumrets.vbt.plot_against(start_value, **main_kwargs, row=row, col=col, fig=fig) # Plot hline if hline_shape_kwargs is None: hline_shape_kwargs = {} fig.add_shape(**merge_dicts( dict(type='line', xref="paper", yref=yref, x0=x_domain[0], y0=start_value, x1=x_domain[1], y1=start_value, line=dict( color="gray", dash="dash", )), hline_shape_kwargs)) return fig
def plot(self, plot_type=go.Ohlc, display_volume=True, ohlc_kwargs=None, bar_kwargs=None, fig=None, **layout_kwargs): """Plot OHLCV data. Args: plot_type: Either `plotly.graph_objects.Ohlc` or `plotly.graph_objects.Candlestick`. display_volume (bool): If True, displays volume as bar chart. ohlc_kwargs (dict): Keyword arguments passed to `plot_type`. bar_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. Example: ```python-repl >>> import vectorbt as vbt >>> import yfinance as yf >>> yf.Ticker("BTC-USD").history(period="max").vbt.ohlcv.plot() ``` ![](/vectorbt/docs/img/ohlcv.png)""" column_names = defaults.ohlcv['column_names'] if self._column_names is None else self._column_names open = self._obj[column_names['open']] high = self._obj[column_names['high']] low = self._obj[column_names['low']] close = self._obj[column_names['close']] # Set up figure if fig is None: fig = CustomFigureWidget() fig.update_layout( showlegend=True, xaxis_rangeslider_visible=False, xaxis_showgrid=True, yaxis_showgrid=True, bargap=0 ) fig.update_layout(**layout_kwargs) if ohlc_kwargs is None: ohlc_kwargs = {} if bar_kwargs is None: bar_kwargs = {} ohlc = plot_type( x=self.index, open=open, high=high, low=low, close=close, name='OHLC', yaxis="y2", xaxis="x", increasing_line_color='#1b9e76', decreasing_line_color='#d95f02' ) ohlc.update(**ohlc_kwargs) fig.add_trace(ohlc) if display_volume: volume = self._obj[column_names['volume']] marker_colors = np.empty(volume.shape, dtype=np.object) marker_colors[(close.values - open.values) > 0] = '#1b9e76' marker_colors[(close.values - open.values) == 0] = 'lightgrey' marker_colors[(close.values - open.values) < 0] = '#d95f02' bar = go.Bar( x=self.index, y=volume, marker_color=marker_colors, marker_line_width=0, marker_opacity=0.7, name='Volume', yaxis="y", xaxis="x" ) bar.update(**bar_kwargs) fig.add_trace(bar) fig.update_layout( yaxis2=dict( domain=[0.33, 1] ), yaxis=dict( domain=[0, 0.33] ) ) return fig
def plot(self, column=None, plot_close=True, plot_zones=True, close_trace_kwargs=None, entry_trace_kwargs=None, exit_trace_kwargs=None, exit_profit_trace_kwargs=None, exit_loss_trace_kwargs=None, active_trace_kwargs=None, profit_shape_kwargs=None, loss_shape_kwargs=None, row=None, col=None, xref='x', yref='y', fig=None, **layout_kwargs): # pragma: no cover """Plot orders. Args: column (str): Name of the column to plot. plot_close (bool): Whether to plot `Trades.close`. plot_zones (bool): Whether to plot zones. Set to False if there are many trades within one position. close_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `Trades.close`. entry_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Entry" markers. exit_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Exit" markers. exit_profit_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Exit - Profit" markers. exit_loss_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Exit - Loss" markers. active_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Active" markers. profit_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for profit zones. loss_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for loss zones. row (int): Row position. col (int): Column position. xref (str): X coordinate axis. yref (str): Y coordinate axis. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> trades.plot() ``` ![](/vectorbt/docs/img/trades_plot.png)""" from vectorbt.settings import color_schema, contrast_color_schema self_col = self.select_series(column=column, group_by=False) if close_trace_kwargs is None: close_trace_kwargs = {} close_trace_kwargs = merge_dicts(dict( line_color=color_schema['blue'], name='Close' if self_col.wrapper.name is None else self_col.wrapper.name ), close_trace_kwargs) if entry_trace_kwargs is None: entry_trace_kwargs = {} if exit_trace_kwargs is None: exit_trace_kwargs = {} if exit_profit_trace_kwargs is None: exit_profit_trace_kwargs = {} if exit_loss_trace_kwargs is None: exit_loss_trace_kwargs = {} if active_trace_kwargs is None: active_trace_kwargs = {} if profit_shape_kwargs is None: profit_shape_kwargs = {} if loss_shape_kwargs is None: loss_shape_kwargs = {} if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) # Plot close if plot_close: fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, row=row, col=col, fig=fig) if len(self_col.values) > 0: # Extract information _id = self_col.values['id'] _id_str = 'Trade Id' if self.trade_type == TradeType.Trade else 'Position Id' size = self_col.values['size'] entry_idx = self_col.values['entry_idx'] entry_price = self_col.values['entry_price'] entry_fees = self_col.values['entry_fees'] exit_idx = self_col.values['exit_idx'] exit_price = self_col.values['exit_price'] exit_fees = self_col.values['exit_fees'] pnl = self_col.values['pnl'] ret = self_col.values['return'] direction_value_map = to_value_map(TradeDirection) direction = self_col.values['direction'] direction = np.vectorize(lambda x: str(direction_value_map[x]))(direction) status = self_col.values['status'] def get_duration_str(from_idx, to_idx): if isinstance(self_col.wrapper.index, DatetimeTypes): duration = self_col.wrapper.index[to_idx] - self_col.wrapper.index[from_idx] elif self_col.wrapper.freq is not None: duration = self_col.wrapper.to_time_units(to_idx - from_idx) else: duration = to_idx - from_idx return np.vectorize(str)(duration) duration = get_duration_str(entry_idx, exit_idx) if len(entry_idx) > 0: # Plot Entry markers entry_customdata = np.stack(( _id, size, entry_fees, direction, *((self_col.values['position_id'],) if self.trade_type == TradeType.Trade else ()) ), axis=1) entry_scatter = go.Scatter( x=self_col.wrapper.index[entry_idx], y=entry_price, mode='markers', marker=dict( symbol='square', color=contrast_color_schema['blue'], size=7, line=dict( width=1, color=adjust_lightness(contrast_color_schema['blue']) ) ), name='Entry', customdata=entry_customdata, hovertemplate=_id_str + ": %{customdata[0]}" "<br>Date: %{x}" "<br>Avg. Price: %{y}" "<br>Size: %{customdata[1]:.6f}" "<br>Fees: %{customdata[2]:.6f}" "<br>Direction: %{customdata[3]}" + ("<br>Position Id: %{customdata[4]}" if self.trade_type == TradeType.Trade else '') ) entry_scatter.update(**entry_trace_kwargs) fig.add_trace(entry_scatter, row=row, col=col) # Plot end markers def _plot_end_markers(mask, name, color, kwargs): if np.any(mask): customdata = np.stack(( _id[mask], duration[mask], size[mask], exit_fees[mask], pnl[mask], ret[mask], direction[mask], *((self_col.values['position_id'][mask],) if self.trade_type == TradeType.Trade else ()) ), axis=1) scatter = go.Scatter( x=self_col.wrapper.index[exit_idx[mask]], y=exit_price[mask], mode='markers', marker=dict( symbol='square', color=color, size=7, line=dict( width=1, color=adjust_lightness(color) ) ), name=name, customdata=customdata, hovertemplate=_id_str + ": %{customdata[0]}" "<br>Date: %{x}" "<br>Duration: %{customdata[1]}" "<br>Avg. Price: %{y}" "<br>Size: %{customdata[2]:.6f}" "<br>Fees: %{customdata[3]:.6f}" "<br>PnL: %{customdata[4]:.6f}" "<br>Return: %{customdata[5]:.2%}" "<br>Direction: %{customdata[6]}" + ("<br>Position Id: %{customdata[7]}" if self.trade_type == TradeType.Trade else '') ) scatter.update(**kwargs) fig.add_trace(scatter, row=row, col=col) # Plot Exit markers _plot_end_markers( (status == TradeStatus.Closed) & (pnl == 0.), 'Exit', contrast_color_schema['gray'], exit_trace_kwargs ) # Plot Exit - Profit markers _plot_end_markers( (status == TradeStatus.Closed) & (pnl > 0.), 'Exit - Profit', contrast_color_schema['green'], exit_profit_trace_kwargs ) # Plot Exit - Loss markers _plot_end_markers( (status == TradeStatus.Closed) & (pnl < 0.), 'Exit - Loss', contrast_color_schema['red'], exit_loss_trace_kwargs ) # Plot Active markers _plot_end_markers( status == TradeStatus.Open, 'Active', contrast_color_schema['orange'], active_trace_kwargs ) if plot_zones: profit_mask = pnl > 0. if np.any(profit_mask): # Plot profit zones for i in np.flatnonzero(profit_mask): fig.add_shape(**merge_dicts(dict( type="rect", xref=xref, yref=yref, x0=self_col.wrapper.index[entry_idx[i]], y0=entry_price[i], x1=self_col.wrapper.index[exit_idx[i]], y1=exit_price[i], fillcolor='green', opacity=0.2, layer="below", line_width=0, ), profit_shape_kwargs)) loss_mask = pnl < 0. if np.any(loss_mask): # Plot loss zones for i in np.flatnonzero(loss_mask): fig.add_shape(**merge_dicts(dict( type="rect", xref=xref, yref=yref, x0=self_col.wrapper.index[entry_idx[i]], y0=entry_price[i], x1=self_col.wrapper.index[exit_idx[i]], y1=exit_price[i], fillcolor='red', opacity=0.2, layer="below", line_width=0, ), loss_shape_kwargs)) return fig
def plot(self, column=None, levels=(30, 70), percent_k_trace_kwargs=None, percent_d_trace_kwargs=None, shape_kwargs=None, row=None, col=None, xref='x', yref='y', fig=None, **layout_kwargs): # pragma: no cover """Plot `STOCH.percent_k` and `STOCH.percent_d`. Args: column (str): Name of the column to plot. levels (tuple): Two extremes: bottom and top. percent_k_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `STOCH.percent_k`. percent_d_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `STOCH.percent_d`. shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for zone between levels. row (int): Row position. col (int): Column position. xref (str): X coordinate axis. yref (str): Y coordinate axis. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.STOCH.run(price['High'], price['Low'], price['Close']).plot() ``` ![](/vectorbt/docs/img/STOCH.png) """ self_col = self.select_series(column=column) if fig is None: fig = CustomFigureWidget() default_layout = dict() default_layout['yaxis' + yref[1:]] = dict(range=[-5, 105]) fig.update_layout(**default_layout) fig.update_layout(**layout_kwargs) if percent_k_trace_kwargs is None: percent_k_trace_kwargs = {} if percent_d_trace_kwargs is None: percent_d_trace_kwargs = {} if shape_kwargs is None: shape_kwargs = {} percent_k_trace_kwargs = merge_dicts(dict(name='%K'), percent_k_trace_kwargs) percent_d_trace_kwargs = merge_dicts(dict(name='%D'), percent_d_trace_kwargs) fig = self_col.percent_k.vbt.plot(trace_kwargs=percent_k_trace_kwargs, row=row, col=col, fig=fig) fig = self_col.percent_d.vbt.plot(trace_kwargs=percent_d_trace_kwargs, row=row, col=col, fig=fig) # Plot levels # Fill void between levels shape_kwargs = merge_dicts( dict( type="rect", xref=xref, yref=yref, x0=self_col.percent_k.index[0], y0=levels[0], x1=self_col.percent_k.index[-1], y1=levels[1], fillcolor="purple", opacity=0.2, layer="below", line_width=0, ), shape_kwargs) fig.add_shape(**shape_kwargs) return fig
def create_heatmap(data=None, x_labels=None, y_labels=None, horizontal=False, trace_kwargs=None, return_trace_idx=False, row=None, col=None, fig=None, **layout_kwargs): """Create a heatmap plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be of shape (`y_labels`, `x_labels`). x_labels (array_like): X-axis labels, corresponding to columns in pandas. y_labels (array_like): Y-axis labels, corresponding to index in pandas. horizontal (bool): Plot horizontally. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Heatmap`. return_trace_idx (bool): Whether to return trace index for `update_heatmap_data`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> vbt.plotting.create_heatmap( ... data=[[1, 2], [3, 4]], ... x_labels=['a', 'b'], ... y_labels=['x', 'y'] ... ) ``` ![](/vectorbt/docs/img/create_heatmap.png) """ from vectorbt.settings import layout if trace_kwargs is None: trace_kwargs = {} if data is None: if x_labels is None or y_labels is None: raise ValueError("At least x_labels and y_labels must be passed") else: data = reshape_fns.to_2d(np.array(data)) if horizontal: y_labels, y_labels = y_labels, x_labels if data is not None: data = data.transpose() horizontal = False if fig is None: fig = CustomFigureWidget() if 'width' in layout: # Calculate nice width and height max_width = layout['width'] if data is not None: x_len = data.shape[1] y_len = data.shape[0] else: x_len = len(x_labels) y_len = len(y_labels) width = math.ceil( renormalize(x_len / (x_len + y_len), [0, 1], [0.3 * max_width, max_width])) width = min(width + 150, max_width) # account for colorbar height = math.ceil( renormalize(y_len / (x_len + y_len), [0, 1], [0.3 * max_width, max_width])) height = min(height, max_width * 0.7) # limit height fig.update_layout(width=width, height=height) fig.update_layout(**layout_kwargs) heatmap = go.Heatmap(hoverongaps=False, colorscale='Plasma', x=x_labels, y=y_labels) heatmap.update(**trace_kwargs) fig.add_trace(heatmap, row=row, col=col) trace_idx = len(fig.data) - 1 if data is not None: update_heatmap_data(fig, data, horizontal=horizontal, trace_idx=trace_idx) if return_trace_idx: return fig, trace_idx return fig
def plot(self, column=None, plot_close=True, close_trace_kwargs=None, buy_trace_kwargs=None, sell_trace_kwargs=None, row=None, col=None, fig=None, **layout_kwargs): # pragma: no cover """Plot orders. Args: column (str): Name of the column to plot. plot_close (bool): Whether to plot `Orders.close`. close_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `Orders.close`. buy_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Buy" markers. sell_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Sell" markers. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> orders.plot() ``` ![](/vectorbt/docs/img/orders_plot.png)""" from vectorbt.settings import color_schema, contrast_color_schema self_col = self.select_series(column=column, group_by=False) if close_trace_kwargs is None: close_trace_kwargs = {} close_trace_kwargs = merge_dicts(dict( line_color=color_schema['blue'], name='Close' if self_col.wrapper.name is None else self_col.wrapper.name ), close_trace_kwargs) if buy_trace_kwargs is None: buy_trace_kwargs = {} if sell_trace_kwargs is None: sell_trace_kwargs = {} if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) # Plot close if plot_close: fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, row=row, col=col, fig=fig) if len(self_col.values) > 0: # Extract information _id = self_col.values['id'] idx = self_col.values['idx'] size = self_col.values['size'] price = self_col.values['price'] fees = self_col.values['fees'] side = self_col.values['side'] # Plot Buy markers buy_mask = side == OrderSide.Buy buy_customdata = np.stack((_id[buy_mask], size[buy_mask], fees[buy_mask]), axis=1) buy_scatter = go.Scatter( x=self_col.wrapper.index[idx[buy_mask]], y=price[buy_mask], mode='markers', marker=dict( symbol='triangle-up', color=contrast_color_schema['green'], size=8, line=dict( width=1, color=adjust_lightness(contrast_color_schema['green']) ) ), name='Buy', customdata=buy_customdata, hovertemplate="Order Id: %{customdata[0]}" "<br>Date: %{x}" "<br>Price: %{y}" "<br>Size: %{customdata[1]:.6f}" "<br>Fees: %{customdata[2]:.6f}" ) buy_scatter.update(**buy_trace_kwargs) fig.add_trace(buy_scatter, row=row, col=col) # Plot Sell markers sell_mask = side == OrderSide.Sell sell_customdata = np.stack((_id[sell_mask], size[sell_mask], fees[sell_mask]), axis=1) sell_scatter = go.Scatter( x=self_col.wrapper.index[idx[sell_mask]], y=price[sell_mask], mode='markers', marker=dict( symbol='triangle-down', color=contrast_color_schema['red'], size=8, line=dict( width=1, color=adjust_lightness(contrast_color_schema['red']) ) ), name='Sell', customdata=sell_customdata, hovertemplate="Order Id: %{customdata[0]}" "<br>Date: %{x}" "<br>Price: %{y}" "<br>Size: %{customdata[1]:.6f}" "<br>Fees: %{customdata[2]:.6f}" ) sell_scatter.update(**sell_trace_kwargs) fig.add_trace(sell_scatter, row=row, col=col) return fig
def create_volume(data=None, x_labels=None, y_labels=None, z_labels=False, trace_kwargs={}, fig=None, **layout_kwargs): """Create a volume plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be a 3-dim array. x_labels (array_like): X-axis labels. y_labels (array_like): Y-axis labels. z_labels (array_like): Z-axis labels. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Volume`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. !!! note Figure widgets have currently problems displaying NaNs. Use `.show()` method for rendering. Example: ```py import vectorbt as vbt import numpy as np vbt.plotting.create_volume( data=np.random.randint(1, 10, size=(3, 3, 3)), x_labels=['a', 'b', 'c'], y_labels=['d', 'e', 'f'], z_labels=['g', 'h', 'i'] ) ``` ![](/vectorbt/docs/img/create_volume.png) """ if data is None: raise ValueError("Data must be passed") data = np.asarray(data) checks.assert_ndim(data, 3) if x_labels is None: x_labels = np.arange(data.shape[0]) if y_labels is None: y_labels = np.arange(data.shape[1]) if z_labels is None: z_labels = np.arange(data.shape[2]) x_labels = np.asarray(x_labels) y_labels = np.asarray(y_labels) z_labels = np.asarray(z_labels) if fig is None: fig = CustomFigureWidget() fig.update_layout( width=700, height=450 ) # Non-numeric data types are not supported by go.Volume, so use ticktext # Note: Currently plotly displays the entire tick array, in future versions it will be more sensible if not np.issubdtype(x_labels.dtype, np.number): x_ticktext = x_labels x_labels = np.arange(data.shape[0]) fig.update_layout(scene=dict(xaxis=dict(ticktext=x_ticktext, tickvals=x_labels, tickmode='array'))) if not np.issubdtype(y_labels.dtype, np.number): y_ticktext = y_labels y_labels = np.arange(data.shape[1]) fig.update_layout(scene=dict(yaxis=dict(ticktext=y_ticktext, tickvals=y_labels, tickmode='array'))) if not np.issubdtype(z_labels.dtype, np.number): z_ticktext = z_labels z_labels = np.arange(data.shape[2]) fig.update_layout(scene=dict(zaxis=dict(ticktext=z_ticktext, tickvals=z_labels, tickmode='array'))) # Arrays must have the same length as the flattened data array x = np.repeat(x_labels, len(y_labels) * len(z_labels)) y = np.tile(np.repeat(y_labels, len(z_labels)), len(x_labels)) z = np.tile(z_labels, len(x_labels) * len(y_labels)) fig.update_layout(**layout_kwargs) volume = go.Volume( x=x, y=y, z=z, value=data.flatten(), opacity=0.15, surface_count=15, # keep low for big data colorscale='Plasma' ) volume.update(**trace_kwargs) fig.add_trace(volume) return fig
def create_scatter(data=None, trace_names=None, x_labels=None, trace_kwargs=None, return_trace_idxs=False, row=None, col=None, fig=None, **layout_kwargs): """Create a scatter plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be of shape (`x_labels`, `trace_names`). trace_names (str or list of str): Trace names, corresponding to columns in pandas. x_labels (array_like): X-axis labels, corresponding to index in pandas. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. return_trace_idxs (bool): Whether to return trace indices for `update_scatter_data`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> vbt.plotting.create_scatter( ... data=[[1, 2], [3, 4]], ... trace_names=['a', 'b'], ... x_labels=['x', 'y'] ... ) ``` ![](/vectorbt/docs/img/create_scatter.png) """ if trace_kwargs is None: trace_kwargs = {} if data is None: if trace_names is None: raise ValueError("At least trace_names must be passed") if trace_names is None: data = reshape_fns.to_2d(data) trace_names = [None] * data.shape[1] if isinstance(trace_names, str): trace_names = [trace_names] if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): if trace_name is not None: trace_name = str(trace_name) scatter = go.Scatter(x=x_labels, name=trace_name, showlegend=trace_name is not None) scatter.update( **(trace_kwargs[i] if isinstance(trace_kwargs, ( list, tuple)) else trace_kwargs)) fig.add_trace(scatter, row=row, col=col) trace_idxs = list(range(len(fig.data) - len(trace_names), len(fig.data))) if data is not None: update_scatter_data(fig, data, trace_idx=trace_idxs) if return_trace_idxs: return fig, trace_idxs return fig
def plot(self, column=None, top_n=5, plot_ts=True, plot_zones=True, ts_trace_kwargs=None, peak_trace_kwargs=None, valley_trace_kwargs=None, recovery_trace_kwargs=None, active_trace_kwargs=None, ptv_shape_kwargs=None, vtr_shape_kwargs=None, active_shape_kwargs=None, row=None, col=None, xref='x', yref='y', fig=None, **layout_kwargs): # pragma: no cover """Plot drawdowns over `Drawdowns.ts`. Args: column (str): Name of the column to plot. top_n (int): Filter top N drawdown records by maximum drawdown. plot_ts (bool): Whether to plot time series. plot_zones (bool): Whether to plot zones. ts_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for time series. peak_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for peak values. valley_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for valley values. recovery_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for recovery values. active_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for active recovery values. ptv_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for PtV zones. vtr_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for VtR zones. active_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for active VtR zones. row (int): Row position. col (int): Column position. xref (str): X coordinate axis. yref (str): Y coordinate axis. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> import pandas as pd >>> ts = pd.Series([1, 2, 1, 2, 3, 2, 1, 2]) >>> vbt.Drawdowns.from_ts(ts, freq='1 days').plot() ``` ![](/vectorbt/docs/img/drawdowns_plot.png) """ from vectorbt.settings import color_schema, contrast_color_schema self_col = self.select_series(column=column, group_by=False) if top_n is not None: # Drawdowns is negative, thus top_n becomes bottom_n self_col = self_col.filter_by_mask( self_col.drawdown.bottom_n_mask(top_n)) if ts_trace_kwargs is None: ts_trace_kwargs = {} ts_trace_kwargs = merge_dicts(dict(line_color=color_schema['blue']), ts_trace_kwargs) if peak_trace_kwargs is None: peak_trace_kwargs = {} if valley_trace_kwargs is None: valley_trace_kwargs = {} if recovery_trace_kwargs is None: recovery_trace_kwargs = {} if active_trace_kwargs is None: active_trace_kwargs = {} if ptv_shape_kwargs is None: ptv_shape_kwargs = {} if vtr_shape_kwargs is None: vtr_shape_kwargs = {} if active_shape_kwargs is None: active_shape_kwargs = {} if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) y_domain = [0, 1] yaxis = 'yaxis' + yref[1:] if yaxis in fig.layout: if 'domain' in fig.layout[yaxis]: if fig.layout[yaxis]['domain'] is not None: y_domain = fig.layout[yaxis]['domain'] if plot_ts: fig = self_col.ts.vbt.plot(trace_kwargs=ts_trace_kwargs, row=row, col=col, fig=fig) if len(self_col.values) > 0: # Extract information _id = self_col.values['id'] start_idx = self_col.values['start_idx'] valley_idx = self_col.values['valley_idx'] end_idx = self_col.values['end_idx'] status = self_col.values['status'] start_val = self_col.ts.values[start_idx] valley_val = self_col.ts.values[valley_idx] end_val = self_col.ts.values[end_idx] def get_duration_str(from_idx, to_idx): if isinstance(self_col.wrapper.index, DatetimeTypes): duration = self_col.wrapper.index[ to_idx] - self_col.wrapper.index[from_idx] elif self_col.wrapper.freq is not None: duration = self_col.wrapper.to_time_units(to_idx - from_idx) else: duration = to_idx - from_idx return np.vectorize(str)(duration) # Plot peak markers peak_mask = start_idx != np.roll( end_idx, 1) # peak and recovery at same time -> recovery wins if np.any(peak_mask): peak_customdata = _id[peak_mask][:, None] peak_scatter = go.Scatter( x=self_col.ts.index[start_idx[peak_mask]], y=start_val[peak_mask], mode='markers', marker=dict(symbol='diamond', color=contrast_color_schema['blue'], size=7, line=dict(width=1, color=adjust_lightness( contrast_color_schema['blue']))), name='Peak', customdata=peak_customdata, hovertemplate="Drawdown Id: %{customdata[0]}" "<br>Date: %{x}" "<br>Price: %{y}") peak_scatter.update(**peak_trace_kwargs) fig.add_trace(peak_scatter, row=row, col=col) recovery_mask = status == DrawdownStatus.Recovered if np.any(recovery_mask): # Plot valley markers valley_drawdown = ( valley_val[recovery_mask] - start_val[recovery_mask]) / start_val[recovery_mask] valley_duration = get_duration_str(start_idx[recovery_mask], valley_idx[recovery_mask]) valley_customdata = np.stack( (_id[recovery_mask], valley_drawdown, valley_duration), axis=1) valley_scatter = go.Scatter( x=self_col.ts.index[valley_idx[recovery_mask]], y=valley_val[recovery_mask], mode='markers', marker=dict(symbol='diamond', color=contrast_color_schema['red'], size=7, line=dict(width=1, color=adjust_lightness( contrast_color_schema['red']))), name='Valley', customdata=valley_customdata, hovertemplate="Drawdown Id: %{customdata[0]}" "<br>Date: %{x}" "<br>Price: %{y}" "<br>Drawdown: %{customdata[1]:.2%}" "<br>Duration: %{customdata[2]}") valley_scatter.update(**valley_trace_kwargs) fig.add_trace(valley_scatter, row=row, col=col) if plot_zones: # Plot drawdown zones for i in np.flatnonzero(recovery_mask): fig.add_shape(**merge_dicts( dict( type="rect", xref=xref, yref="paper", x0=self_col.ts.index[start_idx[i]], y0=y_domain[0], x1=self_col.ts.index[valley_idx[i]], y1=y_domain[1], fillcolor='red', opacity=0.2, layer="below", line_width=0, ), ptv_shape_kwargs)) # Plot recovery markers recovery_return = ( end_val[recovery_mask] - valley_val[recovery_mask]) / valley_val[recovery_mask] recovery_duration = get_duration_str(valley_idx[recovery_mask], end_idx[recovery_mask]) recovery_customdata = np.stack( (_id[recovery_mask], recovery_return, recovery_duration), axis=1) recovery_scatter = go.Scatter( x=self_col.ts.index[end_idx[recovery_mask]], y=end_val[recovery_mask], mode='markers', marker=dict(symbol='diamond', color=contrast_color_schema['green'], size=7, line=dict( width=1, color=adjust_lightness( contrast_color_schema['green']))), name='Recovery/Peak', customdata=recovery_customdata, hovertemplate="Drawdown Id: %{customdata[0]}" "<br>Date: %{x}" "<br>Price: %{y}" "<br>Return: %{customdata[1]:.2%}" "<br>Duration: %{customdata[2]}") recovery_scatter.update(**recovery_trace_kwargs) fig.add_trace(recovery_scatter, row=row, col=col) if plot_zones: # Plot recovery zones for i in np.flatnonzero(recovery_mask): fig.add_shape(**merge_dicts( dict( type="rect", xref=xref, yref="paper", x0=self_col.ts.index[valley_idx[i]], y0=y_domain[0], x1=self_col.ts.index[end_idx[i]], y1=y_domain[1], fillcolor='green', opacity=0.2, layer="below", line_width=0, ), vtr_shape_kwargs)) # Plot active markers active_mask = ~recovery_mask if np.any(active_mask): active_drawdown = ( valley_val[active_mask] - start_val[active_mask]) / start_val[active_mask] active_duration = get_duration_str(valley_idx[active_mask], end_idx[active_mask]) active_customdata = np.stack( (_id[active_mask], active_drawdown, active_duration), axis=1) active_scatter = go.Scatter( x=self_col.ts.index[end_idx[active_mask]], y=end_val[active_mask], mode='markers', marker=dict(symbol='diamond', color=contrast_color_schema['orange'], size=7, line=dict( width=1, color=adjust_lightness( contrast_color_schema['orange']))), name='Active', customdata=active_customdata, hovertemplate="Drawdown Id: %{customdata[0]}" "<br>Date: %{x}" "<br>Price: %{y}" "<br>Drawdown: %{customdata[1]:.2%}" "<br>Duration: %{customdata[2]}") active_scatter.update(**active_trace_kwargs) fig.add_trace(active_scatter, row=row, col=col) if plot_zones: # Plot active drawdown zones for i in np.flatnonzero(active_mask): fig.add_shape(**merge_dicts( dict( type="rect", xref=xref, yref="paper", x0=self_col.ts.index[start_idx[i]], y0=y_domain[0], x1=self_col.ts.index[end_idx[i]], y1=y_domain[1], fillcolor='orange', opacity=0.2, layer="below", line_width=0, ), active_shape_kwargs)) return fig
def plot(self, column=None, plot_close=True, close_trace_kwargs=None, middle_trace_kwargs=None, upper_trace_kwargs=None, lower_trace_kwargs=None, row=None, col=None, fig=None, **layout_kwargs): # pragma: no cover """Plot `BBANDS.middle`, `BBANDS.upper` and `BBANDS.lower` against `BBANDS.close`. Args: column (str): Name of the column to plot. plot_close (bool): Whether to plot `MA.close`. close_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `BBANDS.close`. middle_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `BBANDS.middle`. upper_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `BBANDS.upper`. lower_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `BBANDS.lower`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.BBANDS.run(price['Close']).plot() ``` ![](/vectorbt/docs/img/BBANDS.png) """ from vectorbt.settings import color_schema self_col = self.select_series(column=column) if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) if close_trace_kwargs is None: close_trace_kwargs = {} if middle_trace_kwargs is None: middle_trace_kwargs = {} if upper_trace_kwargs is None: upper_trace_kwargs = {} if lower_trace_kwargs is None: lower_trace_kwargs = {} lower_trace_kwargs = merge_dicts( dict( name='Lower Band', line_color=color_schema['gray'], ), lower_trace_kwargs) upper_trace_kwargs = merge_dicts( dict(name='Upper Band', line_color=color_schema['gray'], fill='tonexty', fillcolor='rgba(128, 128, 128, 0.2)'), upper_trace_kwargs) # default kwargs middle_trace_kwargs = merge_dicts(dict(name='Middle Band'), middle_trace_kwargs) close_trace_kwargs = merge_dicts( dict(name='Close', line=dict(color=color_schema['blue'])), close_trace_kwargs) fig = self_col.lower.vbt.plot(trace_kwargs=lower_trace_kwargs, row=row, col=col, fig=fig) fig = self_col.upper.vbt.plot(trace_kwargs=upper_trace_kwargs, row=row, col=col, fig=fig) fig = self_col.middle.vbt.plot(trace_kwargs=middle_trace_kwargs, row=row, col=col, fig=fig) if plot_close: fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, row=row, col=col, fig=fig) return fig
def create_volume(data=None, x_labels=None, y_labels=None, z_labels=False, trace_kwargs=None, return_trace_idx=False, row=None, col=None, scene_name='scene', fig=None, **layout_kwargs): """Create a volume plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be a 3-dim array. x_labels (array_like): X-axis labels. y_labels (array_like): Y-axis labels. z_labels (array_like): Z-axis labels. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Volume`. return_trace_idx (bool): Whether to return trace index for `update_volume_data`. row (int): Row position. col (int): Column position. scene_name (str): Reference to the 3D scene. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. !!! note Figure widgets have currently problems displaying NaNs. Use `.show()` method for rendering. ## Example ```python-repl >>> import vectorbt as vbt >>> import numpy as np >>> vbt.plotting.create_volume( ... data=np.random.randint(1, 10, size=(3, 3, 3)), ... x_labels=['a', 'b', 'c'], ... y_labels=['d', 'e', 'f'], ... z_labels=['g', 'h', 'i'] ... ) ``` ![](/vectorbt/docs/img/create_volume.png) """ from vectorbt.settings import layout if trace_kwargs is None: trace_kwargs = {} if data is None: raise ValueError("Data must be passed") data = np.asarray(data) checks.assert_ndim(data, 3) if x_labels is None: x_labels = np.arange(data.shape[0]) if y_labels is None: y_labels = np.arange(data.shape[1]) if z_labels is None: z_labels = np.arange(data.shape[2]) x_labels = np.asarray(x_labels) y_labels = np.asarray(y_labels) z_labels = np.asarray(z_labels) if fig is None: fig = CustomFigureWidget() if 'width' in layout: # Calculate nice width and height fig.update_layout(width=layout['width'], height=0.7 * layout['width']) # Non-numeric data types are not supported by go.Volume, so use ticktext # Note: Currently plotly displays the entire tick array, in future versions it will be more sensible more_layout = dict() if not np.issubdtype(x_labels.dtype, np.number): x_ticktext = x_labels x_labels = np.arange(data.shape[0]) more_layout[scene_name] = dict(xaxis=dict( ticktext=x_ticktext, tickvals=x_labels, tickmode='array')) if not np.issubdtype(y_labels.dtype, np.number): y_ticktext = y_labels y_labels = np.arange(data.shape[1]) more_layout[scene_name] = dict(yaxis=dict( ticktext=y_ticktext, tickvals=y_labels, tickmode='array')) if not np.issubdtype(z_labels.dtype, np.number): z_ticktext = z_labels z_labels = np.arange(data.shape[2]) more_layout[scene_name] = dict(zaxis=dict( ticktext=z_ticktext, tickvals=z_labels, tickmode='array')) fig.update_layout(**more_layout) fig.update_layout(**layout_kwargs) # Arrays must have the same length as the flattened data array x = np.repeat(x_labels, len(y_labels) * len(z_labels)) y = np.tile(np.repeat(y_labels, len(z_labels)), len(x_labels)) z = np.tile(z_labels, len(x_labels) * len(y_labels)) volume = go.Volume( x=x, y=y, z=z, value=data.flatten(), opacity=0.2, surface_count=15, # keep low for big data colorscale='Plasma') volume.update(**trace_kwargs) fig.add_trace(volume, row=row, col=col) trace_idx = len(fig.data) - 1 if return_trace_idx: return fig, trace_idx return fig
def plot(self, plot_type='OHLC', display_volume=True, ohlc_kwargs=None, bar_kwargs=None, fig=None, **layout_kwargs): """Plot OHLCV data. Args: plot_type: Either 'OHLC' or 'Candlestick'. display_volume (bool): If True, displays volume as bar chart. ohlc_kwargs (dict): Keyword arguments passed to `plot_type`. bar_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> import yfinance as yf >>> yf.Ticker("BTC-USD").history(period="max").vbt.ohlcv.plot() ``` ![](/vectorbt/docs/img/ohlcv.png) """ from vectorbt.settings import ohlcv, color_schema column_names = ohlcv[ 'column_names'] if self._column_names is None else self._column_names open = self._obj[column_names['open']] high = self._obj[column_names['high']] low = self._obj[column_names['low']] close = self._obj[column_names['close']] # Set up figure if fig is None: fig = CustomFigureWidget() fig.update_layout(showlegend=True, xaxis=dict(rangeslider_visible=False, showgrid=True), yaxis=dict(showgrid=True), bargap=0) fig.update_layout(**layout_kwargs) if ohlc_kwargs is None: ohlc_kwargs = {} if bar_kwargs is None: bar_kwargs = {} if plot_type.lower() == 'ohlc': plot_type = 'OHLC' plot_obj = go.Ohlc elif plot_type.lower() == 'candlestick': plot_type = 'Candlestick' plot_obj = go.Candlestick else: raise ValueError("Plot type can be either 'OHLC' or 'Candlestick'") ohlc = plot_obj(x=self.wrapper.index, open=open, high=high, low=low, close=close, name=plot_type, yaxis="y2", xaxis="x", increasing_line_color=color_schema['increasing'], decreasing_line_color=color_schema['decreasing']) ohlc.update(**ohlc_kwargs) fig.add_trace(ohlc) if display_volume: volume = self._obj[column_names['volume']] marker_colors = np.empty(volume.shape, dtype=np.object) marker_colors[(close.values - open.values) > 0] = color_schema['increasing'] marker_colors[(close.values - open.values) == 0] = color_schema['gray'] marker_colors[(close.values - open.values) < 0] = color_schema['decreasing'] bar = go.Bar(x=self.wrapper.index, y=volume, marker=dict(color=marker_colors, line_width=0), opacity=0.5, name='Volume', yaxis="y", xaxis="x") bar.update(**bar_kwargs) fig.add_trace(bar) fig.update_layout(yaxis2=dict(domain=[0.33, 1]), yaxis=dict(domain=[0, 0.33])) return fig
def plot_pnl(self, column=None, marker_size_range=[7, 14], opacity_range=[0.75, 0.9], closed_profit_trace_kwargs=None, closed_loss_trace_kwargs=None, open_trace_kwargs=None, hline_shape_kwargs=None, row=None, col=None, xref='x', yref='y', fig=None, **layout_kwargs): # pragma: no cover """Plot trade PnL. Args: column (str): Name of the column to plot. closed_profit_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Closed - Profit" markers. closed_loss_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Closed - Loss" markers. open_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Open" markers. hline_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for zeroline. row (int): Row position. col (int): Column position. xref (str): X coordinate axis. yref (str): Y coordinate axis. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> trades.plot_pnl() ``` ![](/vectorbt/docs/img/trades_plot_pnl.png) """ from vectorbt.settings import contrast_color_schema self_col = self.select_series(column=column, group_by=False) if closed_profit_trace_kwargs is None: closed_profit_trace_kwargs = {} if closed_loss_trace_kwargs is None: closed_loss_trace_kwargs = {} if open_trace_kwargs is None: open_trace_kwargs = {} if hline_shape_kwargs is None: hline_shape_kwargs = {} marker_size_range = tuple(marker_size_range) if fig is None: fig = CustomFigureWidget() fig.update_layout(**layout_kwargs) x_domain = [0, 1] xaxis = 'xaxis' + xref[1:] if xaxis in fig.layout: if 'domain' in fig.layout[xaxis]: if fig.layout[xaxis]['domain'] is not None: x_domain = fig.layout[xaxis]['domain'] if len(self_col.values) > 0: # Extract information _id = self.values['id'] _id_str = 'Trade Id' if self.trade_type == TradeType.Trade else 'Position Id' exit_idx = self.values['exit_idx'] pnl = self.values['pnl'] returns = self.values['return'] status = self.values['status'] neutral_mask = pnl == 0 profit_mask = pnl > 0 loss_mask = pnl < 0 marker_size = min_rel_rescale(np.abs(returns), marker_size_range) opacity = max_rel_rescale(np.abs(returns), opacity_range) open_mask = status == TradeStatus.Open closed_profit_mask = (~open_mask) & profit_mask closed_loss_mask = (~open_mask) & loss_mask open_mask &= ~neutral_mask if np.any(closed_profit_mask): # Plot Profit markers profit_scatter = go.Scatter( x=self_col.wrapper.index[exit_idx[closed_profit_mask]], y=pnl[closed_profit_mask], mode='markers', marker=dict( symbol='circle', color=contrast_color_schema['green'], size=marker_size[closed_profit_mask], opacity=opacity[closed_profit_mask], line=dict( width=1, color=adjust_lightness(contrast_color_schema['green']) ), ), name='Closed - Profit', customdata=np.stack((_id[closed_profit_mask], returns[closed_profit_mask]), axis=1), hovertemplate=_id_str + ": %{customdata[0]}" "<br>Date: %{x}" "<br>PnL: %{y}" "<br>Return: %{customdata[1]:.2%}" ) profit_scatter.update(**closed_profit_trace_kwargs) fig.add_trace(profit_scatter, row=row, col=col) if np.any(closed_loss_mask): # Plot Loss markers loss_scatter = go.Scatter( x=self_col.wrapper.index[exit_idx[closed_loss_mask]], y=pnl[closed_loss_mask], mode='markers', marker=dict( symbol='circle', color=contrast_color_schema['red'], size=marker_size[closed_loss_mask], opacity=opacity[closed_loss_mask], line=dict( width=1, color=adjust_lightness(contrast_color_schema['red']) ) ), name='Closed - Loss', customdata=np.stack((_id[closed_loss_mask], returns[closed_loss_mask]), axis=1), hovertemplate=_id_str + ": %{customdata[0]}" "<br>Date: %{x}" "<br>PnL: %{y}" "<br>Return: %{customdata[1]:.2%}" ) loss_scatter.update(**closed_loss_trace_kwargs) fig.add_trace(loss_scatter, row=row, col=col) if np.any(open_mask): # Plot Active markers active_scatter = go.Scatter( x=self_col.wrapper.index[exit_idx[open_mask]], y=pnl[open_mask], mode='markers', marker=dict( symbol='circle', color=contrast_color_schema['orange'], size=marker_size[open_mask], opacity=opacity[open_mask], line=dict( width=1, color=adjust_lightness(contrast_color_schema['orange']) ) ), name='Open', customdata=np.stack((_id[open_mask], returns[open_mask]), axis=1), hovertemplate=_id_str + ": %{customdata[0]}" "<br>Date: %{x}" "<br>PnL: %{y}" "<br>Return: %{customdata[1]:.2%}" ) active_scatter.update(**open_trace_kwargs) fig.add_trace(active_scatter, row=row, col=col) # Plot zeroline fig.add_shape(**merge_dicts(dict( type='line', xref="paper", yref=yref, x0=x_domain[0], y0=0, x1=x_domain[1], y1=0, line=dict( color="gray", dash="dash", ) ), hline_shape_kwargs)) return fig
def create_indicator(value=None, label=None, value_range=None, cmap_name='Spectral', trace_kwargs=None, return_trace_idx=False, row=None, col=None, fig=None, **layout_kwargs): """Create an indicator plot. Args: value (int or float): The value to be displayed. label (str): The label to be displayed. value_range (list or tuple of 2 values): The value range of the gauge. cmap_name (str): A matplotlib-compatible colormap name. See the [list of available colormaps](https://matplotlib.org/tutorials/colors/colormaps.html). trace_kwargs (dict): Keyword arguments passed to the `plotly.graph_objects.Indicator`. return_trace_idx (bool): Whether to return trace index for `update_indicator_data`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> vbt.plotting.create_indicator( ... value=2, ... value_range=(1, 3), ... label='My Indicator' ... ) ``` ![](/vectorbt/docs/img/create_indicator.png) """ from vectorbt.settings import layout if trace_kwargs is None: trace_kwargs = {} if fig is None: fig = CustomFigureWidget() if 'width' in layout: # Calculate nice width and height fig.update_layout(width=layout['width'] * 0.7, height=layout['width'] * 0.5, margin=dict(t=80)) fig.update_layout(**layout_kwargs) indicator = go.Indicator(domain=dict(x=[0, 1], y=[0, 1]), mode="gauge+number+delta", title=dict(text=label)) indicator.update(**trace_kwargs) fig.add_trace(indicator, row=row, col=col) trace_idx = len(fig.data) - 1 if value is not None: update_indicator_data(fig, value, value_range=value_range, cmap_name=cmap_name, trace_idx=trace_idx) if return_trace_idx: return fig, trace_idx return fig
def plot(self, column=None, macd_trace_kwargs=None, signal_trace_kwargs=None, hist_trace_kwargs=None, row=None, col=None, fig=None, **layout_kwargs): # pragma: no cover """Plot `MACD.macd`, `MACD.signal` and `MACD.hist`. Args: column (str): Name of the column to plot. macd_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MACD.macd`. signal_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MACD.signal`. hist_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar` for `MACD.hist`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.MACD.run(price['Close']).plot() ``` ![](/vectorbt/docs/img/MACD.png)""" self_col = self.select_series(column=column) if fig is None: fig = CustomFigureWidget() fig.update_layout(bargap=0) fig.update_layout(**layout_kwargs) if macd_trace_kwargs is None: macd_trace_kwargs = {} if signal_trace_kwargs is None: signal_trace_kwargs = {} if hist_trace_kwargs is None: hist_trace_kwargs = {} macd_trace_kwargs = merge_dicts(dict(name='MACD'), macd_trace_kwargs) signal_trace_kwargs = merge_dicts(dict(name='Signal'), signal_trace_kwargs) hist_trace_kwargs = merge_dicts(dict(name='Histogram'), hist_trace_kwargs) fig = self_col.macd.vbt.plot(trace_kwargs=macd_trace_kwargs, row=row, col=col, fig=fig) fig = self_col.signal.vbt.plot(trace_kwargs=signal_trace_kwargs, row=row, col=col, fig=fig) # Plot hist hist = self_col.hist.values hist_diff = generic_nb.diff_1d_nb(hist) marker_colors = np.full(hist.shape, 'silver', dtype=np.object) marker_colors[(hist > 0) & (hist_diff > 0)] = 'green' marker_colors[(hist > 0) & (hist_diff <= 0)] = 'lightgreen' marker_colors[(hist < 0) & (hist_diff < 0)] = 'red' marker_colors[(hist < 0) & (hist_diff >= 0)] = 'lightcoral' hist_bar = go.Bar(x=self_col.hist.index, y=self_col.hist.values, marker_color=marker_colors, marker_line_width=0) hist_bar.update(**hist_trace_kwargs) fig.add_trace(hist_bar, row=row, col=col) return fig
def plot(self, display_volume=True, candlestick_kwargs={}, bar_kwargs={}, fig=None, **layout_kwargs): """Plot OHLCV data. Args: display_volume (bool): If `True`, displays volume as bar chart. candlestick_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Candlestick`. bar_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. Example: ```py import vectorbt as vbt import yfinance as yf yf.Ticker("BTC-USD").history(period="max").vbt.ohlcv.plot() ``` ![](/vectorbt/docs/img/ohlcv.png)""" column_names = defaults.ohlcv[ 'column_names'] if self._column_names is None else self._column_names open = self._obj[column_names['open']] high = self._obj[column_names['high']] low = self._obj[column_names['low']] close = self._obj[column_names['close']] # Set up figure if fig is None: fig = CustomFigureWidget() candlestick = go.Candlestick(x=self.index, open=open, high=high, low=low, close=close, name='OHLC', yaxis="y2", xaxis="x") candlestick.update(**candlestick_kwargs) fig.add_trace(candlestick) if display_volume: volume = self._obj[column_names['volume']] marker_colors = np.empty(volume.shape, dtype=np.object) marker_colors[(close.values - open.values) > 0] = 'green' marker_colors[(close.values - open.values) == 0] = 'lightgrey' marker_colors[(close.values - open.values) < 0] = 'red' bar = go.Bar(x=self.index, y=volume, marker_color=marker_colors, marker_line_width=0, name='Volume', yaxis="y", xaxis="x") bar.update(**bar_kwargs) fig.add_trace(bar) fig.update_layout(yaxis2=dict(domain=[0.33, 1]), yaxis=dict(domain=[0, 0.33])) fig.update_layout(showlegend=True, xaxis_rangeslider_visible=False, xaxis_showgrid=True, yaxis_showgrid=True) fig.update_layout(**layout_kwargs) return fig
def create_box(data=None, trace_names=None, horizontal=False, remove_nan=True, trace_kwargs=None, return_trace_idxs=False, row=None, col=None, fig=None, **layout_kwargs): """Create a box plot. Args: data (array_like): Data in any format that can be converted to NumPy. Must be of shape (any, `trace_names`). trace_names (str or list of str): Trace names, corresponding to columns in pandas. horizontal (bool): Plot horizontally. remove_nan (bool): Whether to remove NaN values. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Box`. return_trace_idxs (bool): Whether to return trace indices for `update_box_data`. row (int): Row position. col (int): Column position. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> vbt.plotting.create_box( ... data=[[1, 2], [3, 4], [2, 1]], ... trace_names=['a', 'b'] ... ) ``` ![](/vectorbt/docs/img/create_box.png) """ if trace_kwargs is None: trace_kwargs = {} if data is None: if trace_names is None: raise ValueError("At least trace_names must be passed") if trace_names is None: data = reshape_fns.to_2d(data) trace_names = [None] * data.shape[1] if isinstance(trace_names, str): trace_names = [trace_names] if fig is None: fig = CustomFigureWidget() fig.update_layout(barmode='overlay') fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): if trace_name is not None: trace_name = str(trace_name) box = go.Box(name=trace_name, showlegend=trace_name is not None) box.update(**(trace_kwargs[i] if isinstance(trace_kwargs, ( list, tuple)) else trace_kwargs)) fig.add_trace(box, row=row, col=col) trace_idxs = list(range(len(fig.data) - len(trace_names), len(fig.data))) if data is not None: update_box_data(fig, data, horizontal=horizontal, trace_idx=trace_idxs, remove_nan=remove_nan) if return_trace_idxs: return fig, trace_idxs return fig