For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See: http://commonmark.org/help/

Trying to execute on the open, although the order executes the next day



  • Hi,

    I've coded a simple strategy which buys at the open, after price gaps up by at least 1% while the previous bar was an NR7 bar (most narrow bar over the past 7 bars). I understand when making a decision at market close, we can only execute it the next bar. I'm making my decision at the open price however and I want to execute after having that information available. I haven't been able to do this however.

    NR7 indicator:

    class NR7_indicator(bt.Indicator):
        
        lines = ('NR7',)
        
        def __init__(self):
            
            self.HiLo = self.data.high - self.data.low
            
        def next(self):
            
            # get the smallest high-low value of the previous 6 bars
            smallest_hi_lo = min(self.HiLo[-x] for x in range(1,7))
            
            # if the current high - low is smaller than the previous 6 bars, we have an NR7 bar
            if self.HiLo[0] < smallest_hi_lo:
                self.NR7[0] = 1
                
            else:
                self.NR7[0] = 0
    

    Strategy:

    class NR7_strategy(bt.Strategy):
        
        params = (('Gap',.01), ('Target',0.1),)
        
        lines = ("StopLoss", )
        
        def log(self, txt, dt=None):
            ''' Logging function for this strategy'''
            dt = dt or self.datas[0].datetime.datetime(0)
            print('%s, %s' % (dt.strftime("%Y-%m-%d %H:%M"), txt))        
        
        def __init__(self):
            
            self.NR7 = NR7_indicator(self.datas[0])
            self.SQNval = SQN(self.datas[0])
        
            # To keep track of pending orders and buy price/commission
            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
                    
                else:  # Sell
                    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
            
            # Check if an order is pending ... if yes, we cannot send a 2nd one
            if self.order:
                return
            
            # Check if we are in the market
            if not self.position:
                
                # check if we had at least a x% gap at the open and an NR7 the previous day
                if (self.data.open[0]/self.data.close[-1]-1) >= self.params.Gap and self.NR7[-1] ==1:
                    self.order = self.buy()
                    self.log('BUY CREATE, %.2f' % self.data.open[0])
                    # Stoploss is placed at the low of the NR7
                    self.StopLoss = self.data.low[-1]
                    self.log('Stoploss, %.2f' % self.StopLoss)
                    self.Target = self.data.open[0]*(1+self.params.Target)  
                    self.log('Target, %.2f' % self.Target)
                    
                    
            else:
                if self.data.low[0] <= self.StopLoss:
                    self.log('StopLoss Hit, SELL CREATE, %.2f' % self.StopLoss)
                    self.order = self.sell()
                    
    
    
    
                elif self.data.high[0] >= self.Target:
                    self.order = self.sell()
                    self.log('Target Hit, SELL CREATE, %.2f' % self.Target)
                    
            
                        
    if __name__ == '__main__':
    
        cerebro = bt.Cerebro()
    
        # Add a strategy
        cerebro.addstrategy(NR7_strategy)
        
        # Create a Data Feed
        data = bt.feeds.PandasData(dataname=df)
        
        # Set our desired cash start
        cerebro.broker.setcash(100000.0)
        
        # Add the Data Feed to Cerebro
        cerebro.adddata(data)    
        
        # Add a FixedSize sizer according to the stake
        cerebro.addsizer(bt.sizers.PercentSizer, percents=20)
        
        # Print out the starting conditions
        print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
    
        # Run over everything
        cerebro.run()
    
        # Print out the final result
        print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
        
        # Plot the result
        cerebro.plot(style='Candlestick')
    

    I tried to add a limit order which is causing me an error. this is what I've gathered from the documentation so I must be interpreting something incorrectly

    self.buy(exectype=Order.Limit)
    

    Error: NameError: name 'Order' is not defined

    thanks



  • Right now you are making decision at the close of the bar with the gap, and buy at the open of the next bar. If you want to make decisions on the open when the actual gap happens, than there are two options in bt:

    imho cheat-on-open is simpler to implement and understand, but I've used both of them together, unfortunately don't remember the reason. :)

    Error: NameError: name 'Order' is not defined

    should be self.buy(exectype=bt.Order.Limit)



  • @ab_trader

    Right now you are making decision at the close of the bar with the gap, and buy at the open of the next bar.

    Yes, that's what I thought indeed, thanks.

    • cheat-on-open

    I read this as well in the documents and implemented it, it didn't make any change though.

    I just added this:

    cerebro = bt.Cerebro(cheat_on_open=True)
    

    I read the following in the documentation so I thought that's why it doesn't work as I'm working with gaps: Such a use case fails when the opening price gaps (up or down, depending on whether buy or sell is in effect)

    • BarReplayer_Open:

    would you mind giving an example here. I can't really see how to implement this. I've tried the following but it doesn't change anything

        data.addfilter(bt.filters.BarReplayer_Open)
    
    • should be self.buy(exectype=bt.Order.Limit):

    great, thanks, should've realized that!!

    below the start of the log btw. I'd have the same problem with the stoploss that I want to have it executed at the price I set the stoploss at and not the day after.

    Starting Portfolio Value: 100000.00
    2000-06-20 00:00, BUY CREATE, 3.52
    2000-06-20 00:00, Stoploss, 3.45
    2000-06-20 00:00, Target, 3.87
    2000-06-21 00:00, BUY EXECUTED, Price: 3.61, Cost: 19950.62, Comm 0.00
    2000-06-28 00:00, Target Hit, SELL CREATE, 3.87
    2000-06-29 00:00, SELL EXECUTED, Price: 3.79, Cost: 19950.62, Comm 0.00
    2000-06-29 00:00, OPERATION PROFIT, GROSS 1012.35, NET 1012.35
    2000-06-29 00:00, BUY CREATE, 3.79
    2000-06-29 00:00, Stoploss, 3.71
    2000-06-29 00:00, Target, 4.17
    2000-06-30 00:00, BUY EXECUTED, Price: 3.77, Cost: 20107.29, Comm 0.00
    2000-06-30 00:00, StopLoss Hit, SELL CREATE, 3.71
    2000-07-03 00:00, SELL EXECUTED, Price: 3.72, Cost: 20107.29, Comm 0.00
    2000-07-03 00:00, OPERATION PROFIT, GROSS -261.75, NET -261.75
    2000-07-03 00:00, BUY CREATE, 3.72
    2000-07-03 00:00, Stoploss, 3.65
    2000-07-03 00:00, Target, 4.10
    


  • @Jens-Halsberghe said in Trying to execute on the open, although the order executes the next day:

    I just added this:

    In order to use cheat-on-open strategy actions need to move to next_...() calls. Here I posted simple script which trades on the bar open prices, take a look. Maybe it can help to understand the idea.



  • @ab_trader thanks!! that seems to work.


Log in to reply
 

});