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/

    Buying and Selling with Signals

    Indicators/Strategies/Analyzers
    2
    7
    3353
    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.
    • K
      KT last edited by KT

      Im trying to code the strategy that works in this way:

      1. If today is a down candle (open price higher than the closing price), I will go long position. If today is an up candle (closing price is higher than the open price), I will go short position.
      2. If yesterday I was in a long position, today is an up candle, I will close my long position and start a short position.
      3. I am using a stop loss and take profit price for each of my position. As such, I am using the bracket order. However, as the exectype is Limit Order and I would like it to be implemented as a Market Order, I change the price into self.data.open[0] with reference to yesterday's signal.
      from __future__ import (absolute_import, division, print_function,
                              unicode_literals)
      import os.path
      import argparse
      import datetime
      import collections
      
      import backtrader as bt
      import backtrader.feeds as btfeeds
      import backtrader.plot as plt
      import backtrader.indicators as btinds
      
      class Plotter(plt.Plot):
      
          def __init__(self):
              super().__init__(volup='#60cc73')  # custom color for volume up bars 
      
          def show(self):
              mng = self.mpyplot.get_current_fig_manager()
              mng.window.state('zoomed')
              self.mpyplot.show()  
      
      class St(bt.Strategy):
          
          def log(self, txt, dt=None):
              ''' Logging function fot this strategy'''
              dt = dt or self.data.datetime.date(0)
              print('%s, %s' % (dt.isoformat(), txt))
              
          def __init__(self):
              self.signal = 0
              
          def notify_order(self, order):
              if order.status in [order.Submitted, order.Accepted]:
                  return
              
              if order.status in [order.Completed]:
                  if order.isbuy():
                      self.signal +=1
                      self.log(
                          'BUY EXECUTED, Price: %.5f, Cost: %.5f, Position : %d' %
                          (order.executed.price,
                           order.executed.value,self.signal))
                      self.buyprice = order.executed.price
                      
                  else:  # Sell
                      self.signal -= 1    
                      self.log('SELL EXECUTED, Price: %.5f, Cost: %.5f,Position : %d' %
                                   (order.executed.price,
                                    order.executed.value,self.signal))
                  
                      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 %.5f, NET %.5f' %
                       (trade.pnl, trade.pnlcomm))
              
          def next(self):
              txt = ','.join(
                  ['%04d' % len(self.data),
                   self.data.datetime.date(0).isoformat(),
                   'Open : %.5f' % self.data.open[0],
                   'High : %.5f' % self.data.high[0],
                   'Low : %.5f' % self.data.low[0],
                   'Close : %.5f' % self.data.close[0],
                   'Position : %d' % self.signal])
              print(txt)
              
              if self.signal == 0:
                  if self.data.open[-1] > self.data.close[-1]:
                      self.log('BUY CREATE, %.5f, Limitprice : %.5f, Stopprice : %.5f' % (self.data.open[0],1.01*self.data.open[0],0.99*self.data.open[0]))
                      self.order = self.buy_bracket(limitprice = 1.01*self.data.open[0],price=self.data.open[0],stopprice = 0.99*self.data.open[0])
                  elif self.data.open[-1] < self.data.close[-1]:
                      self.log('SELL CREATE, %.5f, Limitprice : %.5f, Stopprice : %.5f' % (self.data.open[0],0.99*self.data.open[0],1.01*self.data.open[0]))
                      self.order = self.sell_bracket(limitprice =0.99*self.data.open[0],
                                                    price = self.data.open[0],
                                                    stopprice= 1.01*self.data.open[0])
              elif self.signal == 1:
                  if self.data.open[-1] > self.data.close[-1]:
                      return
                  elif self.data.open[-1] < self.data.close[-1]:
                      self.log('SELL CREATE, %.5f, Limitprice : %.5f, Stopprice : %.5f' % (self.data.open[0],0.99*self.data.open[0],1.01*self.data.open[0]))
                      self.order = self.sell_bracket(limitprice =0.99*self.data.open[0],
                                                    price = self.data.open[0],
                                                    stopprice= 1.01*self.data.open[0],size=2)
              elif self.signal == -1:
                  if self.data.open[-1] < self.data.close[-1]:
                      return
                  elif self.data.open[-1] > self.data.close[-1]:
                      self.log('BUY CREATE, %.5f, Limitprice : %.5f, Stopprice : %.5f' % (self.data.open[0],1.01*self.data.open[0],0.99*self.data.open[0]))
                      self.order = self.buy_bracket(limitprice = 1.01*self.data.open[0],price=self.data.open[0],stopprice = 0.99*self.data.open[0])
      
      class Plotter(plt.Plot):
      
          def __init__(self):
              super().__init__(volup='#60cc73')  # custom color for volume up bars 
      
          def show(self):
              mng = self.mpyplot.get_current_fig_manager()
              mng.window.state('zoomed')
              self.mpyplot.show()  
                        
      def runstrat():
          args = parse_args()
      
          cerebro = bt.Cerebro()
          modpath = 'd:\\I - TradersGPS\\'
          datapath = os.path.join(modpath, 'GBPUSD_D1_UTC+2_00.csv') 
          data = btfeeds.GenericCSVData(dataname=datapath,
                                         timeframe=bt.TimeFrame.Days,
                                        fromdate = datetime.datetime(2017,4,10),
                                        todate=datetime.datetime(2017,4,20),                                  
                                        nullvalue=0.0,
                                        dtformat=('%Y.%m.%d'),
                                        tmformat=('%H:%M'),
                                        datetime=0,
                                        time=1,
                                        open=2,
                                        high=3,
                                        low=4,
                                        close=5,
                                        volume=6,
                                        openinterest=-1)
      
          cerebro.adddata(data)
      
          cerebro.addstrategy(St)
          cerebro.broker.setcash(100000.0)
          print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
          cerebro.run(stdstats=False)
          print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
          #plotter = Plotter()
          #cerebro.plot(plotter=plotter,subplot=False)
          
      
              
      def parse_args():
          parser = argparse.ArgumentParser(
              formatter_class=argparse.ArgumentDefaultsHelpFormatter,
              description='Sample for pivot point and cross plotting')
      
          parser.add_argument('--data0',
                              default='d:\\I - TradersGPS\\GBPUSD_D1_UTC+2_00.csv',
                              required=False, help='Data0 to read in')
      
          parser.add_argument('--data1', 
                              default='d:\\I - TradersGPS\\GBPUSD_H1_UTC+2_00.csv',
                              required=False, help='Data1 to read in')
      
          parser.add_argument('--fromdate', required=False, default='2001-01-01',
                              help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
          
          parser.add_argument('--todate', required=False, default='2007-01-01',
                              help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
      
          parser.add_argument('--plot', required=False, action='store_true',
                              help=('Plot the result'))
      
          return parser.parse_args()
      
      
      if __name__ == '__main__':
          runstrat()
          
      

      This is a snippet of my data. It is a daily data with date. time, open, high, low,close,volume.

      2017.04.10,00:00,1.23802,1.24286,1.23657,1.24117,196634
      2017.04.11,00:00,1.24116,1.24944,1.24035,1.24893,235307
      2017.04.12,00:00,1.24891,1.25483,1.24801,1.25387,261157
      2017.04.13,00:00,1.2537,1.25742,1.25,1.25008,248594
      2017.04.14,00:00,1.25007,1.25346,1.2497,1.25172,161537
      2017.04.17,00:00,1.25271,1.25959,1.2524,1.25631,164495
      2017.04.18,00:00,1.25638,1.29053,1.25151,1.284,336253
      2017.04.19,00:00,1.28398,1.28603,1.27701,1.27772,278525
      2017.04.20,00:00,1.27773,1.28444,1.27724,1.28298,114281

      This is the output from my code:

      Starting Portfolio Value: 100000.00
      0001,2017-04-10,Open : 1.23802,High : 1.24286,Low : 1.23657,Close : 1.24117,Position : 0
      2017-04-10, BUY CREATE, 1.23802, Limitprice : 1.25040, Stopprice : 1.22564
      0002,2017-04-11,Open : 1.24116,High : 1.24944,Low : 1.24035,Close : 1.24893,Position : 0
      2017-04-11, SELL CREATE, 1.24116, Limitprice : 1.22875, Stopprice : 1.25357
      2017-04-12, SELL EXECUTED, Price: 1.24891, Cost: -1.24891,Position : -1
      0003,2017-04-12,Open : 1.24891,High : 1.25483,Low : 1.24801,Close : 1.25387,Position : -1
      2017-04-13, BUY EXECUTED, Price: 1.25370, Cost: -1.24891, Position : 0
      2017-04-13, Order Canceled/Margin/Rejected
      2017-04-13, OPERATION PROFIT, GROSS -0.00479, NET -0.00479
      0004,2017-04-13,Open : 1.25370,High : 1.25742,Low : 1.25000,Close : 1.25008,Position : 0
      2017-04-13, SELL CREATE, 1.25370, Limitprice : 1.24116, Stopprice : 1.26624
      0005,2017-04-14,Open : 1.25007,High : 1.25346,Low : 1.24970,Close : 1.25172,Position : 0
      2017-04-14, BUY CREATE, 1.25007, Limitprice : 1.26257, Stopprice : 1.23757
      2017-04-17, SELL EXECUTED, Price: 1.25370, Cost: -1.25370,Position : -1
      0006,2017-04-17,Open : 1.25271,High : 1.25959,Low : 1.25240,Close : 1.25631,Position : -1
      2017-04-18, BUY EXECUTED, Price: 1.26624, Cost: -1.25370, Position : 0
      2017-04-18, Order Canceled/Margin/Rejected
      2017-04-18, OPERATION PROFIT, GROSS -0.01254, NET -0.01254
      0007,2017-04-18,Open : 1.25638,High : 1.29053,Low : 1.25151,Close : 1.28400,Position : 0
      2017-04-18, SELL CREATE, 1.25638, Limitprice : 1.24382, Stopprice : 1.26894
      2017-04-19, SELL EXECUTED, Price: 1.28398, Cost: -1.28398,Position : -1
      0008,2017-04-19,Open : 1.28398,High : 1.28603,Low : 1.27701,Close : 1.27772,Position : -1
      Final Portfolio Value: 99999.99
      

      I would like to know how to set the limit price and the stop price to be a percentage of the execution price. For now, the execution price is the open price of the next day but the limit and stop price are based on the open price of that day.

      I would also like to know why are there buy orders that are not executed (e.g. : 2017-04-10, BUY CREATE, 1.23802)

      Thanks a lot :D

      B 1 Reply Last reply Reply Quote 0
      • K
        KT last edited by

        I tried using the manual bracket order to code the same strategies.

        from __future__ import (absolute_import, division, print_function,
                                unicode_literals)
        import os.path
        import argparse
        import datetime
        import collections
        
        import backtrader as bt
        import backtrader.feeds as btfeeds
        import backtrader.plot as plt
        import backtrader.indicators as btinds
        
        MAINSIGNALS = collections.OrderedDict(
                (('longonly',bt.SIGNAL_LONG),
                 ('shortonly',bt.SIGNAL_SHORT),
                ))
        
        class Plotter(plt.Plot):
        
            def __init__(self):
                super().__init__(volup='#60cc73')  # custom color for volume up bars 
        
            def show(self):
                mng = self.mpyplot.get_current_fig_manager()
                mng.window.state('zoomed')
                self.mpyplot.show()  
        
        class St(bt.Strategy):
            
            def log(self, txt, dt=None):
                ''' Logging function fot this strategy'''
                dt = dt or self.data.datetime.date(0)
                print('%s, %s' % (dt.isoformat(), txt))
                
            def __init__(self):
                self.signal = 0
                
            def notify_order(self, order):
                if order.status in [order.Submitted, order.Accepted]:
                    return
                
                if order.status in [order.Completed]:
                    if order.isbuy():
                        self.signal +=1
                        self.log(
                            'BUY EXECUTED, Price: %.5f, Cost: %.5f, Position : %d' %
                            (order.executed.price,
                             order.executed.value,self.signal))
                        self.buyprice = order.executed.price
                        
                    else:  # Sell
                        self.signal -= 1    
                        self.log('SELL EXECUTED, Price: %.5f, Cost: %.5f,Position : %d' %
                                     (order.executed.price,
                                      order.executed.value,self.signal))
                    
                        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 %.5f, NET %.5f' %
                         (trade.pnl, trade.pnlcomm))
                
            def next(self):
                txt = ','.join(
                    ['%04d' % len(self.data),
                     self.data.datetime.date(0).isoformat(),
                     'Open : %.5f' % self.data.open[0],
                     'High : %.5f' % self.data.high[0],
                     'Low : %.5f' % self.data.low[0],
                     'Close : %.5f' % self.data.close[0],
                     'Position : %d' % self.signal])
                print(txt)
                
        
                if self.signal == 0:
                    if self.data.open[0] > self.data.close[0]:
        
                        o1 = self.buy(exectype=bt.Order.Market,
                                      transmit=False)
        
                        print('{}: Oref {} / Buy at {}'.format(
                            self.datetime.date(), o1.ref,self.data.open[1]))
        
                        o2 = self.sell(exectype=bt.Order.Stop,
                                       price=0.99*self.data.open[1],
                                       parent=o1,
                                       transmit=False)
        
                        print('{}: Oref {} / Sell Stop at {}'.format(
                            self.datetime.date(), o2.ref,0.99*self.data.open[1]))
        
                        o3 = self.sell(exectype=bt.Order.Limit,
                                       price=1.01*self.data.open[1],
                                       parent=o1,
                                       transmit=True)
        
                        print('{}: Oref {} / Sell Limit at {}'.format(
                            self.datetime.date(), o3.ref,1.01*self.data.open[1]))
        
                        self.orefs = [o1.ref, o2.ref, o3.ref]
                        
                    elif self.data.open[0] < self.data.close[0]:
                        
                        o1 = self.sell(exectype=bt.Order.Market,
                                      transmit=False)
        
                        print('{}: Oref {} / Sell at {}'.format(
                            self.datetime.date(), o1.ref,self.data.open[1]))
        
                        o2 = self.buy(exectype=bt.Order.Stop,
                                       price=1.01*self.data.open[1],
                                       parent=o1,
                                       transmit=False)
        
                        print('{}: Oref {} / Buy Stop at {}'.format(
                            self.datetime.date(), o2.ref,1.01*self.data.open[1]))
        
                        o3 = self.buy(exectype=bt.Order.Limit,
                                       price=0.99*self.data.open[1],
                                       parent=o1,
                                       transmit=True)
        
                        print('{}: Oref {} / Buy Limit at {}'.format(
                            self.datetime.date(), o3.ref,0.99*self.data.open[1]))
        
                        self.orefs = [o1.ref, o2.ref, o3.ref]
                        
                elif self.signal == 1:
                    if self.data.open[0] > self.data.close[0]:
                        return
                    
                    elif self.data.open[0] < self.data.close[0]:
                        o1 = self.sell(exectype=bt.Order.Market,
                                      transmit=False,size=2)
        
                        print('{}: Oref {} / Sell at {}'.format(
                            self.datetime.date(), o1.ref,self.data.open[1]))
        
                        o2 = self.buy(exectype=bt.Order.Stop,
                                       price=1.01*self.data.open[1],
                                       parent=o1,
                                       transmit=False)
        
                        print('{}: Oref {} / Buy Stop at {}'.format(
                            self.datetime.date(), o2.ref,1.01*self.data.open[1]))
        
                        o3 = self.buy(exectype=bt.Order.Limit,
                                       price=0.99*self.data.open[1],
                                       parent=o1,
                                       transmit=True)
        
                        print('{}: Oref {} / Buy Limit at {}'.format(
                            self.datetime.date(), o3.ref,0.99*self.data.open[1]))
        
                        self.orefs = [o1.ref, o2.ref, o3.ref]
                        
                elif self.signal == -1:
                    if self.data.open[0] < self.data.close[0]:
                        return
                    
                    elif self.data.open[0] > self.data.close[0] :
                        
                        o1 = self.sell(exectype=bt.Order.Market,size=2,
                                      transmit=False)
        
                        print('{}: Oref {} / Sell at {}'.format(
                            self.datetime.date(), o1.ref,self.data.open[1]))
        
                        o2 = self.buy(exectype=bt.Order.Stop,
                                       price=1.01*self.data.open[1],
                                       parent=o1,
                                       transmit=False)
        
                        print('{}: Oref {} / Buy Stop at {}'.format(
                            self.datetime.date(), o2.ref,1.01*self.data.open[1]))
        
                        o3 = self.buy(exectype=bt.Order.Limit,
                                       price=0.99*self.data.open[1],
                                       parent=o1,
                                       transmit=True)
        
                        print('{}: Oref {} / Buy Limit at {}'.format(
                            self.datetime.date(), o3.ref,0.99*self.data.open[1]))
        
                        self.orefs = [o1.ref, o2.ref, o3.ref]
                    
                        
        
        
        class Plotter(plt.Plot):
        
            def __init__(self):
                super().__init__(volup='#60cc73')  # custom color for volume up bars 
        
            def show(self):
                mng = self.mpyplot.get_current_fig_manager()
                mng.window.state('zoomed')
                self.mpyplot.show()  
                          
        def runstrat():
            args = parse_args()
        
            cerebro = bt.Cerebro()
            modpath = 'd:\\I - TradersGPS\\'
            datapath = os.path.join(modpath, 'GBPUSD_D1_UTC+2_00.csv') 
            data = btfeeds.GenericCSVData(dataname=datapath,
                                           timeframe=bt.TimeFrame.Days,
                                          fromdate = datetime.datetime(2017,4,10),
                                          todate=datetime.datetime(2017,4,20),                                  
                                          nullvalue=0.0,
                                          dtformat=('%Y.%m.%d'),
                                          tmformat=('%H:%M'),
                                          datetime=0,
                                          time=1,
                                          open=2,
                                          high=3,
                                          low=4,
                                          close=5,
                                          volume=6,
                                          openinterest=-1)
        
            cerebro.adddata(data)
        
            cerebro.addstrategy(St)
            cerebro.broker.setcash(100000.0)
            print('Starting Portfolio Value: %.2f' % cerebro.broker.getvalue())
            cerebro.run(stdstats=False)
            print('Final Portfolio Value: %.2f' % cerebro.broker.getvalue())
            #plotter = Plotter()
            #cerebro.plot(plotter=plotter,subplot=False)
            
        
                
        def parse_args():
            parser = argparse.ArgumentParser(
                formatter_class=argparse.ArgumentDefaultsHelpFormatter,
                description='Sample for pivot point and cross plotting')
        
            parser.add_argument('--data0',
                                default='d:\\I - TradersGPS\\GBPUSD_D1_UTC+2_00.csv',
                                required=False, help='Data0 to read in')
        
            parser.add_argument('--data1', 
                                default='d:\\I - TradersGPS\\GBPUSD_H1_UTC+2_00.csv',
                                required=False, help='Data1 to read in')
        
            parser.add_argument('--fromdate', required=False, default='2001-01-01',
                                help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
            
            parser.add_argument('--todate', required=False, default='2007-01-01',
                                help='Date[time] in YYYY-MM-DD[THH:MM:SS] format')
        
            parser.add_argument('--plot', required=False, action='store_true',
                                help=('Plot the result'))
        
            return parser.parse_args()
        
        
        if __name__ == '__main__':
            runstrat()
            
        

        I got the warning that the array index out of range. Is it because of the [1] ? Thankss :)

          File "<ipython-input-11-2905f8945d39>", line 176, in next
            self.datetime.date(), o1.ref,self.data.open[1]))
        
          File "C:\Users\KT\Miniconda3\lib\site-packages\backtrader\linebuffer.py", line 163, in __getitem__
            return self.array[self.idx + ago]
        IndexError: array index out of range
        
        1 Reply Last reply Reply Quote 0
        • B
          backtrader administrators @KT last edited by

          @KT said in Buying and Selling with Signals:

          I would like to know how to set the limit price and the stop price to be a percentage of the execution price

          You cannot with a bracket order. You can do it manually or you can set the bracketing orders to be StopTrail orders, where you can set the trailing in percentage mode, but it will not be a percentage of the execution price, because that price is not known in advance.

          @KT said in Buying and Selling with Signals:

          Is it because of the [1]

          [1] is the future and therefore an error can be expected.

          @KT said in Buying and Selling with Signals:

          I tried using the manual bracket

          buy_bracket generates 3 orders. Creating the 3 orders won't also allow you a priori to set things in terms of the execution price because that price is only known after execution and not during order creation.

          1 Reply Last reply Reply Quote 0
          • K
            KT last edited by

            Thanks @backtrader for the help :)

            May I know how to implement it manually?

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

              Once you receive notification of order execution, you use order.executed.price as the reference to send the desired orders into the market at a percentage of the execution price.

              1 Reply Last reply Reply Quote 0
              • K
                KT last edited by

                Hi @backtrader Can I see the sample implementation using the code above? I am quite confused on how to implement it. Thanks :)

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

                  There is no such thing as a sample implementation.

                  • You send an order to the market: self.buy(price=myprice, exectype=bt.Order.MyPreferredExecutionType)
                  • The order is completed and notified to notify_order(order)
                  • order.executed.price contains the actual execution price
                  • A new order is sent to act as a stop-loss order: self.sell(price=% of order.executed.price, exectype=probably Stop)
                  1 Reply Last reply Reply Quote 0
                  • 1 / 1
                  • First post
                    Last post
                  Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors