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/

    Zigzag Indicator

    Indicators/Strategies/Analyzers
    5
    12
    2253
    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.
    • B
      bigdavediode last edited by bigdavediode

      Re: Zigzag indicator

      The previously posted zigzag study above was quite useful and my compliments to the authors. I needed something slightly different, however, more suitable for real-time identification and so here's a slightly tighter version that's about 80% smaller (from 100 lines of code down to about 18).

      This zigzag indicator is more of an indicator than a study and therefore it identifies peaks one bar "late" which is the only way to behave for real time peak identification. Most importantly, it should (in theory) not set peaks/valleys retroactively. It does not offer the various lines of the other zigzag -- I had no need to know the bars since the last peak or valley but these can be added after the fact in a single line by counting a list comprehension or by using a ternary iteration.

      '''
      Author: B. Bradford
      
      MIT License
      
      Copyright (c) B. Bradford
      
      Permission is hereby granted, free of charge, to any person obtaining a copy
      of this software and associated documentation files (the "Software"), to deal
      in the Software without restriction, including without limitation the rights
      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      copies of the Software, and to permit persons to whom the Software is
      furnished to do so, subject to the following conditions:
      
      The above copyright notice and this permission notice shall be included in all
      copies or substantial portions of the Software.
      
      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      SOFTWARE.
      '''
      
      class bbzigzag(bt.Indicator):
          plotinfo = dict(subplot=True,
                          zigzag=dict(_name='zigzag', color='lightblue', ls='--', _skipnan=True), )
      
          plotlines = dict(
              zigzag_peak=dict(marker='v', markersize=4.0, color='red', fillstyle='full', ls=''),
              zigzag_valley=dict(marker='^', markersize=4.0, color='red', fillstyle='full', ls=''),
              zigzag=dict(_name='zigzag', color='red', ls='--', _skipnan=True),
          )
      
          params = (
              ('up_retrace', 0.015),
              ('dn_retrace', 0.015),
              ('bardist', 0.015),  # distance to last max/min (perc/100)
              ('plotdistance', 0.03),  #distance to plot arrows (alters high/low indicator lines but not zigzag line)
          )
      
          lines = ('zigzag',
                   'zigzag_peak',
                   'zigzag_valley')
      
          def __init__(self):
              self.setminperiod(2)
              self.pks = [0]
      
          def once(self, start, end):
              lstinputdata = self.datas[0].array[:]
              self.trnd = [0 if lstinputdata[i] == lstinputdata[i-1] else 1 if lstinputdata[i-1] > lstinputdata[i] else -1 for i in range(1, len(lstinputdata))]
              self.nogaps = [self.trnd[i-1] if self.trnd[i] == 0 else self.trnd[i] for i in range(len(self.trnd))]
      
              nogapslast=self.nogaps[0]
              for i in range(len(self.nogaps)):
                  if nogapslast != self.nogaps[i]:  # peak found
                      if abs(lstinputdata[i] - self.pks[-1]) > self.params.bardist * self.pks[-1]:
                          self.pks.append(lstinputdata[i])
      
                          idx = -(len(self.nogaps)-i-1)
                          absplotdist = lstinputdata[i] * self.params.plotdistance
                          if self.nogaps[i] > nogapslast: self.lines.zigzag_peak[idx] = lstinputdata[i] + absplotdist
                          if self.nogaps[i] < nogapslast: self.lines.zigzag_valley[idx] = lstinputdata[i] - absplotdist
                          self.lines.zigzag[idx] = (self.zigzag_peak[idx] - absplotdist) if self.zigzag_peak[idx] == self.zigzag_peak[idx] else (self.zigzag_valley[idx] + absplotdist) if self.zigzag_valley[idx] == self.zigzag_valley[idx] else float('NaN')
                  nogapslast = self.nogaps[i]
      
      
      B 1 Reply Last reply Reply Quote 0
      • B
        bigdavediode @bigdavediode last edited by bigdavediode

        @bigdavediode

        As well you can specify a minimum threshold for the current bar minus the last bar to qualify as being recognized as a minimum, as well as a threshold for the minimum distance to the last peak/valley. Naturally, as in the case below, if you set these thresholds to non-zero values you can have peaks without valleys and valleys without peaks in some instances.

        If you find a bug please let me know and any feedback is appreciated.

        And here's a screenshot of this on a randomly (and poorly) selected SMA and the thresholds were just set arbitrarily just to show an example:

        0_1538929830702_zigzag screenshot.png

        1 Reply Last reply Reply Quote 0
        • B
          backtrader administrators last edited by

          Thanks for sharing

          B 1 Reply Last reply Reply Quote 0
          • B
            bigdavediode @backtrader last edited by bigdavediode

            @backtrader My pleasure Daniel - I'm probably being too cagey with the above so here's something that might (or might not) help you and what I am working towards. The below is my use of a zigzag indicator with very minimal filtering to identify wavelet inflection points at various increasing frequencies (decomposition level edge detection):

            0_1539389885733_Screenshot from 2018-10-12 17-15-34.png

            So far so good.

            1 Reply Last reply Reply Quote 0
            • A
              amir.najafi66 last edited by

              @bigdavediode said in Zigzag Indicator:

              @bigdavediode

              hi how can i set period in your indicator ?!

              B 1 Reply Last reply Reply Quote 0
              • B
                bigdavediode @amir.najafi66 last edited by

                @amir-najafi66

                Hi Amir, sorry for the delay in responding. There is no period as this pulls out highs and lows (peaks and valleys) where the high is highest compared to the previous low, and the subsequent low is lowest compared to the previous high so it starts from the line's beginning. A period would not work especially for situations such as [5,5,5,5,5,5,5] -- with five being ambiguous as to whether it's a high or a low or somewhere in between.

                1 Reply Last reply Reply Quote 0
                • P
                  Pixelephant last edited by

                  looking into zigzag / swing pivot indicators as well atm. has someone already converted something like https://github.com/tomas-rampas/ZigZag/blob/master/zigzag/init.py to backtrader. i'm pretty new with this tool and it seems as data feed must be processed the other way around as backtrader is looking backwards. any help appreciated :)

                  B 1 Reply Last reply Reply Quote 0
                  • B
                    backtrader administrators @Pixelephant last edited by

                    @pixelephant said in Zigzag Indicator:

                    is looking backwards

                    How do you identify swings without looking backwards? Because the only known method of identifying a swing is when it has already happened.

                    P 1 Reply Last reply Reply Quote 0
                    • P
                      Pixelephant @backtrader last edited by

                      @backtrader yes, sure. sorry for confusion, i meant array sort direction [current, older, oldest] in bt vs [oldest, older, current] in the code i've found on github

                      1 Reply Last reply Reply Quote 0
                      • B
                        backtrader administrators last edited by

                        I think you are confused in general. backtrader doesn't work with that notation. It uses the pivot point 0 as the current moment of time and negative indices point to the last (hence "past") values.

                        If you want to get a complete array of past values, you will get a standard Python array. - Docs - Platform Concepts

                        1 Reply Last reply Reply Quote 0
                        • Yacc Don
                          Yacc Don last edited by

                          @bigdavediode said in Zigzag Indicator:

                                          self.lines.zigzag[idx] = (self.zigzag_peak[idx] - absplotdist) if self.zigzag_peak[idx] == self.zigzag_peak[idx] else (self.zigzag_valley[idx] + absplotdist) if self.zigzag_valley[idx] == self.zigzag_valley[idx] else float('NaN')
                                          self.lines.zigzag[idx] = (self.zigzag_peak[idx] - absplotdist) if True else (self.zigzag_valley[idx] + absplotdist) if True else float('NaN')
                          

                          Thanks for sharing.
                          I have a question, what's the difference between the two lines of the code.

                          Yacc Don 1 Reply Last reply Reply Quote 0
                          • Yacc Don
                            Yacc Don @Yacc Don last edited by

                            @Yacc-Don Or you are testing if it is Nan. Is it equivalent to math.isnan()?

                            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(); }); }