def plot(self, trace_kwargs=None, add_trace_kwargs=None, yref='y', fig=None, **layout_kwargs): # pragma: no cover """Plot Series as a line. Args: trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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 = {} if add_trace_kwargs is None: add_trace_kwargs = {} # Set up figure if fig is None: fig = FigureWidget() 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' 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, **add_trace_kwargs) return fig
def plot(self, column=None, plot_close=True, close_trace_kwargs=None, ma_trace_kwargs=None, add_trace_kwargs=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`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.MA.run(ohlcv['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 = FigureWidget() 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, add_trace_kwargs=add_trace_kwargs, fig=fig) fig = self_col.ma.vbt.plot(trace_kwargs=ma_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) return fig
def plot(self, plot_type=go.Ohlc, ohlc_kwargs=None, entry_trace_kwargs=None, exit_trace_kwargs=None, add_trace_kwargs=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 = FigureWidget() 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 = {} if add_trace_kwargs is None: add_trace_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, **add_trace_kwargs) # 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, add_trace_kwargs=add_trace_kwargs, fig=fig ) return fig
def plot(self, column=None, tr_trace_kwargs=None, atr_trace_kwargs=None, add_trace_kwargs=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`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.ATR.run(ohlcv['High'], ohlcv['Low'], ohlcv['Close'], 10).plot() ``` ![](/vectorbt/docs/img/ATR.png) """ self_col = self.select_series(column=column) if fig is None: fig = FigureWidget() 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, add_trace_kwargs=add_trace_kwargs, fig=fig) fig = self_col.atr.vbt.plot(trace_kwargs=atr_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) return fig
def plot(self, column=None, obv_trace_kwargs=None, add_trace_kwargs=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`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```py >>> vbt.OBV.run(ohlcv['Close'], ohlcv['Volume']).plot() ``` ![](/vectorbt/docs/img/OBV.png) """ self_col = self.select_series(column=column) if fig is None: fig = FigureWidget() 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, add_trace_kwargs=add_trace_kwargs, fig=fig) return fig
def plot(self, column=None, mstd_trace_kwargs=None, add_trace_kwargs=None, fig=None, **layout_kwargs): # pragma: no cover """Plot `MSTD.mstd`. Args: column (str): Name of the column to plot. mstd_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MSTD.mstd`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.MSTD.run(ohlcv['Close'], 10).plot() ``` ![](/vectorbt/docs/img/MSTD.png) """ self_col = self.select_series(column=column) if fig is None: fig = FigureWidget() fig.update_layout(**layout_kwargs) if mstd_trace_kwargs is None: mstd_trace_kwargs = {} mstd_trace_kwargs = merge_dicts(dict(name='MSTD'), mstd_trace_kwargs) fig = self_col.mstd.vbt.plot(trace_kwargs=mstd_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) return fig
def plot(self, column=None, plot_close=True, close_trace_kwargs=None, buy_trace_kwargs=None, sell_trace_kwargs=None, add_trace_kwargs=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. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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 add_trace_kwargs is None: add_trace_kwargs = {} if fig is None: fig = FigureWidget() fig.update_layout(**layout_kwargs) # Plot close if plot_close: fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, add_trace_kwargs=add_trace_kwargs, 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, **add_trace_kwargs) # 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, **add_trace_kwargs) return fig
def plot(self, column=None, macd_trace_kwargs=None, signal_trace_kwargs=None, hist_trace_kwargs=None, add_trace_kwargs=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`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.MACD.run(ohlcv['Close']).plot() ``` ![](/vectorbt/docs/img/MACD.png)""" self_col = self.select_series(column=column) if fig is None: fig = FigureWidget() 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, add_trace_kwargs=add_trace_kwargs, fig=fig) fig = self_col.signal.vbt.plot(trace_kwargs=signal_trace_kwargs, add_trace_kwargs=add_trace_kwargs, 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) if add_trace_kwargs is None: add_trace_kwargs = {} fig.add_trace(hist_bar, **add_trace_kwargs) 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, add_trace_kwargs=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.GenericSRAccessor.plot` for main. benchmark_kwargs (dict): Keyword arguments passed to `vectorbt.generic.accessors.GenericSRAccessor.plot` for benchmark. hline_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for `start_value` line. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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 = FigureWidget() 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, add_trace_kwargs=add_trace_kwargs, 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, add_trace_kwargs=add_trace_kwargs, fig=fig) else: cumrets.vbt.plot_against(start_value, **main_kwargs, add_trace_kwargs=add_trace_kwargs, 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 __init__(self, data=None, x_labels=None, y_labels=None, trace_kwargs=None, add_trace_kwargs=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. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Heatmap`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> heatmap = vbt.plotting.Heatmap( ... data=[[1, 2], [3, 4]], ... x_labels=['a', 'b'], ... y_labels=['x', 'y'] ... ) >>> heatmap.fig ``` ![](/vectorbt/docs/img/Heatmap.png) """ Configured.__init__(self, data=data, x_labels=x_labels, y_labels=y_labels, trace_kwargs=trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig, **layout_kwargs) from vectorbt.settings import layout if trace_kwargs is None: trace_kwargs = {} if add_trace_kwargs is None: add_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 x_labels is not None: x_labels = clean_labels(x_labels) if y_labels is not None: y_labels = clean_labels(y_labels) if fig is None: fig = FigureWidget() 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, **add_trace_kwargs) TraceUpdater.__init__(self, fig, [fig.data[-1]]) if data is not None: self.update(data)
def __init__(self, data=None, trace_names=None, horizontal=False, remove_nan=True, from_quantile=None, to_quantile=None, trace_kwargs=None, add_trace_kwargs=None, fig=None, **layout_kwargs): """Create a box plot. For keyword arguments, see `Histogram`. ## Example ```python-repl >>> import vectorbt as vbt >>> box = vbt.plotting.Box( ... data=[[1, 2], [3, 4], [2, 1]], ... trace_names=['a', 'b'] ... ) >>> box.fig ``` ![](/vectorbt/docs/img/Box.png) """ Configured.__init__(self, data=data, trace_names=trace_names, horizontal=horizontal, remove_nan=remove_nan, from_quantile=from_quantile, to_quantile=to_quantile, trace_kwargs=trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig, **layout_kwargs) if trace_kwargs is None: trace_kwargs = {} if add_trace_kwargs is None: add_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 = FigureWidget() fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): _trace_kwargs = trace_kwargs[i] if isinstance( trace_kwargs, (list, tuple)) else trace_kwargs trace_name = _trace_kwargs.pop('name', trace_name) 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) fig.add_trace(box, **add_trace_kwargs) TraceUpdater.__init__(self, fig, fig.data[-len(trace_names):]) self.horizontal = horizontal self.remove_nan = remove_nan self.from_quantile = from_quantile self.to_quantile = to_quantile if data is not None: self.update(data)
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, add_trace_kwargs=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. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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 add_trace_kwargs is None: add_trace_kwargs = {} if fig is None: fig = FigureWidget() fig.update_layout(**layout_kwargs) # Plot close if plot_close: fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, add_trace_kwargs=add_trace_kwargs, 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, **add_trace_kwargs) # 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, **add_trace_kwargs) # 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_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, add_trace_kwargs=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. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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 = {} if add_trace_kwargs is None: add_trace_kwargs = {} marker_size_range = tuple(marker_size_range) if fig is None: fig = FigureWidget() 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, **add_trace_kwargs) 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, **add_trace_kwargs) 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, **add_trace_kwargs) # 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 plot(self, plot_type='OHLC', display_volume=True, ohlc_kwargs=None, volume_kwargs=None, ohlc_add_trace_kwargs=None, volume_add_trace_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`. volume_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar`. ohlc_add_trace_kwargs (dict): Keyword arguments passed to `add_trace` for OHLC. volume_add_trace_kwargs (dict): Keyword arguments passed to `add_trace` for volume. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> vbt.utils.data.download("BTC-USD").vbt.ohlcv.plot() ``` ![](/vectorbt/docs/img/ohlcv.png) """ from vectorbt.settings import ohlcv, color_schema if ohlc_kwargs is None: ohlc_kwargs = {} if volume_kwargs is None: volume_kwargs = {} if ohlc_add_trace_kwargs is None: ohlc_add_trace_kwargs = {} if volume_add_trace_kwargs is None: volume_add_trace_kwargs = {} if display_volume: ohlc_add_trace_kwargs = merge_dicts(dict(row=1, col=1), ohlc_add_trace_kwargs) volume_add_trace_kwargs = merge_dicts(dict(row=2, col=1), volume_add_trace_kwargs) 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: if display_volume: fig = make_subplots(rows=2, cols=1, shared_xaxes=True, vertical_spacing=0, row_heights=[0.7, 0.3]) else: fig = FigureWidget() fig.update_layout(showlegend=True, xaxis=dict(rangeslider_visible=False, showgrid=True), yaxis=dict(showgrid=True)) if display_volume: fig.update_layout(xaxis2=dict(showgrid=True), yaxis2=dict(showgrid=True), bargap=0) fig.update_layout(**layout_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, increasing_line_color=color_schema['increasing'], decreasing_line_color=color_schema['decreasing']) ohlc.update(**ohlc_kwargs) fig.add_trace(ohlc, **ohlc_add_trace_kwargs) 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'] volume_bar = go.Bar(x=self.wrapper.index, y=volume, marker=dict(color=marker_colors, line_width=0), opacity=0.5, name='Volume') volume_bar.update(**volume_kwargs) fig.add_trace(volume_bar, **volume_add_trace_kwargs) return fig
def plot_as_markers(self, y=None, trace_kwargs=None, add_trace_kwargs=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`. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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 add_trace_kwargs is None: add_trace_kwargs = {} if fig is None: fig = FigureWidget() fig.update_layout(**layout_kwargs) 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, **add_trace_kwargs) return fig
def __init__(self, data=None, trace_names=None, x_labels=None, trace_kwargs=None, add_trace_kwargs=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`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> scatter = vbt.plotting.Scatter( ... data=[[1, 2], [3, 4]], ... trace_names=['a', 'b'], ... x_labels=['x', 'y'] ... ) >>> scatter.fig ``` ![](/vectorbt/docs/img/Scatter.png) """ Configured.__init__(self, data=data, trace_names=trace_names, x_labels=x_labels, trace_kwargs=trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig, **layout_kwargs) if trace_kwargs is None: trace_kwargs = {} if add_trace_kwargs is None: add_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 x_labels is not None: x_labels = clean_labels(x_labels) if fig is None: fig = FigureWidget() fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): _trace_kwargs = trace_kwargs[i] if isinstance( trace_kwargs, (list, tuple)) else trace_kwargs trace_name = _trace_kwargs.pop('name', trace_name) 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) fig.add_trace(scatter, **add_trace_kwargs) TraceUpdater.__init__(self, fig, fig.data[-len(trace_names):]) if data is not None: self.update(data)
def __init__(self, data=None, trace_names=None, horizontal=False, remove_nan=True, from_quantile=None, to_quantile=None, trace_kwargs=None, add_trace_kwargs=None, 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. remove_nan (bool): Whether to remove NaN values. from_quantile (float): Filter out data points before this quantile. Should be in range `[0, 1]`. to_quantile (float): Filter out data points after this quantile. Should be in range `[0, 1]`. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Histogram`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> hist = vbt.plotting.Histogram( ... data=[[1, 2], [3, 4], [2, 1]], ... trace_names=['a', 'b'] ... ) >>> hist.fig ``` ![](/vectorbt/docs/img/Histogram.png) """ Configured.__init__(self, data=data, trace_names=trace_names, horizontal=horizontal, remove_nan=remove_nan, from_quantile=from_quantile, to_quantile=to_quantile, trace_kwargs=trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig, **layout_kwargs) if trace_kwargs is None: trace_kwargs = {} if add_trace_kwargs is None: add_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 = FigureWidget() fig.update_layout(barmode='overlay') fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): _trace_kwargs = trace_kwargs[i] if isinstance( trace_kwargs, (list, tuple)) else trace_kwargs trace_name = _trace_kwargs.pop('name', trace_name) if trace_name is not None: trace_name = str(trace_name) 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) fig.add_trace(hist, **add_trace_kwargs) TraceUpdater.__init__(self, fig, fig.data[-len(trace_names):]) self.horizontal = horizontal self.remove_nan = remove_nan self.from_quantile = from_quantile self.to_quantile = to_quantile if data is not None: self.update(data)
def plot(self, column=None, plot_close=True, close_trace_kwargs=None, middle_trace_kwargs=None, upper_trace_kwargs=None, lower_trace_kwargs=None, add_trace_kwargs=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`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.BBANDS.run(ohlcv['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 = FigureWidget() 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, add_trace_kwargs=add_trace_kwargs, fig=fig) fig = self_col.upper.vbt.plot(trace_kwargs=upper_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) fig = self_col.middle.vbt.plot(trace_kwargs=middle_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) if plot_close: fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) return fig
def __init__(self, value=None, label=None, value_range=None, cmap_name='Spectral', trace_kwargs=None, add_trace_kwargs=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`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (plotly.graph_objects.Figure): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> indicator = vbt.plotting.Indicator( ... value=2, ... value_range=(1, 3), ... label='My Indicator' ... ) >>> indicator.fig ``` ![](/vectorbt/docs/img/Indicator.png) """ Configured.__init__(self, value=value, label=label, value_range=value_range, cmap_name=cmap_name, trace_kwargs=trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig, **layout_kwargs) from vectorbt.settings import layout if trace_kwargs is None: trace_kwargs = {} if add_trace_kwargs is None: add_trace_kwargs = {} if fig is None: fig = FigureWidget() 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, **add_trace_kwargs) TraceUpdater.__init__(self, fig, [fig.data[-1]]) self.value_range = value_range self.cmap_name = cmap_name if value is not None: self.update(value)
def plot(self, column=None, levels=(30, 70), percent_k_trace_kwargs=None, percent_d_trace_kwargs=None, shape_kwargs=None, add_trace_kwargs=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. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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(ohlcv['High'], ohlcv['Low'], ohlcv['Close']).plot() ``` ![](/vectorbt/docs/img/STOCH.png) """ self_col = self.select_series(column=column) if fig is None: fig = FigureWidget() 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, add_trace_kwargs=add_trace_kwargs, fig=fig) fig = self_col.percent_d.vbt.plot(trace_kwargs=percent_d_trace_kwargs, add_trace_kwargs=add_trace_kwargs, 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 __init__(self, data=None, x_labels=None, y_labels=None, z_labels=False, trace_kwargs=None, add_trace_kwargs=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`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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 >>> volume = vbt.plotting.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'] ... ) >>> volume.fig ``` ![](/vectorbt/docs/img/Volume.png) """ Configured.__init__(self, data=data, x_labels=x_labels, y_labels=y_labels, z_labels=z_labels, trace_kwargs=trace_kwargs, add_trace_kwargs=add_trace_kwargs, scene_name=scene_name, fig=fig, **layout_kwargs) from vectorbt.settings import layout if trace_kwargs is None: trace_kwargs = {} if add_trace_kwargs is None: add_trace_kwargs = {} if data is None: if x_labels is None or y_labels is None or z_labels is None: raise ValueError( "At least x_labels, y_labels and z_labels must be passed") x_len = len(x_labels) y_len = len(y_labels) z_len = len(z_labels) else: checks.assert_ndim(data, 3) data = np.asarray(data) x_len, y_len, z_len = data.shape if x_labels is None: x_labels = np.arange(x_len) else: x_labels = clean_labels(x_labels) if y_labels is None: y_labels = np.arange(y_len) else: y_labels = clean_labels(y_labels) if z_labels is None: z_labels = np.arange(z_len) else: z_labels = clean_labels(z_labels) x_labels = np.asarray(x_labels) y_labels = np.asarray(y_labels) z_labels = np.asarray(z_labels) if fig is None: fig = FigureWidget() 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(x_len) 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(y_len) 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(z_len) 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, opacity=0.2, surface_count=15, # keep low for big data colorscale='Plasma') volume.update(**trace_kwargs) fig.add_trace(volume, **add_trace_kwargs) TraceUpdater.__init__(self, fig, [fig.data[-1]]) if data is not None: self.update(data)
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, add_trace_kwargs=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. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. 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 add_trace_kwargs is None: add_trace_kwargs = {} if fig is None: fig = FigureWidget() 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, add_trace_kwargs=add_trace_kwargs, 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, **add_trace_kwargs) 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, **add_trace_kwargs) 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, **add_trace_kwargs) 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, **add_trace_kwargs) 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