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/

    How do I buy the maximum number of shares?

    General Code/Help
    4
    7
    973
    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 Former User last edited by

      Hello, I'm trying to make the example from the Quickstart Guide work with the maximum number of shares but the only thread that I've seen about buying with the maximum number of shares doesn't take into account the commissions.

      Also it isn't clear to me how do I buy with the open price of the next day so in case of a gap the broker doesn't reject the order because there isn't enough cash.

      Could you provide a working example doing it like that instead of using the cerebro.broker.set_coc(True).

      from __future__ import (absolute_import, division, print_function,
                              unicode_literals)
      
      import datetime
      import os.path
      import sys
      import math
      
      import backtrader as bt
      
      class TestStrategy(bt.Strategy):
      
          def log(self, txt, dt=None):
              ''' Logging function for this strategy'''
              dt = dt or self.datas[0].datetime.date(0)
              print('%s, %s' % (dt.isoformat(), txt))
      
          def __init__(self):
              # Keep a reference to the "close" line in the data[0] dataseries
              self.dataclose = self.datas[0].close
      
              # Keep track of pending orders
              self.order = None
              self.buyprice = None
              self.buycomm = None
      
          def notify_order(self, order):
              if order.status in [order.Submitted, order.Accepted]:
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  return
      
              # Check if an order has been completed
              # Attention: broker could reject order if not enough cash
              if order.status in [order.Completed]:
                  if order.isbuy():
                      self.log('BUY EXECUTED, Price: %.2f, Cost: %.2f, Comm: %.2f' %
                               (order.executed.price,
                                order.executed.value,
                                order.executed.comm))
                      self.buyprice = order.executed.price
                      self.buycomm = order.executed.comm
                  elif order.issell():
                      self.log('SELL EXECUTED, Price: %.2f, Cost: %.2f, Comm: %.2f' %
                               (order.executed.price,
                                order.executed.value,
                                order.executed.comm))
      
                  self.bar_executed = len(self)
      
              elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                  self.log('Order Canceled/Margin/Rejected')
      
              self.order = None
      
          def notify_trade(self, trade):
              if not trade.isclosed:
                  return
      
              self.log('OPERATION PROFIT, GROSS %.2f, NET %.2f' %
                       (trade.pnl, trade.pnlcomm))
      
          def next(self):
      
              if self.order:
                  return
      
              if not self.position:
                  # Not yet in the market... we MIGHT BUY if...
                  if self.dataclose[0] < self.dataclose[-1]:
                      if self.dataclose[-1] < self.dataclose[-2]:
                          self.log('BUY CREATE, %.2f' % self.dataclose[0])
                          self.order = self.buy()
              else:
                  # Already in the market... we might sell
                  if len(self) >= (self.bar_executed + 5):
                      self.log('SELL CREATE, %.2f' % self.dataclose[0])
      
                      # Keep track of the created order to avoid a 2nd order
                      self.order = self.sell()
      
      class MaxShares(bt.Sizer):
          def _getsizing(self, comminfo, cash, data, isbuy):
              if isbuy:
                  self.p.stake = math.floor(cash/data.close[0])
                  return self.p.stake
      
              position = self.broker.getposition(data)
              if not position.size:
                  return 0 # do not sell if nothing is open
      
              return self.p.stake
      
      class DegiroCommission(bt.CommInfoBase):
      
          params = (
              ('flat', 0.5),
              ('per_share', 0.004),
          )
      
          def _getcommission(self, size, price, pseudoexec):
              return self.p.flat + size * self.p.per_share
      
      if __name__ == '__main__':
          cerebro = bt.Cerebro()
          cerebro.addstrategy(TestStrategy)
          cerebro.broker.set_cash(10000)
          cerebro.broker.set_coc(True)
      
          cerebro.addsizer(MaxShares)
          comminfo = DegiroCommission()
          cerebro.broker.addcommissioninfo(comminfo)
      
          modpath = os.path.dirname(os.path.abspath(sys.argv[0]))
          datapath = os.path.join(modpath, '../../datas/orcl-1995-2014.txt')
          
           data = bt.feeds.YahooFinanceCSVData(
               dataname=datapath,
               # Do not pass values before this date
               fromdate=datetime.datetime(2000, 1, 1),
               # Do not pass values before this date
               todate=datetime.datetime(2000, 12, 31),
               # Do not pass values after this date
               reverse=False)
          cerebro.adddata(data)
      
          print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
          cerebro.run()
          print('Final Porfolio Value: %.2f' % cerebro.broker.getvalue())
      
          cerebro.plot()
      
      
      1 Reply Last reply Reply Quote 0
      • ?
        A Former User last edited by

        In case it's not completely clear what I want to do is get the number of shares as: shares = (cash - comissions) / (price on the open of the day in which the order executes).

        Sorry I didn't know how to edit my previous post.

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

          Try this post. The op had a reasonably good example. You would need to subtract commission manually.

          Also take a look at the code base to see what's going on under the hood.

          I would also suggest you thoroughly study the docs here.

          RunBacktest.com

          ? 김도언 2 Replies Last reply Reply Quote 1
          • ?
            A Former User @run-out last edited by

            @run-out said in How do I buy the maximum number of shares?:

            Try this post. The op had a reasonably good example.

            The example uses cheat on open which I don't want to use. I want to use the next day open price to make it more realistic.

            @run-out said in How do I buy the maximum number of shares?:

            You would need to subtract commission manually.

            Can I do that from the sizer? I don't know how to call the commissions function that I've created from the sizer.

            A 1 Reply Last reply Reply Quote 0
            • ?
              A Former User last edited by

              I hadn't seen I had the comminfo parameter in the sizer.

              class maxRiskSizer(bt.Sizer):
                  params = (('risk', 0.95),)
              
                  def __init__(self):
                      if self.p.risk > 1 or self.p.risk < 0:
                          raise ValueError('The risk parameter is a percentage which must be'
                              'entered as a float. e.g. 0.5')
              
                  def _getsizing(self, comminfo, cash, data, isbuy):
                      position = self.broker.getposition(data)
              
                      if not position:
                          size = comminfo.getsize(data.close[0], cash * self.p.risk)
                      else:
                          size = position.size
              
                      return size
              
              1 Reply Last reply Reply Quote 0
              • 김도언
                김도언 @run-out last edited by

                @run-out
                Read "Cheat-on-open" again.
                You can buy shares with next day open price.

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

                  @quake004 said in How do I buy the maximum number of shares?:

                  I want to use the next day open price to make it more realistic.

                  In real life you would login to the broker account in the morning and buy number of shares based on the existing amount of cash and open price. Therefore in your case cheat-on-open will be most realistic scenario. If you don't want to use cheat-on-open, than buy using 90-95% of cash to avoid broker rejection.

                  • 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
                  • 1 / 1
                  • First post
                    Last post
                  Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors