예제 #1
0
    def _configure_plotting(self, strategy: bt.Strategy):
        datas, inds, obs = strategy.datas, strategy.getindicators(
        ), strategy.getobservers()

        for objs in [datas, inds, obs]:
            for idx, obj in enumerate(objs):
                self._configure_plotobject(obj, idx, strategy)
예제 #2
0
    def _blueprint_strategy(self,
                            strategy: bt.Strategy,
                            start=None,
                            end=None,
                            tradingdomain=None,
                            **kwargs) -> None:
        if not strategy.datas:
            return

        self._cur_figurepage.analyzers += [
            a for _, a in strategy.analyzers.getitems()
        ]

        data_graph, volume_graph = self._build_graph(strategy.datas,
                                                     strategy.getindicators(),
                                                     strategy.getobservers(),
                                                     tradingdomain)

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

        # reset hover container to not mix hovers with other strategies
        hoverc = HoverContainer(
            hover_tooltip_config=self.p.scheme.hover_tooltip_config,
            is_multidata=len(strategy.datas) > 1)

        figure_envs: List[Figure] = []
        for master, slaves in data_graph.items():
            plotorder = getattr(master.plotinfo, 'plotorder', 0)
            figureenv = Figure(strategy, self._cur_figurepage.cds, hoverc,
                               start, end, self.p.scheme, master, plotorder)

            figureenv.plot(master)

            for s in slaves:
                figureenv.plot(s)
            figure_envs.append(figureenv)

        for f in figure_envs:
            f.bfigure.legend.click_policy = self.p.scheme.legend_click
            f.bfigure.legend.location = self.p.scheme.legend_location
            f.bfigure.legend.background_fill_color = self.p.scheme.legend_background_color
            f.bfigure.legend.label_text_color = self.p.scheme.legend_text_color
            f.bfigure.legend.orientation = self.p.scheme.legend_orientation

        # link axis
        for i in range(1, len(figure_envs)):
            figure_envs[i].bfigure.x_range = figure_envs[0].bfigure.x_range

        hoverc.apply_hovertips(figure_envs)

        self._cur_figurepage.figures += figure_envs

        # volume graphs
        for v in volume_graph:
            plotorder = getattr(v.plotinfo, 'plotorder', 0)
            figureenv = Figure(strategy, self._cur_figurepage.cds, hoverc,
                               start, end, self.p.scheme, v, plotorder)
            figureenv.plot_volume(v)
            self._cur_figurepage.figures.append(figureenv)
예제 #3
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
예제 #4
0
    def list_tradingdomains(self, strategy: bt.Strategy):
        data_graph, volume_graph = self._build_graph(strategy.datas,
                                                     strategy.getindicators(),
                                                     strategy.getobservers())

        lgs = list()
        for master in itertools.chain(data_graph.keys(), volume_graph):
            lg = FigureEnvelope._resolve_tradingdomain(master)
            if isinstance(lg, str) and lg not in lgs:
                lgs.append(lg)

        return lgs
예제 #5
0
    def list_tradingdomains(self, strategy: bt.Strategy):
        """Return a list of all trading domains to be found in a strategy."""
        data_graph, volume_graph = self._build_graph(strategy.datas,
                                                     strategy.getindicators(),
                                                     strategy.getobservers())

        lgs = list()
        for master in itertools.chain(data_graph.keys(), volume_graph):
            lg = get_tradingdomain(master)
            if isinstance(lg, str) and lg not in lgs:
                lgs.append(lg)

        return lgs
예제 #6
0
def find_by_plotid(strategy: bt.Strategy, plotid):
    objs = itertools.chain(strategy.datas, strategy.getindicators(), strategy.getobservers())
    founds = []
    for obj in objs:
        if getattr(obj.plotinfo, 'plotid', None) == plotid:
            founds.append(obj)

    num_results = len(founds)
    if num_results == 0:
        return None
    elif num_results == 1:
        return founds[0]
    else:
        raise RuntimeError(f'Found multiple objects with plotid "{plotid}"')
예제 #7
0
def build_master_clock(strategy: bt.Strategy,
                       start: Optional[datetime.datetime] = None, end: Optional[datetime.datetime] = None,
                       ):
    """Build the master clock which is a clock line that is basically a merged line of all available clocks"""
    master_clock = []
    for obj in itertools.chain(strategy.datas, strategy.getindicators(), strategy.getobservers()):
        line_clk = get_clock_line(obj).plotrange(start, end)
        master_clock += line_clk

    # remove duplicates
    master_clock = list(dict.fromkeys(master_clock))

    master_clock.sort()

    return master_clock
