Пример #1
0
    def build_strategy_data(self,
                            strategy: bt.Strategy,
                            start: Optional[datetime.datetime] = None,
                            end: Optional[datetime.datetime] = None,
                            num_back: Optional[int] = None,
                            startidx: int = 0):
        """startidx: index number to write into the dataframe for the index column"""
        strategydf = pd.DataFrame()

        start, end = Bokeh._get_start_end(strategy, start, end)

        strat_clk: array[float] = strategy.lines.datetime.plotrange(start, end)

        # if patches occured then we see duplicate entries in the strategie clock -> clean them
        strat_clk = np.unique(strat_clk)

        if num_back is None:
            num_back = len(strat_clk)

        strat_clk = strat_clk[-num_back:]

        # we use timezone of first data. we might see duplicated timestamps here
        dtline = [bt.num2date(x, strategy.datas[0]._tz) for x in strat_clk]

        # add an index line to use as x-axis (instead of datetime axis) to avoid datetime gaps (e.g. weekends)
        indices = list(range(startidx, startidx + len(dtline)))
        strategydf['index'] = indices

        strategydf['datetime'] = dtline

        for data in strategy.datas:
            source_id = FigureEnvelope._source_id(data)
            df_data = convert_to_pandas(strat_clk, data, start, end, source_id)

            strategydf = strategydf.join(df_data)

            df_colors = FigureEnvelope.build_color_lines(
                df_data,
                self.p.scheme,
                col_open=source_id + 'open',
                col_close=source_id + 'close',
                col_prefix=source_id)
            strategydf = strategydf.join(df_colors)

        for obj in itertools.chain(strategy.getindicators(),
                                   strategy.getobservers()):
            for lineidx in range(obj.size()):
                line = obj.lines[lineidx]
                source_id = FigureEnvelope._source_id(line)
                dataline = line.plotrange(start, end)

                line_clk = get_clock_line(obj).plotrange(start, end)
                dataline = convert_by_line_clock(dataline, line_clk, strat_clk)
                strategydf[source_id] = dataline

        # apply a proper index (should be identical to 'index' column)
        if strategydf.shape[0] > 0:
            strategydf.index = indices
        return strategydf
Пример #2
0
    def plot_volume(self, obj, alpha, extra_axis=False):
        src_prefix = sanitize_source_name(obj._name)

        df = convert_to_pandas(obj, self._start, self._end)

        if len(nanfilt(df.volume)) == 0:
            return

        colorup = convert_color(self._scheme.volup)
        colordown = convert_color(self._scheme.voldown)

        is_up = df.close > df.open
        colors = [colorup if x else colordown for x in is_up]

        self._add_to_cds(df.volume, src_prefix + 'volume')
        self._add_to_cds(colors, src_prefix + 'volume_colors')

        kwargs = {
            'fill_alpha': alpha,
            'line_alpha': alpha,
            'name': 'Volume',
            'legend': 'Volume'
        }

        ax_formatter = NumeralTickFormatter(format='0.000 a')

        if extra_axis:
            self.figure.extra_y_ranges = {'axvol': DataRange1d()}
            adapt_yranges(self.figure.extra_y_ranges['axvol'], df.volume)
            self.figure.extra_y_ranges['axvol'].end /= self._scheme.volscaling

            ax_color = colorup

            ax = LinearAxis(y_range_name="axvol",
                            formatter=ax_formatter,
                            axis_label_text_color=ax_color,
                            axis_line_color=ax_color,
                            major_label_text_color=ax_color,
                            major_tick_line_color=ax_color,
                            minor_tick_line_color=ax_color)
            self.figure.add_layout(ax, 'left')
            kwargs['y_range_name'] = "axvol"
        else:
            self.figure.yaxis.formatter = ax_formatter
            adapt_yranges(self.figure.y_range, df.volume)
            self.figure.y_range.end /= self._scheme.volscaling

        self.figure.vbar('datetime',
                         get_bar_length_ms(obj) * 0.7,
                         src_prefix + 'volume',
                         0,
                         source=self._cds,
                         fill_color=src_prefix + 'volume_colors',
                         line_color="black",
                         **kwargs)
        self._hoverc.add_hovertip("Volume", f"@{src_prefix}volume{{(0.00 a)}}")
