コード例 #1
0
ファイル: trades.py プロジェクト: koprivers/vectorbt
 def _plot_end_markers(mask, name, color, kwargs):
     if np.any(mask):
         customdata = np.stack(
             (_id[mask], duration[mask], size[mask],
              exit_fees[mask], pnl[mask], ret[mask],
              direction[mask],
              *((self_col.values['position_id'][mask], )
                if self.trade_type == TradeType.Trade else ())),
             axis=1)
         scatter = go.Scatter(
             x=self_col.wrapper.index[exit_idx[mask]],
             y=exit_price[mask],
             mode='markers',
             marker=dict(symbol='square',
                         color=color,
                         size=7,
                         line=dict(width=1,
                                   color=adjust_lightness(color))),
             name=name,
             customdata=customdata,
             hovertemplate=_id_str + ": %{customdata[0]}"
             "<br>Date: %{x}"
             "<br>Duration: %{customdata[1]}"
             "<br>Avg. Price: %{y}"
             "<br>Size: %{customdata[2]:.6f}"
             "<br>Fees: %{customdata[3]:.6f}"
             "<br>PnL: %{customdata[4]:.6f}"
             "<br>Return: %{customdata[5]:.2%}"
             "<br>Direction: %{customdata[6]}" +
             ("<br>Position Id: %{customdata[7]}"
              if self.trade_type == TradeType.Trade else ''))
         scatter.update(**kwargs)
         fig.add_trace(scatter, row=row, col=col)
コード例 #2
0
 def _plot_scatter(mask: tp.Array1d, name: tp.TraceName,
                   color: tp.Any, kwargs: tp.Kwargs) -> None:
     if np.any(mask):
         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=np.stack(
                 (_id[mask],
                  pnl[mask] if as_pct else returns[mask]),
                 axis=1),
             hovertemplate=_id_str + ": %{customdata[0]}"
             "<br>Date: %{x}"
             f"<br>PnL: {_pnl_str}"
             f"<br>Return: {_return_str}")
         scatter.update(**kwargs)
         fig.add_trace(scatter, **add_trace_kwargs)
