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

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(self.datetime.date(), 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()
    cerebro.broker.setcash(300000.0)
    cerebro.broker.setcommission(commission=0.001)
    
    # 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),
                                       name=ticker,
                                       plot=False)
            cerebro.adddata(data)
    

    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.addstrategy(Strategy,
                        selcperc=0.20,
                        vperiod=36,
                        mperiod=6)
    cerebro.addobserver(bt.observers.BuySell)
    cerebro.addobserver(bt.observers.Value)
    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' % cerebro.broker.getvalue())
    # Run the strategy. Results will be output from stop.
    results = cerebro.run(stdstats=True, tradehistory=False)
    
    # # Run over everything
    # results = cerebro.run(maxcpus=1)
    
    # Print out the final result
    print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
    

    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.
    Thanks


Log in to reply
 

});