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/

    Changing tickets orders leads to different results

    General Discussion
    2
    10
    71
    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.
    • M
      marsario last edited by

      Hello,

      I'm making a simple strategy: every day, the program checks the performance of all tickers, buys the one with the best performance (the greatest increase in the last 60 working days), while selling the rest.

      The results should be the same regardless of the order of the tickers. But it's not so. The performance is VERY different. Can you help me spot the problem?

      This is the method that selects the best stock:

      def buyBestGrowing(self):
          best = self.datas[0]
          bestgrowth = best.close[0]/best.close[-60]
          for i,stock in enumerate(self.datas):
              print("i =",i,"; stock =",stock)
              stockgrowth = stock.close[0]/stock.close[-60]
              if stockgrowth > bestgrowth:
                  self.close(best)
                  best = stock
          buy(self,best)  
      

      The buy method:

      def buy(self,dataX,size=None):
          #buys the wished size of the specified stock data. If no size is mentioned, buys as much as possible with the current capital based on tomorrow's open price
          try:
              self.buy(dataX,size or self.cerebro.broker.get_cash()/dataX.open[1])
          except:
              pass
      

      Thank you!

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

        @marsario Your code is working too hard. Backtrader has built in indicators for this.

        You can use the momentum indicator in the init section of your Strategy class, and go through all of your datas to create a momentum indicator for each, and then store them in the dictionary using the data object as key.

        Then in next at each bar, you can go through each momentum indictor and check for the max.

        Try the following:

        import datetime
        import backtrader as bt
        
        class Strategy(bt.Strategy):
        
            def log(self, txt, dt=None):
                """ Logging function fot this strategy"""
                dt = dt or self.data.datetime[0]
                if isinstance(dt, float):
                    dt = bt.num2date(dt)
                print("%s, %s" % (dt.date(), txt))
        
           
            def __init__(self):
                self.mo = dict()
        
                for d in self.datas:
                    self.mo[d] = bt.ind.Momentum(d.close, period=10)
        
        
            def next(self):
                best_mo_val = None
                best_mo_data = None
                for dmo, mom in self.mo.items():
                    if not best_mo_val or mom[0] > best_mo_val:
                        best_mo_val = mom[0]
                        best_mo_data = dmo
        
                self.log(f"{best_mo_data._name}, {best_mo_val:5.2f}")
        
        
        
        
        if __name__ == "__main__":
        
            cerebro = bt.Cerebro()
        
            """ NEW DATA PARAMETERS """
            for ticker in [
                "AAPL",
                "AMZN",
                "BAC",
                "BUD",
                "FB",
                "GOOG",
                "JNJ",
                "MSFT",
                "PG",
                "T",
                "TSLA",
                "XOM",
                "v",
            ]:
                data = bt.feeds.YahooFinanceData(
                    dataname=ticker,
                    timeframe=bt.TimeFrame.Days,
                    fromdate=datetime.date(2020, 1, 1),
                    todate=datetime.date(2020, 12, 31),
                    reverse=False,
                )
                cerebro.adddata(data)
        
            cerebro.addstrategy(Strategy)
        
            # Execute
            cerebro.run()
        
        
        1 Reply Last reply Reply Quote 1
        • M
          marsario last edited by

          Amazing, thanks @run-out !

          Can you tell me if I understand correctly?

                      self.mo[d] = bt.ind.Momentum(d.close, period=10)
          

          The period is the number of days I want to consider, so if I want to check the increase in the last three months, I should write: period = 60. Correct?

          Also, if I want to sell all the positions I had in my portfolio when there is a change of best stock, and if I want to buy the new best stock, I should change this part:

                     if not best_mo_val or mom[0] > best_mo_val:
                         self.close(best_mo_data)
                         best_mo_val = mom[0]
                         best_mo_data = dmo
          
                     self.log(f"{best_mo_data._name}, {best_mo_val:5.2f}")
                     try:
                         self.buy(dataX,self.cerebro.broker.get_cash()/dataX.open[1])
                     except:
                         pass
          

          Thank you so much for taking the time to reply and helping with my code!!

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

            @marsario said in Changing tickets orders leads to different results:

            The period is the number of days I want to consider, so if I want to check the increase in the last three months, I should write: period = 60. Correct?

            Period is the number of bars.

            M 1 Reply Last reply Reply Quote 0
            • M
              marsario @run-out last edited by

              @run-out Hi again!

              I tried to run this code

              import datetime
              import backtrader as bt
              
              class Strategy(bt.Strategy):
              
                  def log(self, txt, dt=None):
                      """ Logging function fot this strategy"""
                      dt = dt or self.data.datetime[0]
                      if isinstance(dt, float):
                          dt = bt.num2date(dt)
                      print("%s, %s" % (dt.date(), txt))
              
                 
                  def __init__(self):
                      self.mo = dict()
              
                      for d in self.datas:
                          self.mo[d] = bt.ind.Momentum(d.close, period=10)
              
              
                  def next(self):
                      best_mo_val = None
                      best_mo_data = None
                      for dmo, mom in self.mo.items():
                          if not best_mo_val or mom[0] > best_mo_val:
                              self.close(best_mo_data)
                              best_mo_val = mom[0]
                              best_mo_data = dmo
              
                      self.log(f"{best_mo_data._name}, {best_mo_val:5.2f}")
                      try:
                          self.buy(best_mo_data,self.cerebro.broker.get_cash()/best_mo_data.open[1])
                      except:
                          pass
              
              
              
              
              if __name__ == "__main__":
              
                  cerebro = bt.Cerebro()
              
                  """ NEW DATA PARAMETERS """
                  for ticker in [
                      "BUD",
                      "FB",
                      "GOOG",
                      "JNJ",
                      "MSFT",
                      "PG",
                      "T",
                      "TSLA",
                      "XOM",
                      "v",
                      "AAPL",
                      "AMZN",
                      "BAC"
                  ]:
                      data = bt.feeds.YahooFinanceData(
                          dataname=ticker,
                          timeframe=bt.TimeFrame.Days,
                          fromdate=datetime.date(2020, 1, 1),
                          todate=datetime.date(2020, 12, 31),
                          reverse=False,
                      )
                      cerebro.adddata(data)
              
                  cerebro.addstrategy(Strategy)
              
                  # Execute
                  print('Initial Portfolio Value: %.2f' % cerebro.broker.getvalue())
                  cerebro.run()
                  print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
              

              This is the result:

              Initial Portfolio Value: 10000.00
              2020-01-16, GOOG, 84.33
              2020-01-17, GOOG, 119.73
              2020-01-21, GOOG, 90.19
              2020-01-22, GOOG, 92.61
              2020-01-23, GOOG, 82.33
              2020-01-24, GOOG, 46.88
              2020-01-27, TSLA, 15.97
              2020-01-28, GOOG, 13.33
              ...
              2020-12-22, AMZN, 29.23
              2020-12-23, AMZN, 81.07
              2020-12-24, AMZN, 71.20
              2020-12-28, AMZN, 167.54
              2020-12-29, AMZN, 165.03
              2020-12-30, AMZN, 120.73
              Final Portfolio Value: 16231.82
              

              If I change the tickers' order to:

                  for ticker in [
                      "TSLA",
                      "XOM",
                      "v",
                      "AAPL",
                      "AMZN",
                      "BAC",
                      "BUD",
                      "FB",
                      "GOOG",
                      "JNJ",
                      "MSFT",
                      "PG",
                      "T"
                  ]:
              

              the log is the same but the final portfolio value is 11890.82

              How is it possible?

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

                @marsario Can you share with us the steps you took to debug your code including logs? Thanks.

                M 1 Reply Last reply Reply Quote 0
                • M
                  marsario @run-out last edited by

                  @run-out

                  These are some trials.

                  I tried to print the value of the stocks in my portfolio:

                  import datetime
                  import backtrader as bt
                  
                  class Strategy(bt.Strategy):
                  
                      def log(self, txt, dt=None):
                          """ Logging function fot this strategy"""
                          dt = dt or self.data.datetime[0]
                          if isinstance(dt, float):
                              dt = bt.num2date(dt)
                          print("%s, %s" % (dt.date(), txt))
                  
                     
                      def __init__(self):
                          self.mo = dict()
                  
                          for d in self.datas:
                              self.mo[d] = bt.ind.Momentum(d.close, period=10)
                  
                  
                      def next(self):
                          best_mo_val = None
                          best_mo_data = None
                          for dmo, mom in self.mo.items():
                              print("The portfolio contains",self.broker.getposition(dmo).size*dmo.close[0],"of",dmo._name)
                              if not best_mo_val or mom[0] > best_mo_val:
                                  self.close(best_mo_data)
                                  best_mo_val = mom[0]
                                  best_mo_data = dmo
                  
                          self.log(f"{best_mo_data._name}, {best_mo_val:5.2f}")
                          try:
                              self.buy(best_mo_data,self.cerebro.broker.get_cash()/best_mo_data.open[1])
                          except:
                              pass
                  
                  
                  
                  
                  if __name__ == "__main__":
                  
                      cerebro = bt.Cerebro()
                  
                      """ NEW DATA PARAMETERS """
                      for ticker in [
                          "TSLA",
                          "XOM",
                          "v",
                          "AAPL",
                          "AMZN",
                          "BAC",
                          "BUD",
                          "FB",
                          "GOOG",
                          "JNJ",
                          "MSFT",
                          "PG",
                          "T"
                      ]:
                          data = bt.feeds.YahooFinanceData(
                              dataname=ticker,
                              timeframe=bt.TimeFrame.Days,
                              fromdate=datetime.date(2020, 1, 1),
                              todate=datetime.date(2020, 12, 31),
                              reverse=False,
                          )
                          cerebro.adddata(data)
                  
                      cerebro.addstrategy(Strategy)
                  
                      # Execute
                      print('Initial Portfolio Value: %.2f' % cerebro.broker.getvalue())
                      cerebro.run()
                      print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
                  
                  

                  The result shows that it buys Google at first (which is the best), and then it keeps it till the end.

                  Initial Portfolio Value: 10000.00
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 0.0 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-01-16, GOOG, 84.33
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 10119.487870067194 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-01-17, GOOG, 119.73
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 10146.898989001375 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-01-21, GOOG, 90.19
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 10157.494309287653 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-01-22, GOOG, 92.61
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 10162.279292642746 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-01-23, GOOG, 82.33
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 10025.97562392765 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-01-24, GOOG, 46.88
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 9801.696618383905 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-01-27, TSLA, 15.97
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 9929.250603249686 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  ...
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 12022.065608957488 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-12-29, AMZN, 165.03
                  The portfolio contains 0.0 of TSLA
                  The portfolio contains 0.0 of XOM
                  The portfolio contains 0.0 of v
                  The portfolio contains 0.0 of AAPL
                  The portfolio contains 0.0 of AMZN
                  The portfolio contains 0.0 of BAC
                  The portfolio contains 0.0 of BUD
                  The portfolio contains 0.0 of FB
                  The portfolio contains 11890.820351217777 of GOOG
                  The portfolio contains 0.0 of JNJ
                  The portfolio contains 0.0 of MSFT
                  The portfolio contains 0.0 of PG
                  The portfolio contains 0.0 of T
                  2020-12-30, AMZN, 120.73
                  Final Portfolio Value: 11890.82
                  

                  After that, I tried to put the close orders at different places and change the close order with a sell order. But none of the results made any sense..

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

                    @marsario I think you should spend some time working through the examples in the documentation so that you can get a firm foundation on how backtrader works.

                    In your example above you have not sold Google, that's why it stay there. And then when the system tries to buy, you will get a margin error, which you should be seeing in logs, and you would know how to after working through the docs. This is a really basic error and is why I'm suggesting you spend some time in the docs.

                    We are lucky that backtrader has really good documentation, try to work through some of it for a while then we can help you as you go along. Good luck!

                    M 1 Reply Last reply Reply Quote 2
                    • M
                      marsario @run-out last edited by

                      @run-out

                      I appreciate that you are taking the time to reply each time, but I feel you are underestimating how much effort I'm putting in to try to make this code run. It's been a week that I have been going through the documentation and if I wrote to this forum it's because I have no idea of how to make it run. Yes, I understand it doesn't close orders. And how to make them close? I've been trying both with sell and close orders, changing the piece of code, nothing helps.

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

                        @marsario I know that backtrader can be frustrating when you first start. Trust me I know. However, I would argue, after looking some more at your code, that you must first learn to walk before you run. And you are already trying to run.

                        You need to take a step back and work through some of the examples.

                        But if you insist on tackling a multi data/multi indicator dictionary strategy to start, here are a few more tips.

                        Add in these loggers they will give you more information:

                            def notify_order(self, order):
                                self.log(
                                    "Order ref: {} / Type {} / Status {}".format(
                                        order.ref, "Buy" * order.isbuy() or "Sell", order.getstatusname()
                                    )
                                )
                        
                                if order.status == order.Completed:
                                    self.holdstart = len(self)
                        
                                # if not order.alive() and order.ref in self.orefs:
                                #     self.orefs.remove(order.ref)
                        
                            def notify_trade(self, trade):
                                """Provides notification of closed trades."""
                        
                                dt = self.data.datetime.datetime()
                                if trade.isclosed:
                        
                                    print(
                                        "{} {} Closed: PnL Gross {}, Net {},".format(
                                            dt,
                                            trade.data._name,
                                            round(trade.pnl, 2),
                                            round(trade.pnlcomm, 1),
                                        )
                                    )
                        

                        You don't need the try/except clause.

                        When you add the loggers above, you will see you are getting margin notice. This means there's not enough cash. This is because you are trying to buy 100% of the cash value of the account and TSLA is rising. You need to use a percentage of the account. You could use Cheat On Open, but again, that's a bit advanced.

                        The following makes no sense in backtrader.

                        best_mo_data.open[1]
                        

                        The numbering goes 0, -1, -2, etc.

                        IMHO, you need to read the docs and work on simpler examples.

                        Good luck.

                        1 Reply Last reply Reply Quote 0
                        • 1 / 1
                        • First post
                          Last post
                        Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
                        $(document).ready(function () { app.coldLoad(); }); }