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 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!

Metastock Formula:

``````{ Copyright (c) 2004, John Bruns and Financial Trading Inc. }
reversal:=Input("Reversal",0,100,5);
pc:=Input("Use Percentage?",0,1,1);
z:=If(pc,Zig(CLOSE,reversal,%),Zig(CLOSE,reversal,\$));
lastpeak:=LastValue(Ref(z,-peakbar));
lastend:=LastValue(z);
bars:=Cum(1);
invalid:=If(pc,If(Abs(lastend-lastpeak)*100/lastpeak<reversal,1,0),If(Abs(lastend-lastpeak)<reversal,1,0));
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

# Only get the adjusted close.
"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')
axs.legend()
plt.show()
``````

• 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.

• Input("Reversal",0,100,5);

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.

});