For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See:

Volume in multidata

  • Hi All,

    I am facing issue to access for multi-data, please refer the code below:

        params = dict(
            selcperc=0.10,  # percentage of stocks to select from the universe
            rperiod=1,  # period for the returns calculation, default 1 period
            vperiod=36,  # lookback period for volatility - default 36 periods
            mperiod=12,  # lookback period for momentum - default 12 periods
            reserve=5,  # 5% reserve capital
        def log(self, arg):
                print('{} {}'.format(, arg))   
        def __init__(self):
            # calculate 1st the amount of stocks that will be selected
            self.selnum = int(len(self.datas) * self.p.selcperc)
            print(int(len(self.datas) * self.p.selcperc))
            # allocation perc per stock
            # reserve kept to make sure orders are not rejected due to
            # margin. Prices are calculated when known (close), but orders can only
            # be executed next day (opening price). Price can gap upwards
            self.perctarget = (100 - self.p.reserve) / self.selnum
            print((100 - self.p.reserve) / self.selnum)
            # returns, volatilities and momentums
            rs = [bt.ind.PctChange(d, period=self.p.rperiod) for d in self.datas]
            vs = [bt.ind.StdDev(ret, period=self.p.vperiod) for ret in rs]
            ms = [bt.ind.ROC(d, period=self.p.mperiod) for d in self.datas]
            volume = [bt.indicators.MovingAverageSimple(d, period = 2) for d in self.datas[0].volume]
            # simple rank formula: (momentum * net payout) / volatility
            # the highest ranked: low vol, large momentum, large payout
            # self.ranks = {d: d.npy * m / v for d, v, m in zip(self.datas, vs, ms)}
            self.ranks = {d: bt.DivByZero(m, v) for d, v, m, volu in zip(self.datas, vs, ms, volume) if volu > 100000}

    Above is giving error:

        self.ranks = {d: bt.DivByZero(m, v) for d, v, m, volu in zip(self.datas, vs, ms, volume) if volu > 100000}
    TypeError: __bool__ should return bool, returned LineOwnOperation

    I am not an expert, any pointers to fix the issue?

  • volu refers to volume which is I think list comprehenion of SMA indicator objects. You won't be able to compare each value with a scalar.

  • thanks @run-out , is there any other way? I am trying to filter out stocks whose average volume is greater than certain value.

  • @gten Yes, you create an dictionary to keep track of your indicators for each datas you have put into the backtest.

    Then in init you loop through the datas to create your indicator. If you use > you will have a line of binary 1 or 0. You can then call these values at each 'next' to determine the truth value an any bar of your data volume being greater than the threshold. Here is the sample code:

    import backtrader as bt
    import yfinance as yf
    class Strategy(bt.Strategy):
        def log(self, txt, dt=None):
            """ Logging function fot this strategy"""
            dt = dt or[0]
            if isinstance(dt, float):
                dt = bt.num2date(dt)
            print("%s, %s" % (dt, txt))
        def __init__(self):
            self.sma_dict = {}
            self.p.volume_threshold = 15000000
            # Average volume over threshold
            for d in self.datas:
                self.sma_dict[d] = bt.ind.SMA(d.volume, period=30) > self.p.volume_threshold
        def next(self):
            for d in self.datas:
                self.log(f"{d._name},\tvolume: {int(d.volume[0]):10,d},\tave_volume_gt: {int(self.sma_dict[d][0]):2d}")
    def runstrategy():
        cerebro = bt.Cerebro()
        fromdate = "2020-01-15"
        todate = "2020-06-19"
        interval = "1d"
        data0 = bt.feeds.PandasData(
                "AAPL", start=fromdate, stop=todate, interval=interval
        data1 = bt.feeds.PandasData(
                "MSFT", start=fromdate, stop=todate, interval=interval
        data2 = bt.feeds.PandasData(
                "TSLA", start=fromdate, stop=todate, interval=interval
    if __name__ == "__main__":

  • Thank you @run-out, makes sense.

Log in to reply