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/

    Sample Code All In Strategy

    General Code/Help
    3
    13
    3530
    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.
    • A
      Alain last edited by

      Hi!

      Does anyone have a sample code for an all in strategy which uses cheat-on-open ?

      That would be very helpful...

      thank you!

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

        What in particular do you need? And what does All In means?

        I've written strategies using cheat-on-open, didn't see any difference from common approach in terms of strategy development.

        • 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 1
        • B
          backtrader administrators last edited by

          You simply need to use the opening price to calculate the stake for the available cash.

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

            I would like to write an All In strategy for Bitcoin trading.

            On buy signal it should buy as many coins as possible (All In) on the open of next candle.

            On close signal it should sell all coins on the open of next candle (or sell on close would be fine too, but i think that needs cheating as well)

            You can see my attempt in the following code...

            I actually think this creates and executes orders at the right prices and dates. Just not sure if I did the indexing right on next_open(). And if I don't need next() anymore... Also, this somehow always only sells 1 BTC instead of the whole position..

            Would be so helpful to see a working example.

            Thank you so much

            def MyAllInSizer(self):
                if not self.position:
                    size = self.broker.get_cash() / self.datas[0].open
                else:
                    size = self.broker.getposition(data = self.datas[0]).size
            
                return size
                
             def next_open(self):
                
                if self.order:
                    return
                
                if self.position:
                    if self.buysig < 0:
                        self.log('SELL CREATE, %.2f' % self.dataclose[-1])
                        self.MyAllInSizer()
                        print('Position Size: %.2f BTC' % self.MyAllInSizer())     
                        # Keep track of the created order to avoid a 2nd order
                        self.order = self.sell()
            
                elif self.buysig > 0:
                    self.log('BUY CREATE, %.2f' % self.dataclose[-1])
                    self.MyAllInSizer()
                    print('Position Size: %.2f BTC' % self.MyAllInSizer())
                    # Keep track of the created order to avoid a 2nd order
                    self.order = self.buy()
            
            
            if __name__ == '__main__':
            
            #initiate brain
            cerebro = bt.Cerebro(cheat_on_open=True)
            

            Returns look as follows (part of it):

            2014-06-16 00:00:00, BUY CREATE, 588.55
            Position Size: 16.89 BTC
            2014-06-16 00:00:00, BUY EXECUTED, 592.00
            2014-08-24 00:00:00, SELL CREATE, 497.00
            Position Size: 1.00 BTC
            2014-08-24 00:00:00, SELL EXECUTED, 496.96
            2015-04-02 00:00:00, BUY CREATE, 246.69
            Position Size: 40.15 BTC
            2015-04-02 00:00:00, BUY EXECUTED, 246.68
            2015-05-02 00:00:00, SELL CREATE, 231.00
            Position Size: 1.00 BTC
            2015-05-02 00:00:00, SELL EXECUTED, 231.05
            2015-07-03 00:00:00, BUY CREATE, 254.54
            Position Size: 38.85 BTC
            2015-07-03 00:00:00, BUY EXECUTED, 254.54

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

              @alain said in Sample Code All In Strategy:

              self.order = self.sell()
              

              It should be obvious why it does only sell 1

              Incidentally ... it does also only buy 1

              self.order = self.buy()
              

              See the reference for the buy and sell methods: Docs - Strategy

              A 1 Reply Last reply Reply Quote 0
              • A
                Alain @backtrader last edited by

                @backtrader said in Sample Code All In Strategy:

                Docs - Strategy

                Ok, yes now this is obvious. thanks.

                Next try:

                def next_open(self):
                    
                    if self.order:
                        return
                    
                    if self.position:
                        if self.buysig < 0:
                            self.log('SELL CREATE, %.2f' % self.dataclose[0])                
                            sizer = self.broker.getposition(data = self.datas[0]).size
                            print('Position Size: %.2f BTC' % sizer)     
                            # Keep track of the created order to avoid a 2nd order
                            self.order = self.sell(size = sizer)
                
                    elif self.buysig > 0:
                        self.log('BUY CREATE, %.2f' % self.dataclose[0])            
                        sizer = self.broker.get_cash() / self.datas[0].open
                        print('Position Size: %.2f BTC' % sizer)
                        # Keep track of the created order to avoid a 2nd order
                        self.order = self.buy(size = sizer)
                
                if __name__ == '__main__':
                cerebro = bt.Cerebro(cheat_on_open=True)
                

                Obviously when it only bought 1 BTC as before there were no orders canceled. But now I have this problem again, which means something is wrong and it doesn't use the next day's open to calculate the sizer ?

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

                  @alain said in Sample Code All In Strategy:

                  I have this problem again

                  What problem? On the first glance the code you posted should work good.

                  Edit: I would use self.datas[0].open[0]

                  • 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 1
                  • B
                    backtrader administrators @Alain last edited by

                    @alain said in Sample Code All In Strategy:

                    But now I have this problem again

                    We don't know which problem it is that you are having again, because there is no log of what's happening to you. Your original problem was that onle 1 unit of BTC was being bought/sold.

                    @alain said in Sample Code All In Strategy:

                    self.log('SELL CREATE, %.2f' % self.dataclose[0])          
                    

                    It would help you (and the logs) if you logged the value you are actually using for the sizing calculations, which is the open when using cheat-on-open

                    @alain said in Sample Code All In Strategy:

                    self.order = self.sell(size = sizer)
                    

                    You can close a position by using self.close() (Docs - Strategy)

                    @alain said in Sample Code All In Strategy:

                    sizer = self.broker.getposition(data = self.datas[0]).size
                    

                    If you only have one data, there is no need to specify the data feed here.

                    1 Reply Last reply Reply Quote 1
                    • A
                      Alain last edited by Alain

                      @backtrader and @ab_trader thank you for your help. I still have the following problem: Even though I seem to calculate the right amount of BTC to go all in on the next open I sometimes get the buy orders rejected.

                      Here I implemented the most simple strategy which is to buy on one candle, sell on the next one and so on...

                      def next(self):
                          self.log('open %.2f and close %.2f' % (self.datas[0].open[0], self.dataclose[0])) 
                          
                          
                      def next_open(self):
                          self.log('open %.2f and close %.2f' % (self.datas[0].open[0], self.dataclose[0])) 
                          sizer = self.broker.get_cash() / self.datas[0].open[0] 
                          print("sizer: ", sizer)
                          print("cash: ", self.broker.get_cash())
                          print("next_open price: ", self.datas[0].open[0])
                          if self.position:
                              self.order = self.close()
                          
                          else:
                             self.order = self.buy(size = sizer)
                      

                      "It would help you (and the logs) if you logged the value you are actually using for the sizing calculations, which is the open when using cheat-on-open" . I did exactly that to check if I calculate the sizer with the right open price but I still sometimes get buy orders rejected as can be seen here:

                      Starting Portfolio Value: 10000.00

                      2017-04-01 00:00:00, open 1033.79 and close 1070.31
                      2017-04-02 00:00:00, open 1070.93 and close 1083.40
                      sizer: 9.337678466379689
                      cash: 10000.0
                      next_open price: 1070.93
                      2017-04-02 00:00:00, Order Canceled/Margin/Rejected
                      2017-04-02 00:00:00, open 1070.93 and close 1083.40
                      2017-04-03 00:00:00, open 1083.33 and close 1077.88
                      sizer: 9.230797633223487
                      cash: 10000.0
                      next_open price: 1083.33
                      2017-04-03 00:00:00, BUY EXECUTED, 1083.33
                      2017-04-03 00:00:00, open 1083.33 and close 1077.88
                      2017-04-04 00:00:00, open 1077.04 and close 1146.42
                      sizer: 0.0
                      cash: 0.0
                      next_open price: 1077.04
                      2017-04-04 00:00:00, SELL EXECUTED, 1077.04
                      2017-04-04 00:00:00, open 1077.04 and close 1146.42
                      2017-04-05 00:00:00, open 1145.62 and close 1143.00
                      sizer: 8.678216409356528
                      cash: 9941.938282887024
                      next_open price: 1145.62
                      2017-04-05 00:00:00, Order Canceled/Margin/Rejected
                      2017-04-05 00:00:00, open 1145.62 and close 1143.00

                      Final Portfolio Value: 9941.94

                      I also tried to only return the next open from the next_open() method and execute orders from next. But that didn't solve my problem of rejected orders either...

                      Any ideas ?

                      Thank you so much!

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

                        This is a basic: floating point precision.

                        a = 10000.0
                        b = 1070.93
                        c =  a / b
                        d = c * b
                        
                        print('a:', a)
                        print('b:', b)
                        print('c:', c)
                        print('d:', d)
                        
                        assert d == a
                        

                        I guess you know what the answer to that assertion is.

                        1 Reply Last reply Reply Quote 1
                        • A
                          Alain last edited by

                          yes! I thought the issue could be something like that. Thank you @backtrader.
                          What I find strange though is that if I buy and sell on the close by use of "cerebro.broker.set_coc(True)" and use the built in all in sizer "cerebro.addsizer(bt.sizers.AllInSizer)" I don't get any errors because of floating point precision:

                          backtrader sizers

                          def _getsizing(self, comminfo, cash, data, isbuy):

                          position = self.broker.getposition(data)
                          
                          if not position:
                              size = cash / data.close[0] * (self.params.percents / 100)
                              
                          else:
                              size = position.size
                              
                          return size
                          

                          I don't see why this won't give me any floating point errors ? I mean I'm happy if it doesn't, but I'm not sure if anything in this code differs from my implementation above.

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

                            @backtrader Ok, I actually did find canceled orders because of floating point errors also when "buy on close" with "bt.sizers.AllInsizer).

                            So I tried to fix this problem by simply subtracting a small number from the position size, so there would be enough cash to enter the position. However I found canceled orders even though I subtracted a pretty large number 0.1 :

                            Same code with corrected sizer by 0.1 :

                            def next(self):
                                self.log('open %.2f and close %.2f' % (self.datas[0].open[0], self.dataclose[0])) 
                                
                                
                            def next_open(self):
                                self.log('open %.2f and close %.2f' % (self.datas[0].open[0], self.dataclose[0])) 
                                sizer = self.broker.get_cash() / self.datas[0].open[0] - 0.1
                                print("sizer: ", sizer)
                                print("cash: ", self.broker.get_cash())
                                print("next_open price: ", self.datas[0].open[0])
                                if self.position:
                                    self.order = self.close()
                                
                                else:
                                   self.order = self.buy(size = sizer)
                            

                            I receive:

                            2017-04-01 00:00:00, open 1033.79 and close 1070.31
                            2017-04-02 00:00:00, open 1070.93 and close 1083.40
                            sizer: 9.23767846637969
                            cash: 10000.0
                            next_open price: 1070.93
                            2017-04-02 00:00:00, Order Canceled/Margin/Rejected
                            2017-04-02 00:00:00, open 1070.93 and close 1083.40
                            2017-04-03 00:00:00, open 1083.33 and close 1077.88
                            sizer: 9.130797633223487
                            cash: 10000.0
                            next_open price: 1083.33
                            2017-04-03 00:00:00, BUY EXECUTED, 1083.33
                            2017-04-03 00:00:00, BUY EXECUTED, 9.130797633223487
                            2017-04-03 00:00:00, open 1083.33 and close 1077.88
                            2017-04-04 00:00:00, open 1077.04 and close 1146.42
                            sizer: 0.0005840080219866872
                            cash: 108.33300000000054
                            next_open price: 1077.04
                            2017-04-04 00:00:00, SELL EXECUTED, 1077.04
                            2017-04-04 00:00:00, open 1077.04 and close 1146.42
                            2017-04-05 00:00:00, open 1145.62 and close 1143.00
                            sizer: 8.578765457033768
                            cash: 9942.567282887025
                            next_open price: 1145.62
                            2017-04-05 00:00:00, BUY EXECUTED, 1145.62
                            2017-04-05 00:00:00, BUY EXECUTED, 8.578765457033768
                            2017-04-05 00:00:00, open 1145.62 and close 1143.00

                            Which is weird to me, because 1070.93... * 9.2376... ~ 9892.18... which is clearly less than 10k.
                            ?! What did I do wrong this time ?

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

                              The problem here is that the broker, being unaware of the order being issued during next_open, tries to see if you are submitting an order which exceeds your current cash reserves (and the current price is already the close)

                              You can disable the submission check with checksubmit=False. See Docs - Broker

                              And this other topic for example: https://community.backtrader.com/topic/782/help-with-simple-bband-strategy

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