Пример #3
0
    def plot_volume(self, data: bt.feeds.DataBase, strat_clk: array, alpha, extra_axis=False):
        source_id = Figure._source_id(data)

        df = convert_to_pandas(strat_clk, data, self._start, self._end)

        if len(nanfilt(df.volume)) == 0:
            return

        colorup = convert_color(self._scheme.volup)
        colordown = convert_color(self._scheme.voldown)

        is_up = df.close > df.open
        colors = [colorup if x else colordown for x in is_up]

        self._add_to_cds(df.volume, f'{source_id}volume')
        self._add_to_cds(colors, f'{source_id}volume_colors')

        kwargs = {'fill_alpha': alpha,
                  'line_alpha': alpha,
                  'name': 'Volume',
                  'legend': 'Volume'}

        ax_formatter = NumeralTickFormatter(format=self._scheme.number_format)

        if extra_axis:
            self.figure.extra_y_ranges = {'axvol': DataRange1d()}
            adapt_yranges(self.figure.extra_y_ranges['axvol'], df.volume)
            self.figure.extra_y_ranges['axvol'].end /= self._scheme.volscaling

            ax_color = colorup

            ax = LinearAxis(y_range_name="axvol", formatter=ax_formatter,
                            axis_label_text_color=ax_color, axis_line_color=ax_color, major_label_text_color=ax_color,
                            major_tick_line_color=ax_color, minor_tick_line_color=ax_color)
            self.figure.add_layout(ax, 'left')
            kwargs['y_range_name'] = "axvol"
        else:
            self.figure.yaxis.formatter = ax_formatter
            adapt_yranges(self.figure.y_range, df.volume)
            self.figure.y_range.end /= self._scheme.volscaling

        self.figure.vbar('index', get_bar_width(), f'{source_id}volume', 0, source=self._cds, fill_color=f'{source_id}volume_colors', line_color="black", **kwargs)

        hover_target = None if self._scheme.merge_data_hovers else self.figure
        self._hoverc.add_hovertip("Volume", f"@{source_id}volume{{({self._scheme.number_format})}}", hover_target)
