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

Buy at open price and close at close price in the same day



  • I have the following data

    date,open,close
    19-May-20,155.6,169.78
    20-May-20,153.39,149.51
    21-May-20,151,153.6
    

    What i want to do is : buy at open price and close at close price in the same day
    Expected result

    2020-05-19, BUY EXECUTED, Price: 155.6,
    2020-05-19, SELL EXECUTED, Price: 169.78
    2020-05-20, BUY EXECUTED, Price: 153.39
    2020-05-20, SELL EXECUTED, Price: 149.51
    2020-05-21, BUY EXECUTED, Price: 151
    2020-05-21, SELL EXECUTED, Price: 153.6
    

    I have read the section Cheat-on-open and an old post
    https://community.backtrader.com/topic/1864/a-day-buy-and-close-trade-with-cheat-on-open-and-stop-loss
    but I still cant solve the problem.

    My code:

    class TestStrategy(bt.Strategy):
        def log(self, txt, dt=None):
            ''' Logging function fot this strategy'''
            dt = dt or self.datas[0].datetime.date(0)
            print('%s, %s' % (dt.isoformat(), txt))
    
        def __init__(self):
            # 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 next_open(self):
            self.buy(price=self.data.open[0], coc=False)
    
        def next(self):
            pos = self.getposition()
            if pos:
                self.close(price=self.data.close[0], coc=False)
    
    cerebro = bt.Cerebro(cheat_on_open=True)
    cerebro.broker.set_coc(True)
    ...
    

    The actual outcome:

    2020-05-20, BUY EXECUTED, Price: 153.39, Cost: 153.39, Comm 0.00
    2020-05-21, SELL EXECUTED, Price: 151.00, Cost: 153.39, Comm 0.00
    2020-05-21, BUY EXECUTED, Price: 151.00, Cost: 151.00, Comm 0.00
    


  • @zevcc-gh said in Buy at open price and close at close price in the same day:

            self.close(price=self.data.close[0], coc=False)
    

    you may want to remove coc=False from the self.close. coc=False deactivates cheat-on-close for the order.



  • @ab_trader
    I have removed coc=False from the self.close
    but the result is the same



  • @zevcc-gh said in Buy at open price and close at close price in the same day:

    but the result is the same

    If the results are the same, than coc=False was not removed correctly. Results should be different. The approach proposed above works for me. This script buys open and sells close on every bar:

    import backtrader as bt
    
    class TestStr(bt.Strategy):
        
        def log(self, txt, dt=None):
            dt = dt or self.data0.datetime.date(0)
            tt = self.data.datetime.time(0)
            print('%s, %s, %s' % (dt.isoformat(), tt.isoformat(), txt))
    
        def __init__(self):
            pass
    
        def notify_order(self, order):
            if order.status in [order.Submitted, order.Accepted]:
                return
    
            if order.status in [order.Completed]:
                if order.isbuy():
                    self.log('BUY EXECUTED, %.2f' % order.executed.price)
                elif order.issell():
                    self.log('SELL EXECUTED, %.2f' % order.executed.price)
    
                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_open(self):
            self.buy(coc=False)
    
        def next(self):       
            self.log('NEXT o %0.2f, h %0.2f, l %0.2f, c %0.2f' % (self.data.open[0],
                     self.data.high[0], self.data.low[0], self.data.close[0]))
            if self.position:
                self.close()
    
    
    cerebro = bt.Cerebro(cheat_on_open=True)
    cerebro.addstrategy(TestStr)
    data = ... data feed setup ...
    cerebro.adddata(data)
    cerebro.broker.setcash(100000.0)
    cerebro.broker.set_coc(True)
    cerebro.run()
    


  • @ab_trader
    I have tried your code, the result is not as expected

    csv file:

    date,open,close
    19-May-20,155.6,169.78
    20-May-20,153.39,149.51
    21-May-20,151,153.6
    

    Code:

    import backtrader as bt
    
    class TestStr(bt.Strategy):
        
        def log(self, txt, dt=None):
            dt = dt or self.data0.datetime.date(0)
            tt = self.data.datetime.time(0)
            print('%s, %s, %s' % (dt.isoformat(), tt.isoformat(), txt))
    
        def __init__(self):
            pass
    
        def notify_order(self, order):
            if order.status in [order.Submitted, order.Accepted]:
                return
    
            if order.status in [order.Completed]:
                if order.isbuy():
                    self.log('BUY EXECUTED, %.2f' % order.executed.price)
                elif order.issell():
                    self.log('SELL EXECUTED, %.2f' % order.executed.price)
    
                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_open(self):
            self.buy(coc=False)
    
        def next(self):       
            self.log('NEXT o %0.2f, h %0.2f, l %0.2f, c %0.2f' % (self.data.open[0],
                     self.data.high[0], self.data.low[0], self.data.close[0]))
            if self.position:
                self.close()
    
    cerebro = bt.Cerebro(cheat_on_open=True)
    cerebro.addstrategy(TestStr)
    data = btfeeds.GenericCSVData(dataname='test.csv',
                    nullvalue=0.0,
                    dtformat=('%d-%b-%y'),
                    datetime=0,
                    open=1,
                    high=-1,
                    low=-1,
                    close=2,
                    volume=-1,
                    openinterest=-1,)
    cerebro.adddata(data) 
    cerebro.broker.set_cash(cash=10000)
    cerebro.broker.set_coc(True)
    cerebro.run()
    cerebro.plot()
    

    The actual result:

    2020-05-19, 23:59:59.999989, NEXT o 155.60, h 0.00, l 0.00, c 169.78
    2020-05-20, 23:59:59.999989, BUY EXECUTED, 153.39
    2020-05-20, 23:59:59.999989, NEXT o 153.39, h 0.00, l 0.00, c 149.51
    2020-05-21, 23:59:59.999989, SELL EXECUTED, 149.51
    2020-05-21, 23:59:59.999989, BUY EXECUTED, 151.00
    2020-05-21, 23:59:59.999989, OPERATION PROFIT, GROSS -3.88, NET -3.88
    2020-05-21, 23:59:59.999989, NEXT o 151.00, h 0.00, l 0.00, c 153.60
    

    Two problems:

    1. No trade record on 2020-05-19
    2. The remaining records are incorrect (the executed date).
      I want to execute buy and sell orders in the same day.

    For the first problem, I have overridden the start method for the record on 2020-05-19, but cannot close the order as well

        def start(self):
            self.buy(coc=False)
            self.close()
    

    Result:

    2020-05-19, 23:59:59.999989, BUY EXECUTED, 155.60
    2020-05-19, 23:59:59.999989, NEXT o 155.60, h 0.00, l 0.00, c 169.78
    2020-05-20, 23:59:59.999989, SELL EXECUTED, 169.78
    2020-05-20, 23:59:59.999989, BUY EXECUTED, 153.39
    2020-05-20, 23:59:59.999989, OPERATION PROFIT, GROSS 14.18, NET 14.18
    2020-05-20, 23:59:59.999989, NEXT o 153.39, h 0.00, l 0.00, c 149.51
    2020-05-21, 23:59:59.999989, SELL EXECUTED, 149.51
    2020-05-21, 23:59:59.999989, BUY EXECUTED, 151.00
    2020-05-21, 23:59:59.999989, OPERATION PROFIT, GROSS -3.88, NET -3.88
    2020-05-21, 23:59:59.999989, NEXT o 151.00, h 0.00, l 0.00, c 153.60
    

    For the second problem, I am really exhausted, I have tried coc=True/False, coo=True/False in different place, but still cannot solve it.



  • @zevcc-gh orders executed as you want: buy order at open price, sell order at close price. For sell order notification comes next day, but this is how the cheat-on-close was implemented. First bar is typically skipped due to bt internal mechanics.



  • @ab_trader
    Thanks! I understand more on how cheat-on-close works!

    I have two more problems

    1. As the sell order notification always comes next day, the graph from cerebro.plot() is always "incorrect" (buy/sell symbols are on the wrong places)
      I cannot correct the graph without modify the code in backtrader
    2. How to handle the last bar? for the last bar, the sell order will not be executed as there is no next bar.


  • @zevcc-gh as an idea - there is a data feed filter 'DaySplittter_Close(https://www.backtrader.com/docu/filters-reference/) which returns two sub-bars per each bar of data feed. Using this filter withcheat-on-openmight help: usenext_open()for operations, and issuebuyorder on the first sub-bar andsell` order on the second sub-bar. This solution may fix both items for you.


Log in to reply
 

});