Backtrader Community

    • 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/

    Simple buy-and-hold strategy

    General Code/Help
    4
    8
    2024
    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.
    • T
      tw00000 last edited by tw00000

      I'm trying to simulate a very simple buy-and-hold strategy, but my code never seems to close its position. Data is SPY daily candles from 2000 to current.

      Strategy
      My logic is basically to say that if we're at the beginning of the data frame, place a buy. If we're at the end of the dataframe, close the position.

      # Define our backtester class
      class BuyAndHold(bt.Strategy):
      
          def __init__(self):
              self.startcash = self.broker.getvalue()
      
          def next(self):
      
              for index, data in enumerate(self.datas):
                  datetime, dataname = self.datetime.date(), data._name
      
                  pos = self.getposition(data).size
                  if not pos:
      
                      # print(self.datetime.date().strftime("%Y-%m-%d %H:%M:%S"))
      
                      if self.datetime.date().strftime("%Y-%m-%d") == pd.read_pickle('data').head(2).date[0].strftime("%Y-%m-%d"):
                          trade_setup = 'LONG'
                      elif self.datetime.date().strftime("%Y-%m-%d") == pd.read_pickle('data').tail(2).date[0].strftime("%Y-%m-%d"):
                          trade_setup = 'CLOSE'
                      else:
                          trade_setup = None
      
                      if trade_setup == 'LONG':
                          print("buying")
                          self.buy()
      
                      elif trade_setup == 'CLOSE':
                          print("closing ")
                          self.close()
      
      

      Run the strategy and print relevant bits:

      def run_the_strategy():
      
          one_run_data = []
          # one_run_data.append(params)
      
          #Variable for our starting cash
          start_cash = 100000
      
          # Create an instance of cerebro
          cerebro = Cerebro()
      
          # Set the starting cash
          cerebro.broker.setcash(start_cash)
      
          # Add our strategy
          cerebro.addstrategy(BuyAndHold)
      
      
          data = PandasData(dataname=pd.read_pickle('data'), timeframe=bt.TimeFrame.Days)
          cerebro.adddata(data, name='data')
      
          # Add a sizer
          cerebro.addsizer(bt.sizers.AllInSizer)
      
          # Add the analyzers we are interested in
          cerebro.addanalyzer(bt.analyzers.SQN, _name="sqn")    
          cerebro.addanalyzer(bt.analyzers.DrawDown, _name="drawdown")
          cerebro.addanalyzer(bt.analyzers.SharpeRatio, _name='sharpe', timeframe=bt.TimeFrame.Days)
          cerebro.addanalyzer(bt.analyzers.Returns, _name="returns")
      
          # Run the strategy!!
          strategy = cerebro.run()
      
          # Calculate success 
          sqn = strategy[0].analyzers.sqn.get_analysis()['sqn']
          n_trades_taken = strategy[0].analyzers.sqn.get_analysis()['trades']
          pnl = cerebro.broker.getvalue()
          print("SQN: ", sqn, "n trades", n_trades_taken, "ending PnL: $", pnl)
      

      However, this is what the strategy does when run:

      $ python3 buy-and-hold.py
      Current time is 2018-11-25 14:51:49.310095
      Press Enter to continue...
      buying
      closing 
      SQN:  0 n trades 0 ending PnL: $ 100000.0
      

      It apparently tries to open the position (buy) and then close (with self.close) but makes no trades and clearly does not calculate the PnL properly. Why? I've tried switching out sizers and some other things. My only guess is that either self.buy() or self.close() is not working as intended here.

      B 1 Reply Last reply Reply Quote 0
      • B
        backtrader administrators @tw00000 last edited by

        @tw00000 said in Simple buy-and-hold strategy:

        My only guess is that either self.buy() or self.close() is not working as intended here.

        Sorry, but with a statement like that I don't really feel like writing a proper answer. Please have a look at your own code.

        1 Reply Last reply Reply Quote -2
        • A
          ab_trader last edited by ab_trader

          Since the broker values is not changed, than it looks like the script didn't buy anything. Did you check order notification if the orders were issued and executed?

          Simpler way to open trade at the very beginning is

          if not pos:
              self.buy()
          

          Will buy only at the very first next()

          • If my answer helped, hit reputation up arrow at lower right corner of the post.
          • Python Debugging With Pdb
          • New to python and bt - check this out
          T 1 Reply Last reply Reply Quote 1
          • T
            tw00000 @ab_trader last edited by tw00000

            @ab_trader said in Simple buy-and-hold strategy:

            Since the broker values is not changed, than it looks like the script didn't buy anything. Did you check order notification if the orders were issued and executed?

            Simpler way to open trade at the very beginning is

            if not pos:
                self.buy()
            

            Will buy only at the very first next()

            Thanks for this advice, this helped me realize what my problem was with putting the self.close() inside of the if not pos:, which clearly would never happen! Also, this led me to simplify the next code down:

            def next(self):
            
                for index, data in enumerate(self.datas):
                    datetime, dataname = self.datetime.date(), data._name
            
                    pos = self.getposition(data).size
                    if not pos:
                        print("buying")
                        self.buy()
            
                    if self.datetime.date().strftime("%Y-%m-%d") == pd.read_pickle('data').tail(1).date[0].strftime("%Y-%m-%d"):
                        self.close()
                        print("closing")
                    else:
                        trade_setup = None
            
            

            Strangely, now it (apparently) buys multiple times, but at least moving the self.close() statement out of the if not pos: conditional solved the problem with closing the trade!

            $ python3 buy-and-hold.py
            Current time is 2018-11-26 21:58:09.593324
            Press Enter to continue...
            buying
            buying
            buying
            buying
            buying
            closing
            SQN:  0 n trades 1 ending PnL: $ 188986.74126607418
            See REPORT-buy-and-hold.pdf for report with backtest results.
            Completed at 2018-11-26 21:58:17.480872
            

            I'm not sure why the buy section is triggered so many times, but this definitely solved my problem @ab_trader ! Thanks!

            1 Reply Last reply Reply Quote 0
            • A
              ab_trader last edited by

              I think that position closing can be also simplified (didn't tested by myself):

              if (len(self.datas) - len(self)) == 1:
                  self.close()
              

              It seems to me that such script should issue closing order before last bar. But, again, I didn't test it.

              As a wild guess about several buy signals - might be a case that open price was so different from close price that bt was not able to buy number of stocks based on AllInSizer calcs. Try with size=1.

              • If my answer helped, hit reputation up arrow at lower right corner of the post.
              • Python Debugging With Pdb
              • New to python and bt - check this out
              A 1 Reply Last reply Reply Quote 1
              • A
                abhishek.anand 1 last edited by

                @tw00000 said in Simple buy-and-hold strategy:

                if self.datetime.date().strftime("%Y-%m-%d") == pd.read_pickle('data').tail(1).date[0].strftime("%Y-%m-%d"):

                Hey! I am trying to implement something similar. By executing this same line i am getting the below error -

                  File "C:\Users\40100147\AppData\Roaming\Python\Python37\site-packages\pandas\io\common.py", line 651, in 
                get_handle
                    handle = open(handle, ioargs.mode)
                PermissionError: [Errno 13] Permission denied: 'data'
                

                Can you explain how you are using pd.pickle here ? I am using a single source of data. Below is the complete next() code

                    def next(self):
                
                        pos = self.getposition(self.data).size
                        if not pos:
                            print("buying")
                            self.buy()
                        if self.datetime.date().strftime("%Y-%m-%d") == pd.read_pickle('data').tail(1).date[0].strftime("%Y-%m-%d"):
                            self.close()
                            print("closing")
                        else:
                            trade_setup = None    
                
                1 Reply Last reply Reply Quote 0
                • A
                  abhishek.anand 1 @ab_trader last edited by

                  @ab_trader Hey! Did this line work for you ? I am getting the same value for len(self.data) and len(self) at every next step so the difference is never 1.

                  A 1 Reply Last reply Reply Quote 0
                  • A
                    ab_trader @abhishek.anand 1 last edited by

                    @abhishek-anand-1 i never checked this by myself.

                    • If my answer helped, hit reputation up arrow at lower right corner of the post.
                    • Python Debugging With Pdb
                    • New to python and bt - check this out
                    1 Reply Last reply Reply Quote 0
                    • 1 / 1
                    • First post
                      Last post
                    Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors