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/

    Close a short position with trailing stop

    General Code/Help
    2
    2
    1112
    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.
    • J T
      J T last edited by

      Hi Good Sirs,
      I am at wits end after trying this all day. Code as follows, before I explain:

      import backtrader as bt
      import math
      
      
      # Create a Stratey
      class MyStrat(bt.Strategy):  # Strategy is a lines object
          params = (('order_percentage', 0.95), ('ticker', 'ORA'), ('fast', 10), ('slow', 20))
      
          def __init__(self):
              self.order = None  # To keep track of pending orders, init with None
              self.buyprice = None
              self.buycomm = None
              self.bar_executed = None
              self.size = None
              self.broker.set_coc(True)
              self.fast_sma = bt.indicators.SMA(self.data.close, period=self.params.fast, plotname='{}day SMA'.format(self.params.fast))
              self.slow_sma = bt.indicators.SMA(self.data.close, period=self.params.slow, plotname='{}day SMA'.format(self.params.slow))
              self.crossover = bt.indicators.CrossOver(self.fast_sma, self.slow_sma)  # return 1 if fast cross slow upwards, returns -1 if fast cross slow downwards
      
      
      class AutoStopOrStopTrail(MyStrat):  # inherit MyStrat
          params = dict(stop_loss=0.02,  # price is 2% less than the entry point
                        trail=0.005, trail_for_short=-0.0005)
      
          parent_order = None  # default value for a potential order
      
          def notify_order(self, order):  # called when a buy or sell is requested
              print('outstanding order: ', order.status)
      
              if order.status == order.Cancelled:  # status 5
                  print('CANCEL@price: {:.2f} {}'.format(order.executed.price, 'long' if order.isbuy() else 'short'))
                  return
      
              if order.status in [order.Submitted]:  # status 1
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  print('Order Submitted...')
                  return
      
              if order.status in [order.Accepted]:  # status 2
                  # Buy/Sell order submitted/accepted to/by broker - Nothing to do
                  print('Order Accepted...')
                  return
      
              if not order.status == order.Completed:
                  print('Order is not completed...')
                  return  # discard any other notification
      
              if not self.position:  # we left the market
                  print('CLOSE@price: {:.2f}'.format(order.executed.price))
                  return
      
              if order.status in [order.Margin, order.Rejected]:
                  print('Order Margin/Rejected')
                  return
      
              # Check if an order has been completed, Attention: broker could reject order if not enough cash
              if order.status in [order.Completed]:  # status 4
                  if order.isbuy():
                      print('BUY EXECUTED on {}: {:d} shares of {}, Price: {:.2f}, Value: {:.2f}, Comm: {:.2f}'.format(self.datas[0].datetime.date(0), self.size, self.p.ticker, order.executed.price, order.executed.value, order.executed.comm))
      
                  elif order.issell():  # if order.issell()
                      print('SEL EXECUTED on {}: {:d} shares of {}, Price: {:.2f}, Value: {:.2f}, Comm: {:.2f}'.format(self.datas[0].datetime.date(0), self.size, self.p.ticker, order.executed.price, order.executed.value, order.executed.comm))
      
              self.bar_executed = len(self)
      
          def next(self):
              print('current close px: ', self.datas[0].datetime.date(0), self.datas[0].datetime.time(0), self.data.close[0])
      
              # Check if we are in the market
      
              if (not self.position) and self.crossover != 0:
      
                  amount_to_invest = (self.params.order_percentage * self.broker.cash)
                  self.size = math.floor(amount_to_invest / self.data.close)
                  px_to_exe = self.data.close[0] * 1.01
      
                  if self.parent_order:  # something was pending
                      self.cancel(self.parent_order)
                      print('parent cancelled...')
      
                  # Not yet ... we MIGHT BUY if ...
                  if self.crossover > 0:  # go 'long':
                      print('LONG CREATE, CURRENT PX: {:.2f}, LONG AT {}'.format(self.data.close[0], px_to_exe))
                      self.parent_order = self.buy(price=px_to_exe, size=self.size, exectype=bt.Order.Stop, transmit=False, valid=None)
                      self.sell(exectype=bt.Order.StopTrail, trailpercent=self.p.trail, parent=self.parent_order)
      
                  elif self.crossover < 0:  # short
                      print('SHORT CREATE, CURRENT PX: {:.2f}, SHORT AT {}'.format(self.data.close[0], px_to_exe))
                      self.parent_order = self.sell(price=px_to_exe, size=self.size, exectype=bt.Order.Stop, transmit=False, valid=None)
                      self.buy(exectype=bt.Order.StopTrail, trailpercent=self.p.trail_for_short, parent=self.parent_order)
      
          def start(self):
              print('Backtesting is about to start...')
      
      

      I want to go long or short using stop orders. This is so I confirm a trend. So if price is now 1.00,
      a. I want to place a long stop order at 1.01. When price rises to 1.01, my order would be executed.
      b. Like wise, if I want to go short, I will place the order at 0.99. When price falls to 0.99, my order would be executed.

      Now along with this, I want to have a trailing stop loss. I have read the guide on using parent order so 2 orders go at once. This is not really working for me.

      1. I do not know how to close a short position using the child order. I cannot go the below becasue the order will not be executed.
      self.close(exectype=bt.Order.StopTrail, trailpercent=self.p.trail_for_short, parent=self.parent_order)
      
      1. When I go with self.buy(...) as per my code above, it seems to be running a different order and not related to the parent order.

      2. Going long and then selling seem ok but in my print statement, its odd I got
        BUY EXECUTED on 2020-03-27: 372 shares of ORA, Price: 2.56, Value: 952.51, Comm: 0.95
        and when sold
        SEL EXECUTED on 2020-03-27: 372 shares of ORA, Price: 2.56, Value: 2.56, Comm: 0.00
        Both these code use the same code essentially but value and commision is odd? Also no more buying or selling there after, only 1 trade.

      I am really hoping you can offer me a lifeline! Thanks in advance, stay safe all.

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

        @J-T You might want to try bracket orders

        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