def plot_func(self, *args, _px_func_name: str = px_func_name, _px_func: tp.Callable = px_func, **kwargs) -> tp.BaseFigure: from vectorbt.settings import layout layout_kwargs = dict( template=kwargs.pop('template', layout['template']), width=kwargs.pop('width', layout['width']), height=kwargs.pop('height', layout['height']) ) # Fix category_orders if 'color' in kwargs: if isinstance(kwargs['color'], str): if isinstance(self._obj, pd.DataFrame): if kwargs['color'] in self._obj.columns: category_orders = dict() category_orders[kwargs['color']] = sorted(self._obj[kwargs['color']].unique()) kwargs = merge_dicts(dict(category_orders=category_orders), kwargs) # Fix Series name obj = self._obj.copy(deep=False) if isinstance(obj, pd.Series): if obj.name is not None: obj = obj.rename(str(obj.name)) else: obj.columns = clean_labels(obj.columns) obj.index = clean_labels(obj.index) if _px_func_name == 'imshow': return make_figure(_px_func( obj.vbt.to_2d_array(), *args, **layout_kwargs, **kwargs ), layout=layout_kwargs) return make_figure(_px_func( obj, *args, **layout_kwargs, **kwargs ), layout=layout_kwargs)
def plot(self, column: tp.Optional[tp.Label] = None, plot_close: bool = True, close_trace_kwargs: tp.KwargsLike = None, ma_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.MA.run(ohlcv['Close'], 10).plot() ``` ![](/docs/img/MA.svg) """ from vectorbt._settings import settings plotting_cfg = settings['plotting'] self_col = self.select_one(column=column) if fig is None: fig = make_figure() 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=dict( color=plotting_cfg['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, column: tp.Optional[tp.Label] = None, tr_trace_kwargs: tp.KwargsLike = None, atr_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): 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() ``` ![](/docs/img/ATR.svg) """ self_col = self.select_one(column=column) if fig is None: fig = make_figure() 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: tp.Optional[tp.Label] = None, mstd_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): 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.svg) """ self_col = self.select_one(column=column) if fig is None: fig = make_figure() 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: tp.Optional[tp.Label] = None, obv_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```py >>> vbt.OBV.run(ohlcv['Close'], ohlcv['Volume']).plot() ``` ![](/docs/img/OBV.svg) """ self_col = self.select_one(column=column) if fig is None: fig = make_figure() 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_cum_returns(self, benchmark_rets: tp.Optional[tp.ArrayLike] = None, start_value: float = 1, fill_to_benchmark: bool = False, main_kwargs: tp.KwargsLike = None, benchmark_kwargs: tp.KwargsLike = None, hline_shape_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, xref: str = 'x', yref: str = 'y', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): 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.svg) """ from vectorbt._settings import settings plotting_cfg = settings['plotting'] if fig is None: fig = make_figure() 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 = broadcast_to(benchmark_rets, self._obj) if benchmark_kwargs is None: benchmark_kwargs = {} benchmark_kwargs = merge_dicts( dict(trace_kwargs=dict(line_color=plotting_cfg['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=plotting_cfg['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 plot(self, plot_type: tp.Union[None, str, tp.BaseTraceType] = None, display_volume: bool = True, ohlc_kwargs: tp.KwargsLike = None, volume_kwargs: tp.KwargsLike = None, ohlc_add_trace_kwargs: tp.KwargsLike = None, volume_add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: """Plot OHLCV data. Args: plot_type: Either 'OHLC', 'Candlestick' or Plotly trace. Pass None to use the default. 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> vbt.YFData.download("BTC-USD").get().vbt.ohlcv.plot() ``` ![](/vectorbt/docs/img/ohlcv.svg) """ 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 = make_figure() 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 is None: plot_type = ohlcv['plot_type'] if isinstance(plot_type, str): 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'") else: plot_obj = plot_type 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=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 __init__(self, data: tp.Optional[tp.ArrayLike] = None, x_labels: tp.Optional[tp.Labels] = None, y_labels: tp.Optional[tp.Labels] = None, z_labels: tp.Optional[tp.Labels] = None, trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, scene_name: str = 'scene', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> None: """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 (Figure or FigureWidget): 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.svg) """ 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 settings layout_cfg = settings['plotting']['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 = make_figure() if 'width' in layout_cfg: # Calculate nice width and height fig.update_layout(width=layout_cfg['width'], height=0.7 * layout_cfg['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: tp.Optional[tp.Label] = None, levels: tp.Tuple[float, float] = (30, 70), rsi_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, xref: str = 'x', yref: str = 'y', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # pragma: no cover """Plot `RSI.rsi`. Args: column (str): Name of the column to plot. levels (tuple): Two extremes: bottom and top. rsi_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `RSI.rsi`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. xref (str): X coordinate axis. yref (str): Y coordinate axis. fig (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.RSI.run(ohlcv['Close']).plot() ``` ![](/vectorbt/docs/img/RSI.svg) """ self_col = self.select_series(column=column) if fig is None: fig = make_figure() default_layout = dict() default_layout['yaxis' + yref[1:]] = dict(range=[-5, 105]) fig.update_layout(**default_layout) fig.update_layout(**layout_kwargs) if rsi_trace_kwargs is None: rsi_trace_kwargs = {} rsi_trace_kwargs = merge_dicts(dict( name='RSI' ), rsi_trace_kwargs) fig = self_col.rsi.vbt.plot( trace_kwargs=rsi_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) # Fill void between levels fig.add_shape( type="rect", xref=xref, yref=yref, x0=self_col.rsi.index[0], y0=levels[0], x1=self_col.rsi.index[-1], y1=levels[1], fillcolor="purple", opacity=0.2, layer="below", line_width=0, ) return fig
def plot(self, column: tp.Optional[tp.Label] = None, macd_trace_kwargs: tp.KwargsLike = None, signal_trace_kwargs: tp.KwargsLike = None, hist_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.MACD.run(ohlcv['Close']).plot() ``` ![](/docs/img/MACD.svg)""" self_col = self.select_one(column=column) if fig is None: fig = make_figure() 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, adjust_opacity('silver', 0.75), dtype=object) marker_colors[(hist > 0) & (hist_diff > 0)] = adjust_opacity('green', 0.75) marker_colors[(hist > 0) & (hist_diff <= 0)] = adjust_opacity('lightgreen', 0.75) marker_colors[(hist < 0) & (hist_diff < 0)] = adjust_opacity('red', 0.75) marker_colors[(hist < 0) & (hist_diff >= 0)] = adjust_opacity('lightcoral', 0.75) 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 __init__(self, data: tp.Optional[tp.ArrayLike] = None, trace_names: tp.TraceNames = None, horizontal: bool = False, remove_nan: bool = True, from_quantile: tp.Optional[float] = None, to_quantile: tp.Optional[float] = None, trace_kwargs: tp.KwargsLikeSequence = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> None: """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 or list of dict): Keyword arguments passed to `plotly.graph_objects.Histogram`. Can be specified per trace as a sequence of dicts. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (Figure or FigureWidget): 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.svg) """ 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 = make_figure() fig.update_layout(barmode='overlay') fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): _trace_kwargs = resolve_dict(trace_kwargs, i=i) 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 __init__(self, data: tp.Optional[tp.ArrayLike] = None, trace_names: tp.TraceNames = None, x_labels: tp.Optional[tp.Labels] = None, trace_kwargs: tp.KwargsLikeSequence = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> None: """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 or list of dict): Keyword arguments passed to `plotly.graph_objects.Scatter`. Can be specified per trace as a sequence of dicts. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (Figure or FigureWidget): 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.svg) """ 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 = make_figure() fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): _trace_kwargs = resolve_dict(trace_kwargs, i=i) 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 plot(self, column: tp.Optional[tp.Label] = None, top_n: int = 5, plot_zones: bool = True, ts_trace_kwargs: tp.KwargsLike = None, start_trace_kwargs: tp.KwargsLike = None, end_trace_kwargs: tp.KwargsLike = None, open_shape_kwargs: tp.KwargsLike = None, closed_shape_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, xref: str = 'x', yref: str = 'y', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # pragma: no cover """Plot ranges. Args: column (str): Name of the column to plot. top_n (int): Filter top N range records by maximum duration. plot_zones (bool): Whether to plot zones. ts_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `Ranges.ts`. start_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for start values. end_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for end values. open_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for open zones. closed_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for closed zones. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. xref (str): X coordinate axis. yref (str): Y coordinate axis. fig (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> from datetime import datetime, timedelta >>> import pandas as pd >>> price = pd.Series([1, 2, 1, 2, 3, 2, 1, 2], name='Price') >>> price.index = [datetime(2020, 1, 1) + timedelta(days=i) for i in range(len(price))] >>> vbt.Ranges.from_ts(price >= 2, wrapper_kwargs=dict(freq='1 day')).plot() ``` ![](/docs/img/ranges_plot.svg) """ from vectorbt._settings import settings plotting_cfg = settings['plotting'] self_col = self.select_one(column=column, group_by=False) if top_n is not None: self_col = self_col.apply_mask(self_col.duration.top_n_mask(top_n)) if ts_trace_kwargs is None: ts_trace_kwargs = {} ts_trace_kwargs = merge_dicts( dict(line=dict(color=plotting_cfg['color_schema']['blue'])), ts_trace_kwargs) if start_trace_kwargs is None: start_trace_kwargs = {} if end_trace_kwargs is None: end_trace_kwargs = {} if open_shape_kwargs is None: open_shape_kwargs = {} if closed_shape_kwargs is None: closed_shape_kwargs = {} if add_trace_kwargs is None: add_trace_kwargs = {} if fig is None: fig = make_figure() fig.update_layout(**layout_kwargs) y_domain = get_domain(yref, fig) if self_col.ts is not None: fig = self_col.ts.vbt.plot(trace_kwargs=ts_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) if self_col.count() > 0: # Extract information id_ = self_col.get_field_arr('id') id_title = self_col.get_field_title('id') start_idx = self_col.get_map_field_to_index('start_idx') start_idx_title = self_col.get_field_title('start_idx') if self_col.ts is not None: start_val = self_col.ts.loc[start_idx] else: start_val = np.full(len(start_idx), 0) end_idx = self_col.get_map_field_to_index('end_idx') end_idx_title = self_col.get_field_title('end_idx') if self_col.ts is not None: end_val = self_col.ts.loc[end_idx] else: end_val = np.full(len(end_idx), 0) duration = np.vectorize(str)(self_col.wrapper.to_timedelta( self_col.duration.values, to_pd=True, silence_warnings=True)) status = self_col.get_field_arr('status') # Plot start markers start_customdata = id_[:, None] start_scatter = go.Scatter( x=start_idx, y=start_val, mode='markers', marker=dict( symbol='diamond', color=plotting_cfg['contrast_color_schema']['blue'], size=7, line=dict( width=1, color=adjust_lightness( plotting_cfg['contrast_color_schema']['blue']))), name='Start', customdata=start_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{start_idx_title}: %{{x}}") start_scatter.update(**start_trace_kwargs) fig.add_trace(start_scatter, **add_trace_kwargs) closed_mask = status == RangeStatus.Closed if closed_mask.any(): # Plot end markers closed_end_customdata = np.stack( (id_[closed_mask], duration[closed_mask]), axis=1) closed_end_scatter = go.Scatter( x=end_idx[closed_mask], y=end_val[closed_mask], mode='markers', marker=dict( symbol='diamond', color=plotting_cfg['contrast_color_schema']['green'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['contrast_color_schema'] ['green']))), name='Closed', customdata=closed_end_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{end_idx_title}: %{{x}}" f"<br>Duration: %{{customdata[1]}}") closed_end_scatter.update(**end_trace_kwargs) fig.add_trace(closed_end_scatter, **add_trace_kwargs) if plot_zones: # Plot closed range zones for i in range(len(id_[closed_mask])): fig.add_shape(**merge_dicts( dict( type="rect", xref=xref, yref="paper", x0=start_idx[closed_mask][i], y0=y_domain[0], x1=end_idx[closed_mask][i], y1=y_domain[1], fillcolor='teal', opacity=0.2, layer="below", line_width=0, ), closed_shape_kwargs)) open_mask = status == RangeStatus.Open if open_mask.any(): # Plot end markers open_end_customdata = np.stack( (id_[open_mask], duration[open_mask]), axis=1) open_end_scatter = go.Scatter( x=end_idx[open_mask], y=end_val[open_mask], mode='markers', marker=dict( symbol='diamond', color=plotting_cfg['contrast_color_schema']['orange'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['contrast_color_schema'] ['orange']))), name='Open', customdata=open_end_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{end_idx_title}: %{{x}}" f"<br>Duration: %{{customdata[1]}}") open_end_scatter.update(**end_trace_kwargs) fig.add_trace(open_end_scatter, **add_trace_kwargs) if plot_zones: # Plot open range zones for i in range(len(id_[open_mask])): fig.add_shape(**merge_dicts( dict( type="rect", xref=xref, yref="paper", x0=start_idx[open_mask][i], y0=y_domain[0], x1=end_idx[open_mask][i], y1=y_domain[1], fillcolor='orange', opacity=0.2, layer="below", line_width=0, ), open_shape_kwargs)) return fig
def plot(self, column: tp.Optional[tp.Label] = None, close_trace_kwargs: tp.KwargsLike = None, buy_trace_kwargs: tp.KwargsLike = None, sell_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # pragma: no cover """Plot orders. Args: column (str): Name of the column to plot. 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import pandas as pd >>> from datetime import datetime, timedelta >>> import vectorbt as vbt >>> price = pd.Series([1., 2., 3., 2., 1.], name='Price') >>> price.index = [datetime(2020, 1, 1) + timedelta(days=i) for i in range(len(price))] >>> size = pd.Series([1., 1., 1., 1., -1.]) >>> orders = vbt.Portfolio.from_orders(price, size).orders >>> orders.plot() ``` ![](/docs/img/orders_plot.svg)""" from vectorbt._settings import settings plotting_cfg = settings['plotting'] self_col = self.select_one(column=column, group_by=False) if close_trace_kwargs is None: close_trace_kwargs = {} close_trace_kwargs = merge_dicts(dict( line=dict( color=plotting_cfg['color_schema']['blue'] ), name='Close' ), 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 = make_figure() fig.update_layout(**layout_kwargs) # Plot price if self_col.close is not None: fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) if self_col.count() > 0: # Extract information id_ = self_col.get_field_arr('id') id_title = self_col.get_field_title('id') idx = self_col.get_map_field_to_index('idx') idx_title = self_col.get_field_title('idx') size = self_col.get_field_arr('size') size_title = self_col.get_field_title('size') fees = self_col.get_field_arr('fees') fees_title = self_col.get_field_title('fees') price = self_col.get_field_arr('price') price_title = self_col.get_field_title('price') side = self_col.get_field_arr('side') buy_mask = side == OrderSide.Buy if buy_mask.any(): # Plot buy markers buy_customdata = np.stack(( id_[buy_mask], size[buy_mask], fees[buy_mask] ), axis=1) buy_scatter = go.Scatter( x=idx[buy_mask], y=price[buy_mask], mode='markers', marker=dict( symbol='triangle-up', color=plotting_cfg['contrast_color_schema']['green'], size=8, line=dict( width=1, color=adjust_lightness(plotting_cfg['contrast_color_schema']['green']) ) ), name='Buy', customdata=buy_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{idx_title}: %{{x}}" f"<br>{price_title}: %{{y}}" f"<br>{size_title}: %{{customdata[1]:.6f}}" f"<br>{fees_title}: %{{customdata[2]:.6f}}" ) buy_scatter.update(**buy_trace_kwargs) fig.add_trace(buy_scatter, **add_trace_kwargs) sell_mask = side == OrderSide.Sell if sell_mask.any(): # Plot sell markers sell_customdata = np.stack(( id_[sell_mask], size[sell_mask], fees[sell_mask] ), axis=1) sell_scatter = go.Scatter( x=idx[sell_mask], y=price[sell_mask], mode='markers', marker=dict( symbol='triangle-down', color=plotting_cfg['contrast_color_schema']['red'], size=8, line=dict( width=1, color=adjust_lightness(plotting_cfg['contrast_color_schema']['red']) ) ), name='Sell', customdata=sell_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{idx_title}: %{{x}}" f"<br>{price_title}: %{{y}}" f"<br>{size_title}: %{{customdata[1]:.6f}}" f"<br>{fees_title}: %{{customdata[2]:.6f}}" ) sell_scatter.update(**sell_trace_kwargs) fig.add_trace(sell_scatter, **add_trace_kwargs) return fig
def plot(self, column: tp.Optional[tp.Label] = None, top_n: int = 5, plot_ts: bool = True, plot_zones: bool = True, ts_trace_kwargs: tp.KwargsLike = None, peak_trace_kwargs: tp.KwargsLike = None, valley_trace_kwargs: tp.KwargsLike = None, recovery_trace_kwargs: tp.KwargsLike = None, active_trace_kwargs: tp.KwargsLike = None, ptv_shape_kwargs: tp.KwargsLike = None, vtr_shape_kwargs: tp.KwargsLike = None, active_shape_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, xref: str = 'x', yref: str = 'y', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): 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.svg) """ from vectorbt._settings import settings plotting_cfg = settings['plotting'] self_col = self.select_one(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=dict(color=plotting_cfg['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 = make_figure() fig.update_layout(**layout_kwargs) y_domain = get_domain(yref, fig) 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, DatetimeIndexes): 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=plotting_cfg['contrast_color_schema']['blue'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['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=plotting_cfg['contrast_color_schema']['red'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['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=plotting_cfg['contrast_color_schema']['green'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['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=plotting_cfg['contrast_color_schema']['orange'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['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
def plot(self, column: tp.Optional[tp.Label] = None, plot_close: bool = True, close_trace_kwargs: tp.KwargsLike = None, buy_trace_kwargs: tp.KwargsLike = None, sell_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> orders.plot() ``` ![](/vectorbt/docs/img/orders_plot.svg)""" 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 = make_figure() 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: tp.Optional[tp.Label] = None, plot_close: bool = True, close_trace_kwargs: tp.KwargsLike = None, middle_trace_kwargs: tp.KwargsLike = None, upper_trace_kwargs: tp.KwargsLike = None, lower_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.BBANDS.run(ohlcv['Close']).plot() ``` ![](/docs/img/BBANDS.svg) """ from vectorbt._settings import settings plotting_cfg = settings['plotting'] self_col = self.select_one(column=column) if fig is None: fig = make_figure() 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=dict( color=adjust_opacity(plotting_cfg['color_schema']['gray'], 0.75) ), ), lower_trace_kwargs) upper_trace_kwargs = merge_dicts(dict( name='Upper Band', line=dict( color=adjust_opacity(plotting_cfg['color_schema']['gray'], 0.75) ), 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=plotting_cfg['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 plot(self, column: tp.Optional[tp.Label] = None, levels: tp.Tuple[float, float] = (30, 70), percent_k_trace_kwargs: tp.KwargsLike = None, percent_d_trace_kwargs: tp.KwargsLike = None, shape_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, xref: str = 'x', yref: str = 'y', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 `Figure or FigureWidget.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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> vbt.STOCH.run(ohlcv['High'], ohlcv['Low'], ohlcv['Close']).plot() ``` ![](/docs/img/STOCH.svg) """ self_col = self.select_one(column=column) if fig is None: fig = make_figure() 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: tp.Optional[tp.ArrayLike] = None, trace_names: tp.TraceNames = None, horizontal: bool = False, remove_nan: bool = True, from_quantile: tp.Optional[float] = None, to_quantile: tp.Optional[float] = None, trace_kwargs: tp.KwargsLikeSequence = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> None: """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.svg) """ 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 = make_figure() fig.update_layout(**layout_kwargs) for i, trace_name in enumerate(trace_names): _trace_kwargs = resolve_dict(trace_kwargs, i=i) 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, plot_type: tp.Union[None, str, tp.BaseTraceType] = None, ohlc_kwargs: tp.KwargsLike = None, entry_trace_kwargs: tp.KwargsLike = None, exit_trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, _base_cls_plot: tp.Callable = base_cls_plot, **layout_kwargs) -> tp.BaseFigure: # pragma: no cover from vectorbt._settings import settings ohlcv_cfg = settings['ohlcv'] plotting_cfg = settings['plotting'] if self.wrapper.ndim > 1: raise TypeError("Select a column first. Use indexing.") if ohlc_kwargs is None: ohlc_kwargs = {} if add_trace_kwargs is None: add_trace_kwargs = {} if fig is None: fig = make_figure() fig.update_layout(showlegend=True, xaxis_rangeslider_visible=False, xaxis_showgrid=True, yaxis_showgrid=True) fig.update_layout(**layout_kwargs) if plot_type is None: plot_type = ohlcv_cfg['plot_type'] if isinstance(plot_type, str): 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'") else: plot_obj = plot_type ohlc = plot_obj( x=self.wrapper.index, open=self.open, high=self.high, low=self.low, close=self.close, name=plot_type, increasing_line_color=plotting_cfg['color_schema']['increasing'], decreasing_line_color=plotting_cfg['color_schema']['decreasing']) 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_pnl_returns(self, column: tp.Optional[tp.Label] = None, as_pct: bool = True, marker_size_range: tp.Tuple[float, float] = (7, 14), opacity_range: tp.Tuple[float, float] = (0.75, 0.9), closed_profit_trace_kwargs: tp.KwargsLike = None, closed_loss_trace_kwargs: tp.KwargsLike = None, open_trace_kwargs: tp.KwargsLike = None, hline_shape_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, xref: str = 'x', yref: str = 'y', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # pragma: no cover """Plot trade PnL. Args: column (str): Name of the column to plot. as_pct (bool): Whether to set y-axis to `Trades.returns`, otherwise to `Trades.pnl`. marker_size_range (tuple): Range of marker size. opacity_range (tuple): Range of marker opacity. 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. """ from vectorbt._settings import settings plotting_cfg = settings['plotting'] self_col = self.select_one(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) xaxis = 'xaxis' + xref[1:] yaxis = 'yaxis' + yref[1:] if fig is None: fig = make_figure() if as_pct: _layout_kwargs = dict() _layout_kwargs[yaxis] = dict(tickformat='.2%') fig.update_layout(**_layout_kwargs) fig.update_layout(**layout_kwargs) x_domain = get_domain(xref, fig) if len(self_col.values) > 0: # Extract information _pnl_str = '%{customdata[1]:.6f}' if as_pct else '%{y}' _return_str = '%{y}' if as_pct else '%{customdata[1]:.2%}' exit_idx = self_col.values['exit_idx'] pnl = self_col.values['pnl'] returns = self_col.values['return'] status = self_col.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 def _plot_scatter(mask: tp.Array1d, name: tp.TraceName, color: tp.Any, kwargs: tp.Kwargs) -> None: if np.any(mask): if self_col.trade_type == TradeType.Trade: customdata = np.stack( (self_col.values['id'][mask], self_col.values['position_id'][mask], pnl[mask] if as_pct else returns[mask]), axis=1) hovertemplate = "Trade Id: %{customdata[0]}" \ "<br>Position Id: %{customdata[1]}" \ "<br>Date: %{x}" \ f"<br>PnL: {_pnl_str}" \ f"<br>Return: {_return_str}" else: customdata = np.stack( (self_col.values['id'][mask], pnl[mask] if as_pct else returns[mask]), axis=1) hovertemplate = "Position Id: %{customdata[0]}" \ "<br>Date: %{x}" \ f"<br>PnL: {_pnl_str}" \ f"<br>Return: {_return_str}" scatter = go.Scatter( x=self_col.wrapper.index[exit_idx[mask]], y=returns[mask] if as_pct else pnl[mask], mode='markers', marker=dict( symbol='circle', color=color, size=marker_size[mask], opacity=opacity[mask], line=dict(width=1, color=adjust_lightness(color)), ), name=name, customdata=customdata, hovertemplate=hovertemplate) scatter.update(**kwargs) fig.add_trace(scatter, **add_trace_kwargs) # Plot Closed - Profit scatter _plot_scatter(closed_profit_mask, 'Closed - Profit', plotting_cfg['contrast_color_schema']['green'], closed_profit_trace_kwargs) # Plot Closed - Profit scatter _plot_scatter(closed_loss_mask, 'Closed - Loss', plotting_cfg['contrast_color_schema']['red'], closed_loss_trace_kwargs) # Plot Open scatter _plot_scatter(open_mask, 'Open', plotting_cfg['contrast_color_schema']['orange'], open_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 __init__(self, data: tp.Optional[tp.ArrayLike] = None, x_labels: tp.Optional[tp.Labels] = None, y_labels: tp.Optional[tp.Labels] = None, is_x_category: bool = False, is_y_category: bool = False, trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> None: """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. is_x_category (bool): Whether X-axis is a categorical axis. is_y_category (bool): Whether Y-axis is a categorical axis. trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Heatmap`. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. fig (Figure or FigureWidget): 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.svg) """ 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 settings layout_cfg = settings['plotting']['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.asarray(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 = make_figure() if 'width' in layout_cfg: # Calculate nice width and height max_width = layout_cfg['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) heatmap = go.Heatmap(hoverongaps=False, colorscale='Plasma', x=x_labels, y=y_labels) heatmap.update(**trace_kwargs) fig.add_trace(heatmap, **add_trace_kwargs) axis_kwargs = dict() if is_x_category: if fig.data[-1]['xaxis'] is not None: axis_kwargs['xaxis' + fig.data[-1]['xaxis'][1:]] = dict(type='category') else: axis_kwargs['xaxis'] = dict(type='category') if is_y_category: if fig.data[-1]['yaxis'] is not None: axis_kwargs['yaxis' + fig.data[-1]['yaxis'][1:]] = dict(type='category') else: axis_kwargs['yaxis'] = dict(type='category') fig.update_layout(**axis_kwargs) fig.update_layout(**layout_kwargs) TraceUpdater.__init__(self, fig, (fig.data[-1], )) if data is not None: self.update(data)
def plot(self, column: tp.Optional[tp.Label] = None, plot_close: bool = True, plot_zones: bool = True, close_trace_kwargs: tp.KwargsLike = None, entry_trace_kwargs: tp.KwargsLike = None, exit_trace_kwargs: tp.KwargsLike = None, exit_profit_trace_kwargs: tp.KwargsLike = None, exit_loss_trace_kwargs: tp.KwargsLike = None, active_trace_kwargs: tp.KwargsLike = None, profit_shape_kwargs: tp.KwargsLike = None, loss_shape_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, xref: str = 'x', yref: str = 'y', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> trades.plot() ``` ![](/vectorbt/docs/img/trades_plot.svg)""" from vectorbt._settings import settings plotting_cfg = settings['plotting'] self_col = self.select_one(column=column, group_by=False) if close_trace_kwargs is None: close_trace_kwargs = {} close_trace_kwargs = merge_dicts( dict(line=dict(color=plotting_cfg['color_schema']['blue']), name='Close'), 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 = make_figure() 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 = enum_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: int, to_idx: int) -> tp.Array1d: if isinstance(self_col.wrapper.index, DatetimeIndexes): 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=plotting_cfg['contrast_color_schema']['blue'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['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: tp.Array1d, name: tp.TraceName, color: tp.Any, kwargs: tp.Kwargs) -> None: 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', plotting_cfg['contrast_color_schema']['gray'], exit_trace_kwargs) # Plot Exit - Profit markers _plot_end_markers((status == TradeStatus.Closed) & (pnl > 0.), 'Exit - Profit', plotting_cfg['contrast_color_schema']['green'], exit_profit_trace_kwargs) # Plot Exit - Loss markers _plot_end_markers((status == TradeStatus.Closed) & (pnl < 0.), 'Exit - Loss', plotting_cfg['contrast_color_schema']['red'], exit_loss_trace_kwargs) # Plot Active markers _plot_end_markers(status == TradeStatus.Open, 'Active', plotting_cfg['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: tp.Optional[tp.Label] = None, top_n: int = 5, plot_zones: bool = True, ts_trace_kwargs: tp.KwargsLike = None, peak_trace_kwargs: tp.KwargsLike = None, valley_trace_kwargs: tp.KwargsLike = None, recovery_trace_kwargs: tp.KwargsLike = None, active_trace_kwargs: tp.KwargsLike = None, decline_shape_kwargs: tp.KwargsLike = None, recovery_shape_kwargs: tp.KwargsLike = None, active_shape_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, xref: str = 'x', yref: str = 'y', fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> tp.BaseFigure: # pragma: no cover """Plot drawdowns. Args: column (str): Name of the column to plot. top_n (int): Filter top N drawdown records by maximum drawdown. plot_zones (bool): Whether to plot zones. ts_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `Drawdowns.ts`. 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. decline_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for decline zones. recovery_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for recovery zones. active_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for active recovery zones. add_trace_kwargs (dict): Keyword arguments passed to `add_trace`. xref (str): X coordinate axis. yref (str): Y coordinate axis. fig (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> from datetime import datetime, timedelta >>> import pandas as pd >>> price = pd.Series([1, 2, 1, 2, 3, 2, 1, 2], name='Price') >>> price.index = [datetime(2020, 1, 1) + timedelta(days=i) for i in range(len(price))] >>> vbt.Drawdowns.from_ts(price, wrapper_kwargs=dict(freq='1 day')).plot() ``` ![](/docs/img/drawdowns_plot.svg) """ from vectorbt._settings import settings plotting_cfg = settings['plotting'] self_col = self.select_one(column=column, group_by=False) if top_n is not None: # Drawdowns is negative, thus top_n becomes bottom_n self_col = self_col.apply_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=dict(color=plotting_cfg['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 decline_shape_kwargs is None: decline_shape_kwargs = {} if recovery_shape_kwargs is None: recovery_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 = make_figure() fig.update_layout(**layout_kwargs) y_domain = get_domain(yref, fig) if self_col.ts is not None: fig = self_col.ts.vbt.plot(trace_kwargs=ts_trace_kwargs, add_trace_kwargs=add_trace_kwargs, fig=fig) if self_col.count() > 0: # Extract information id_ = self_col.get_field_arr('id') id_title = self_col.get_field_title('id') peak_idx = self_col.get_map_field_to_index('peak_idx') peak_idx_title = self_col.get_field_title('peak_idx') if self_col.ts is not None: peak_val = self_col.ts.loc[peak_idx] else: peak_val = self_col.get_field_arr('peak_val') peak_val_title = self_col.get_field_title('peak_val') valley_idx = self_col.get_map_field_to_index('valley_idx') valley_idx_title = self_col.get_field_title('valley_idx') if self_col.ts is not None: valley_val = self_col.ts.loc[valley_idx] else: valley_val = self_col.get_field_arr('valley_val') valley_val_title = self_col.get_field_title('valley_val') end_idx = self_col.get_map_field_to_index('end_idx') end_idx_title = self_col.get_field_title('end_idx') if self_col.ts is not None: end_val = self_col.ts.loc[end_idx] else: end_val = self_col.get_field_arr('end_val') end_val_title = self_col.get_field_title('end_val') drawdown = self_col.drawdown.values recovery_return = self_col.recovery_return.values decline_duration = np.vectorize(str)(self_col.wrapper.to_timedelta( self_col.decline_duration.values, to_pd=True, silence_warnings=True)) recovery_duration = np.vectorize(str)( self_col.wrapper.to_timedelta( self_col.recovery_duration.values, to_pd=True, silence_warnings=True)) duration = np.vectorize(str)(self_col.wrapper.to_timedelta( self_col.duration.values, to_pd=True, silence_warnings=True)) status = self_col.get_field_arr('status') peak_mask = peak_idx != np.roll( end_idx, 1) # peak and recovery at same time -> recovery wins if peak_mask.any(): # Plot peak markers peak_customdata = id_[peak_mask][:, None] peak_scatter = go.Scatter( x=peak_idx[peak_mask], y=peak_val[peak_mask], mode='markers', marker=dict( symbol='diamond', color=plotting_cfg['contrast_color_schema']['blue'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['contrast_color_schema'] ['blue']))), name='Peak', customdata=peak_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{peak_idx_title}: %{{x}}" f"<br>{peak_val_title}: %{{y}}") peak_scatter.update(**peak_trace_kwargs) fig.add_trace(peak_scatter, **add_trace_kwargs) recovered_mask = status == DrawdownStatus.Recovered if recovered_mask.any(): # Plot valley markers valley_customdata = np.stack( (id_[recovered_mask], drawdown[recovered_mask], decline_duration[recovered_mask]), axis=1) valley_scatter = go.Scatter( x=valley_idx[recovered_mask], y=valley_val[recovered_mask], mode='markers', marker=dict( symbol='diamond', color=plotting_cfg['contrast_color_schema']['red'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['contrast_color_schema'] ['red']))), name='Valley', customdata=valley_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{valley_idx_title}: %{{x}}" f"<br>{valley_val_title}: %{{y}}" f"<br>Drawdown: %{{customdata[1]:.2%}}" f"<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 range(len(id_[recovered_mask])): fig.add_shape(**merge_dicts( dict( type="rect", xref=xref, yref="paper", x0=peak_idx[recovered_mask][i], y0=y_domain[0], x1=valley_idx[recovered_mask][i], y1=y_domain[1], fillcolor='red', opacity=0.2, layer="below", line_width=0, ), decline_shape_kwargs)) # Plot recovery markers recovery_customdata = np.stack( (id_[recovered_mask], recovery_return[recovered_mask], recovery_duration[recovered_mask]), axis=1) recovery_scatter = go.Scatter( x=end_idx[recovered_mask], y=end_val[recovered_mask], mode='markers', marker=dict( symbol='diamond', color=plotting_cfg['contrast_color_schema']['green'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['contrast_color_schema'] ['green']))), name='Recovery/Peak', customdata=recovery_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{end_idx_title}: %{{x}}" f"<br>{end_val_title}: %{{y}}" f"<br>Return: %{{customdata[1]:.2%}}" f"<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 range(len(id_[recovered_mask])): fig.add_shape(**merge_dicts( dict( type="rect", xref=xref, yref="paper", x0=valley_idx[recovered_mask][i], y0=y_domain[0], x1=end_idx[recovered_mask][i], y1=y_domain[1], fillcolor='green', opacity=0.2, layer="below", line_width=0, ), recovery_shape_kwargs)) # Plot active markers active_mask = status == DrawdownStatus.Active if active_mask.any(): active_customdata = np.stack( (id_[active_mask], drawdown[active_mask], duration[active_mask]), axis=1) active_scatter = go.Scatter( x=end_idx[active_mask], y=end_val[active_mask], mode='markers', marker=dict( symbol='diamond', color=plotting_cfg['contrast_color_schema']['orange'], size=7, line=dict(width=1, color=adjust_lightness( plotting_cfg['contrast_color_schema'] ['orange']))), name='Active', customdata=active_customdata, hovertemplate=f"{id_title}: %{{customdata[0]}}" f"<br>{end_idx_title}: %{{x}}" f"<br>{end_val_title}: %{{y}}" f"<br>Return: %{{customdata[1]:.2%}}" f"<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 range(len(id_[active_mask])): fig.add_shape(**merge_dicts( dict( type="rect", xref=xref, yref="paper", x0=peak_idx[active_mask][i], y0=y_domain[0], x1=end_idx[active_mask][i], y1=y_domain[1], fillcolor='orange', opacity=0.2, layer="below", line_width=0, ), active_shape_kwargs)) return fig
def __init__(self, value: tp.Optional[float] = None, label: tp.Optional[str] = None, value_range: tp.Optional[tp.Tuple[float, float]] = None, cmap_name: str = 'Spectral', trace_kwargs: tp.KwargsLike = None, add_trace_kwargs: tp.KwargsLike = None, fig: tp.Optional[tp.BaseFigure] = None, **layout_kwargs) -> None: """Create a gauge plot. Args: value (float): The value to be displayed. label (str): The label to be displayed. value_range (tuple of float): 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 (Figure or FigureWidget): Figure to add traces to. **layout_kwargs: Keyword arguments for layout. ## Example ```python-repl >>> import vectorbt as vbt >>> gauge = vbt.plotting.Gauge( ... value=2, ... value_range=(1, 3), ... label='My Gauge' ... ) >>> gauge.fig ``` ![](/vectorbt/docs/img/Gauge.svg) """ 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 settings layout_cfg = settings['plotting']['layout'] if trace_kwargs is None: trace_kwargs = {} if add_trace_kwargs is None: add_trace_kwargs = {} if fig is None: fig = make_figure() if 'width' in layout_cfg: # Calculate nice width and height fig.update_layout(width=layout_cfg['width'] * 0.7, height=layout_cfg['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)