Navigation

    Backtrader Community

    • Register
    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    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

    Indicators/Strategies/Analyzers
    3
    5
    204
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • Sabir Jana
      Sabir Jana last edited by

      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

      1 Reply Last reply Reply Quote 0
      • Sabir Jana
        Sabir Jana last edited by

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

        run-out 1 Reply Last reply Reply Quote 0
        • run-out
          run-out @Sabir Jana last edited by

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

          RunBacktest.com

          1 Reply Last reply Reply Quote 0
          • D
            dasch last edited by

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

            1 Reply Last reply Reply Quote 0
            • Sabir Jana
              Sabir Jana last edited by

              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

              1 Reply Last reply Reply Quote 1
              • 1 / 1
              • First post
                Last post
              Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors