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/

    How to Exit Current Position and Enter Opposite Position at Same Time

    General Code/Help
    4
    6
    3076
    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.
    • vensaiten
      vensaiten last edited by

      Hi Backtrader Community,

      I am trying to modify "Quickstart" strategy as a common Renko strategy.

      Strategy:

      • Buy: If two consecutive candles are bullish
      • Sell: If two consecutive candles are bearish
      • Exit: If two consecutive candles move to the opposite direction

      As a start, I changed the logic as follows:

      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):
              # Keep a reference to the "close" line in the data[0] dataseries
              self.dataclose = self.datas[0].close
              # Keep a reference to the "open" line in the data[0] dataseries
              self.dataopen = self.datas[0].open
      
              # To keep track of pending orders
              self.order = 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, %.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')
      
              # Write down: no pending order
              self.order = None
      
          def next(self):
              # Simply log the closing price of the series from the reference
              self.log('Open, %.2f' % self.dataopen[0])
              self.log('Close, %.2f' % self.dataclose[0])
      
              # 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:
      
                  if self.dataclose[0] > self.dataopen[0]:
                      # current bar is bullish
      
                      if self.dataclose[-1] > self.dataopen[-1]:
                          # previous bar is bullish
      
                          # BUY with all possible default parameters
                          self.log('BUY CREATE, %.2f' % self.dataclose[0])
                          # Keep track of the created order to avoid a 2nd order
                          self.order = self.buy()
      
                  if self.dataclose[0] < self.dataopen[0]:
                      # current bar is bearish
      
                      if self.dataclose[-1] < self.dataopen[-1]:
                          # previous bar is bearish
      
      
                      # SELL with all possible default parameters
                          self.log('SELL CREATE, %.2f' % self.dataclose[0])
      
                          # Keep track of the created order to avoid a 2nd order
                          self.order = self.sell()
      
              else:
      
                  # Already in the market ... we might exit
                  if self.dataclose[0] > self.dataopen[0]:
                      # current bar is bullish
      
                      if self.dataclose[-1] > self.dataopen[-1]:
                          # previous bar is bullish
      
                          # Exit
                          self.log('Exit: BUY CREATE, %.2f' % self.dataclose[0])
                          # Keep track of the created order to avoid a 2nd order
                          self.order = self.buy()
      
                  # Already in the market ... we might exit
                  if self.dataclose[0] < self.dataopen[0]:
                      # current bar is bearish
      
                      if self.dataclose[-1] < self.dataopen[-1]:
                          # previous bar is bearish
      
                      # Exit
                          self.log('Exit: SELL CREATE, %.2f' % self.dataclose[0])
      
                          # Keep track of the created order to avoid a 2nd order
                          self.order = self.sell()
      

      This, of course, is unsuccessful because it fails to avoid a 2nd order and it fails to exit the current position and entering the opposite position at same time.

      How could I code this strategy? Thanks for your insights!

      1 Reply Last reply Reply Quote 0
      • A
        ab_trader last edited by

        I think you can use order_target_xxx for backtests. Lets operate with 100 stocks. If you have buy signal, you do

        self.order_target_size(size=100)
        

        bt buys 100 stocks. If then you have sell signal, you do

        self.order_target_size(size=-100)
        

        And bt will reverse position selling 200 stocks.

        Docs - Target Orders

        • If my answer helped, hit reputation up arrow at lower right corner of the post.
        • Python Debugging With Pdb
        • New to python and bt - check this out
        1 Reply Last reply Reply Quote 1
        • B
          backtrader administrators last edited by

          The approach by @ab_trader is probably the cleanest.

          See also how you can reverse position with a sizer and buy, sell commands (where the size is not specified and left to the Sizer to calculate)

          • Docs - Sizers - Smart Staking
          1 Reply Last reply Reply Quote 0
          • vensaiten
            vensaiten last edited by

            Somehow I am having hard time understanding how order_target_xxx works and I ended up using buy and sell commands with size.

            # Check if we are in the market
                if not self.position: #Enter Signal
                    # Two Bullish Candles
                    if self.dataclose[0] > self.dataopen[0] and self.dataclose[-1] > self.dataopen[-1]:
                        # BUY 
                        self.order = self.buy(size=100)
                    
                    # Two Bearish Candles
                    elif self.dataclose[0] < self.dataopen[0] and self.dataclose[-1] < self.dataopen[-1]:
                        # SELL 
                        self.order = self.sell(size=100)
            
                    else:
                        pass
            
                else: #Exit Signal
                        # Already in the market & Two Bullish Candles
                    if self.position.size < 0 and self.dataclose[0] > self.dataopen[0] and self.dataclose[-1] > self.dataopen[-1]:
                        self.order = self.buy(size=100)
            
                        # Already in the market & Two Bearish Candles
                    if self.position.size > 0 and self.dataclose[0] < self.dataopen[0] and self.dataclose[-1] < self.dataopen[-1]:
                        self.order = self.sell(size=100)
            

            This does avoid 2nd order but I would like to know how order_target_xxx is different (or better) and how it will change the above code.

            Also, this made me question how size works. Feel stupid to ask but I do not get why buy size=100 and then sell size=100 end up selling 200. If I continue to reverse the position, size will continue to increase as well? I guess I'm not understanding the concept intuitively. I am grateful if you could help me understand.

            B 杨志超 2 Replies Last reply Reply Quote 0
            • B
              backtrader administrators @vensaiten last edited by

              Instead of doing a buy / sell and later sell / buy, you replace each pair of calls with a single order_target_size.

              1 Reply Last reply Reply Quote 0
              • 杨志超
                杨志超 @vensaiten last edited by

                @vensaiten

                Hi, I am running into the same problem with you, do you figure out to solve this problem finally?

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