Exemplo n.º 1
0
    def plot(self,
             name=None,
             trace_kwargs={},
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot Series as a line.

        Args:
            name (str): Name of the trace.
            trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.
        Example:
            ```py
            df['a'].vbt.plot()
            ```

            ![](/vectorbt/docs/img/sr_plot.png)"""
        if fig is None:
            fig = CustomFigureWidget()
        fig.update_layout(**layout_kwargs)
        if name is None:
            name = self._obj.name

        scatter = go.Scatter(x=self.index,
                             y=self._obj.values,
                             mode='lines',
                             name=str(name),
                             showlegend=name is not None)
        scatter.update(**trace_kwargs)
        fig.add_trace(scatter)

        return fig
Exemplo n.º 2
0
    def plot(self,
             column=None,
             plot_close=True,
             close_trace_kwargs=None,
             ma_trace_kwargs=None,
             row=None,
             col=None,
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot `MA.ma` against `MA.close`.

        Args:
            column (str): Name of the column to plot.
            plot_close (bool): Whether to plot `MA.close`.
            close_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MA.close`.
            ma_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MA.ma`.
            row (int): Row position.
            col (int): Column position.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> vbt.MA.run(price['Close'], 10).plot()
        ```

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

        self_col = self.select_series(column=column)

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

        if close_trace_kwargs is None:
            close_trace_kwargs = {}
        if ma_trace_kwargs is None:
            ma_trace_kwargs = {}
        close_trace_kwargs = merge_dicts(
            dict(name='Close', line_color=color_schema['blue']),
            close_trace_kwargs)
        ma_trace_kwargs = merge_dicts(dict(name='MA'), ma_trace_kwargs)

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

        return fig
Exemplo n.º 3
0
    def plot(self,
             name=None,
             trace_kwargs=None,
             row=None,
             col=None,
             yref='y',
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot Series as a line.

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

        ## Example

        ```python-repl
        >>> sig['a'].vbt.signals.plot()
        ```

        ![](/vectorbt/docs/img/signals_sr_plot.png)
        """
        if trace_kwargs is None:
            trace_kwargs = {}
        # Set up figure
        if fig is None:
            fig = CustomFigureWidget()
        default_layout = dict()
        default_layout['yaxis' + yref[1:]] = dict(tickmode='array',
                                                  tickvals=[0, 1],
                                                  ticktext=['false', 'true'])
        fig.update_layout(**default_layout)
        fig.update_layout(**layout_kwargs)
        if name is None:
            if 'name' in trace_kwargs:
                name = trace_kwargs.pop('name')
            else:
                name = self._obj.name
        if name is not None:
            name = str(name)

        scatter = go.Scatter(x=self.wrapper.index,
                             y=self._obj.values,
                             mode='lines',
                             name=name,
                             showlegend=name is not None)
        scatter.update(**trace_kwargs)
        fig.add_trace(scatter, row=row, col=col)

        return fig
Exemplo n.º 4
0
    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
Exemplo n.º 5
0
    def plot(self,
             column=None,
             tr_trace_kwargs=None,
             atr_trace_kwargs=None,
             row=None,
             col=None,
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot `ATR.tr` and `ATR.atr`.

        Args:
            column (str): Name of the column to plot.
            tr_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `ATR.tr`.
            atr_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `ATR.atr`.
            row (int): Row position.
            col (int): Column position.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> vbt.ATR.run(price['High'], price['Low'], price['Close'], 10).plot()
        ```

        ![](/vectorbt/docs/img/ATR.png)
        """
        self_col = self.select_series(column=column)

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

        if tr_trace_kwargs is None:
            tr_trace_kwargs = {}
        if atr_trace_kwargs is None:
            atr_trace_kwargs = {}
        tr_trace_kwargs = merge_dicts(dict(name='TR'), tr_trace_kwargs)
        atr_trace_kwargs = merge_dicts(dict(name='ATR'), atr_trace_kwargs)

        fig = self_col.tr.vbt.plot(trace_kwargs=tr_trace_kwargs,
                                   row=row,
                                   col=col,
                                   fig=fig)
        fig = self_col.atr.vbt.plot(trace_kwargs=atr_trace_kwargs,
                                    row=row,
                                    col=col,
                                    fig=fig)

        return fig
Exemplo n.º 6
0
def create_scatter(data=None, trace_names=None, x_labels=None,
                   trace_kwargs={}, fig=None, **layout_kwargs):
    """Create a scatter plot.

    Args:
        data (array_like): Data in any format that can be converted to NumPy.

            Must be of shape (`x_labels`, `trace_names`).
        trace_names (str or list of str): Trace names, corresponding to columns in pandas.
        x_labels (array_like): X-axis labels, corresponding to index in pandas.
        trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.
    Example:
        ```py
        import vectorbt as vbt

        vbt.plotting.create_scatter(
            data=[[1, 2], [3, 4]],
            trace_names=['a', 'b'],
            x_labels=['x', 'y']
        )
        ```
        ![](/vectorbt/docs/img/create_scatter.png)
        """
    if data is None:
        if trace_names is None:
            raise ValueError("At least trace_names must be passed")
    if trace_names is None:
        data = reshape_fns.to_2d(data)
        trace_names = [None] * data.shape[1]
    if isinstance(trace_names, str):
        trace_names = [trace_names]
    if fig is None:
        fig = CustomFigureWidget()
    fig.update_layout(**layout_kwargs)
    for i, trace_name in enumerate(trace_names):
        scatter = go.Scatter(
            x=x_labels,
            name=trace_name,
            showlegend=trace_name is not None
        )
        scatter.update(**(trace_kwargs[i] if isinstance(trace_kwargs, (list, tuple)) else trace_kwargs))
        fig.add_trace(scatter)

    if data is not None:
        trace_idx = np.arange(len(fig.data) - len(trace_names), len(fig.data))
        update_scatter_data(fig, data, trace_idx=trace_idx)
    return fig
Exemplo n.º 7
0
def create_hist(data=None, trace_names=None, horizontal=False,
                trace_kwargs={}, fig=None, **layout_kwargs):
    """Create a histogram plot.

    Args:
        data (array_like): Data in any format that can be converted to NumPy.

            Must be of shape (any, `trace_names`).
        trace_names (str or list of str): Trace names, corresponding to columns in pandas.
        horizontal (bool): Plot horizontally.
        trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Histogram`.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.
    Example:
        ```py
        import vectorbt as vbt

        vbt.plotting.create_hist(
            data=[[1, 2], [3, 4], [2, 1]],
            trace_names=['a', 'b']
        )
        ```
        ![](/vectorbt/docs/img/create_hist.png)
        """
    if data is None:
        if trace_names is None:
            raise ValueError("At least trace_names must be passed")
    if trace_names is None:
        data = reshape_fns.to_2d(data)
        trace_names = [None] * data.shape[1]
    if isinstance(trace_names, str):
        trace_names = [trace_names]
    if fig is None:
        fig = CustomFigureWidget()
        fig.update_layout(barmode='overlay')
    fig.update_layout(**layout_kwargs)
    for i, trace_name in enumerate(trace_names):
        hist = go.Histogram(
            opacity=0.75 if len(trace_names) > 1 else 1,
            name=trace_name,
            showlegend=trace_name is not None
        )
        hist.update(**(trace_kwargs[i] if isinstance(trace_kwargs, (list, tuple)) else trace_kwargs))
        fig.add_trace(hist)

    if data is not None:
        trace_idx = np.arange(len(fig.data) - len(trace_names), len(fig.data))
        update_hist_data(fig, data, horizontal=horizontal, trace_idx=trace_idx)
    return fig
Exemplo n.º 8
0
def create_heatmap(data=None, x_labels=None, y_labels=None, horizontal=False,
                   trace_kwargs={}, fig=None, **layout_kwargs):
    """Create a heatmap plot.

    Args:
        data (array_like): Data in any format that can be converted to NumPy.

            Must be of shape (`y_labels`, `x_labels`).
        x_labels (array_like): X-axis labels, corresponding to columns in pandas.
        y_labels (array_like): Y-axis labels, corresponding to index in pandas.
        horizontal (bool): Plot horizontally.
        trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Heatmap`.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.
    Example:
        ```py
        import vectorbt as vbt

        vbt.plotting.create_heatmap(
            data=[[1, 2], [3, 4]],
            x_labels=['a', 'b'],
            y_labels=['x', 'y']
        )
        ```
        ![](/vectorbt/docs/img/create_heatmap.png)
        """
    if data is None:
        if x_labels is None or y_labels is None:
            raise ValueError("At least x_labels and y_labels must be passed")
    if fig is None:
        fig = CustomFigureWidget()
        fig.update_layout(width=600, height=450)
    fig.update_layout(**layout_kwargs)
    heatmap = go.Heatmap(
        hoverongaps=False,
        colorscale='Plasma'
    )
    if horizontal:
        heatmap.y = x_labels
        heatmap.x = y_labels
    else:
        heatmap.x = x_labels
        heatmap.y = y_labels
    heatmap.update(**trace_kwargs)
    fig.add_trace(heatmap)
    if data is not None:
        update_heatmap_data(fig, data, horizontal=horizontal, trace_idx=len(fig.data) - 1)
    return fig
Exemplo n.º 9
0
    def plot(self,
             plot_type=go.Ohlc,
             ohlc_kwargs=None,
             entry_trace_kwargs=None,
             exit_trace_kwargs=None,
             row=None,
             col=None,
             fig=None,
             **layout_kwargs):  # pragma: no cover
        if self.wrapper.ndim > 1:
            raise TypeError("Select a column first. Use indexing.")

        if fig is None:
            fig = CustomFigureWidget()
            fig.update_layout(showlegend=True,
                              xaxis_rangeslider_visible=False,
                              xaxis_showgrid=True,
                              yaxis_showgrid=True)
        fig.update_layout(**layout_kwargs)
        if ohlc_kwargs is None:
            ohlc_kwargs = {}

        # Plot OHLC
        ohlc = plot_type(x=self.wrapper.index,
                         open=self.open,
                         high=self.high,
                         low=self.low,
                         close=self.close,
                         name='OHLC',
                         increasing_line_color='#1b9e76',
                         decreasing_line_color='#d95f02',
                         opacity=0.7)
        ohlc.update(**ohlc_kwargs)
        fig.add_trace(ohlc, row=row, col=col)

        # Plot entry and exit markers
        base_cls.plot(self,
                      entry_y=self.open,
                      exit_y=self.hit_price,
                      exit_types=self.stop_type_readable,
                      entry_trace_kwargs=entry_trace_kwargs,
                      exit_trace_kwargs=exit_trace_kwargs,
                      row=row,
                      col=col,
                      fig=fig)
        return fig
Exemplo n.º 10
0
    def plot(self,
             column=None,
             obv_trace_kwargs=None,
             row=None,
             col=None,
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot `OBV.obv`.

        Args:
            column (str): Name of the column to plot.
            obv_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `OBV.obv`.
            row (int): Row position.
            col (int): Column position.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```py
        >>> vbt.OBV.run(price['Close'], price['Volume']).plot()
        ```

        ![](/vectorbt/docs/img/OBV.png)
        """
        self_col = self.select_series(column=column)

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

        if obv_trace_kwargs is None:
            obv_trace_kwargs = {}
        obv_trace_kwargs = merge_dicts(dict(name='OBV'), obv_trace_kwargs)

        fig = self_col.obv.vbt.plot(trace_kwargs=obv_trace_kwargs,
                                    row=row,
                                    col=col,
                                    fig=fig)

        return fig
Exemplo n.º 11
0
    def plot(self, name=None, trace_kwargs={}, fig=None, **layout_kwargs):  # pragma: no cover
        """Plot Series as a line.

        Args:
            name (str): Name of the signals.
            trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.
        Example:
            ```python-repl
            >>> signals['a'].vbt.signals.plot()
            ```

            ![](/vectorbt/docs/img/signals_sr_plot.png)"""
        # Set up figure
        if fig is None:
            fig = CustomFigureWidget()
        fig.update_layout(
            yaxis=dict(
                tickmode='array',
                tickvals=[0, 1],
                ticktext=['false', 'true']
            )
        )
        fig.update_layout(**layout_kwargs)
        if name is None:
            name = self._obj.name

        scatter = go.Scatter(
            x=self.index,
            y=self._obj.values,
            mode='lines',
            name=str(name),
            showlegend=name is not None
        )
        scatter.update(**trace_kwargs)
        fig.add_trace(scatter)

        return fig
Exemplo n.º 12
0
def create_indicator(value=None, label=None, value_range=None, cmap_name='Spectral',
                     trace_kwargs={}, fig=None, **layout_kwargs):
    """Create an indicator plot.

    Args:
        value (int or float): The value to be displayed.
        label (str): The label to be displayed.
        value_range (list or tuple of 2 values): The value range of the gauge.
        cmap_name (str): A matplotlib-compatible colormap name.

            See the [list of available colormaps](https://matplotlib.org/tutorials/colors/colormaps.html).
        trace_kwargs (dict): Keyword arguments passed to the `plotly.graph_objects.Indicator`.
        **layout_kwargs: Keyword arguments for layout.
    Example:
        ```py
        import vectorbt as vbt

        vbt.plotting.create_indicator(
            value=2,
            value_range=(1, 3),
            label='My Indicator'
        )
        ```
        ![](/vectorbt/docs/img/create_indicator.png)
        """
    if fig is None:
        fig = CustomFigureWidget()
        fig.update_layout(width=500, height=300)
    fig.update_layout(**layout_kwargs)
    indicator = go.Indicator(
        domain=dict(x=[0, 1], y=[0, 1]),
        mode="gauge+number+delta",
        title=dict(text=label)
    )
    indicator.update(**trace_kwargs)
    fig.add_trace(indicator)
    if value is not None:
        update_indicator_data(fig, value, value_range=value_range, cmap_name=cmap_name, trace_idx=len(fig.data) - 1)
    return fig
Exemplo n.º 13
0
    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
Exemplo n.º 14
0
    def plot_cum_returns(self,
                         benchmark_rets=None,
                         start_value=1,
                         fill_to_benchmark=False,
                         main_kwargs=None,
                         benchmark_kwargs=None,
                         hline_shape_kwargs=None,
                         row=None,
                         col=None,
                         xref='x',
                         yref='y',
                         fig=None,
                         **layout_kwargs):  # pragma: no cover
        """Plot cumulative returns.

        Args:
            benchmark_rets (array_like): Benchmark return to compare returns against.
                Will broadcast per element.
            start_value (float): The starting returns.
            fill_to_benchmark (bool): Whether to fill between main and benchmark, or between main and `start_value`.
            main_kwargs (dict): Keyword arguments passed to `vectorbt.generic.accessors.Generic_SRAccessor.plot` for main.
            benchmark_kwargs (dict): Keyword arguments passed to `vectorbt.generic.accessors.Generic_SRAccessor.plot` for benchmark.
            hline_shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for `start_value` line.
            row (int): Row position.
            col (int): Column position.
            xref (str): X coordinate axis.
            yref (str): Y coordinate axis.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> import pandas as pd
        >>> import numpy as np

        >>> np.random.seed(0)
        >>> rets = pd.Series(np.random.uniform(-0.05, 0.05, size=100))
        >>> benchmark_rets = pd.Series(np.random.uniform(-0.05, 0.05, size=100))
        >>> rets.vbt.returns.plot_cum_returns(benchmark_rets=benchmark_rets)
        ```

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

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

        if benchmark_rets is not None:
            # Plot benchmark
            benchmark_rets = reshape_fns.broadcast_to(benchmark_rets,
                                                      self._obj)
            if benchmark_kwargs is None:
                benchmark_kwargs = {}
            benchmark_kwargs = merge_dicts(
                dict(trace_kwargs=dict(line_color=color_schema['gray'],
                                       name='Benchmark')), benchmark_kwargs)
            benchmark_cumrets = benchmark_rets.vbt.returns.cumulative(
                start_value=start_value)
            benchmark_cumrets.vbt.plot(**benchmark_kwargs,
                                       row=row,
                                       col=col,
                                       fig=fig)
        else:
            benchmark_cumrets = None

        # Plot main
        if main_kwargs is None:
            main_kwargs = {}
        main_kwargs = merge_dicts(
            dict(trace_kwargs=dict(line_color=color_schema['purple'], ),
                 other_trace_kwargs='hidden'), main_kwargs)
        cumrets = self.cumulative(start_value=start_value)
        if fill_to_benchmark:
            cumrets.vbt.plot_against(benchmark_cumrets,
                                     **main_kwargs,
                                     row=row,
                                     col=col,
                                     fig=fig)
        else:
            cumrets.vbt.plot_against(start_value,
                                     **main_kwargs,
                                     row=row,
                                     col=col,
                                     fig=fig)

        # Plot hline
        if hline_shape_kwargs is None:
            hline_shape_kwargs = {}
        fig.add_shape(**merge_dicts(
            dict(type='line',
                 xref="paper",
                 yref=yref,
                 x0=x_domain[0],
                 y0=start_value,
                 x1=x_domain[1],
                 y1=start_value,
                 line=dict(
                     color="gray",
                     dash="dash",
                 )), hline_shape_kwargs))

        return fig
Exemplo n.º 15
0
    def plot(self,
             plot_type=go.Ohlc,
             display_volume=True,
             ohlc_kwargs=None,
             bar_kwargs=None,
             fig=None,
             **layout_kwargs):
        """Plot OHLCV data.

        Args:
            plot_type: Either `plotly.graph_objects.Ohlc` or `plotly.graph_objects.Candlestick`.
            display_volume (bool): If True, displays volume as bar chart.
            ohlc_kwargs (dict): Keyword arguments passed to `plot_type`.
            bar_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar`.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.
        Example:
            ```python-repl
            >>> import vectorbt as vbt
            >>> import yfinance as yf

            >>> yf.Ticker("BTC-USD").history(period="max").vbt.ohlcv.plot()
            ```

            ![](/vectorbt/docs/img/ohlcv.png)"""
        column_names = defaults.ohlcv['column_names'] if self._column_names is None else self._column_names
        open = self._obj[column_names['open']]
        high = self._obj[column_names['high']]
        low = self._obj[column_names['low']]
        close = self._obj[column_names['close']]

        # Set up figure
        if fig is None:
            fig = CustomFigureWidget()
            fig.update_layout(
                showlegend=True,
                xaxis_rangeslider_visible=False,
                xaxis_showgrid=True,
                yaxis_showgrid=True,
                bargap=0
            )
        fig.update_layout(**layout_kwargs)
        if ohlc_kwargs is None:
            ohlc_kwargs = {}
        if bar_kwargs is None:
            bar_kwargs = {}
        ohlc = plot_type(
            x=self.index,
            open=open,
            high=high,
            low=low,
            close=close,
            name='OHLC',
            yaxis="y2",
            xaxis="x",
            increasing_line_color='#1b9e76',
            decreasing_line_color='#d95f02'
        )
        ohlc.update(**ohlc_kwargs)
        fig.add_trace(ohlc)
        if display_volume:
            volume = self._obj[column_names['volume']]

            marker_colors = np.empty(volume.shape, dtype=np.object)
            marker_colors[(close.values - open.values) > 0] = '#1b9e76'
            marker_colors[(close.values - open.values) == 0] = 'lightgrey'
            marker_colors[(close.values - open.values) < 0] = '#d95f02'
            bar = go.Bar(
                x=self.index,
                y=volume,
                marker_color=marker_colors,
                marker_line_width=0,
                marker_opacity=0.7,
                name='Volume',
                yaxis="y",
                xaxis="x"
            )
            bar.update(**bar_kwargs)
            fig.add_trace(bar)
            fig.update_layout(
                yaxis2=dict(
                    domain=[0.33, 1]
                ),
                yaxis=dict(
                    domain=[0, 0.33]
                )
            )
        return fig
Exemplo n.º 16
0
    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
Exemplo n.º 17
0
    def plot(self,
             column=None,
             levels=(30, 70),
             percent_k_trace_kwargs=None,
             percent_d_trace_kwargs=None,
             shape_kwargs=None,
             row=None,
             col=None,
             xref='x',
             yref='y',
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot `STOCH.percent_k` and `STOCH.percent_d`.

        Args:
            column (str): Name of the column to plot.
            levels (tuple): Two extremes: bottom and top.
            percent_k_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `STOCH.percent_k`.
            percent_d_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `STOCH.percent_d`.
            shape_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Figure.add_shape` for zone between levels.
            row (int): Row position.
            col (int): Column position.
            xref (str): X coordinate axis.
            yref (str): Y coordinate axis.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> vbt.STOCH.run(price['High'], price['Low'], price['Close']).plot()
        ```

        ![](/vectorbt/docs/img/STOCH.png)
        """
        self_col = self.select_series(column=column)

        if fig is None:
            fig = CustomFigureWidget()
        default_layout = dict()
        default_layout['yaxis' + yref[1:]] = dict(range=[-5, 105])
        fig.update_layout(**default_layout)
        fig.update_layout(**layout_kwargs)

        if percent_k_trace_kwargs is None:
            percent_k_trace_kwargs = {}
        if percent_d_trace_kwargs is None:
            percent_d_trace_kwargs = {}
        if shape_kwargs is None:
            shape_kwargs = {}
        percent_k_trace_kwargs = merge_dicts(dict(name='%K'),
                                             percent_k_trace_kwargs)
        percent_d_trace_kwargs = merge_dicts(dict(name='%D'),
                                             percent_d_trace_kwargs)

        fig = self_col.percent_k.vbt.plot(trace_kwargs=percent_k_trace_kwargs,
                                          row=row,
                                          col=col,
                                          fig=fig)
        fig = self_col.percent_d.vbt.plot(trace_kwargs=percent_d_trace_kwargs,
                                          row=row,
                                          col=col,
                                          fig=fig)

        # Plot levels
        # Fill void between levels
        shape_kwargs = merge_dicts(
            dict(
                type="rect",
                xref=xref,
                yref=yref,
                x0=self_col.percent_k.index[0],
                y0=levels[0],
                x1=self_col.percent_k.index[-1],
                y1=levels[1],
                fillcolor="purple",
                opacity=0.2,
                layer="below",
                line_width=0,
            ), shape_kwargs)
        fig.add_shape(**shape_kwargs)

        return fig
Exemplo n.º 18
0
def create_heatmap(data=None,
                   x_labels=None,
                   y_labels=None,
                   horizontal=False,
                   trace_kwargs=None,
                   return_trace_idx=False,
                   row=None,
                   col=None,
                   fig=None,
                   **layout_kwargs):
    """Create a heatmap plot.

    Args:
        data (array_like): Data in any format that can be converted to NumPy.

            Must be of shape (`y_labels`, `x_labels`).
        x_labels (array_like): X-axis labels, corresponding to columns in pandas.
        y_labels (array_like): Y-axis labels, corresponding to index in pandas.
        horizontal (bool): Plot horizontally.
        trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Heatmap`.
        return_trace_idx (bool): Whether to return trace index for `update_heatmap_data`.
        row (int): Row position.
        col (int): Column position.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.

    ## Example

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

    >>> vbt.plotting.create_heatmap(
    ...     data=[[1, 2], [3, 4]],
    ...     x_labels=['a', 'b'],
    ...     y_labels=['x', 'y']
    ... )
    ```
    ![](/vectorbt/docs/img/create_heatmap.png)
    """
    from vectorbt.settings import layout

    if trace_kwargs is None:
        trace_kwargs = {}
    if data is None:
        if x_labels is None or y_labels is None:
            raise ValueError("At least x_labels and y_labels must be passed")
    else:
        data = reshape_fns.to_2d(np.array(data))
    if horizontal:
        y_labels, y_labels = y_labels, x_labels
        if data is not None:
            data = data.transpose()
        horizontal = False
    if fig is None:
        fig = CustomFigureWidget()
        if 'width' in layout:
            # Calculate nice width and height
            max_width = layout['width']
            if data is not None:
                x_len = data.shape[1]
                y_len = data.shape[0]
            else:
                x_len = len(x_labels)
                y_len = len(y_labels)
            width = math.ceil(
                renormalize(x_len / (x_len + y_len), [0, 1],
                            [0.3 * max_width, max_width]))
            width = min(width + 150, max_width)  # account for colorbar
            height = math.ceil(
                renormalize(y_len / (x_len + y_len), [0, 1],
                            [0.3 * max_width, max_width]))
            height = min(height, max_width * 0.7)  # limit height
            fig.update_layout(width=width, height=height)

    fig.update_layout(**layout_kwargs)
    heatmap = go.Heatmap(hoverongaps=False,
                         colorscale='Plasma',
                         x=x_labels,
                         y=y_labels)
    heatmap.update(**trace_kwargs)
    fig.add_trace(heatmap, row=row, col=col)
    trace_idx = len(fig.data) - 1
    if data is not None:
        update_heatmap_data(fig,
                            data,
                            horizontal=horizontal,
                            trace_idx=trace_idx)
    if return_trace_idx:
        return fig, trace_idx
    return fig
Exemplo n.º 19
0
    def plot(self,
             column=None,
             plot_close=True,
             close_trace_kwargs=None,
             buy_trace_kwargs=None,
             sell_trace_kwargs=None,
             row=None, col=None,
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot orders.

        Args:
            column (str): Name of the column to plot.
            plot_close (bool): Whether to plot `Orders.close`.
            close_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `Orders.close`.
            buy_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Buy" markers.
            sell_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for "Sell" markers.
            row (int): Row position.
            col (int): Column position.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

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

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

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

        if close_trace_kwargs is None:
            close_trace_kwargs = {}
        close_trace_kwargs = merge_dicts(dict(
            line_color=color_schema['blue'],
            name='Close' if self_col.wrapper.name is None else self_col.wrapper.name
        ), close_trace_kwargs)
        if buy_trace_kwargs is None:
            buy_trace_kwargs = {}
        if sell_trace_kwargs is None:
            sell_trace_kwargs = {}

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

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

        if len(self_col.values) > 0:
            # Extract information
            _id = self_col.values['id']
            idx = self_col.values['idx']
            size = self_col.values['size']
            price = self_col.values['price']
            fees = self_col.values['fees']
            side = self_col.values['side']

            # Plot Buy markers
            buy_mask = side == OrderSide.Buy
            buy_customdata = np.stack((_id[buy_mask], size[buy_mask], fees[buy_mask]), axis=1)
            buy_scatter = go.Scatter(
                x=self_col.wrapper.index[idx[buy_mask]],
                y=price[buy_mask],
                mode='markers',
                marker=dict(
                    symbol='triangle-up',
                    color=contrast_color_schema['green'],
                    size=8,
                    line=dict(
                        width=1,
                        color=adjust_lightness(contrast_color_schema['green'])
                    )
                ),
                name='Buy',
                customdata=buy_customdata,
                hovertemplate="Order Id: %{customdata[0]}"
                              "<br>Date: %{x}"
                              "<br>Price: %{y}"
                              "<br>Size: %{customdata[1]:.6f}"
                              "<br>Fees: %{customdata[2]:.6f}"
            )
            buy_scatter.update(**buy_trace_kwargs)
            fig.add_trace(buy_scatter, row=row, col=col)

            # Plot Sell markers
            sell_mask = side == OrderSide.Sell
            sell_customdata = np.stack((_id[sell_mask], size[sell_mask], fees[sell_mask]), axis=1)
            sell_scatter = go.Scatter(
                x=self_col.wrapper.index[idx[sell_mask]],
                y=price[sell_mask],
                mode='markers',
                marker=dict(
                    symbol='triangle-down',
                    color=contrast_color_schema['red'],
                    size=8,
                    line=dict(
                        width=1,
                        color=adjust_lightness(contrast_color_schema['red'])
                    )
                ),
                name='Sell',
                customdata=sell_customdata,
                hovertemplate="Order Id: %{customdata[0]}"
                              "<br>Date: %{x}"
                              "<br>Price: %{y}"
                              "<br>Size: %{customdata[1]:.6f}"
                              "<br>Fees: %{customdata[2]:.6f}"
            )
            sell_scatter.update(**sell_trace_kwargs)
            fig.add_trace(sell_scatter, row=row, col=col)

        return fig
Exemplo n.º 20
0
def create_volume(data=None, x_labels=None, y_labels=None, z_labels=False,
                  trace_kwargs={}, fig=None, **layout_kwargs):
    """Create a volume plot.

    Args:
        data (array_like): Data in any format that can be converted to NumPy.

            Must be a 3-dim array.
        x_labels (array_like): X-axis labels.
        y_labels (array_like): Y-axis labels.
        z_labels (array_like): Z-axis labels.
        trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Volume`.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.

    !!! note
        Figure widgets have currently problems displaying NaNs.
        Use `.show()` method for rendering.

    Example:
        ```py
        import vectorbt as vbt
        import numpy as np

        vbt.plotting.create_volume(
            data=np.random.randint(1, 10, size=(3, 3, 3)),
            x_labels=['a', 'b', 'c'],
            y_labels=['d', 'e', 'f'],
            z_labels=['g', 'h', 'i']
        )
        ```
        ![](/vectorbt/docs/img/create_volume.png)
        """

    if data is None:
        raise ValueError("Data must be passed")
    data = np.asarray(data)
    checks.assert_ndim(data, 3)
    if x_labels is None:
        x_labels = np.arange(data.shape[0])
    if y_labels is None:
        y_labels = np.arange(data.shape[1])
    if z_labels is None:
        z_labels = np.arange(data.shape[2])
    x_labels = np.asarray(x_labels)
    y_labels = np.asarray(y_labels)
    z_labels = np.asarray(z_labels)

    if fig is None:
        fig = CustomFigureWidget()
        fig.update_layout(
            width=700,
            height=450
        )

    # Non-numeric data types are not supported by go.Volume, so use ticktext
    # Note: Currently plotly displays the entire tick array, in future versions it will be more sensible
    if not np.issubdtype(x_labels.dtype, np.number):
        x_ticktext = x_labels
        x_labels = np.arange(data.shape[0])
        fig.update_layout(scene=dict(xaxis=dict(ticktext=x_ticktext, tickvals=x_labels, tickmode='array')))
    if not np.issubdtype(y_labels.dtype, np.number):
        y_ticktext = y_labels
        y_labels = np.arange(data.shape[1])
        fig.update_layout(scene=dict(yaxis=dict(ticktext=y_ticktext, tickvals=y_labels, tickmode='array')))
    if not np.issubdtype(z_labels.dtype, np.number):
        z_ticktext = z_labels
        z_labels = np.arange(data.shape[2])
        fig.update_layout(scene=dict(zaxis=dict(ticktext=z_ticktext, tickvals=z_labels, tickmode='array')))

    # Arrays must have the same length as the flattened data array
    x = np.repeat(x_labels, len(y_labels) * len(z_labels))
    y = np.tile(np.repeat(y_labels, len(z_labels)), len(x_labels))
    z = np.tile(z_labels, len(x_labels) * len(y_labels))

    fig.update_layout(**layout_kwargs)
    volume = go.Volume(
        x=x,
        y=y,
        z=z,
        value=data.flatten(),
        opacity=0.15,
        surface_count=15,  # keep low for big data
        colorscale='Plasma'
    )
    volume.update(**trace_kwargs)
    fig.add_trace(volume)
    return fig
Exemplo n.º 21
0
def create_scatter(data=None,
                   trace_names=None,
                   x_labels=None,
                   trace_kwargs=None,
                   return_trace_idxs=False,
                   row=None,
                   col=None,
                   fig=None,
                   **layout_kwargs):
    """Create a scatter plot.

    Args:
        data (array_like): Data in any format that can be converted to NumPy.

            Must be of shape (`x_labels`, `trace_names`).
        trace_names (str or list of str): Trace names, corresponding to columns in pandas.
        x_labels (array_like): X-axis labels, corresponding to index in pandas.
        trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter`.
        return_trace_idxs (bool): Whether to return trace indices for `update_scatter_data`.
        row (int): Row position.
        col (int): Column position.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.

    ## Example

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

    >>> vbt.plotting.create_scatter(
    ...     data=[[1, 2], [3, 4]],
    ...     trace_names=['a', 'b'],
    ...     x_labels=['x', 'y']
    ... )
    ```
    ![](/vectorbt/docs/img/create_scatter.png)
    """
    if trace_kwargs is None:
        trace_kwargs = {}
    if data is None:
        if trace_names is None:
            raise ValueError("At least trace_names must be passed")
    if trace_names is None:
        data = reshape_fns.to_2d(data)
        trace_names = [None] * data.shape[1]
    if isinstance(trace_names, str):
        trace_names = [trace_names]
    if fig is None:
        fig = CustomFigureWidget()
    fig.update_layout(**layout_kwargs)
    for i, trace_name in enumerate(trace_names):
        if trace_name is not None:
            trace_name = str(trace_name)
        scatter = go.Scatter(x=x_labels,
                             name=trace_name,
                             showlegend=trace_name is not None)
        scatter.update(
            **(trace_kwargs[i] if isinstance(trace_kwargs, (
                list, tuple)) else trace_kwargs))
        fig.add_trace(scatter, row=row, col=col)

    trace_idxs = list(range(len(fig.data) - len(trace_names), len(fig.data)))
    if data is not None:
        update_scatter_data(fig, data, trace_idx=trace_idxs)
    if return_trace_idxs:
        return fig, trace_idxs
    return fig
Exemplo n.º 22
0
    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
Exemplo n.º 23
0
    def plot(self,
             column=None,
             plot_close=True,
             close_trace_kwargs=None,
             middle_trace_kwargs=None,
             upper_trace_kwargs=None,
             lower_trace_kwargs=None,
             row=None,
             col=None,
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot `BBANDS.middle`, `BBANDS.upper` and `BBANDS.lower` against
        `BBANDS.close`.

        Args:
            column (str): Name of the column to plot.
            plot_close (bool): Whether to plot `MA.close`.
            close_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `BBANDS.close`.
            middle_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `BBANDS.middle`.
            upper_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `BBANDS.upper`.
            lower_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `BBANDS.lower`.
            row (int): Row position.
            col (int): Column position.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> vbt.BBANDS.run(price['Close']).plot()
        ```

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

        self_col = self.select_series(column=column)

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

        if close_trace_kwargs is None:
            close_trace_kwargs = {}
        if middle_trace_kwargs is None:
            middle_trace_kwargs = {}
        if upper_trace_kwargs is None:
            upper_trace_kwargs = {}
        if lower_trace_kwargs is None:
            lower_trace_kwargs = {}
        lower_trace_kwargs = merge_dicts(
            dict(
                name='Lower Band',
                line_color=color_schema['gray'],
            ), lower_trace_kwargs)
        upper_trace_kwargs = merge_dicts(
            dict(name='Upper Band',
                 line_color=color_schema['gray'],
                 fill='tonexty',
                 fillcolor='rgba(128, 128, 128, 0.2)'),
            upper_trace_kwargs)  # default kwargs
        middle_trace_kwargs = merge_dicts(dict(name='Middle Band'),
                                          middle_trace_kwargs)
        close_trace_kwargs = merge_dicts(
            dict(name='Close', line=dict(color=color_schema['blue'])),
            close_trace_kwargs)

        fig = self_col.lower.vbt.plot(trace_kwargs=lower_trace_kwargs,
                                      row=row,
                                      col=col,
                                      fig=fig)
        fig = self_col.upper.vbt.plot(trace_kwargs=upper_trace_kwargs,
                                      row=row,
                                      col=col,
                                      fig=fig)
        fig = self_col.middle.vbt.plot(trace_kwargs=middle_trace_kwargs,
                                       row=row,
                                       col=col,
                                       fig=fig)
        if plot_close:
            fig = self_col.close.vbt.plot(trace_kwargs=close_trace_kwargs,
                                          row=row,
                                          col=col,
                                          fig=fig)

        return fig
Exemplo n.º 24
0
def create_volume(data=None,
                  x_labels=None,
                  y_labels=None,
                  z_labels=False,
                  trace_kwargs=None,
                  return_trace_idx=False,
                  row=None,
                  col=None,
                  scene_name='scene',
                  fig=None,
                  **layout_kwargs):
    """Create a volume plot.

    Args:
        data (array_like): Data in any format that can be converted to NumPy.

            Must be a 3-dim array.
        x_labels (array_like): X-axis labels.
        y_labels (array_like): Y-axis labels.
        z_labels (array_like): Z-axis labels.
        trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Volume`.
        return_trace_idx (bool): Whether to return trace index for `update_volume_data`.
        row (int): Row position.
        col (int): Column position.
        scene_name (str): Reference to the 3D scene.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.

    !!! note
        Figure widgets have currently problems displaying NaNs.
        Use `.show()` method for rendering.

    ## Example

    ```python-repl
    >>> import vectorbt as vbt
    >>> import numpy as np

    >>> vbt.plotting.create_volume(
    ...     data=np.random.randint(1, 10, size=(3, 3, 3)),
    ...     x_labels=['a', 'b', 'c'],
    ...     y_labels=['d', 'e', 'f'],
    ...     z_labels=['g', 'h', 'i']
    ... )
    ```

    ![](/vectorbt/docs/img/create_volume.png)
    """
    from vectorbt.settings import layout

    if trace_kwargs is None:
        trace_kwargs = {}
    if data is None:
        raise ValueError("Data must be passed")
    data = np.asarray(data)
    checks.assert_ndim(data, 3)
    if x_labels is None:
        x_labels = np.arange(data.shape[0])
    if y_labels is None:
        y_labels = np.arange(data.shape[1])
    if z_labels is None:
        z_labels = np.arange(data.shape[2])
    x_labels = np.asarray(x_labels)
    y_labels = np.asarray(y_labels)
    z_labels = np.asarray(z_labels)

    if fig is None:
        fig = CustomFigureWidget()
        if 'width' in layout:
            # Calculate nice width and height
            fig.update_layout(width=layout['width'],
                              height=0.7 * layout['width'])

    # Non-numeric data types are not supported by go.Volume, so use ticktext
    # Note: Currently plotly displays the entire tick array, in future versions it will be more sensible
    more_layout = dict()
    if not np.issubdtype(x_labels.dtype, np.number):
        x_ticktext = x_labels
        x_labels = np.arange(data.shape[0])
        more_layout[scene_name] = dict(xaxis=dict(
            ticktext=x_ticktext, tickvals=x_labels, tickmode='array'))
    if not np.issubdtype(y_labels.dtype, np.number):
        y_ticktext = y_labels
        y_labels = np.arange(data.shape[1])
        more_layout[scene_name] = dict(yaxis=dict(
            ticktext=y_ticktext, tickvals=y_labels, tickmode='array'))
    if not np.issubdtype(z_labels.dtype, np.number):
        z_ticktext = z_labels
        z_labels = np.arange(data.shape[2])
        more_layout[scene_name] = dict(zaxis=dict(
            ticktext=z_ticktext, tickvals=z_labels, tickmode='array'))
    fig.update_layout(**more_layout)
    fig.update_layout(**layout_kwargs)

    # Arrays must have the same length as the flattened data array
    x = np.repeat(x_labels, len(y_labels) * len(z_labels))
    y = np.tile(np.repeat(y_labels, len(z_labels)), len(x_labels))
    z = np.tile(z_labels, len(x_labels) * len(y_labels))

    volume = go.Volume(
        x=x,
        y=y,
        z=z,
        value=data.flatten(),
        opacity=0.2,
        surface_count=15,  # keep low for big data
        colorscale='Plasma')
    volume.update(**trace_kwargs)
    fig.add_trace(volume, row=row, col=col)
    trace_idx = len(fig.data) - 1
    if return_trace_idx:
        return fig, trace_idx
    return fig
Exemplo n.º 25
0
    def plot(self,
             plot_type='OHLC',
             display_volume=True,
             ohlc_kwargs=None,
             bar_kwargs=None,
             fig=None,
             **layout_kwargs):
        """Plot OHLCV data.

        Args:
            plot_type: Either 'OHLC' or 'Candlestick'.
            display_volume (bool): If True, displays volume as bar chart.
            ohlc_kwargs (dict): Keyword arguments passed to `plot_type`.
            bar_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar`.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> import vectorbt as vbt
        >>> import yfinance as yf

        >>> yf.Ticker("BTC-USD").history(period="max").vbt.ohlcv.plot()
        ```

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

        column_names = ohlcv[
            'column_names'] if self._column_names is None else self._column_names
        open = self._obj[column_names['open']]
        high = self._obj[column_names['high']]
        low = self._obj[column_names['low']]
        close = self._obj[column_names['close']]

        # Set up figure
        if fig is None:
            fig = CustomFigureWidget()
            fig.update_layout(showlegend=True,
                              xaxis=dict(rangeslider_visible=False,
                                         showgrid=True),
                              yaxis=dict(showgrid=True),
                              bargap=0)
        fig.update_layout(**layout_kwargs)
        if ohlc_kwargs is None:
            ohlc_kwargs = {}
        if bar_kwargs is None:
            bar_kwargs = {}
        if plot_type.lower() == 'ohlc':
            plot_type = 'OHLC'
            plot_obj = go.Ohlc
        elif plot_type.lower() == 'candlestick':
            plot_type = 'Candlestick'
            plot_obj = go.Candlestick
        else:
            raise ValueError("Plot type can be either 'OHLC' or 'Candlestick'")
        ohlc = plot_obj(x=self.wrapper.index,
                        open=open,
                        high=high,
                        low=low,
                        close=close,
                        name=plot_type,
                        yaxis="y2",
                        xaxis="x",
                        increasing_line_color=color_schema['increasing'],
                        decreasing_line_color=color_schema['decreasing'])
        ohlc.update(**ohlc_kwargs)
        fig.add_trace(ohlc)
        if display_volume:
            volume = self._obj[column_names['volume']]

            marker_colors = np.empty(volume.shape, dtype=np.object)
            marker_colors[(close.values -
                           open.values) > 0] = color_schema['increasing']
            marker_colors[(close.values -
                           open.values) == 0] = color_schema['gray']
            marker_colors[(close.values -
                           open.values) < 0] = color_schema['decreasing']
            bar = go.Bar(x=self.wrapper.index,
                         y=volume,
                         marker=dict(color=marker_colors, line_width=0),
                         opacity=0.5,
                         name='Volume',
                         yaxis="y",
                         xaxis="x")
            bar.update(**bar_kwargs)
            fig.add_trace(bar)
            fig.update_layout(yaxis2=dict(domain=[0.33, 1]),
                              yaxis=dict(domain=[0, 0.33]))
        return fig
Exemplo n.º 26
0
    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
Exemplo n.º 27
0
def create_indicator(value=None,
                     label=None,
                     value_range=None,
                     cmap_name='Spectral',
                     trace_kwargs=None,
                     return_trace_idx=False,
                     row=None,
                     col=None,
                     fig=None,
                     **layout_kwargs):
    """Create an indicator plot.

    Args:
        value (int or float): The value to be displayed.
        label (str): The label to be displayed.
        value_range (list or tuple of 2 values): The value range of the gauge.
        cmap_name (str): A matplotlib-compatible colormap name.

            See the [list of available colormaps](https://matplotlib.org/tutorials/colors/colormaps.html).
        trace_kwargs (dict): Keyword arguments passed to the `plotly.graph_objects.Indicator`.
        return_trace_idx (bool): Whether to return trace index for `update_indicator_data`.
        row (int): Row position.
        col (int): Column position.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.

    ## Example

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

    >>> vbt.plotting.create_indicator(
    ...     value=2,
    ...     value_range=(1, 3),
    ...     label='My Indicator'
    ... )
    ```
    ![](/vectorbt/docs/img/create_indicator.png)
    """
    from vectorbt.settings import layout

    if trace_kwargs is None:
        trace_kwargs = {}
    if fig is None:
        fig = CustomFigureWidget()
        if 'width' in layout:
            # Calculate nice width and height
            fig.update_layout(width=layout['width'] * 0.7,
                              height=layout['width'] * 0.5,
                              margin=dict(t=80))
    fig.update_layout(**layout_kwargs)
    indicator = go.Indicator(domain=dict(x=[0, 1], y=[0, 1]),
                             mode="gauge+number+delta",
                             title=dict(text=label))
    indicator.update(**trace_kwargs)
    fig.add_trace(indicator, row=row, col=col)
    trace_idx = len(fig.data) - 1
    if value is not None:
        update_indicator_data(fig,
                              value,
                              value_range=value_range,
                              cmap_name=cmap_name,
                              trace_idx=trace_idx)
    if return_trace_idx:
        return fig, trace_idx
    return fig
Exemplo n.º 28
0
    def plot(self,
             column=None,
             macd_trace_kwargs=None,
             signal_trace_kwargs=None,
             hist_trace_kwargs=None,
             row=None,
             col=None,
             fig=None,
             **layout_kwargs):  # pragma: no cover
        """Plot `MACD.macd`, `MACD.signal` and `MACD.hist`.

        Args:
            column (str): Name of the column to plot.
            macd_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MACD.macd`.
            signal_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Scatter` for `MACD.signal`.
            hist_trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar` for `MACD.hist`.
            row (int): Row position.
            col (int): Column position.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.

        ## Example

        ```python-repl
        >>> vbt.MACD.run(price['Close']).plot()
        ```

        ![](/vectorbt/docs/img/MACD.png)"""
        self_col = self.select_series(column=column)

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

        if macd_trace_kwargs is None:
            macd_trace_kwargs = {}
        if signal_trace_kwargs is None:
            signal_trace_kwargs = {}
        if hist_trace_kwargs is None:
            hist_trace_kwargs = {}
        macd_trace_kwargs = merge_dicts(dict(name='MACD'), macd_trace_kwargs)
        signal_trace_kwargs = merge_dicts(dict(name='Signal'),
                                          signal_trace_kwargs)
        hist_trace_kwargs = merge_dicts(dict(name='Histogram'),
                                        hist_trace_kwargs)

        fig = self_col.macd.vbt.plot(trace_kwargs=macd_trace_kwargs,
                                     row=row,
                                     col=col,
                                     fig=fig)
        fig = self_col.signal.vbt.plot(trace_kwargs=signal_trace_kwargs,
                                       row=row,
                                       col=col,
                                       fig=fig)

        # Plot hist
        hist = self_col.hist.values
        hist_diff = generic_nb.diff_1d_nb(hist)
        marker_colors = np.full(hist.shape, 'silver', dtype=np.object)
        marker_colors[(hist > 0) & (hist_diff > 0)] = 'green'
        marker_colors[(hist > 0) & (hist_diff <= 0)] = 'lightgreen'
        marker_colors[(hist < 0) & (hist_diff < 0)] = 'red'
        marker_colors[(hist < 0) & (hist_diff >= 0)] = 'lightcoral'

        hist_bar = go.Bar(x=self_col.hist.index,
                          y=self_col.hist.values,
                          marker_color=marker_colors,
                          marker_line_width=0)
        hist_bar.update(**hist_trace_kwargs)
        fig.add_trace(hist_bar, row=row, col=col)

        return fig
Exemplo n.º 29
0
    def plot(self,
             display_volume=True,
             candlestick_kwargs={},
             bar_kwargs={},
             fig=None,
             **layout_kwargs):
        """Plot OHLCV data.

        Args:
            display_volume (bool): If `True`, displays volume as bar chart.
            candlestick_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Candlestick`.
            bar_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Bar`.
            fig (plotly.graph_objects.Figure): Figure to add traces to.
            **layout_kwargs: Keyword arguments for layout.
        Example:
            ```py
            import vectorbt as vbt
            import yfinance as yf

            yf.Ticker("BTC-USD").history(period="max").vbt.ohlcv.plot()
            ```

            ![](/vectorbt/docs/img/ohlcv.png)"""
        column_names = defaults.ohlcv[
            'column_names'] if self._column_names is None else self._column_names
        open = self._obj[column_names['open']]
        high = self._obj[column_names['high']]
        low = self._obj[column_names['low']]
        close = self._obj[column_names['close']]

        # Set up figure
        if fig is None:
            fig = CustomFigureWidget()
        candlestick = go.Candlestick(x=self.index,
                                     open=open,
                                     high=high,
                                     low=low,
                                     close=close,
                                     name='OHLC',
                                     yaxis="y2",
                                     xaxis="x")
        candlestick.update(**candlestick_kwargs)
        fig.add_trace(candlestick)
        if display_volume:
            volume = self._obj[column_names['volume']]

            marker_colors = np.empty(volume.shape, dtype=np.object)
            marker_colors[(close.values - open.values) > 0] = 'green'
            marker_colors[(close.values - open.values) == 0] = 'lightgrey'
            marker_colors[(close.values - open.values) < 0] = 'red'
            bar = go.Bar(x=self.index,
                         y=volume,
                         marker_color=marker_colors,
                         marker_line_width=0,
                         name='Volume',
                         yaxis="y",
                         xaxis="x")
            bar.update(**bar_kwargs)
            fig.add_trace(bar)
            fig.update_layout(yaxis2=dict(domain=[0.33, 1]),
                              yaxis=dict(domain=[0, 0.33]))
        fig.update_layout(showlegend=True,
                          xaxis_rangeslider_visible=False,
                          xaxis_showgrid=True,
                          yaxis_showgrid=True)
        fig.update_layout(**layout_kwargs)

        return fig
Exemplo n.º 30
0
def create_box(data=None,
               trace_names=None,
               horizontal=False,
               remove_nan=True,
               trace_kwargs=None,
               return_trace_idxs=False,
               row=None,
               col=None,
               fig=None,
               **layout_kwargs):
    """Create a box plot.

    Args:
        data (array_like): Data in any format that can be converted to NumPy.

            Must be of shape (any, `trace_names`).
        trace_names (str or list of str): Trace names, corresponding to columns in pandas.
        horizontal (bool): Plot horizontally.
        remove_nan (bool): Whether to remove NaN values.
        trace_kwargs (dict): Keyword arguments passed to `plotly.graph_objects.Box`.
        return_trace_idxs (bool): Whether to return trace indices for `update_box_data`.
        row (int): Row position.
        col (int): Column position.
        fig (plotly.graph_objects.Figure): Figure to add traces to.
        **layout_kwargs: Keyword arguments for layout.

    ## Example

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

    >>> vbt.plotting.create_box(
    ...     data=[[1, 2], [3, 4], [2, 1]],
    ...     trace_names=['a', 'b']
    ... )
    ```
    ![](/vectorbt/docs/img/create_box.png)
    """
    if trace_kwargs is None:
        trace_kwargs = {}
    if data is None:
        if trace_names is None:
            raise ValueError("At least trace_names must be passed")
    if trace_names is None:
        data = reshape_fns.to_2d(data)
        trace_names = [None] * data.shape[1]
    if isinstance(trace_names, str):
        trace_names = [trace_names]
    if fig is None:
        fig = CustomFigureWidget()
        fig.update_layout(barmode='overlay')
    fig.update_layout(**layout_kwargs)
    for i, trace_name in enumerate(trace_names):
        if trace_name is not None:
            trace_name = str(trace_name)
        box = go.Box(name=trace_name, showlegend=trace_name is not None)
        box.update(**(trace_kwargs[i] if isinstance(trace_kwargs, (
            list, tuple)) else trace_kwargs))
        fig.add_trace(box, row=row, col=col)

    trace_idxs = list(range(len(fig.data) - len(trace_names), len(fig.data)))
    if data is not None:
        update_box_data(fig,
                        data,
                        horizontal=horizontal,
                        trace_idx=trace_idxs,
                        remove_nan=remove_nan)
    if return_trace_idxs:
        return fig, trace_idxs
    return fig