For code/output blocks: Use ``` (aka backtick or grave accent) in a single line before and after the block. See:

ZigZag based on Close Prices

  • Hey guys, I'm new here. I'm trying to reply a zigzag based on closes prices in python. I have this Metastock Formula. I have a python code with similar results but not the right ones. The timeseries of python and Metastock are the same from Yahoo finance!
    Thanks for your help!

    Metastock Formula:

    { Copyright (c) 2004, John Bruns and Financial Trading Inc. }
    pc:=Input("Use Percentage?",0,1,1);
    peakbar:=LastValue(BarsSince((z>Ref(z,-1)AND Ref(Z,-1)<Ref(Z,-2)) OR (z<Ref(z,-1))AND Ref(Z,-1)>Ref(Z,-2)))+1;
    If(bars>=LastValue(bars)-peakbar AND invalid,lastpeak,z);

    Metastock Results:

    Python Results:

    Python code:

    from __future__ import division
    import matplotlib.pyplot as plt
    import numpy as np
    def islocalmax(x):
        """Both neighbors are lower,
        assumes a centered window of size 3"""
        return (x[0] < x[1]) & (x[2] < x[1])
    def islocalmin(x):
        """Both neighbors are higher,
        assumes a centered window of size 3"""
        return (x[0] > x[1]) & (x[2] > x[1])
    def isextrema(x):
        return islocalmax(x) or islocalmin(x)
    def create_zigzag(col, p=0.05):
        # Find the local min/max
        # converting to bool converts NaN to True, which makes it include the endpoints
        ext_loc = col.rolling(3, center=True).apply(isextrema, raw=False).astype(np.bool_)
        # extract values at local min/max
        ext_val = col[ext_loc]
        # filter locations based on threshold
        thres_ext_loc = (ext_val.diff().abs() > (ext_val.shift(-1).abs() * p))
        # Keep the endpoints
        thres_ext_loc.iloc[0] = True
        thres_ext_loc.iloc[-1] = True
        thres_ext_loc = thres_ext_loc[thres_ext_loc]
        # extract values at filtered locations 
        thres_ext_val = col.loc[thres_ext_loc.index]
        # again search the extrema to force the zigzag to always go from high > low or vice versa,
        # never low > low, or high > high
        ext_loc = thres_ext_val.rolling(3, center=True).apply(isextrema, raw=False).astype(np.bool_)
        thres_ext_val  =thres_ext_val[ext_loc]
        return thres_ext_val
    from pandas_datareader import data
    # Only get the adjusted close.
    serie = data.DataReader(
        "AAPL", start='2018-1-1', end='2020-12-31', data_source='yahoo'
    dfzigzag = serie.apply(create_zigzag)
    data1_zigzag = dfzigzag['Close'].dropna()
    fig, axs = plt.subplots(figsize=(10, 3))
    axs.plot(serie.Close, '-', ms=4, label='original')
    axs.plot(data1_zigzag, 'ro-', ms=4, label='zigzag')

  • Just a friendly notice, that this forum is dedicated to backtrader, so you may not be able to see an answer on your question since it is not related to bt. As of zigzag indicator for bt - it was several topics, you may want to search it on the forum.

  • @Martin-Bouhier said in ZigZag based on Close Prices:


    Hi Martin, I would suspect that you're either not using the same input data (ie. a moving average or smoother that is smaller and finer in the Metastock formula) or that the "percentage" input involves specifying a retracement perhaps before it counts as a peak or valley in that zig zag routine. Also I'm curious to know what the 5 in the "reversal" params specifies.

    I don't like that python version. If there are repeated values at a peak, for example such as 200, 201, 201, 199, then it's possible for the code to entirely miss a peak.

    Good luck.

Log in to reply