Пример #4
0
    def plot_data(self, data: bt.AbstractDataBase, strat_clk: array = None):
        source_id = Figure._source_id(data)
        title = sanitize_source_name(label_resolver.datatarget2label([data]))

        # append to title
        self._figure_append_title(title)

        df = convert_to_pandas(strat_clk, data, self._start, self._end)

        # configure colors
        colorup = convert_color(self._scheme.barup)
        colordown = convert_color(self._scheme.bardown)
        colorup_wick = convert_color(self._scheme.barup_wick)
        colordown_wick = convert_color(self._scheme.bardown_wick)
        colorup_outline = convert_color(self._scheme.barup_outline)
        colordown_outline = convert_color(self._scheme.bardown_outline)
        is_up = df.close > df.open

        self._add_to_cds(df.open, source_id + 'open')
        self._add_to_cds(df.high, source_id + 'high')
        self._add_to_cds(df.low, source_id + 'low')
        self._add_to_cds(df.close, source_id + 'close')
        self._add_to_cds([colorup if x else colordown for x in is_up],
                         source_id + 'colors_bars')
        self._add_to_cds(
            [colorup_wick if x else colordown_wick for x in is_up],
            source_id + 'colors_wicks')
        self._add_to_cds(
            [colorup_outline if x else colordown_outline for x in is_up],
            source_id + 'colors_outline')

        if self._scheme.style == 'line':
            if data.plotinfo.plotmaster is None:
                color = convert_color(self._scheme.loc)
            else:
                self._nextcolor(data.plotinfo.plotmaster)
                color = convert_color(self._color(data.plotinfo.plotmaster))

            renderer = self.figure.line('index',
                                        source_id + 'close',
                                        source=self._cds,
                                        line_color=color,
                                        legend=title)
            self._set_single_hover_renderer(renderer)

            self._hoverc.add_hovertip("Close", f"@{source_id}close", data)
        elif self._scheme.style == 'bar':
            self.figure.segment('index',
                                source_id + 'high',
                                'index',
                                source_id + 'low',
                                source=self._cds,
                                color=source_id + 'colors_wicks',
                                legend_label=title)
            renderer = self.figure.vbar(
                'index',
                get_bar_width(),
                source_id + 'open',
                source_id + 'close',
                source=self._cds,
                fill_color=source_id + 'colors_bars',
                line_color=source_id + 'colors_outline',
                legend_label=title,
            )

            self._set_single_hover_renderer(renderer)

            self._hoverc.add_hovertip(
                "Open", f"@{source_id}open{{{self._scheme.number_format}}}",
                data)
            self._hoverc.add_hovertip(
                "High", f"@{source_id}high{{{self._scheme.number_format}}}",
                data)
            self._hoverc.add_hovertip(
                "Low", f"@{source_id}low{{{self._scheme.number_format}}}",
                data)
            self._hoverc.add_hovertip(
                "Close", f"@{source_id}close{{{self._scheme.number_format}}}",
                data)
        else:
            raise Exception(f"Unsupported style '{self._scheme.style}'")

        adapt_yranges(self.figure.y_range, df.low, df.high)

        # check if we have to plot volume overlay
        if self._scheme.volume and self._scheme.voloverlay:
            self.plot_volume(data, strat_clk, self._scheme.voltrans, True)
Пример #5
0
    def plot_data(self, data: bt.feeds.DataBase, master):
        source_id = Figure._source_id(data)
        title = sanitize_source_name(data._name)
        if len(data._env.strats) > 1:
            title += f" ({get_strategy_label(self._strategy)})"

        # append to title
        self._figure_append_title(title)

        df = convert_to_pandas(data, self._start, self._end)

        # configure colors
        colorup = convert_color(self._scheme.barup)
        colordown = convert_color(self._scheme.bardown)
        colorup_wick = convert_color(self._scheme.barup_wick)
        colordown_wick = convert_color(self._scheme.bardown_wick)
        colorup_outline = convert_color(self._scheme.barup_outline)
        colordown_outline = convert_color(self._scheme.bardown_outline)
        is_up = df.close > df.open

        self._add_to_cds(df.open, source_id + 'open')
        self._add_to_cds(df.high, source_id + 'high')
        self._add_to_cds(df.low, source_id + 'low')
        self._add_to_cds(df.close, source_id + 'close')
        self._add_to_cds([colorup if x else colordown for x in is_up],
                         source_id + 'colors_bars')
        self._add_to_cds(
            [colorup_wick if x else colordown_wick for x in is_up],
            source_id + 'colors_wicks')
        self._add_to_cds(
            [colorup_outline if x else colordown_outline for x in is_up],
            source_id + 'colors_outline')

        if self._scheme.style == 'line':
            if data.plotinfo.plotmaster is None:
                color = convert_color(self._scheme.loc)
            else:
                self._nextcolor(data.plotinfo.plotmaster)
                color = convert_color(self._color(data.plotinfo.plotmaster))

            self.figure.line('datetime',
                             source_id + 'close',
                             source=self._cds,
                             line_color=color,
                             legend=data._name)
        elif self._scheme.style == 'bar':
            self.figure.segment('datetime',
                                source_id + 'high',
                                'datetime',
                                source_id + 'low',
                                source=self._cds,
                                color=source_id + 'colors_wicks',
                                legend=data._name)
            renderer = self.figure.vbar('datetime',
                                        get_bar_length_ms(data) * 0.7,
                                        source_id + 'open',
                                        source_id + 'close',
                                        source=self._cds,
                                        fill_color=source_id + 'colors_bars',
                                        line_color=source_id +
                                        'colors_outline')
            self._set_single_hover_renderer(renderer)

            self._hoverc.add_hovertip("Open", f"@{source_id}open{{0,0.000}}")
            self._hoverc.add_hovertip("High", f"@{source_id}high{{0,0.000}}")
            self._hoverc.add_hovertip("Low", f"@{source_id}low{{0,0.000}}")
            self._hoverc.add_hovertip("Close", f"@{source_id}close{{0,0.000}}")
        else:
            raise Exception(f"Unsupported style '{self._scheme.style}'")

        adapt_yranges(self.figure.y_range, df.low, df.high)

        # check if we have to plot volume overlay
        if self._scheme.volume and self._scheme.voloverlay:
            self.plot_volume(data, self._scheme.voltrans, True)
