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?



  • 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()
    
    


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



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



  • @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.



  • 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
    


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



  • @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.


Log in to reply
 

});