예제 #8
0
    def _blueprint_strategy(self,
                            strategy: bt.Strategy,
                            start=None,
                            end=None,
                            tradingdomain=None,
                            **kwargs) -> None:
        if not strategy.datas:
            return

        self._cur_figurepage.analyzers += [
            a for _, a in strategy.analyzers.getitems()
        ]

        data_graph, volume_graph = self._build_graph(strategy.datas,
                                                     strategy.getindicators(),
                                                     strategy.getobservers(),
                                                     tradingdomain)

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

        # reset hover container to not mix hovers with other strategies
        hoverc = HoverContainer(
            hover_tooltip_config=self.p.scheme.hover_tooltip_config,
            is_multidata=len(strategy.datas) > 1)

        strat_figures = []
        for master, slaves in data_graph.items():
            plotorder = getattr(master.plotinfo, 'plotorder', 0)
            figure = FigureEnvelope(strategy, self._cur_figurepage.cds, hoverc,
                                    start, end, self.p.scheme, master,
                                    plotorder,
                                    len(strategy.datas) > 1)

            figure.plot(master, None)

            for s in slaves:
                figure.plot(s, master)
            strat_figures.append(figure)

        for f in strat_figures:
            f.figure.legend.click_policy = self.p.scheme.legend_click
            f.figure.legend.location = self.p.scheme.legend_location
            f.figure.legend.background_fill_color = self.p.scheme.legend_background_color
            f.figure.legend.label_text_color = self.p.scheme.legend_text_color
            f.figure.legend.orientation = self.p.scheme.legend_orientation

        # link axis
        for i in range(1, len(strat_figures)):
            strat_figures[i].figure.x_range = strat_figures[0].figure.x_range

        # configure xaxis visibility
        if self.p.scheme.xaxis_pos == "bottom":
            for i, f in enumerate(strat_figures):
                f.figure.xaxis.visible = False if i <= len(
                    strat_figures) else True

        hoverc.apply_hovertips(strat_figures)

        self._cur_figurepage.figure_envs += strat_figures

        # volume graphs
        for v in volume_graph:
            plotorder = getattr(v.plotinfo, 'plotorder', 0)
            figure = FigureEnvelope(strategy,
                                    self._cur_figurepage.cds,
                                    hoverc,
                                    start,
                                    end,
                                    self.p.scheme,
                                    v,
                                    plotorder,
                                    is_multidata=len(strategy.datas) > 1)
            figure.plot_volume(v)
            self._cur_figurepage.figure_envs.append(figure)
예제 #9
0
    def _blueprint_strategy(self,
                            strategy: bt.Strategy,
                            start=None,
                            end=None,
                            **kwargs):
        if not strategy.datas:
            return

        if not len(strategy):
            return

        strat_figures = []
        self._fp.analyzers = [a for _, a in strategy.analyzers.getitems()]

        st_dtime = strategy.lines.datetime.plot()
        if start is None:
            start = 0
        if end is None:
            end = len(st_dtime)

        if isinstance(start, datetime.date):
            start = bisect.bisect_left(st_dtime, bt.date2num(start))

        if isinstance(end, datetime.date):
            end = bisect.bisect_right(st_dtime, bt.date2num(end))

        if end < 0:
            end = len(st_dtime) + 1 + end  # -1 =  len() -2 = len() - 1

        # TODO: using a pandas.DataFrame is desired. On bokeh 0.12.13 this failed cause of this issue:
        # https://github.com/bokeh/bokeh/issues/7400
        strat_clk: array[float] = strategy.lines.datetime.plotrange(start, end)

        if self._fp.cds is None:
            # we use timezone of first data
            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(0, len(dtline)))
            self._fp.cds = ColumnDataSource(
                data=dict(datetime=dtline, index=indices))

        self._build_graph(strategy.datas, strategy.getindicators(),
                          strategy.getobservers())

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

        # reset hover container to not mix hovers with other strategies
        hoverc = HoverContainer()

        for master, slaves in self._data_graph.items():
            plotabove = getattr(master.plotinfo, 'plotabove', False)
            bf = Figure(strategy, self._fp.cds, hoverc, start, end,
                        self.p.scheme, type(master), plotabove)
            strat_figures.append(bf)

            bf.plot(master, strat_clk, None)

            for s in slaves:
                bf.plot(s, strat_clk, master)

        for v in self._volume_graphs:
            bf = Figure(strategy, self._fp.cds, hoverc, start, end,
                        self.p.scheme)
            bf.plot_volume(v, strat_clk, 1.0, start, end)

        # apply legend click policy
        for f in strat_figures:
            f.figure.legend.click_policy = self.p.scheme.legend_click

        for f in strat_figures:
            f.figure.legend.background_fill_color = self.p.scheme.legend_background_color
            f.figure.legend.label_text_color = self.p.scheme.legend_text_color

        # link axis
        for i in range(1, len(strat_figures)):
            strat_figures[i].figure.x_range = strat_figures[0].figure.x_range

        # configure xaxis visibility
        if self.p.scheme.xaxis_pos == "bottom":
            for i, f in enumerate(strat_figures):
                f.figure.xaxis.visible = False if i <= len(
                    strat_figures) else True

        hoverc.apply_hovertips(strat_figures)

        self._fp.figures += strat_figures