コード例 #3
0
ファイル: accessors.py プロジェクト: ag-ds-bubble/vectorbt
    def plot_as_markers(self, y=None, **kwargs):  # pragma: no cover
        """Plot Series as markers.

        Args:
            y (array_like): Y-axis values to plot markers on.
            **kwargs: Keyword arguments passed to `vectorbt.generic.accessors.GenericAccessor.scatterplot`.

        ## Example

        ```python-repl
        >>> ts = pd.Series([1, 2, 3, 2, 1], index=sig.index)
        >>> fig = ts.vbt.lineplot()
        >>> 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 y is None:
            y = pd.Series.vbt.empty_like(self._obj, 1)

        return y[self._obj].vbt.scatterplot(**merge_dicts(
            dict(trace_kwargs=dict(marker=dict(
                symbol='circle',
                color=contrast_color_schema['blue'],
                size=7,
                line=dict(width=1,
                          color=adjust_lightness(
                              contrast_color_schema['blue']))))), kwargs))
コード例 #4
0
ファイル: accessors.py プロジェクト: khprash/vectorbt
    def plot_as_markers(self,
                        ts,
                        name=None,
                        trace_kwargs={},
                        fig=None,
                        **layout_kwargs):  # pragma: no cover
        """Plot Series as markers.

        Args:
            ts (pandas.Series): Time series to plot markers on.

                !!! note
                    Doesn't plot `ts`.

            name (str): Name of the signals.
            trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.
        Example:
            ```py
            ts = pd.Series([1, 2, 3, 2, 1], index=sig.index)
            fig = ts.vbt.plot()
            sig['b'].vbt.signals.plot_as_entry_markers(ts, fig=fig)
            (~sig['b']).vbt.signals.plot_as_exit_markers(ts, fig=fig)
            ```

            ![](/vectorbt/docs/img/signals_plot_as_markers.png)"""
        checks.assert_type(ts, pd.Series)
        checks.assert_same_index(self._obj, ts)

        if fig is None:
            fig = CustomFigureWidget()
        fig.update_layout(**layout_kwargs)
        if name is None:
            name = self._obj.name

        # Plot markers
        scatter = go.Scatter(
            x=ts.index[self._obj],
            y=ts[self._obj],
            mode='markers',
            marker=dict(symbol='circle',
                        color=contrast_color_schema['blue'],
                        size=7,
                        line=dict(width=1,
                                  color=adjust_lightness(
                                      contrast_color_schema['blue']))),
            name=str(name),
            showlegend=name is not None)
        scatter.update(**trace_kwargs)
        fig.add_trace(scatter)
        return fig
コード例 #5
0
ファイル: accessors.py プロジェクト: varnittewari/vectorbt
 def plot_as_exit_markers(self, *args, name='Exit', trace_kwargs={}, **kwargs):  # pragma: no cover
     """Plot signals as exit markers.
     
     See `Signals_SRAccessor.plot_as_markers`."""
     trace_kwargs = merge_kwargs(dict(
         marker=dict(
             symbol='circle',
             color=contrast_color_schema['orange'],
             size=7,
             line=dict(
                 width=1,
                 color=adjust_lightness(contrast_color_schema['orange'])
             )
         )
     ), trace_kwargs)
     return self.plot_as_markers(*args, name=name, trace_kwargs=trace_kwargs, **kwargs)
コード例 #6
0
ファイル: accessors.py プロジェクト: ag-ds-bubble/vectorbt
    def plot_as_exit_markers(self, y=None, **kwargs):  # pragma: no cover
        """Plot signals as exit markers.

        See `SignalsSRAccessor.plot_as_markers`."""
        from vectorbt.settings import contrast_color_schema

        return self.plot_as_markers(
            y=y,
            **merge_dicts(
                dict(trace_kwargs=dict(marker=dict(
                    symbol='triangle-down',
                    color=contrast_color_schema['red'],
                    size=8,
                    line=dict(width=1,
                              color=adjust_lightness(
                                  contrast_color_schema['red']))),
                                       name='Exit')), kwargs))
コード例 #7
0
ファイル: accessors.py プロジェクト: jzay/vectorbt
    def plot_as_entry_markers(self, *args, name='Entry', trace_kwargs=None, **kwargs):  # pragma: no cover
        """Plot signals as entry markers.

        See `Signals_SRAccessor.plot_as_markers`."""
        from vectorbt.settings import contrast_color_schema

        if trace_kwargs is None:
            trace_kwargs = {}
        trace_kwargs = merge_dicts(dict(
            marker=dict(
                symbol='triangle-up',
                color=contrast_color_schema['green'],
                size=8,
                line=dict(
                    width=1,
                    color=adjust_lightness(contrast_color_schema['green'])
                )
            )
        ), trace_kwargs)
        return self.plot_as_markers(*args, name=name, trace_kwargs=trace_kwargs, **kwargs)
コード例 #8
0
ファイル: accessors.py プロジェクト: vlam020/vectorbt
    def plot_as_entry_markers(
        self,
        y: tp.Optional[tp.ArrayLike] = None,
        **kwargs
    ) -> tp.Union[tp.BaseFigure, plotting.Scatter]:  # pragma: no cover
        """Plot signals as entry markers.

        See `SignalsSRAccessor.plot_as_markers`."""
        from vectorbt.settings import contrast_color_schema

        return self.plot_as_markers(
            y=y,
            **merge_dicts(
                dict(trace_kwargs=dict(marker=dict(
                    symbol='triangle-up',
                    color=contrast_color_schema['green'],
                    size=8,
                    line=dict(width=1,
                              color=adjust_lightness(
                                  contrast_color_schema['green']))),
                                       name='Entry')), kwargs))
コード例 #9
0
    def plot_as_markers(
        self,
        y: tp.Optional[tp.ArrayLike] = None,
        **kwargs
    ) -> tp.Union[tp.BaseFigure, plotting.Scatter]:  # pragma: no cover
        """Plot Series as markers.

        Args:
            y (array_like): Y-axis values to plot markers on.
            **kwargs: Keyword arguments passed to `vectorbt.generic.accessors.GenericAccessor.scatterplot`.

        ## Example

        ```python-repl
        >>> ts = pd.Series([1, 2, 3, 2, 1], index=sig.index)
        >>> fig = ts.vbt.lineplot()
        >>> 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.svg)
        """
        from vectorbt._settings import settings
        plotting_cfg = settings['plotting']

        if y is None:
            y = pd.Series.vbt.empty_like(self._obj, 1)
        else:
            y = reshape_fns.to_pd_array(y)

        return y[self._obj].vbt.scatterplot(**merge_dicts(
            dict(trace_kwargs=dict(marker=dict(
                symbol='circle',
                color=plotting_cfg['contrast_color_schema']['blue'],
                size=7,
                line=dict(width=1,
                          color=adjust_lightness(
                              plotting_cfg['contrast_color_schema']
                              ['blue']))))), kwargs))
コード例 #10
0
 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)
コード例 #11
0
ファイル: events.py プロジェクト: yamen/vectorbt
 def plot_end_markers(mask, name, color, kwargs):
     customdata = np.stack((size[mask], exit_fees[mask], pnl[mask],
                            ret[mask], duration[mask]),
                           axis=1)
     scatter = go.Scatter(x=self.wrapper.index[exit_idx[mask]],
                          y=exit_price[mask],
                          mode='markers',
                          marker=dict(
                              symbol='circle',
                              color=color,
                              size=7,
                              line=dict(width=1,
                                        color=adjust_lightness(color))),
                          name=name,
                          customdata=customdata,
                          hovertemplate="%{x}<br>Price: %{y}" +
                          "<br>Size: %{customdata[0]:.4f}" +
                          "<br>Fees: %{customdata[1]:.2f}" +
                          "<br>PnL: %{customdata[2]:.2f}" +
                          "<br>Return: %{customdata[3]:.2%}" +
                          "<br>Duration: %{customdata[4]}")
     scatter.update(**kwargs)
     fig.add_trace(scatter)
コード例 #12
0
    def plot_as_exit_markers(
        self,
        y: tp.Optional[tp.ArrayLike] = None,
        **kwargs
    ) -> tp.Union[tp.BaseFigure, plotting.Scatter]:  # pragma: no cover
        """Plot signals as exit markers.

        See `SignalsSRAccessor.plot_as_markers`."""
        from vectorbt._settings import settings
        plotting_cfg = settings['plotting']

        return self.plot_as_markers(
            y=y,
            **merge_dicts(
                dict(trace_kwargs=dict(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='Exit')), kwargs))
コード例 #13
0
    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
コード例 #14
0
    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
コード例 #15
0
ファイル: events.py プロジェクト: yamen/vectorbt
    def plot(self,
             main_price_trace_kwargs={},
             entry_trace_kwargs={},
             exit_trace_kwargs={},
             exit_profit_trace_kwargs={},
             exit_loss_trace_kwargs={},
             active_trace_kwargs={},
             profit_shape_kwargs={},
             loss_shape_kwargs={},
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot orders.

        Args:
            main_price_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for main price.
            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.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.
        Example:
            ```py
            import vectorbt as vbt
            import pandas as pd

            price = pd.Series([1, 2, 3, 2, 1])
            orders = pd.Series([1, -1, 1, -1, 0])
            portfolio = vbt.Portfolio.from_orders(price, orders, freq='1D')

            portfolio.trades.plot()
            ```

            ![](/vectorbt/docs/img/events.png)"""
        if self.wrapper.ndim > 1:
            raise TypeError("You must select a column first")

        # Plot main price
        fig = self.main_price.vbt.plot(trace_kwargs=main_price_trace_kwargs,
                                       fig=fig,
                                       **layout_kwargs)

        # Extract information
        size = self.records_arr['size']
        entry_idx = self.records_arr['entry_idx']
        entry_price = self.records_arr['entry_price']
        entry_fees = self.records_arr['entry_fees']
        exit_idx = self.records_arr['exit_idx']
        exit_price = self.records_arr['exit_price']
        exit_fees = self.records_arr['exit_fees']
        pnl = self.records_arr['pnl']
        ret = self.records_arr['return']
        status = self.records_arr['status']

        def get_duration_str(from_idx, to_idx):
            if isinstance(self.wrapper.index, DatetimeTypes):
                duration = self.wrapper.index[to_idx] - self.wrapper.index[
                    from_idx]
            elif self.wrapper.freq is not None:
                duration = self.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)

        # Plot Entry markers
        entry_customdata = np.stack((size, entry_fees), axis=1)
        entry_scatter = go.Scatter(
            x=self.wrapper.index[entry_idx],
            y=entry_price,
            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='Entry',
            customdata=entry_customdata,
            hovertemplate=
            "%{x}<br>Price: %{y}<br>Size: %{customdata[0]:.4f}<br>Fees: %{customdata[1]:.2f}"
        )
        entry_scatter.update(**entry_trace_kwargs)
        fig.add_trace(entry_scatter)

        # Plot end markers
        def plot_end_markers(mask, name, color, kwargs):
            customdata = np.stack((size[mask], exit_fees[mask], pnl[mask],
                                   ret[mask], duration[mask]),
                                  axis=1)
            scatter = go.Scatter(x=self.wrapper.index[exit_idx[mask]],
                                 y=exit_price[mask],
                                 mode='markers',
                                 marker=dict(
                                     symbol='circle',
                                     color=color,
                                     size=7,
                                     line=dict(width=1,
                                               color=adjust_lightness(color))),
                                 name=name,
                                 customdata=customdata,
                                 hovertemplate="%{x}<br>Price: %{y}" +
                                 "<br>Size: %{customdata[0]:.4f}" +
                                 "<br>Fees: %{customdata[1]:.2f}" +
                                 "<br>PnL: %{customdata[2]:.2f}" +
                                 "<br>Return: %{customdata[3]:.2%}" +
                                 "<br>Duration: %{customdata[4]}")
            scatter.update(**kwargs)
            fig.add_trace(scatter)

        # Plot Exit markers
        plot_end_markers((status == EventStatus.Closed) & (pnl == 0.), 'Exit',
                         contrast_color_schema['gray'], exit_trace_kwargs)

        # Plot Exit - Profit markers
        plot_end_markers((status == EventStatus.Closed) & (pnl > 0.),
                         'Exit - Profit', contrast_color_schema['green'],
                         exit_profit_trace_kwargs)

        # Plot Exit - Loss markers
        plot_end_markers((status == EventStatus.Closed) & (pnl < 0.),
                         'Exit - Loss', contrast_color_schema['red'],
                         exit_loss_trace_kwargs)

        # Plot Active markers
        plot_end_markers(status == EventStatus.Open, 'Active',
                         contrast_color_schema['orange'], active_trace_kwargs)

        # Plot profit zones
        profit_mask = pnl > 0.
        for i in np.flatnonzero(profit_mask):
            fig.add_shape(**merge_kwargs(
                dict(
                    type="rect",
                    xref="x",
                    yref="y",
                    x0=self.wrapper.index[entry_idx[i]],
                    y0=entry_price[i],
                    x1=self.wrapper.index[exit_idx[i]],
                    y1=exit_price[i],
                    fillcolor='green',
                    opacity=0.15,
                    layer="below",
                    line_width=0,
                ), profit_shape_kwargs))

        # Plot loss zones
        loss_mask = pnl < 0.
        for i in np.flatnonzero(loss_mask):
            fig.add_shape(**merge_kwargs(
                dict(
                    type="rect",
                    xref="x",
                    yref="y",
                    x0=self.wrapper.index[entry_idx[i]],
                    y0=entry_price[i],
                    x1=self.wrapper.index[exit_idx[i]],
                    y1=exit_price[i],
                    fillcolor='red',
                    opacity=0.15,
                    layer="below",
                    line_width=0,
                ), loss_shape_kwargs))

        return fig
コード例 #16
0
ファイル: accessors.py プロジェクト: jzay/vectorbt
    def plot_as_markers(self, y=None, name=None, trace_kwargs=None, row=None, col=None,
                        fig=None, **layout_kwargs):  # pragma: no cover
        """Plot Series as markers.

        Args:
            y (array_like): Y-axis values to plot markers on.

                !!! note
                    Doesn't plot `y`.

            name (str): Name of the signals.
            trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`.
            row (int): Row position.
            col (int): Column position.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> ts = pd.Series([1, 2, 3, 2, 1], index=sig.index)
        >>> fig = ts.vbt.plot()
        >>> sig['b'].vbt.signals.plot_as_entry_markers(y=ts, fig=fig)
        >>> (~sig['b']).vbt.signals.plot_as_exit_markers(y=ts, fig=fig)
        ```

        ![](/vectorbt/docs/img/signals_plot_as_markers.png)
        """
        from vectorbt.settings import contrast_color_schema

        if trace_kwargs is None:
            trace_kwargs = {}

        if fig is None:
            fig = CustomFigureWidget()
        fig.update_layout(**layout_kwargs)
        if name is None:
            if 'name' in trace_kwargs:
                name = trace_kwargs.pop('name')
            else:
                name = self._obj.name
        if name is not None:
            name = str(name)

        # Plot markers
        _y = 1 if y is None else y
        scatter = go.Scatter(
            x=self.wrapper.index,
            y=np.where(self._obj, _y, np.nan),
            mode='markers',
            marker=dict(
                symbol='circle',
                color=contrast_color_schema['blue'],
                size=7,
                line=dict(
                    width=1,
                    color=adjust_lightness(contrast_color_schema['blue'])
                )
            ),
            name=name,
            showlegend=name is not None
        )
        scatter.update(**trace_kwargs)
        fig.add_trace(scatter, row=row, col=col)
        return fig
コード例 #17
0
ファイル: ranges.py プロジェクト: vroomzel/vectorbt
    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
コード例 #18
0
    def plot(self,
             ts_trace_kwargs={},
             peak_trace_kwargs={},
             valley_trace_kwargs={},
             recovery_trace_kwargs={},
             active_trace_kwargs={},
             ptv_shape_kwargs={},
             vtr_shape_kwargs={},
             active_shape_kwargs={},
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot drawdowns over `Drawdowns.ts`.

        Args:
            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.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.
        Example:
            ```py
            import vectorbt as vbt
            import pandas as pd

            ts = pd.Series([1, 2, 1, 2, 3, 2, 1, 2])
            vbt.records.Drawdowns.from_ts(ts, freq='1 days').plot()
            ```

            ![](/vectorbt/docs/img/drawdowns.png)"""
        if self.wrapper.ndim > 1:
            raise TypeError("You must select a column first")

        fig = self.ts.vbt.plot(trace_kwargs=ts_trace_kwargs, fig=fig, **layout_kwargs)

        if self.records_arr.shape[0] == 0:
            return fig

        # Extract information
        start_idx = self.records_arr['start_idx']
        valley_idx = self.records_arr['valley_idx']
        end_idx = self.records_arr['end_idx']
        status = self.records_arr['status']

        start_val = self.ts.values[start_idx]
        valley_val = self.ts.values[valley_idx]
        end_val = self.ts.values[end_idx]

        def get_duration_str(from_idx, to_idx):
            if isinstance(self.wrapper.index, DatetimeTypes):
                duration = self.wrapper.index[to_idx] - self.wrapper.index[from_idx]
            elif self.wrapper.freq is not None:
                duration = self.wrapper.to_time_units(to_idx - from_idx)
            else:
                duration = to_idx - from_idx
            return np.vectorize(str)(duration)

        # Plot peak markers and zones
        peak_mask = start_idx != np.roll(end_idx, 1)  # peak and recovery at same time -> recovery wins
        peak_scatter = go.Scatter(
            x=self.ts.index[start_idx[peak_mask]],
            y=start_val[peak_mask],
            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='Peak'
        )
        peak_scatter.update(**peak_trace_kwargs)
        fig.add_trace(peak_scatter)

        recovery_mask = status == DrawdownStatus.Recovered
        if np.any(recovery_mask):
            # Plot valley markers and zones
            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((valley_drawdown, valley_duration), axis=1)
            valley_scatter = go.Scatter(
                x=self.ts.index[valley_idx[recovery_mask]],
                y=valley_val[recovery_mask],
                mode='markers',
                marker=dict(
                    symbol='circle',
                    color=contrast_color_schema['red'],
                    size=7,
                    line=dict(
                        width=1,
                        color=adjust_lightness(contrast_color_schema['red'])
                    )
                ),
                name='Valley',
                customdata=valley_customdata,
                hovertemplate="(%{x}, %{y})<br>Drawdown: %{customdata[0]:.2%}<br>Duration: %{customdata[1]}"
            )
            valley_scatter.update(**valley_trace_kwargs)
            fig.add_trace(valley_scatter)

            for i in np.flatnonzero(recovery_mask):
                fig.add_shape(**merge_kwargs(dict(
                    type="rect",
                    xref="x",
                    yref="paper",
                    x0=self.ts.index[start_idx[i]],
                    y0=0,
                    x1=self.ts.index[valley_idx[i]],
                    y1=1,
                    fillcolor='red',
                    opacity=0.15,
                    layer="below",
                    line_width=0,
                ), ptv_shape_kwargs))

            # Plot recovery markers and zones
            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((recovery_return, recovery_duration), axis=1)
            recovery_scatter = go.Scatter(
                x=self.ts.index[end_idx[recovery_mask]],
                y=end_val[recovery_mask],
                mode='markers',
                marker=dict(
                    symbol='circle',
                    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="(%{x}, %{y})<br>Return: %{customdata[0]:.2%}<br>Duration: %{customdata[1]}"
            )
            recovery_scatter.update(**recovery_trace_kwargs)
            fig.add_trace(recovery_scatter)

            for i in np.flatnonzero(recovery_mask):
                fig.add_shape(**merge_kwargs(dict(
                    type="rect",
                    xref="x",
                    yref="paper",
                    x0=self.ts.index[valley_idx[i]],
                    y0=0,
                    x1=self.ts.index[end_idx[i]],
                    y1=1,
                    fillcolor='green',
                    opacity=0.15,
                    layer="below",
                    line_width=0,
                ), vtr_shape_kwargs))

        # Plot active markers and zones
        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((active_drawdown, active_duration), axis=1)
            active_scatter = go.Scatter(
                x=self.ts.index[end_idx[active_mask]],
                y=end_val[active_mask],
                mode='markers',
                marker=dict(
                    symbol='circle',
                    color=contrast_color_schema['orange'],
                    size=7,
                    line=dict(
                        width=1,
                        color=adjust_lightness(contrast_color_schema['orange'])
                    )
                ),
                name='Active',
                customdata=active_customdata,
                hovertemplate="(%{x}, %{y})<br>Drawdown: %{customdata[0]:.2%}<br>Duration: %{customdata[1]}"
            )
            active_scatter.update(**active_trace_kwargs)
            fig.add_trace(active_scatter)

            for i in np.flatnonzero(active_mask):
                fig.add_shape(**merge_kwargs(dict(
                    type="rect",
                    xref="x",
                    yref="paper",
                    x0=self.ts.index[start_idx[i]],
                    y0=0,
                    x1=self.ts.index[end_idx[i]],
                    y1=1,
                    fillcolor='orange',
                    opacity=0.15,
                    layer="below",
                    line_width=0,
                ), active_shape_kwargs))

        return fig
コード例 #19
0
ファイル: trades.py プロジェクト: barnjamin/vectorbt
    def plot(self,
             column=None,
             plot_close=True,
             plot_zones=True,
             close_trace_kwargs=None,
             entry_trace_kwargs=None,
             exit_trace_kwargs=None,
             exit_profit_trace_kwargs=None,
             exit_loss_trace_kwargs=None,
             active_trace_kwargs=None,
             profit_shape_kwargs=None,
             loss_shape_kwargs=None,
             row=None, col=None,
             xref='x', yref='y',
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot orders.

        Args:
            column (str): Name of the column to plot.
            plot_close (bool): Whether to plot `Trades.close`.
            plot_zones (bool): Whether to plot zones.

                Set to False if there are many trades within one position.
            close_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `Trades.close`.
            entry_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Entry" markers.
            exit_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Exit" markers.
            exit_profit_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Exit - Profit" markers.
            exit_loss_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Exit - Loss" markers.
            active_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Active" markers.
            profit_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for profit zones.
            loss_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for loss zones.
            row (int): Row position.
            col (int): Column position.
            xref (str): X coordinate axis.
            yref (str): Y coordinate axis.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> trades.plot()
        ```

        ![](/vectorbt/docs/img/trades_plot.png)"""
        from vectorbt.settings import color_schema, contrast_color_schema

        self_col = self.select_series(column=column, group_by=False)

        if close_trace_kwargs is None:
            close_trace_kwargs = {}
        close_trace_kwargs = merge_dicts(dict(
            line_color=color_schema['blue'],
            name='Close' if self_col.wrapper.name is None else self_col.wrapper.name
        ), close_trace_kwargs)
        if entry_trace_kwargs is None:
            entry_trace_kwargs = {}
        if exit_trace_kwargs is None:
            exit_trace_kwargs = {}
        if exit_profit_trace_kwargs is None:
            exit_profit_trace_kwargs = {}
        if exit_loss_trace_kwargs is None:
            exit_loss_trace_kwargs = {}
        if active_trace_kwargs is None:
            active_trace_kwargs = {}
        if profit_shape_kwargs is None:
            profit_shape_kwargs = {}
        if loss_shape_kwargs is None:
            loss_shape_kwargs = {}

        if fig is None:
            fig = CustomFigureWidget()
        fig.update_layout(**layout_kwargs)

        # Plot close
        if plot_close:
            fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs, row=row, col=col, fig=fig)

        if len(self_col.values) > 0:
            # Extract information
            _id = self_col.values['id']
            _id_str = 'Trade Id' if self.trade_type == TradeType.Trade else 'Position Id'
            size = self_col.values['size']
            entry_idx = self_col.values['entry_idx']
            entry_price = self_col.values['entry_price']
            entry_fees = self_col.values['entry_fees']
            exit_idx = self_col.values['exit_idx']
            exit_price = self_col.values['exit_price']
            exit_fees = self_col.values['exit_fees']
            pnl = self_col.values['pnl']
            ret = self_col.values['return']
            direction_value_map = to_value_map(TradeDirection)
            direction = self_col.values['direction']
            direction = np.vectorize(lambda x: str(direction_value_map[x]))(direction)
            status = self_col.values['status']

            def get_duration_str(from_idx, to_idx):
                if isinstance(self_col.wrapper.index, DatetimeTypes):
                    duration = self_col.wrapper.index[to_idx] - self_col.wrapper.index[from_idx]
                elif self_col.wrapper.freq is not None:
                    duration = self_col.wrapper.to_time_units(to_idx - from_idx)
                else:
                    duration = to_idx - from_idx
                return np.vectorize(str)(duration)

            duration = get_duration_str(entry_idx, exit_idx)

            if len(entry_idx) > 0:
                # Plot Entry markers
                entry_customdata = np.stack((
                    _id,
                    size,
                    entry_fees,
                    direction,
                    *((self_col.values['position_id'],)
                      if self.trade_type == TradeType.Trade else ())
                ), axis=1)
                entry_scatter = go.Scatter(
                    x=self_col.wrapper.index[entry_idx],
                    y=entry_price,
                    mode='markers',
                    marker=dict(
                        symbol='square',
                        color=contrast_color_schema['blue'],
                        size=7,
                        line=dict(
                            width=1,
                            color=adjust_lightness(contrast_color_schema['blue'])
                        )
                    ),
                    name='Entry',
                    customdata=entry_customdata,
                    hovertemplate=_id_str + ": %{customdata[0]}"
                                            "<br>Date: %{x}"
                                            "<br>Avg. Price: %{y}"
                                            "<br>Size: %{customdata[1]:.6f}"
                                            "<br>Fees: %{customdata[2]:.6f}"
                                            "<br>Direction: %{customdata[3]}"
                                  + ("<br>Position Id: %{customdata[4]}"
                                     if self.trade_type == TradeType.Trade else '')
                )
                entry_scatter.update(**entry_trace_kwargs)
                fig.add_trace(entry_scatter, row=row, col=col)

            # Plot end markers
            def _plot_end_markers(mask, name, color, kwargs):
                if np.any(mask):
                    customdata = np.stack((
                        _id[mask],
                        duration[mask],
                        size[mask],
                        exit_fees[mask],
                        pnl[mask],
                        ret[mask],
                        direction[mask],
                        *((self_col.values['position_id'][mask],)
                          if self.trade_type == TradeType.Trade else ())
                    ), axis=1)
                    scatter = go.Scatter(
                        x=self_col.wrapper.index[exit_idx[mask]],
                        y=exit_price[mask],
                        mode='markers',
                        marker=dict(
                            symbol='square',
                            color=color,
                            size=7,
                            line=dict(
                                width=1,
                                color=adjust_lightness(color)
                            )
                        ),
                        name=name,
                        customdata=customdata,
                        hovertemplate=_id_str + ": %{customdata[0]}"
                                                "<br>Date: %{x}"
                                                "<br>Duration: %{customdata[1]}"
                                                "<br>Avg. Price: %{y}"
                                                "<br>Size: %{customdata[2]:.6f}"
                                                "<br>Fees: %{customdata[3]:.6f}"
                                                "<br>PnL: %{customdata[4]:.6f}"
                                                "<br>Return: %{customdata[5]:.2%}"
                                                "<br>Direction: %{customdata[6]}"
                                      + ("<br>Position Id: %{customdata[7]}"
                                         if self.trade_type == TradeType.Trade else '')
                    )
                    scatter.update(**kwargs)
                    fig.add_trace(scatter, row=row, col=col)

            # Plot Exit markers
            _plot_end_markers(
                (status == TradeStatus.Closed) & (pnl == 0.),
                'Exit',
                contrast_color_schema['gray'],
                exit_trace_kwargs
            )

            # Plot Exit - Profit markers
            _plot_end_markers(
                (status == TradeStatus.Closed) & (pnl > 0.),
                'Exit - Profit',
                contrast_color_schema['green'],
                exit_profit_trace_kwargs
            )

            # Plot Exit - Loss markers
            _plot_end_markers(
                (status == TradeStatus.Closed) & (pnl < 0.),
                'Exit - Loss',
                contrast_color_schema['red'],
                exit_loss_trace_kwargs
            )

            # Plot Active markers
            _plot_end_markers(
                status == TradeStatus.Open,
                'Active',
                contrast_color_schema['orange'],
                active_trace_kwargs
            )

            if plot_zones:
                profit_mask = pnl > 0.
                if np.any(profit_mask):
                    # Plot profit zones
                    for i in np.flatnonzero(profit_mask):
                        fig.add_shape(**merge_dicts(dict(
                            type="rect",
                            xref=xref,
                            yref=yref,
                            x0=self_col.wrapper.index[entry_idx[i]],
                            y0=entry_price[i],
                            x1=self_col.wrapper.index[exit_idx[i]],
                            y1=exit_price[i],
                            fillcolor='green',
                            opacity=0.2,
                            layer="below",
                            line_width=0,
                        ), profit_shape_kwargs))

                loss_mask = pnl < 0.
                if np.any(loss_mask):
                    # Plot loss zones
                    for i in np.flatnonzero(loss_mask):
                        fig.add_shape(**merge_dicts(dict(
                            type="rect",
                            xref=xref,
                            yref=yref,
                            x0=self_col.wrapper.index[entry_idx[i]],
                            y0=entry_price[i],
                            x1=self_col.wrapper.index[exit_idx[i]],
                            y1=exit_price[i],
                            fillcolor='red',
                            opacity=0.2,
                            layer="below",
                            line_width=0,
                        ), loss_shape_kwargs))

        return fig
コード例 #20
0
ファイル: trades.py プロジェクト: barnjamin/vectorbt
    def plot_pnl(self,
                 column=None,
                 marker_size_range=[7, 14],
                 opacity_range=[0.75, 0.9],
                 closed_profit_trace_kwargs=None,
                 closed_loss_trace_kwargs=None,
                 open_trace_kwargs=None,
                 hline_shape_kwargs=None,
                 row=None, col=None,
                 xref='x', yref='y',
                 fig=None,
                 **layout_kwargs):  # pragma: no cover
        """Plot trade PnL.

        Args:
            column (str): Name of the column to plot.
            closed_profit_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Closed - Profit" markers.
            closed_loss_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Closed - Loss" markers.
            open_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Open" markers.
            hline_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for zeroline.
            row (int): Row position.
            col (int): Column position.
            xref (str): X coordinate axis.
            yref (str): Y coordinate axis.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> trades.plot_pnl()
        ```

        ![](/vectorbt/docs/img/trades_plot_pnl.png)
        """
        from vectorbt.settings import contrast_color_schema

        self_col = self.select_series(column=column, group_by=False)


        if closed_profit_trace_kwargs is None:
            closed_profit_trace_kwargs = {}
        if closed_loss_trace_kwargs is None:
            closed_loss_trace_kwargs = {}
        if open_trace_kwargs is None:
            open_trace_kwargs = {}
        if hline_shape_kwargs is None:
            hline_shape_kwargs = {}
        marker_size_range = tuple(marker_size_range)

        if fig is None:
            fig = CustomFigureWidget()
        fig.update_layout(**layout_kwargs)
        x_domain = [0, 1]
        xaxis = 'xaxis' + xref[1:]
        if xaxis in fig.layout:
            if 'domain' in fig.layout[xaxis]:
                if fig.layout[xaxis]['domain'] is not None:
                    x_domain = fig.layout[xaxis]['domain']

        if len(self_col.values) > 0:
            # Extract information
            _id = self.values['id']
            _id_str = 'Trade Id' if self.trade_type == TradeType.Trade else 'Position Id'
            exit_idx = self.values['exit_idx']
            pnl = self.values['pnl']
            returns = self.values['return']
            status = self.values['status']

            neutral_mask = pnl == 0
            profit_mask = pnl > 0
            loss_mask = pnl < 0

            marker_size = min_rel_rescale(np.abs(returns), marker_size_range)
            opacity = max_rel_rescale(np.abs(returns), opacity_range)

            open_mask = status == TradeStatus.Open
            closed_profit_mask = (~open_mask) & profit_mask
            closed_loss_mask = (~open_mask) & loss_mask
            open_mask &= ~neutral_mask

            if np.any(closed_profit_mask):
                # Plot Profit markers
                profit_scatter = go.Scatter(
                    x=self_col.wrapper.index[exit_idx[closed_profit_mask]],
                    y=pnl[closed_profit_mask],
                    mode='markers',
                    marker=dict(
                        symbol='circle',
                        color=contrast_color_schema['green'],
                        size=marker_size[closed_profit_mask],
                        opacity=opacity[closed_profit_mask],
                        line=dict(
                            width=1,
                            color=adjust_lightness(contrast_color_schema['green'])
                        ),
                    ),
                    name='Closed - Profit',
                    customdata=np.stack((_id[closed_profit_mask], returns[closed_profit_mask]), axis=1),
                    hovertemplate=_id_str + ": %{customdata[0]}"
                                            "<br>Date: %{x}"
                                            "<br>PnL: %{y}"
                                            "<br>Return: %{customdata[1]:.2%}"
                )
                profit_scatter.update(**closed_profit_trace_kwargs)
                fig.add_trace(profit_scatter, row=row, col=col)

            if np.any(closed_loss_mask):
                # Plot Loss markers
                loss_scatter = go.Scatter(
                    x=self_col.wrapper.index[exit_idx[closed_loss_mask]],
                    y=pnl[closed_loss_mask],
                    mode='markers',
                    marker=dict(
                        symbol='circle',
                        color=contrast_color_schema['red'],
                        size=marker_size[closed_loss_mask],
                        opacity=opacity[closed_loss_mask],
                        line=dict(
                            width=1,
                            color=adjust_lightness(contrast_color_schema['red'])
                        )
                    ),
                    name='Closed - Loss',
                    customdata=np.stack((_id[closed_loss_mask], returns[closed_loss_mask]), axis=1),
                    hovertemplate=_id_str + ": %{customdata[0]}"
                                            "<br>Date: %{x}"
                                            "<br>PnL: %{y}"
                                            "<br>Return: %{customdata[1]:.2%}"
                )
                loss_scatter.update(**closed_loss_trace_kwargs)
                fig.add_trace(loss_scatter, row=row, col=col)

            if np.any(open_mask):
                # Plot Active markers
                active_scatter = go.Scatter(
                    x=self_col.wrapper.index[exit_idx[open_mask]],
                    y=pnl[open_mask],
                    mode='markers',
                    marker=dict(
                        symbol='circle',
                        color=contrast_color_schema['orange'],
                        size=marker_size[open_mask],
                        opacity=opacity[open_mask],
                        line=dict(
                            width=1,
                            color=adjust_lightness(contrast_color_schema['orange'])
                        )
                    ),
                    name='Open',
                    customdata=np.stack((_id[open_mask], returns[open_mask]), axis=1),
                    hovertemplate=_id_str + ": %{customdata[0]}"
                                            "<br>Date: %{x}"
                                            "<br>PnL: %{y}"
                                            "<br>Return: %{customdata[1]:.2%}"
                )
                active_scatter.update(**open_trace_kwargs)
                fig.add_trace(active_scatter, row=row, col=col)

        # Plot zeroline
        fig.add_shape(**merge_dicts(dict(
            type='line',
            xref="paper",
            yref=yref,
            x0=x_domain[0],
            y0=0,
            x1=x_domain[1],
            y1=0,
            line=dict(
                color="gray",
                dash="dash",
            )
        ), hline_shape_kwargs))
        return fig
コード例 #21
0
ファイル: orders.py プロジェクト: varnittewari/vectorbt
    def plot(self,
             column=None,
             ref_price_trace_kwargs=None,
             buy_trace_kwargs=None,
             sell_trace_kwargs=None,
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot orders.

        Args:
            column (str): Name of the column to plot.
            ref_price_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for main price.
            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.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.
        Example:
            ```py
            portfolio.orders.plot()
            ```

            ![](/vectorbt/docs/img/orders.png)"""
        if column is not None:
            if self.wrapper.grouper.group_by is None:
                self_col = self[column]
            else:
                self_col = self.copy(wrapper=self.wrapper.copy(group_by=None))[column]
        else:
            self_col = self
        if self_col.wrapper.ndim > 1:
            raise TypeError("Select a column first. Use indexing or column argument.")

        if ref_price_trace_kwargs is None:
            ref_price_trace_kwargs = {}
        if buy_trace_kwargs is None:
            buy_trace_kwargs = {}
        if sell_trace_kwargs is None:
            sell_trace_kwargs = {}

        # Plot main price
        fig = self_col.close.vbt.plot(trace_kwargs=ref_price_trace_kwargs, fig=fig, **layout_kwargs)

        # Extract information
        idx = self_col.records_arr['idx']
        size = self_col.records_arr['size']
        price = self_col.records_arr['price']
        fees = self_col.records_arr['fees']
        side = self_col.records_arr['side']

        # Plot Buy markers
        buy_mask = side == OrderSide.Buy
        buy_customdata = np.stack((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='circle',
                color=contrast_color_schema['green'],
                size=7,
                line=dict(
                    width=1,
                    color=adjust_lightness(contrast_color_schema['green'])
                )
            ),
            name='Buy',
            customdata=buy_customdata,
            hovertemplate="%{x}<br>Price: %{y}<br>Size: %{customdata[0]:.4f}<br>Fees: %{customdata[1]:.4f}"
        )
        buy_scatter.update(**buy_trace_kwargs)
        fig.add_trace(buy_scatter)

        # Plot Sell markers
        sell_mask = side == OrderSide.Sell
        sell_customdata = np.stack((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='circle',
                color=contrast_color_schema['orange'],
                size=7,
                line=dict(
                    width=1,
                    color=adjust_lightness(contrast_color_schema['orange'])
                )
            ),
            name='Sell',
            customdata=sell_customdata,
            hovertemplate="%{x}<br>Price: %{y}<br>Size: %{customdata[0]:.4f}<br>Fees: %{customdata[1]:.4f}"
        )
        sell_scatter.update(**sell_trace_kwargs)
        fig.add_trace(sell_scatter)

        return fig
コード例 #22
0
ファイル: drawdowns.py プロジェクト: sumystic/vectorbt
    def plot(self,
             column=None,
             top_n=5,
             plot_ts=True,
             plot_zones=True,
             ts_trace_kwargs=None,
             peak_trace_kwargs=None,
             valley_trace_kwargs=None,
             recovery_trace_kwargs=None,
             active_trace_kwargs=None,
             ptv_shape_kwargs=None,
             vtr_shape_kwargs=None,
             active_shape_kwargs=None,
             row=None,
             col=None,
             xref='x',
             yref='y',
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot drawdowns over `Drawdowns.ts`.

        Args:
            column (str): Name of the column to plot.
            top_n (int): Filter top N drawdown records by maximum drawdown.
            plot_ts (bool): Whether to plot time series.
            plot_zones (bool): Whether to plot zones.
            ts_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for time series.
            peak_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for peak values.
            valley_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for valley values.
            recovery_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for recovery values.
            active_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for active recovery values.
            ptv_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for PtV zones.
            vtr_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for VtR zones.
            active_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for active VtR zones.
            row (int): Row position.
            col (int): Column position.
            xref (str): X coordinate axis.
            yref (str): Y coordinate axis.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> import vectorbt as vbt
        >>> import pandas as pd

        >>> ts = pd.Series([1, 2, 1, 2, 3, 2, 1, 2])
        >>> vbt.Drawdowns.from_ts(ts, freq='1 days').plot()
        ```

        ![](/vectorbt/docs/img/drawdowns_plot.png)
        """
        from vectorbt.settings import color_schema, contrast_color_schema

        self_col = self.select_series(column=column, group_by=False)
        if top_n is not None:
            # Drawdowns is negative, thus top_n becomes bottom_n
            self_col = self_col.filter_by_mask(
                self_col.drawdown.bottom_n_mask(top_n))

        if ts_trace_kwargs is None:
            ts_trace_kwargs = {}
        ts_trace_kwargs = merge_dicts(dict(line_color=color_schema['blue']),
                                      ts_trace_kwargs)
        if peak_trace_kwargs is None:
            peak_trace_kwargs = {}
        if valley_trace_kwargs is None:
            valley_trace_kwargs = {}
        if recovery_trace_kwargs is None:
            recovery_trace_kwargs = {}
        if active_trace_kwargs is None:
            active_trace_kwargs = {}
        if ptv_shape_kwargs is None:
            ptv_shape_kwargs = {}
        if vtr_shape_kwargs is None:
            vtr_shape_kwargs = {}
        if active_shape_kwargs is None:
            active_shape_kwargs = {}

        if fig is None:
            fig = CustomFigureWidget()
        fig.update_layout(**layout_kwargs)
        y_domain = [0, 1]
        yaxis = 'yaxis' + yref[1:]
        if yaxis in fig.layout:
            if 'domain' in fig.layout[yaxis]:
                if fig.layout[yaxis]['domain'] is not None:
                    y_domain = fig.layout[yaxis]['domain']

        if plot_ts:
            fig = self_col.ts.vbt.plot(trace_kwargs=ts_trace_kwargs,
                                       row=row,
                                       col=col,
                                       fig=fig)

        if len(self_col.values) > 0:
            # Extract information
            _id = self_col.values['id']
            start_idx = self_col.values['start_idx']
            valley_idx = self_col.values['valley_idx']
            end_idx = self_col.values['end_idx']
            status = self_col.values['status']

            start_val = self_col.ts.values[start_idx]
            valley_val = self_col.ts.values[valley_idx]
            end_val = self_col.ts.values[end_idx]

            def get_duration_str(from_idx, to_idx):
                if isinstance(self_col.wrapper.index, DatetimeTypes):
                    duration = self_col.wrapper.index[
                        to_idx] - self_col.wrapper.index[from_idx]
                elif self_col.wrapper.freq is not None:
                    duration = self_col.wrapper.to_time_units(to_idx -
                                                              from_idx)
                else:
                    duration = to_idx - from_idx
                return np.vectorize(str)(duration)

            # Plot peak markers
            peak_mask = start_idx != np.roll(
                end_idx, 1)  # peak and recovery at same time -> recovery wins
            if np.any(peak_mask):
                peak_customdata = _id[peak_mask][:, None]
                peak_scatter = go.Scatter(
                    x=self_col.ts.index[start_idx[peak_mask]],
                    y=start_val[peak_mask],
                    mode='markers',
                    marker=dict(symbol='diamond',
                                color=contrast_color_schema['blue'],
                                size=7,
                                line=dict(width=1,
                                          color=adjust_lightness(
                                              contrast_color_schema['blue']))),
                    name='Peak',
                    customdata=peak_customdata,
                    hovertemplate="Drawdown Id: %{customdata[0]}"
                    "<br>Date: %{x}"
                    "<br>Price: %{y}")
                peak_scatter.update(**peak_trace_kwargs)
                fig.add_trace(peak_scatter, row=row, col=col)

            recovery_mask = status == DrawdownStatus.Recovered
            if np.any(recovery_mask):
                # Plot valley markers
                valley_drawdown = (
                    valley_val[recovery_mask] -
                    start_val[recovery_mask]) / start_val[recovery_mask]
                valley_duration = get_duration_str(start_idx[recovery_mask],
                                                   valley_idx[recovery_mask])
                valley_customdata = np.stack(
                    (_id[recovery_mask], valley_drawdown, valley_duration),
                    axis=1)
                valley_scatter = go.Scatter(
                    x=self_col.ts.index[valley_idx[recovery_mask]],
                    y=valley_val[recovery_mask],
                    mode='markers',
                    marker=dict(symbol='diamond',
                                color=contrast_color_schema['red'],
                                size=7,
                                line=dict(width=1,
                                          color=adjust_lightness(
                                              contrast_color_schema['red']))),
                    name='Valley',
                    customdata=valley_customdata,
                    hovertemplate="Drawdown Id: %{customdata[0]}"
                    "<br>Date: %{x}"
                    "<br>Price: %{y}"
                    "<br>Drawdown: %{customdata[1]:.2%}"
                    "<br>Duration: %{customdata[2]}")
                valley_scatter.update(**valley_trace_kwargs)
                fig.add_trace(valley_scatter, row=row, col=col)

                if plot_zones:
                    # Plot drawdown zones
                    for i in np.flatnonzero(recovery_mask):
                        fig.add_shape(**merge_dicts(
                            dict(
                                type="rect",
                                xref=xref,
                                yref="paper",
                                x0=self_col.ts.index[start_idx[i]],
                                y0=y_domain[0],
                                x1=self_col.ts.index[valley_idx[i]],
                                y1=y_domain[1],
                                fillcolor='red',
                                opacity=0.2,
                                layer="below",
                                line_width=0,
                            ), ptv_shape_kwargs))

                # Plot recovery markers
                recovery_return = (
                    end_val[recovery_mask] -
                    valley_val[recovery_mask]) / valley_val[recovery_mask]
                recovery_duration = get_duration_str(valley_idx[recovery_mask],
                                                     end_idx[recovery_mask])
                recovery_customdata = np.stack(
                    (_id[recovery_mask], recovery_return, recovery_duration),
                    axis=1)
                recovery_scatter = go.Scatter(
                    x=self_col.ts.index[end_idx[recovery_mask]],
                    y=end_val[recovery_mask],
                    mode='markers',
                    marker=dict(symbol='diamond',
                                color=contrast_color_schema['green'],
                                size=7,
                                line=dict(
                                    width=1,
                                    color=adjust_lightness(
                                        contrast_color_schema['green']))),
                    name='Recovery/Peak',
                    customdata=recovery_customdata,
                    hovertemplate="Drawdown Id: %{customdata[0]}"
                    "<br>Date: %{x}"
                    "<br>Price: %{y}"
                    "<br>Return: %{customdata[1]:.2%}"
                    "<br>Duration: %{customdata[2]}")
                recovery_scatter.update(**recovery_trace_kwargs)
                fig.add_trace(recovery_scatter, row=row, col=col)

                if plot_zones:
                    # Plot recovery zones
                    for i in np.flatnonzero(recovery_mask):
                        fig.add_shape(**merge_dicts(
                            dict(
                                type="rect",
                                xref=xref,
                                yref="paper",
                                x0=self_col.ts.index[valley_idx[i]],
                                y0=y_domain[0],
                                x1=self_col.ts.index[end_idx[i]],
                                y1=y_domain[1],
                                fillcolor='green',
                                opacity=0.2,
                                layer="below",
                                line_width=0,
                            ), vtr_shape_kwargs))

            # Plot active markers
            active_mask = ~recovery_mask
            if np.any(active_mask):
                active_drawdown = (
                    valley_val[active_mask] -
                    start_val[active_mask]) / start_val[active_mask]
                active_duration = get_duration_str(valley_idx[active_mask],
                                                   end_idx[active_mask])
                active_customdata = np.stack(
                    (_id[active_mask], active_drawdown, active_duration),
                    axis=1)
                active_scatter = go.Scatter(
                    x=self_col.ts.index[end_idx[active_mask]],
                    y=end_val[active_mask],
                    mode='markers',
                    marker=dict(symbol='diamond',
                                color=contrast_color_schema['orange'],
                                size=7,
                                line=dict(
                                    width=1,
                                    color=adjust_lightness(
                                        contrast_color_schema['orange']))),
                    name='Active',
                    customdata=active_customdata,
                    hovertemplate="Drawdown Id: %{customdata[0]}"
                    "<br>Date: %{x}"
                    "<br>Price: %{y}"
                    "<br>Drawdown: %{customdata[1]:.2%}"
                    "<br>Duration: %{customdata[2]}")
                active_scatter.update(**active_trace_kwargs)
                fig.add_trace(active_scatter, row=row, col=col)

                if plot_zones:
                    # Plot active drawdown zones
                    for i in np.flatnonzero(active_mask):
                        fig.add_shape(**merge_dicts(
                            dict(
                                type="rect",
                                xref=xref,
                                yref="paper",
                                x0=self_col.ts.index[start_idx[i]],
                                y0=y_domain[0],
                                x1=self_col.ts.index[end_idx[i]],
                                y1=y_domain[1],
                                fillcolor='orange',
                                opacity=0.2,
                                layer="below",
                                line_width=0,
                            ), active_shape_kwargs))

        return fig
コード例 #23
0
ファイル: orders.py プロジェクト: vroomzel/vectorbt
    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