Пример #6
0
    def build_strategy_data(self,
                            strategy: bt.Strategy,
                            start: Optional[datetime.datetime] = None,
                            end: Optional[datetime.datetime] = None,
                            num_back: Optional[int] = None,
                            startidx: int = 0):
        """startidx: index number to write into the dataframe for the index column"""
        strategydf = pd.DataFrame()

        master_clock = build_master_clock(strategy, start, end)

        start, end = get_strategy_start_end(strategy, start, end)

        if num_back is None:
            num_back = len(master_clock)

        master_clock = master_clock[-num_back:]
        strategydf['master_clock'] = master_clock

        # we use timezone of first data. we might see duplicated timestamps here
        dtline = [bt.num2date(x, strategy.datas[0]._tz) for x in master_clock]

        # add an index line to use as x-axis (instead of datetime axis) to avoid datetime gaps (e.g. weekends)
        indices = list(range(startidx, startidx + len(dtline)))
        strategydf['index'] = indices

        strategydf['datetime'] = dtline

        for data in strategy.datas:
            source_id = get_source_id(data)
            df_data = convert_to_pandas(master_clock, data, start, end,
                                        source_id)

            strategydf = strategydf.join(df_data)

            df_colors = Figure.build_color_lines(df_data,
                                                 self.p.scheme,
                                                 col_open=source_id + 'open',
                                                 col_close=source_id + 'close',
                                                 col_prefix=source_id)
            strategydf = strategydf.join(df_colors)

        for obj in itertools.chain(strategy.getindicators(),
                                   strategy.getobservers()):
            for lineidx, line, source_id in get_lines(obj):
                dataline = line.plotrange(start, end)

                plottype = get_plottype(obj, lineidx)

                line_clk = get_clock_line(obj).plotrange(start, end)
                dataline = convert_to_master_clock(
                    dataline,
                    line_clk,
                    master_clock,
                    forward_fill=plottype == PlotType.LINE)
                strategydf[source_id] = dataline

        # now iterate again over indicators to calculate area plots (_fill_gt / _fill_lt)
        for ind in strategy.getindicators():
            for lineidx, line, source_id in get_lines(ind):
                for fattr, _, y2, _, _, fop in get_ind_areas(ind, lineidx):
                    if fop is None:
                        continue  # we only need to take care when operator is used

                    if isinstance(y2, int):
                        # scalar value
                        pass
                    elif isinstance(y2, str):
                        y2 = strategydf[y2]
                    else:
                        raise RuntimeError('Unexpected type')

                    dataline_pd = pd.Series(strategydf[source_id])
                    lineid = source_id + fattr
                    strategydf[lineid] = dataline_pd.where(
                        fop(dataline_pd, y2), y2).to_numpy()

        # apply a proper index (should be identical to 'index' column)
        if strategydf.shape[0] > 0:
            strategydf.index = indices
        return strategydf