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/

    Don't understand "buy" amount

    General Code/Help
    buy strategy
    3
    12
    7151
    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.
    • F
      Farence Kotraphali last edited by

      Hi,

      I would like to test an extremely easy strategy: on every 15th day of month, buy the symbol for fixed amount of money. But I must be missing something...

      Here is my code:

      class LazyStrategy(bt.Strategy):
          params = {'day_to_buy': 15}
          
          def log(self, txt, dt=None):
                  dt = dt or self.datas[0].datetime.date(0)
                  print('%s, %s' % (dt.isoformat(), txt))
      
          def next(self):
              if self.data.datetime.date().day == self.params.day_to_buy:
                  self.log('BUY CREATE, %.2f' % self.datas[0].close[0])
                  self.buy(size=1000)
      
      cerebro = bt.Cerebro()
      cerebro.broker.setcash(100000.0)
      cerebro.broker.setcommission(commission=0.009)
      
      cerebro.addstrategy(LazyStrategy)
      
      new_data = df.assign(date=pd.to_datetime(df.date)).set_index('date', drop=True)
      data = btfeeds.PandasData(dataname=new_data, datetime=None, openinterest=None)
      cerebro.adddata(data)
      
      cerebro.run()
      print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
      

      I mostly copied that from the quickstart example. But this doesn't reflect the fact I that I would like to buy the symbol for a specific amount of money (each time condition in next is true). When I tried to add some values to buy, it didn't work either (I got an error). And like this the final portfolio value is still same as on the beginning.

      Thank you

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

        Would be useful to have some output. Maybe prices are so high that it is not enough capital to buy 1000 shares.

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

          @Farence-Kotraphali said in Don't understand "buy" amount:

          def next(self):
              if self.data.datetime.date().day == self.params.day_to_buy:
                  self.log('BUY CREATE, %.2f' % self.datas[0].close[0])
                  self.buy(size=1000)
          

          Nobody can guarantee that day_to_buy (which is 15 in your case) is a trading day, unless the asset trades 7 days a week (which is unsual)

          As pointed out by @ab_trader some output does always help (like for example which timestamps and prices the strategy see in each next iteration)

          1 Reply Last reply Reply Quote 0
          • F
            Farence Kotraphali last edited by Farence Kotraphali

            Hey! Thanks for the response!

            It seems that @ab_trader is right - changing to size=1 helped. Stupid mistakes, thanks.

            And may I know how to check for a trading day?

            Next time I am going to put an output as well, sorry.

            I must admit I found it quite hard to work with backtrader. Even though I would say I am quite experienced python programmer and the OOP design of backtrader seems nice, I didn't expect that it will take so long for me to get to some working state. The quickstart example is quite complicated to me as a newcomer. Maybe it is because my knowledge of trading is very bad right now. But all I want to do is to test a long time passive investing strategy - the most easy one IMO.
            Still buy, for the same amount every month, never sell, get evaluation based on dividends and a hope that the market is going to go up on average over decades. And I wasn't able to program even something as easy like this. Don't take this as something I think you made wrong - just a feedback from an honest user :hand_splayed: .

            I am having a different problem right now, let's assume this:

                def next(self):
                    if self.data.datetime.date().day == self.params.day_to_buy:
                        cerebro.broker.cash += 1000
                        self.log('BUY CREATE, %.2f' % self.datas[0].close[0])
                        self.buy(price=cerebro.broker.cash)
            

            what I would expect this to do is "increase broker's cash by 1000 and then buy maximum number of what you can buy for everything you have". But for some reason, I don't get that result. When I debug it, sometimes self.buy(price=cerebro.broker.cash) doesn't do anything (cash is not lowered, but sometimes it does:

            Start Portfolio Value: 0.00
            2010-09-15, BUY CREATE, 103.30
            2010-10-15, BUY CREATE, 107.56
            2010-11-15, BUY CREATE, 109.72
            2010-12-15, BUY CREATE, 113.42
            2011-02-15, BUY CREATE, 121.65
            2011-03-15, BUY CREATE, 117.68
            2011-04-15, BUY CREATE, 120.72
            2011-06-15, BUY CREATE, 116.16
            2011-07-15, BUY CREATE, 120.46
            2011-08-15, BUY CREATE, 110.26
            2011-09-15, BUY CREATE, 111.04
            2011-11-15, BUY CREATE, 115.34
            2011-12-15, BUY CREATE, 111.72
            2012-02-15, BUY CREATE, 123.12
            2012-03-15, BUY CREATE, 128.70
            2012-05-15, BUY CREATE, 122.02
            2012-06-15, BUY CREATE, 123.28
            2012-08-15, BUY CREATE, 128.98
            2012-10-15, BUY CREATE, 131.90
            2012-11-15, BUY CREATE, 124.14
            2013-01-15, BUY CREATE, 134.66
            2013-02-15, BUY CREATE, 139.32
            2013-03-15, BUY CREATE, 143.32
            2013-04-15, BUY CREATE, 142.14
            2013-05-15, BUY CREATE, 152.14
            2013-07-15, BUY CREATE, 154.04
            2013-08-15, BUY CREATE, 152.36
            2013-10-15, BUY CREATE, 155.48
            2013-11-15, BUY CREATE, 165.00
            2014-01-15, BUY CREATE, 169.20
            2014-04-15, BUY CREATE, 168.76
            2014-05-15, BUY CREATE, 171.67
            2014-07-15, BUY CREATE, 180.85
            2014-08-15, BUY CREATE, 179.43
            2014-09-15, BUY CREATE, 182.46
            2014-10-15, BUY CREATE, 170.83
            2014-12-15, BUY CREATE, 182.93
            2015-01-15, BUY CREATE, 182.54
            2015-04-15, BUY CREATE, 192.90
            2015-05-15, BUY CREATE, 194.73
            2015-06-15, BUY CREATE, 191.62
            2015-07-15, BUY CREATE, 193.14
            2015-09-15, BUY CREATE, 181.98
            2015-10-15, BUY CREATE, 185.45
            2015-12-15, BUY CREATE, 188.03
            2016-01-15, BUY CREATE, 172.15
            2016-03-15, BUY CREATE, 185.46
            2016-04-15, BUY CREATE, 190.56
            2016-06-15, BUY CREATE, 190.52
            2016-07-15, BUY CREATE, 198.01
            2016-08-15, BUY CREATE, 201.05
            2016-09-15, BUY CREATE, 196.66
            2016-11-15, BUY CREATE, 200.41
            2016-12-15, BUY CREATE, 208.23
            2017-02-15, BUY CREATE, 215.68
            2017-03-15, BUY CREATE, 219.37
            Final Portfolio Value: 56000.00
            

            0_1490283842903_upload-c574d8b4-a46a-4bd9-8124-9b14710c8b82

            How can cash be the same as portfolio value, if everything is spent in each step? And apparently, money were only added to the broker cash (56 times thousand...)

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

              You are manually increasing the cash in the broker each day you operate.

              cerebro.broker.cash += 1000
              

              And then you tell the platform something very strange

              self.buy(price=cerebro.broker.cash)
              

              In all trading platforms: price refers to the expected acquisition price and not to the total amount of money you want to buy. The 1st time you tell the platform to buy 1 item (you have left size as the default) for a price of 11,000 (the initial 10,000 plus your 1st 1,000.

              The platform tries to see if there is enough to buy that before accepting the order you just issued. Since you also have a commission (0.9%), there isn't enough money to buy and the order is rejected. (You would see that in you had a notify_order method receiving the notifications)

              And that happens over and over again. That's why there is no single Buy (upwards looking green triangle) along the development of the prices.

              You are looking for: order_target_percent, which tells the system to invest in an asset to reach a target percentage. To make sure you get a buy executed for your full amount (percentage of 1.0) and not suffer from potential gaps between the current close and the next open (which will lead to order reject) and since you are simulating a simple scenario, you should activate cheat-on-close

              cerebro.broker.set_coc(True)
              

              See the following docs:

              • For order_target_percent: Docs - Strategy
              • For cheat-on-close: Docs - Broker
                cerebro

              As stated above you will miss some months, because the 15th of each month must not be a trading day. See

              ...
              2014-05-15, BUY CREATE, 171.67
              2014-07-15, BUY CREATE, 180.85
              ...
              

              It is probably not relevant to get your simulation up and running and get an initial perspective. But the logic to be in each month on the 15th or the 1st trading day thereafter needs a couple of extra lines.

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

                @backtrader this approach n next()

                cerebro.broker.cash += 1000
                

                does it work good in bt?

                Earlier I was thinking about adding dividends directly to the cash. Then I found out another discussion about dividends implemented as commission scheme, and decided that adding directly to cash doesn't work.

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

                  Doing that will probably break the meaning of the results delivered by some analyzers, but there is nothing against doing it.

                  This is the thread in which is reasoned how to use credit interest rate to simulate dividends without affecting the logic of trading:

                  • https://community.backtrader.com/topic/97/taking-into-account-of-periodic-payments/
                  1 Reply Last reply Reply Quote 0
                  • F
                    Farence Kotraphali last edited by

                    Thank you for detailed information. I tried another iteration, but still without success. Now, only a first order is executed and that's it.

                        def next(self):
                            if self.data.datetime.date().day == self.params.day_to_buy:
                                self.counter += 1
                                cerebro.broker.cash += self.params.cash_to_buy
                                self.log('%s. BUY CREATE, %.2f' % (self.counter, self.datas[0].close[0]))
                                self.order = self.order_target_size(target=1)
                    
                                
                        def start(self):
                            self.order = None  # sentinel to avoid operrations on pending order
                                
                        def stop(self):
                            self.log('(cash to buy %2d) Ending Value %.2f' % (self.params.cash_to_buy, self.broker.getvalue()))
                            
                        def notify_order(self, order):
                            #import pdb; pdb.set_trace()
                            if order.status in [order.Submitted, order.Accepted]:
                                # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                                self.order = None
                                self.log('ORDER ACCEPTED/SUBMITTED')
                                return
                            
                            if not order.alive():
                                self.order = None  # indicate no order is pending
                    
                            if order.status in [order.Expired]:
                                self.log('BUY EXPIRED')
                    
                            # Check if an order has been completed
                            # Attention: broker could reject order if not enougth cash
                            if order.status in [order.Completed, order.Canceled, order.Margin]:
                                if order.isbuy():
                                    self.log(
                                        'BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm %.2f' %
                                        (order.executed.price,
                                         order.executed.value,
                                         order.executed.comm))
                                else:
                                    raise ValueError('Ehh? We do not sell our precious stocks!')
                            else:
                                self.log('BUY NOT EXECUTED, WHATEVER *** REASON')
                    

                    the output:

                    Start Portfolio Value: 0.00
                    2010-09-15, 1. BUY CREATE, 103.30
                    2010-09-16, ORDER ACCEPTED/SUBMITTED
                    2010-09-16, ORDER ACCEPTED/SUBMITTED
                    2010-09-16, BUY EXECUTED, Price: 103.32, Cost: 10.33, Comm 0.09
                    2010-10-15, 2. BUY CREATE, 107.56
                    2010-11-15, 3. BUY CREATE, 109.72
                    2010-12-15, 4. BUY CREATE, 113.42
                    2011-02-15, 5. BUY CREATE, 121.65
                    2011-03-15, 6. BUY CREATE, 117.68
                    2011-04-15, 7. BUY CREATE, 120.72
                    2011-06-15, 8. BUY CREATE, 116.16
                    2011-07-15, 9. BUY CREATE, 120.46
                    2011-08-15, 10. BUY CREATE, 110.26
                    2011-09-15, 11. BUY CREATE, 111.04
                    2011-11-15, 12. BUY CREATE, 115.34
                    2011-12-15, 13. BUY CREATE, 111.72
                    2012-02-15, 14. BUY CREATE, 123.12
                    2012-03-15, 15. BUY CREATE, 128.70
                    2012-05-15, 16. BUY CREATE, 122.02
                    2012-06-15, 17. BUY CREATE, 123.28
                    2012-08-15, 18. BUY CREATE, 128.98
                    2012-10-15, 19. BUY CREATE, 131.90
                    2012-11-15, 20. BUY CREATE, 124.14
                    2013-01-15, 21. BUY CREATE, 134.66
                    2013-02-15, 22. BUY CREATE, 139.32
                    2013-03-15, 23. BUY CREATE, 143.32
                    2013-04-15, 24. BUY CREATE, 142.14
                    2013-05-15, 25. BUY CREATE, 152.14
                    2013-07-15, 26. BUY CREATE, 154.04
                    2013-08-15, 27. BUY CREATE, 152.36
                    2013-10-15, 28. BUY CREATE, 155.48
                    2013-11-15, 29. BUY CREATE, 165.00
                    2014-01-15, 30. BUY CREATE, 169.20
                    2014-04-15, 31. BUY CREATE, 168.76
                    2014-05-15, 32. BUY CREATE, 171.67
                    2014-07-15, 33. BUY CREATE, 180.85
                    2014-08-15, 34. BUY CREATE, 179.43
                    2014-09-15, 35. BUY CREATE, 182.46
                    2014-10-15, 36. BUY CREATE, 170.83
                    2014-12-15, 37. BUY CREATE, 182.93
                    2015-01-15, 38. BUY CREATE, 182.54
                    2015-04-15, 39. BUY CREATE, 192.90
                    2015-05-15, 40. BUY CREATE, 194.73
                    2015-06-15, 41. BUY CREATE, 191.62
                    2015-07-15, 42. BUY CREATE, 193.14
                    2015-09-15, 43. BUY CREATE, 181.98
                    2015-10-15, 44. BUY CREATE, 185.45
                    2015-12-15, 45. BUY CREATE, 188.03
                    2016-01-15, 46. BUY CREATE, 172.15
                    2016-03-15, 47. BUY CREATE, 185.46
                    2016-04-15, 48. BUY CREATE, 190.56
                    2016-06-15, 49. BUY CREATE, 190.52
                    2016-07-15, 50. BUY CREATE, 198.01
                    2016-08-15, 51. BUY CREATE, 201.05
                    2016-09-15, 52. BUY CREATE, 196.66
                    2016-11-15, 53. BUY CREATE, 200.41
                    2016-12-15, 54. BUY CREATE, 208.23
                    2017-02-15, 55. BUY CREATE, 215.68
                    2017-03-15, 56. BUY CREATE, 219.37
                    2017-03-21, (cash to buy 1000) Ending Value 56011.13
                    Final Portfolio Value: 56011.13
                    

                    I tried to tweak for an hour or so but still without any success.

                    I used set_coc(True) as you recommended and let's ignore that problem with trading day.

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

                      Definition of self.order_target_size():

                      Place an order to rebalance a position to have final size of target

                      First order issued and executed, position size is 1.
                      Your target is still 1 for all next orders, so no other orders is executed.
                      If you want to buy 1 share on every next(), then just use self.buy(size=1). Or your target should be increased on each 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
                      1 Reply Last reply Reply Quote 0
                      • F
                        Farence Kotraphali last edited by

                        Ah! I accidentaly used target_order_size instead targed_order_percent. Thanks, it seems to work now.

                        There is another problem regarding what you asked before: cerebro.broker.cash += self.params.cash_to_buy. It seems that the money addition is not acknowledged immediately by the platform but in the next step. So this doesn't work for the first trade, because there are no money acknowledged on the third line.

                        cerebro.broker.set_cash(0)
                        cerebro.broker.cash += 1000
                        self.order = self.order_target_percent(target=1)
                        

                        when I use this instead:

                        cerebro.broker.set_cash(1000)
                        self.order = self.order_target_percent(target=1)
                        cerebro.broker.cash += 1000
                        

                        then it works (and the logic is preserved - having +1000 for following trades). Is there any canonical way how to add money to the broker?

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

                          When you are in next the broker has already evaluated the orders. You see a closed bar.

                          The cheat-on-close trick is there to tell the broker to consider the previous close for execution instead of the current (and more approximate to reality) price.

                          The canonical way is set_cash.

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

                            See: Community - Release 1.9.44.116

                            For Cheat-On-Open see Blog - Cheat On Open

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