예제 #10
0
    def _blueprint_strategy(self,
                            strategy: bt.Strategy,
                            start=None,
                            end=None,
                            **kwargs):
        if not strategy.datas:
            return

        if not len(strategy):
            return

        self._figurepage.analyzers += [
            a for _, a in strategy.analyzers.getitems()
        ]

        st_dtime = strategy.lines.datetime.plot()
        if start is None:
            start = 0
        if end is None:
            end = len(st_dtime)

        if isinstance(start, datetime.date):
            start = bisect.bisect_left(st_dtime, bt.date2num(start))

        if isinstance(end, datetime.date):
            end = bisect.bisect_right(st_dtime, bt.date2num(end))

        if end < 0:
            end = len(st_dtime) + 1 + end  # -1 =  len() -2 = len() - 1

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

        if self._figurepage.cds is None:
            # we use timezone of first data
            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(0, len(dtline)))
            self._figurepage.cds = ColumnDataSource(
                data=dict(datetime=dtline, index=indices))

        data_graph, volume_graph = self._build_graph(strategy.datas,
                                                     strategy.getindicators(),
                                                     strategy.getobservers())

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

        # reset hover container to not mix hovers with other strategies
        hoverc = HoverContainer(
            hover_tooltip_config=self.p.scheme.hover_tooltip_config,
            is_multidata=len(strategy.datas) > 1)

        strat_figures = []
        for master, slaves in data_graph.items():
            plotorder = getattr(master.plotinfo, 'plotorder', 0)
            figure = Figure(strategy, self._figurepage.cds, hoverc, start, end,
                            self.p.scheme, master, plotorder,
                            len(strategy.datas) > 1)

            figure.plot(master, strat_clk, None)

            for s in slaves:
                figure.plot(s, strat_clk, master)
            strat_figures.append(figure)

        for f in strat_figures:
            f.figure.legend.click_policy = self.p.scheme.legend_click
            f.figure.legend.location = self.p.scheme.legend_location
            f.figure.legend.background_fill_color = self.p.scheme.legend_background_color
            f.figure.legend.label_text_color = self.p.scheme.legend_text_color
            f.figure.legend.orientation = self.p.scheme.legend_orientation

        # link axis
        for i in range(1, len(strat_figures)):
            strat_figures[i].figure.x_range = strat_figures[0].figure.x_range

        # configure xaxis visibility
        if self.p.scheme.xaxis_pos == "bottom":
            for i, f in enumerate(strat_figures):
                f.figure.xaxis.visible = False if i <= len(
                    strat_figures) else True

        hoverc.apply_hovertips(strat_figures)

        self._figurepage.figures += strat_figures

        # volume graphs
        for v in volume_graph:
            plotorder = getattr(v.plotinfo, 'plotorder', 0)
            figure = Figure(strategy, self._figurepage.cds, hoverc, start, end,
                            self.p.scheme, v, plotorder,
                            len(strategy.datas) > 1)
            figure.plot_volume(v, strat_clk, 1.0)
            self._figurepage.figures.append(figure)
예제 #11
0
    def _plot_strategy(self,
                       strategy: bt.Strategy,
                       start=None,
                       end=None,
                       **kwargs):
        if not strategy.datas:
            return

        if not len(strategy):
            return

        strat_figures = []
        # reset hover container to not mix hovers with other strategies
        hoverc = HoverContainer()
        for name, a in strategy.analyzers.getitems():
            self._fp.analyzers.append((name, a, strategy, None))

        # TODO: using a pandas.DataFrame is desired. On bokeh 0.12.13 this failed cause of this issue:
        # https://github.com/bokeh/bokeh/issues/7400

        if self._fp.cds is None:
            # use datetime line of first data as master datetime. also convert it according to user provided tz
            dtline = pandas.Series([
                bt.num2date(x, strategy.datas[0]._tz)
                for x in strategy.datas[0].lines.datetime.plotrange(
                    start, end)
            ],
                                   name="DateTime")
            self._fp.cds = ColumnDataSource(data={'datetime': dtline})

        self._build_graph(strategy.datas, strategy.getindicators(),
                          strategy.getobservers())

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

        for master, slaves in self._data_graph.items():
            plotabove = getattr(master.plotinfo, 'plotabove', False)
            bf = Figure(strategy, self._fp.cds, hoverc, start, end,
                        self.p.scheme, type(master), plotabove)
            strat_figures.append(bf)

            bf.plot(master, None)

            for s in slaves:
                bf.plot(s, master)

        for v in self._volume_graphs:
            bf = Figure(strategy, self._fp.cds, hoverc, start, end,
                        self.p.scheme)
            bf.plot_volume(v, 1.0, start, end)

        # apply legend click policy
        for f in strat_figures:
            f.figure.legend.click_policy = self.p.scheme.legend_click

        for f in strat_figures:
            f.figure.legend.background_fill_color = self.p.scheme.legend_background_color
            f.figure.legend.label_text_color = self.p.scheme.legend_text_color

        # link axis
        for i in range(1, len(strat_figures)):
            strat_figures[i].figure.x_range = strat_figures[0].figure.x_range

        # configure xaxis visibility
        if self.p.scheme.xaxis_pos == "bottom":
            for i, f in enumerate(strat_figures):
                f.figure.xaxis.visible = False if i <= len(
                    strat_figures) else True

        hoverc.apply_hovertips(strat_figures)

        self._fp.figures += strat_figures
예제 #12
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