Navigation

    Backtrader Community

    • Register
    • 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/

    take profit- stop loss

    Indicators/Strategies/Analyzers
    3
    9
    1034
    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.
    • 8
      8m last edited by

      Hello, i'm very very new to python, i tried to use Backtrader using a strategy that i made, but i have some problems, the entries are very good and accurate but the problem is i don't know how to put a take profit or stop loss, i'm now stuck into selling based only on indicators which is kinda annoying because i wont be doing this on live trading with real money, of course i would be using stop loss and take profit and i would manage my money and risks and not rely on indicators to sell and i always get a bad final balance after i run my backtest not because my entries were bad but because my exit points were inaccurate, i use this to exit trades for example:

      if self.rsi > 70:
         print("Sell {} shares at {}".format(self.size, self.data.close[0]))
         self.close() 
      

      please don't laugh at me, i know its a terrible sell indicator but that all what i'm capable to do right now, feel free to help but please don't bully me :),
      Thank you for this great tool!

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

        @8m Hey, no one's going to bully you. We all start somewhere! Also, rsi is a popular indicator and nothing wrong with that. Have a look at this article on bracket orders. It's a great starting place. Let us know if you have further questions or need help.

        1 Reply Last reply Reply Quote 1
        • 8
          8m last edited by

          i have checked the page and to be honest i see it quite hard, because i want to specify the Tp and Sl with percent %% not a price, for example i want on every trade, a stop loss of 3% and a profit of 1.5%, this is the strategy for example:

          import os, math
          import sys
          import pandas as pd
          import backtrader as bt
          
          class EMACROSSOVER(bt.Strategy):
            
          
            params = (('period1', 20), ('devfactor', 2), ('fastvsma', 10), ('order_pct', 0.95), 
                        ('rsip', 14), ('slowvsma', 50)
                      , ('slowsma', 25), ('fastsma', 10))
            
          
            def __init__(self):
                  self.data.close = self.datas[0].close
                  self.BB= bt.indicators.BollingerBands(self.datas[0], period=self.params.period1, devfactor=self.params.devfactor)
                  self.fastvSMA= bt.indicators.SMA(self.data.volume, period=self.params.fastvsma, plotname='FvSMA')
                  self.rsi= bt.indicators.RSI(self.data, period=self.params.rsip, plotname='RSI 14')
                  self.slowvSMA= bt.indicators.SMA(self.data.volume, period=self.params.slowvsma, plotname='SvSMA')
                  self.slowSMA= bt.indicators.SMA(self.data.close, period=self.params.slowsma, plotname='SSMA')
                  self.fastSMA= bt.indicators.SMA(self.data.close, period=self.params.fastsma, plotname='FSMA')
             
          
          
           def next(self):
                  if self.position.size == 0:
                     if self.data.low[0] < self.BB.lines.bot[0]:
                         if self.fastvSMA > self.slowvSMA:
                               amount_to_invest = (self.params.order_pct * self.broker.cash)
                               self.size = math.floor(amount_to_invest / self.data.close)
                               print("Buy {} shares at {}".format(self.size, self.data.close[0]))
                               self.buy(size=self.size)
                 
                  if self.position.size > 0:
                     if self.rsi > 70:
                        print("Sell {} shares at {}".format(self.size, self.data.close[0]))
                        self.close() 
          
          
          
          1 Reply Last reply Reply Quote 0
          • run-out
            run-out last edited by

            I'll create a sample code based on your supplied code. This might be a useful example for anyone new to making bracket orders.

            @8m said in take profit- stop loss:

            self.data.close = self.datas[0].close

            You don't need this line since backtader already has a built in short cut with exactly the same name self.data.close.

            In order to make your bracket order you need to calculate your prices first.

            price = self.data.close[0] * (1.0 - self.p.buy_price_adjust)
            price_limit = price * (1.0 + self.p.buy_limit_adjust)
            price_stop = price * (1.0 - self.p.buy_stop_adjust)
            
            

            Then you use these prices in a bracket order. Assign the result of the bracket order to a variable. (add in your own sizer)

            self.long_buy_order = self.buy_bracket(
                data=self.datas[0],
                size=1,
                exectype=bt.Order.Limit,
                plimit=price,
                stopprice=price_stop,
                stopexec=bt.Order.Stop,
                limitprice=price_limit,
                limitexec=bt.Order.Limit,
            )
            

            You will now have bracket orders executing. However, it's important to keep track of the orders, particularly if you want to sell under other conditions such as:

            @8m said in take profit- stop loss:

            if self.rsi > 70:
            print("Sell {} shares at {}".format(self.size, self.data.close[0]))
            self.close()

            To keep track of the orders, we will use a list created in init.:

            def __init__(self):
                self.o_li = list()
            

            Then after the order we will populate this list with the orders you made which can be found in self.long_buy_order, which is a list of orders:

            self.o_li = [o for o in self.long_buy_order]
            

            We will remove orders from the list after they are closed/cancelled at the end of notify_order:

            if not order.alive() and order in self.o_li:
                self.o_li.remove(order)
            

            We can now use this list to check for outstanding orders as a precondition to trading:

            if self.position.size == 0 and len(self.o_li) == 0:
            

            And if you sell based on your rsi condtion you need to clean up the list:

            if self.position.size > 0:
                if self.rsi > 70:
                    print("Sell shares at {}".format(self.data.close[0]))
                    self.close()
                    self.o_li = list()
            
            

            I know that's a lot, but here is my sample code for you to follow along with. Please take some time to try and understand the documentation for brackets.

            import backtrader as bt
            
            class Strategy(bt.Strategy):
            
                params = (
                    ("period1", 2),
                    ("devfactor", 2),
                    ("rsip", 8),
                    ("buy_price_adjust", 0.0),
                    ("buy_limit_adjust", 0.005),
                    ("buy_stop_adjust", 0.002),
                )
            
                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):
            
                    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):
                    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 enougth cash
                    if order.status in [order.Canceled, order.Margin]:
                        if order.isbuy():
                            self.log("BUY FAILED, Cancelled or Margin")
                        self.log
                    if order.status in [order.Completed, order.Canceled, order.Margin]:
                        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)
            
                    # 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 __init__(self):
                    self.o_li = list()
            
                    self.BB = bt.indicators.BollingerBands(self.datas[0], period=self.params.period1, devfactor=self.params.devfactor)
                    self.rsi = bt.indicators.RSI(self.data, period=self.params.rsip, plotname='RSI 14')
            
            
                def next(self):
            
                    self.print_signal()
            
                    if self.position.size == 0 and len(self.o_li) == 0:
                        if self.data.low[0] < self.BB.lines.bot[0]:
                            price = self.data.close[0] * (1.0 - self.p.buy_price_adjust)
                            price_limit = price * (1.0 + self.p.buy_limit_adjust)
                            price_stop = price * (1.0 - self.p.buy_stop_adjust)
            
                            self.long_buy_order = self.buy_bracket(
                                data=self.datas[0],
                                size=1,
                                exectype=bt.Order.Limit,
                                plimit=price,
                                stopprice=price_stop,
                                stopexec=bt.Order.Stop,
                                limitprice=price_limit,
                                limitexec=bt.Order.Limit,
                            )
            
                            # Store orders in a list
                            self.o_li = [o for o in self.long_buy_order]
            
                            self.log(
                                "LONG BUY limit Targets: Buy {:8.2f}, Limit {:8.2f}, Stop {:8.2f}".format(
                                    price, price_limit, price_stop
                                )
                            )
            
            
                    if self.position.size > 0:
                        if self.rsi > 70:
                            print("Sell shares at {}".format(self.data.close[0]))
                            self.close()
                            self.o_li = list()
            
            
            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(Strategy)
            
                # Execute
                cerebro.run()
            
            cept0r 1 Reply Last reply Reply Quote 1
            • cept0r
              cept0r last edited by

              @run-out said in take profit- stop loss:

              self.print_signal()

              Thank you for this, I've been looking for a solution similar to this for days now!

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

                    self.o_li = [o for o in self.long_buy_order]
                TypeError: 'BuyOrder' object is not iterable
                
                

                I'm getting this output when running:

                        if pos == 0 and len(self.o_li) == 0:
                            if close < mean:
                                self.long_buy_order = self.buy(price=buy1, size=size1, exectype=bt.Order.Limit)
                                self.log('Init... %.2f' % close)
                
                                self.o_li = [o for o in self.long_buy_order]
                
                        if pos > 0 and len(self.o_li) == 1:
                            if close < mean:
                                self.sell_order = self.sell(price=sell1, size=-size1, exectype=bt.Order.Limit)
                                self.log('Executing sell order... %.2f' % close)
                                self.o_li = list()
                
                run-out 1 Reply Last reply Reply Quote 0
                • run-out
                  run-out @cept0r last edited by

                  self.long_buy_order = self.buy_bracket(
                                      data=self.datas[0],
                                      size=1,
                                      exectype=bt.Order.Limit,
                                      plimit=price,
                                      stopprice=price_stop,
                                      stopexec=bt.Order.Stop,
                                      limitprice=price_limit,
                                      limitexec=bt.Order.Limit,
                                  )
                  
                  

                  In my example there are three orders placed at the same time in the bracket ordder and self.long_buy_order in my example is a list of three orders, which is iterable.

                  @cept0r said in take profit- stop loss:

                  self.long_buy_order = self.buy(price=buy1, size=size1, exectype=bt.Order.Limit)

                  In your example you are using only one order by itself resulting in a singular order object, which is not iterable.

                  When you are using a single buy order there's no need to use a list, you can just use the self.long_buy_order by itself.

                  1 Reply Last reply Reply Quote 1
                  • cept0r
                    cept0r last edited by

                    I see, so I'm back to square one.. I'd love to use bracket orders but Binance Futures does not support them so I have to do this using only limit/market orders. Anyhow, thanks for the fast reply I'll get back to trying to solve my issue..

                    While you're here I might as well try and ask..
                    I don't want to hijack this but I'm sure a few more have similar issues.

                    I'm trying to finish my grid ama band bot and im having issues at last part..

                    How do I make sure I only put one limitbuy per "step"..
                    So I have 4 bands below and 4 above and id like to make it long-only to begin with..

                    But I'm issuing more than one order per step.

                        def __init__(self):
                            self.dataclose = self.datas[0].close
                            self.ind = AmaBands(plot=True, subplot=False)
                            self.step = False
                            self.order = None
                    
                        def next(self):
                            self.log('Close %0.2f, Mean %0.2f, Buy1 %0.2f, Sell1 %0.2f, Buy2 %0.2f, Sell2 %0.2f, Stop %0.2f'
                                     % (self.dataclose[0], self.ind[0], self.ind.bot[0],
                                        self.ind.top[0], self.ind.bot2[0], self.ind.top2[0],
                                        self.ind.bot5[0]))
                    
                            orders = self.broker.get_orders_open()
                    
                            if self.order:
                                return
                    
                            mean = self.ind[0]  # Current mean(moving average) value
                    
                            size1 = cerebro.broker.get_cash() * 0.035 / self.data
                            size2 = size1 * 2
                            size3 = size2 * 2
                            size4 = size3 * 2
                    
                            pos = self.position.size
                    
                            stop = self.ind.bot5[0]
                            close = self.dataclose[0]  # Current close
                    
                            # Buy levels
                            buy1 = self.ind.bot[0]
                            buy2 = self.ind.bot2[0]
                            buy3 = self.ind.bot3[0]
                            buy4 = self.ind.bot4[0]
                    
                            # Sell levels
                            sell1 = self.ind.top[0]
                            sell2 = self.ind.top2[0]
                            sell3 = self.ind.top3[0]
                            sell4 = self.ind.top4[0]
                    
                            """Initializing algorithm..."""
                            if not self.position:
                                if close < mean:
                                    self.long = self.buy(price=buy1, size=size1, exectype=bt.Order.Limit)
                                    self.log('Init... %.2f' % close)
                            if pos > 0:
                                if close < mean:
                                    self.sell_order = self.sell(price=sell1, size=-size1, exectype=bt.Order.Stop)
                                    self.log('Executing sell order... %.2f' % close)
                    
                            if pos < size2 and close <= buy1:
                                self.long2 = self.buy(price=buy1, size=size1, exectype=bt.Order.Limit)
                                self.log('Going long step 2... %.2f' % close)
                            if pos < size2 and close >= sell1:
                                self.closepos = self.close(price=sell2)
                                self.log('Exiting position starting new cycle... %.2f' % close)
                    

                    I want to only issue one buy order at the first band if we're not in a position and currentclose goes below my mean. Then if price goes below my "buy1" id like to double my long at buy2 or if price reaches my sell1 id like to sell my current position and go back to step 1. Pretty much repeat this process for all 4 steps..

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

                      No problem. But since this is a different thread that might help others, would you mind copying it into a new post stand alone with a good title? Thanks.

                      1 Reply Last reply Reply Quote 0
                      • 1 / 1
                      • First post
                        Last post
                      Copyright © 2016, 2017, 2018 NodeBB Forums | Contributors
                      $(document).ready(function () { app.coldLoad(); }); }