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/

    Share my implementation of the trend following strategy in the book "Following the trend" by Andreas Clenow

    Indicators/Strategies/Analyzers
    2
    3
    239
    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.
    • S
      soulmachine last edited by

      I implemented the trend following strategy in the book "Following the trend" by Andreas Clenow. The following is the core logic:

      class ClenowTrendFollowingStrategy(bt.Strategy):
          """The trend following strategy from the book "Following the trend" by Andreas Clenow."""
          alias = ('MeanReversion',)
      
          params = (
              ('trend_filter_fast_period', 50),
              ('trend_filter_slow_period', 100),
              ('fast_donchian_channel_period', 25),
              ('slow_donchian_channel_period', 50),
              ('trailing_stop_atr_period', 100),
              ('trailing_stop_atr_count', 3),
              ('risk_factor', 0.002)
          )
      
          def __init__(self):
              self.trend_filter_fast = bt.indicators.EMA(period=self.params.trend_filter_fast_period)
              self.trend_filter_slow = bt.indicators.EMA(period=self.params.trend_filter_slow_period)
              self.dc_fast = DonchianChannelsIndicator(period=self.params.fast_donchian_channel_period)
              self.dc_slow = DonchianChannelsIndicator(period=self.params.slow_donchian_channel_period)
              self.atr = bt.indicators.ATR(period=self.params.trailing_stop_atr_period)
              # For trailing stop
              self.max_price = self.data.close[0] # track the highest price after opening long positions
              self.min_price = self.data.close[0] # track the lowest price after opening short positions
      
          def next(self):
              is_long = self.trend_filter_fast > self.trend_filter_slow # trend filter
              
              # Position size rule
              max_loss = self.broker.getvalue() * self.p.risk_factor # cash you afford to loss
              position_size = max_loss / self.atr
      
              # self.dc_slow.low <= self.dc_fast.low <= self.dc_fast.high <= self.dc_slow.high
              assert self.dc_slow.low <= self.dc_fast.low
              assert self.dc_fast.low <= self.dc_fast.high
              assert self.dc_fast.high <= self.dc_slow.high
      
              if self.data.close > self.dc_slow.high:
                  if is_long and self.position.size == 0:
                      self.long_order = self.buy(size=position_size) # Entry rule 1
                      print(f'Long {position_size}')
                      self.max_price = self.data.close[0]
                      return
              elif self.data.close > self.dc_fast.high:
                  if self.position.size < 0:
                      print(f'Close {self.position.size} by exit rule 2')
                      self.close() # Exit rule 2
                      return
              elif self.data.close > self.dc_fast.low:
                  pass
              elif self.data.close > self.dc_slow.low:
                  if self.position.size > 0:
                      print(f'Close {self.position.size} by exit rule 1')
                      self.close() # Exit rule 1
                      return
              else:
                  if (not is_long) and self.position.size == 0:
                      self.short_order = self.sell(size=position_size) # Entry rule 2
                      print(f'Short {position_size}')
                      self.min_price = self.data.close[0]
                      return
      
              # Trailing stop
              if self.position.size > 0:
                  self.max_price = max(self.max_price, self.data.close[0])
                  if self.data.close[0] < (self.max_price-self.atr[0]*3):
                      print(f'Close {self.position.size}  by trailing stop rule')
                      self.close()
                      return
              if self.position.size < 0:
                  self.min_price = min(self.max_price, self.data.close[0])
                  if self.data.close[0] > (self.min_price+self.atr[0]*3):
                      print(f'Close {self.position.size} by trailing stop rule')
                      self.close()
                      return
      

      Jupyter notebook: https://github.com/soulmachine/crypto-notebooks/blob/master/backtest/Clenow-trend-following.ipynb

      Any improvement suggestions? Thanks.

      1 Reply Last reply Reply Quote 3
      • S
        soulmachine last edited by

        Typo: alias = ('ClenowTrendFollowing',)

        1 Reply Last reply Reply Quote 1
        • Cole Johnson
          Cole Johnson last edited by

          Nice work! Look forward to testing this out. Did you see positive results in backtesting?

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