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/

    I am new to backtrader and want to build a strategy, details below

    Indicators/Strategies/Analyzers
    3
    15
    1430
    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.
    • Sajil Thamban
      Sajil Thamban last edited by

      -- Buying Rules

      (1).Buy when 8 ema crosses the 21 ema to the upside.

      (2).Place your stop loss below the most recent swing low point.

      (3).Your take profit target, aim for 200 pips.

      -- Selling Rule

      You do the exact opposite of the buy rule when you sell.

      (1).Sell when 8 ema crosses the 21 ema to the downside.

      (2).Place your stop loss below the most recent swing high point.

      (3).For your take profit target, aim for 200 pips.

      Can anyone help?

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

        You could start here for the crosses...

        Look here for bracket orders.

        RunBacktest.com

        1 Reply Last reply Reply Quote 0
        • Sajil Thamban
          Sajil Thamban last edited by

          Thanks for your help, I went through the whole document but even after using brackets the sharpe ratio is negative and I cant figure out why.
          @backtrader can you help?

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

            It would be great if you could share you code.

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

              @Sajil-Thamban
              We definitely want to help just show us your code and we'll point you in the right direction.

              RunBacktest.com

              Sajil Thamban 1 Reply Last reply Reply Quote 1
              • Sajil Thamban
                Sajil Thamban last edited by

                import backtrader as bt
                import datetime
                
                
                class MyStrategy(bt.Strategy):
                    def __init__(self):
                        # Keep a reference to the "close" line in the data[0] dataseries
                        self.dataclose = self.datas[0].close
                
                    def log(self, txt, dt=None):
                        dt = dt or self.datas[0].datetime.date(0)
                        print('%s, %s' % (dt.isoformat(), txt))  # Print date and close
                
                    def next(self):
                        # Log closing price to 2 decimals
                        self.log('Close: %.2f' % self.dataclose[0])
                
                
                class MAcrossover(bt.Strategy):
                    # Moving average parameters
                    params = (('pfast', 8), ('pslow', 21),)
                
                    def log(self, txt, dt=None):
                        dt = dt or self.datas[0].datetime.date(0)
                        print('%s, %s' % (dt.isoformat(), txt))
                
                    def __init__(self):
                        self.dataclose = self.datas[0].close
                        # Order variable will contain ongoing order details/status
                        self.order = None
                        # Instantiate moving averages
                        self.slow_sma = bt.indicators.EMA(self.datas[0],
                                                                          period=self.p.pslow)
                        self.fast_sma = bt.indicators.EMA(self.datas[0],
                                                                          period=self.p.pfast)
                
                        self.crossover = bt.indicators.CrossOver(self.fast_sma, self.slow_sma)
                        self.datalow = self.datas[0].low
                        self.datahigh = self.datas[0].high
                        self.recent_low = ''
                        self.recent_high = ''
                        self.order_signals = []
                
                
                    def notify_trade(self, trade):
                        date = self.data.datetime.datetime()
                        if trade.isclosed:
                            print('-' * 32, ' NOTIFY TRADE ', '-' * 32)
                
                            print('-- {} ---{}, Close Price: {}, Profit, Gross {}, Net {}'.format(self.order_signals,
                                date,
                                trade.price,
                                round(trade.pnl, 2),
                                round(trade.pnlcomm, 2)))
                            print('-' * 80)
                            self.order_signals = []
                
                    def notify_order(self, order):
                        if order.status in [order.Submitted, order.Accepted]:
                            # Active Buy/Sell order submitted/accepted - 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.order_signals.append('BUY')
                            elif order.issell():
                                self.order_signals.append('SELL')
                            self.bar_executed = len(self)
                        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
                            self.order = None
                
                    def next(self):
                        if self.order:
                            return
                        close = self.data.close[0]
                        try:
                            highs = self.data.high.get(size=5)
                            lows = self.data.low.get(size=5)
                            if highs.pop(2) > max(highs):
                                self.recent_high = highs.pop(2)
                            if lows.pop(2) < min(lows):
                                self.recent_low = lows.pop(2)
                        except Exception as e:
                            self.log(e)
                            
                        # Check if we are in the market
                        if not self.position:
                            # if self.crossover > 0:
                            if self.fast_sma[0] > self.slow_sma[0] and self.fast_sma[-1] < self.slow_sma[-1]:
                                long_tp = close + 0.02
                                long_stop = self.recent_low
                                self.order = self.buy_bracket(limitprice=long_tp, stopprice=long_stop,exectype=bt.Order.Market)
                
                        # elif self.crossover < 0:
                        elif self.fast_sma[0] < self.slow_sma[0] and self.fast_sma[-1] > self.slow_sma[-1]:
                            short_tp = close - 0.02
                            short_stop = self.recent_high
                            self.order = self.sell_bracket(limitprice=short_tp, stopprice=short_stop, exectype=bt.Order.Market)
                         
                
                cerebro = bt.Cerebro()
                
                complete_data = bt.feeds.YahooFinanceCSVData(dataname='EURUSD=X-yahoo.csv', round=False)
                
                cerebro.adddata(complete_data)
                
                # Add strategy to Cerebro
                cerebro.addstrategy(MAcrossover)
                
                # Add strategy to Cerebro
                cerebro.addanalyzer(bt.analyzers.SharpeRatio)
                cerebro.addanalyzer(bt.analyzers.DrawDown)
                cerebro.addanalyzer(bt.analyzers.PyFolio)
                if __name__ == '__main__':
                    # Run Cerebro Engine
                    start_portfolio_value = cerebro.broker.getvalue()
                    thestrats = cerebro.run()
                    print('Sharpe Ratio:', thestrats[0].analyzers.sharperatio.get_analysis()['sharperatio'])
                    print('Max Draw Down:', thestrats[0].analyzers.drawdown.get_analysis()['max']['drawdown'])
                    # print('PyFolio:', thestrats[0].analyzers.pyfolio.get_analysis())
                    end_portfolio_value = cerebro.broker.getvalue()
                    pnl = end_portfolio_value - start_portfolio_value
                    print('Starting Portfolio Value: %.2f' % start_portfolio_value)
                    print('Final Portfolio Value: %.2f' % end_portfolio_value)
                    print('PnL: %.2f' % pnl)
                
                    # print("Sharpe Ratio ", sharpe['sharperatio'])
                
                    cerebro.plot(style='candlestick', barup='green', subplot=True)
                
                1 Reply Last reply Reply Quote 0
                • Sajil Thamban
                  Sajil Thamban @vladisld last edited by

                  @vladisld I just shared the Code,please take a look and tell me what my mistakes / blunders are

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

                    @run-out I just shared the Code,please take a look and tell me what my mistakes / blunders are

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

                      I thought it might be easier just to generate the code that should be very close to what you are looking for.

                      I wasn't sure what you were trying to accomplish with the 'recent_highs' and lows so I just took the max/min over get 5 days.

                      import backtrader as bt
                      
                      class MAcrossoveer(bt.Strategy):
                          # Moving average parameters
                          params = (('pfast', 8), ('pslow', 21),)
                      
                          def __init__(self):
                              # Keeps track of bracket orders.
                              self.o_li = list()
                      
                              self.ema_fast = bt.ind.EMA(self.data, period=self.p.pfast)
                              self.ema_slow = bt.ind.EMA(self.data, period=self.p.pslow)
                      
                              self.crossover = bt.ind.CrossUp(self.ema_fast, self.ema_slow)
                      
                      
                          def log(self, txt, dt=None):
                              """ Logging function fot this strategy"""
                              dt = dt or self.data.datetime[0]
                              if isinstance(dt, float):
                                  dt = bt.num2date(dt)
                              print("%s, %s" % (dt.date(), txt))
                      
                          def print_signal(self):
                              """ Prints OHLCV """
                              self.log(
                                  "o {:5.2f}\th {:5.2f}\tl {:5.2f}\tc {:5.2f}\tv {:5.0f}".format(
                                      self.datas[0].open[0],
                                      self.datas[0].high[0],
                                      self.datas[0].low[0],
                                      self.datas[0].close[0],
                                      self.datas[0].volume[0],
                                  )
                              )
                      
                          def notify_order(self, order):
                              """Triggered upon changes to orders. Notifications on order changes are here."""
                      
                              # Suppress notification if it is just a submitted order.
                              if order.status == order.Submitted:
                                  return
                      
                              # Print out the date, security name, order number and status.
                              dt, dn = self.datetime.date(), order.data._name
                      
                              self.log(
                                  "{} Order {} Status {}".format(dn, order.ref, order.getstatusname())
                              )
                      
                              # Check if an order has been completed
                              # Attention: broker could reject order if not enough cash
                              if order.status in [order.Completed, order.Margin]:
                                  if order.isbuy():
                                      self.log(
                                          "BUY EXECUTED for {}, Price: {:.2f}, Cost: {:.2f}, Comm {:.2f}".format(
                                              dn,
                                              order.executed.price,
                                              order.executed.value,
                                              order.executed.comm,
                                          )
                                      )
                                  else:  # Sell
                                      self.log(
                                          "SELL EXECUTED for {}, Price: {:.2f}, Cost: {:.2f}, Comm {:.2f}".format(
                                              dn,
                                              order.executed.price,
                                              order.executed.value,
                                              order.executed.comm,
                                          )
                                      )
                      
                              # Cleans up the order list.
                              if not order.alive() and order in self.o_li:
                                  self.o_li.remove(order)
                      
                          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):
                              self.print_signal()
                      
                              # pending opening orders do nothing
                              if len(self.o_li) > 0:
                                  return
                      
                              if not self.position and self.crossover == 1:
                                  self.long_buy_order = self.buy_bracket(
                                      data=self.datas[0],
                                      size=1,
                                      exectype=bt.Order.Market,
                                      stopprice=min(self.data.low.get(size=5)),
                                      stopexec=bt.Order.Stop,
                                      limitprice=self.datas[0].close[0] + 200,
                                      limitexec=bt.Order.Limit,
                                  )
                      
                                  self.log(
                                      "LONG BUY at market {}: Oref {} / Buy at {}".format(
                                          self.datetime.date(),
                                          self.long_buy_order[0].ref,
                                          self.data.close[0],
                                      )
                                  )
                      
                                  # Store orders in a list
                                  self.o_li = [o for o in self.long_buy_order]
                      
                              else:
                                  pass
                      
                              if not self.position and self.crossover == -1:
                                  self.short_sell_order = self.sell_bracket(
                                      data=self.datas[0],
                                      size=1,
                                      exectype=bt.Order.Market,
                                      stopprice=max(self.data.high.get(size=5)),
                                      stopexec=bt.Order.Stop,
                                      limitprice=self.datas[0].close[0] - 200,
                                      limitexec=bt.Order.Limit,
                                  )
                      
                                  self.log(
                                      "SHORT SELL at market {}: Oref {} / Sell at {}".format(
                                          self.datetime.date(),
                                          self.long_buy_order[0].ref,
                                          self.data.close[0],
                                      )
                                  )
                      
                                  # Store orders in a list
                                  self.o_li = [o for o in self.short_sell_order]
                      
                              else:
                                  pass
                      
                      
                      
                      if __name__ == "__main__":
                      
                          cerebro = bt.Cerebro()
                      
                          data = bt.feeds.GenericCSVData(
                              dataname="data/2006-day-001.txt",
                              dtformat=("%Y-%m-%d"),
                              timeframe=bt.TimeFrame.Days,
                              compression=1,
                          )
                          cerebro.adddata(data)
                      
                          cerebro.addstrategy(MAcrossoveer)
                      
                          # Execute
                          cerebro.run()
                      
                      

                      RunBacktest.com

                      1 Reply Last reply Reply Quote 0
                      • Sajil Thamban
                        Sajil Thamban last edited by

                        Thanks for that quick response. I was trying to find the swing low point in case of a buy and swing high point in case of a sell.

                        I just ran the code you sent and noticed that upon a crossover to the downside it was not going to the sell condition.

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

                          OK well see if you can debug it from there. If you get stuck, let us know.

                          RunBacktest.com

                          Sajil Thamban 1 Reply Last reply Reply Quote 1
                          • Sajil Thamban
                            Sajil Thamban @run-out last edited by

                            @run-out Yes sure, thank you very much for your help. Really appreciate it.

                            1 Reply Last reply Reply Quote 1
                            • Sajil Thamban
                              Sajil Thamban last edited by

                              Hi, I might sound dumb here but just wanted to tell you Im working with FOREX data (Currency Pairs) Ex - EURUSD. So my question is if the starting cash value is 10000 and I am triggering a buy or a sell upon a crossover to the upside or downside respectively then can the first signal be a sell signal (say if the first crossover is on the downside) ??

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

                                @Sajil-Thamban said in I am new to backtrader and want to build a strategy, details below:

                                I just ran the code you sent and noticed that upon a crossover to the downside it was not going to the sell condition.

                                The bug is here:

                                self.crossover = bt.ind.CrossUp(self.ema_fast, self.ema_slow)
                                

                                should be:

                                self.crossover = bt.ind.CrossOver(self.ema_fast, self.ema_slow)
                                

                                RunBacktest.com

                                1 Reply Last reply Reply Quote 1
                                • run-out
                                  run-out @Sajil Thamban last edited by

                                  @Sajil-Thamban said in I am new to backtrader and want to build a strategy, details below:

                                  can the first signal be a sell signal (say if the first crossover is on the downside)

                                  I the __init__ section include a variable set to None:

                                  self.trades_occured = False
                                  

                                  Then include this in the long section to reject the trade if it's the first crossover. The second crossover must be the opposite so this should work.

                                    if not self.position and self.crossover == 1 and self.trades_occured:
                                  

                                  Then once the first sell happens change self.trades_occured to True.

                                  if not self.position and self.crossover == -1:
                                              self.trades_occured = True
                                              self.short_sell_order = self.sell_bracket(....
                                  

                                  RunBacktest.com

                                  1 Reply Last reply Reply Quote 1
                                  • 1 / 1
                                  • First post
                                    Last post
                                  Copyright © 2016, 2017, 2018, 2019, 2020, 2021 NodeBB Forums | Contributors