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

Rebalancing - Conservative Formula

  • Hi,
    I am trying to replicate the strategy published in the article - 'Rebalancing - Conservative Formula' with my own data. However, ranks and final portfolio values are coming as nan . Appreciate any help!! below is the code for your reference

    class Strategy(bt.Strategy):
        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=0.05  # 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)
            # 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 = (1.0 - 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]
            # 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: m / v for d, v, m in zip(self.datas, vs, ms)}
        def next(self):
            # sort data and current rank
            ranks = sorted(
                self.ranks.items(),  # get the (d, rank), pair
                key=lambda x: x[1][0],  # use rank (elem 1) and current time "0"
                reverse=True,  # highest ranked 1st ... please
            # put top ranked in dict with data as key to test for presence
            rtop = dict(ranks[:self.selnum])
            # For logging purposes of stocks leaving the portfolio
            rbot = dict(ranks[self.selnum:])
            # prepare quick lookup list of stocks currently holding a position
            posdata = [d for d, pos in self.getpositions().items() if pos]
            # remove those no longer top ranked
            # do this first to issue sell orders and free cash
            for d in (d for d in posdata if d not in rtop):
                self.log('Leave {} - Rank {:.2f}'.format(d._name, rbot[d][0]))
                self.order_target_percent(d, target=0.0)
            # rebalance those already top ranked and still there
            for d in (d for d in posdata if d in rtop):
                self.log('Rebal {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
                self.order_target_percent(d, target=self.perctarget)
                del rtop[d]  # remove it, to simplify next iteration
            # issue a target order for the newly top ranked stocks
            # do this last, as this will generate buy orders consuming cash
            for d in rtop:
                self.log('Enter {} - Rank {:.2f}'.format(d._name, rtop[d][0]))
                self.order_target_percent(d, target=self.perctarget)
    cerebro = bt.Cerebro()
    # Add securities as datas:
    for ticker, data in prices.groupby(level=0):
        if ticker in TICKERS:
            print(f"Adding ticker: {ticker}")
            data = bt.feeds.PandasData(dataname=data.droplevel(level=0),

    Adding ticker: ACC.NS
    Adding ticker: ADANIPORTS.NS
    Adding ticker: AMBUJACEM.NS
    Adding ticker: ASHOKLEY.NS
    Adding ticker: ASIANPAINT.NS
    Adding ticker: AUROPHARMA.NS
    Adding ticker: AXISBANK.NS
    Adding ticker: BAJAJ-AUTO.NS
    Adding ticker: BAJAJFINSV.NS

    cerebro.addanalyzer(bt.analyzers.Returns, _name='returns')
    cerebro.addanalyzer(bt.analyzers.TimeReturn, _name='time_return')
    cerebro.addanalyzer(bt.analyzers.PyFolio, _name='pyfolio')
    print('Starting Portfolio Value: %.2f' %
    # Run the strategy. Results will be output from stop.
    results =, tradehistory=False)
    # # Run over everything
    # results =
    # Print out the final result
    print('Final Portfolio Value: %.2f' %

    Starting Portfolio Value: 300000.00
    2017-01-31 Enter ACC.NS - Rank nan
    2017-01-31 Enter ADANIPORTS.NS - Rank nan
    2017-01-31 Enter AMBUJACEM.NS - Rank nan
    2017-01-31 Enter ASHOKLEY.NS - Rank nan
    2017-01-31 Enter ASIANPAINT.NS - Rank nan
    2017-01-31 Enter AUROPHARMA.NS - Rank nan
    2017-01-31 Enter AXISBANK.NS - Rank nan
    2017-01-31 Enter BAJAJ-AUTO.NS - Rank nan
    2017-01-31 Enter BAJAJFINSV.NS - Rank nan
    2017-01-31 Enter BAJAJHLDNG.NS - Rank nan
    2017-01-31 Enter BAJFINANCE.NS - Rank nan
    2017-01-31 Enter BANKBARODA.NS - Rank nan
    2017-01-31 Enter BERGEPAINT.NS - Rank nan
    2017-01-31 Enter BHARTIARTL.NS - Rank nan
    2017-01-31 Enter BIOCON.NS - Rank nan
    2017-01-31 Enter BOSCHLTD.NS - Rank nan
    2017-01-31 Enter BPCL.NS - Rank nan
    2017-01-31 Enter BRITANNIA.NS - Rank nan
    2017-02-28 Rebal ACC.NS - Rank nan
    2017-02-28 Rebal ADANIPORTS.NS - Rank nan
    2017-02-28 Rebal AMBUJACEM.NS - Rank nan
    2017-02-28 Rebal ASHOKLEY.NS - Rank nan
    2017-02-28 Rebal ASIANPAINT.NS - Rank nan
    Final Portfolio Value: nan

  • It looks like a data issue, I get this when I change the frequency from daily to monthly.

  • @Sabir-Jana I'm curious if someone has an answer because I couldn't see error in your code.

  • I did not went through the code, but check maybe if the analyser use a timeframe value.

  • There is no issue with the code. Data wasn't clean hence causing the issue. Once I run the code with clean data, it worked.

Log in to reply