# zigzag_horz_sr_lines_0
# i used the original zigzag study, not a modified one
# draw horz lines from the 3 most recent peaks and valleys
# use reverse counters to determine most recent
# ---------------------------------
# ZigZagHighLow
# TD Ameritrade IP Company, Inc. (c) 2013-2022
input priceH = high;
input priceL = low;
input percentageReversal = 5.0;
input absoluteReversal = 0.0;
input atrLength = 5;
input atrReversal = 1.5;
input tickReversal = 0;
Assert(percentageReversal >= 0, "'percentage reversal' must not be negative: " + percentageReversal);
Assert(absoluteReversal >= 0, "'absolute reversal' must not be negative: " + absoluteReversal);
Assert(atrReversal >= 0, "'atr reversal' must not be negative: " + atrReversal);
Assert(tickReversal >= 0, "'ticks' must not be negative: " + tickReversal);
Assert(percentageReversal != 0 or absoluteReversal != 0 or atrReversal != 0 or tickReversal != 0, "Either 'percentage reversal' or 'absolute reversal' or 'atr reversal' or 'tick reversal' must not be zero");
def absReversal;
if (absoluteReversal != 0) {
absReversal = absoluteReversal;
} else {
absReversal = tickReversal * TickSize();
}
def hlPivot;
if (atrReversal != 0) {
hlPivot = percentageReversal / 100 + WildersAverage(TrueRange(high, close, low), atrLength) / close * atrReversal;
} else {
hlPivot = percentageReversal / 100;
}
def state = {default init, undefined, uptrend, downtrend};
def maxPriceH;
def minPriceL;
def newMax;
def newMin;
def prevMaxH = GetValue(maxPriceH, 1);
def prevMinL = GetValue(minPriceL, 1);
if GetValue(state, 1) == GetValue(state.init, 0) {
maxPriceH = priceH;
minPriceL = priceL;
newMax = yes;
newMin = yes;
state = state.undefined;
} else if GetValue(state, 1) == GetValue(state.undefined, 0) {
if priceH >= prevMaxH {
state = state.uptrend;
maxPriceH = priceH;
minPriceL = prevMinL;
newMax = yes;
newMin = no;
} else if priceL <= prevMinL {
state = state.downtrend;
maxPriceH = prevMaxH;
minPriceL = priceL;
newMax = no;
newMin = yes;
} else {
state = state.undefined;
maxPriceH = prevMaxH;
minPriceL = prevMinL;
newMax = no;
newMin = no;
}
} else if GetValue(state, 1) == GetValue(state.uptrend, 0) {
if priceL <= prevMaxH - prevMaxH * hlPivot - absReversal {
state = state.downtrend;
maxPriceH = prevMaxH;
minPriceL = priceL;
newMax = no;
newMin = yes;
} else {
state = state.uptrend;
if (priceH >= prevMaxH) {
maxPriceH = priceH;
newMax = yes;
} else {
maxPriceH = prevMaxH;
newMax = no;
}
minPriceL = prevMinL;
newMin = no;
}
} else {
if priceH >= prevMinL + prevMinL * hlPivot + absReversal {
state = state.uptrend;
maxPriceH = priceH;
minPriceL = prevMinL;
newMax = yes;
newMin = no;
} else {
state = state.downtrend;
maxPriceH = prevMaxH;
newMax = no;
if (priceL <= prevMinL) {
minPriceL = priceL;
newMin = yes;
} else {
minPriceL = prevMinL;
newMin = no;
}
}
}
def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(priceH), 0, barNumber));
def newState = GetValue(state, 0) != GetValue(state, 1);
def offset = barCount - barNumber + 1;
def highPoint = state == state.uptrend and priceH == maxPriceH;
def lowPoint = state == state.downtrend and priceL == minPriceL;
def lastH;
if highPoint and offset > 1 {
lastH = fold iH = 1 to offset with tH = priceH while !IsNaN(tH) and !GetValue(newState, -iH) do if GetValue(newMax, -iH) or iH == offset - 1 and GetValue(priceH, -iH) == tH then Double.NaN else tH;
} else {
lastH = Double.NaN;
}
def lastL;
if lowPoint and offset > 1 {
lastL = fold iL = 1 to offset with tL = priceL while !IsNaN(tL) and !GetValue(newState, -iL) do if GetValue(newMin, -iL) or iL == offset - 1 and GetValue(priceL, -iL) == tL then Double.NaN else tL;
} else {
lastL = Double.NaN;
}
plot ZZ;
if barNumber == 1 {
ZZ = fold iF = 1 to offset with tP = Double.NaN while IsNaN(tP) do if GetValue(state, -iF) == GetValue(state.uptrend, 0) then priceL else if GetValue(state, -iF) == GetValue(state.downtrend, 0) then priceH else Double.NaN;
} else if barNumber == barCount {
ZZ = if highPoint or state == state.downtrend and priceL > minPriceL then priceH else if lowPoint or state == state.uptrend and priceH < maxPriceH then priceL else Double.NaN;
} else {
ZZ = if !IsNaN(lastH) then lastH else if !IsNaN(lastL) then lastL else Double.NaN;
}
ZZ.SetDefaultColor(GetColor(1));
ZZ.EnableApproximation();
# ---------------------------------
# draw horz lines from the 3 most recent peaks and valleys
# use reverse counters to determine most recent
def na = double.nan;
def bn = BarNumber();
def lastbn = HighestAll( if !IsNaN(close) then bn else 0);
# zz is not error on peaks and valleys, price level, of high or low
#addchartbubble(1, low, zz, color.yellow, no);
# convert na to 0, so following formulas dont err
def zz2 = if isnan(zz) then 0 else zz;
# count peaks and valleys
# peaks , R levels
# valleys, S levels
def rcnt = if bn == 1 then 0 else if zz2 == high then rcnt[1] + 1 else rcnt[1];
def scnt = if bn == 1 then 0 else if zz2 == low then scnt[1] + 1 else scnt[1];
def rttl = HighestAll(rcnt);
def sttl = HighestAll(scnt);
# rev counts
def revrcnt = rttl - rcnt + 1;
def revscnt = sttl - scnt + 1;
# ---------------------------
# horz lines
def r1_line = if bn == 1 then na else if revrcnt == 1 and zz2 == high then high else r1_line[1];
def r2_line = if bn == 1 then na else if revrcnt == 2 and zz2 == high then high else r2_line[1];
def r3_line = if bn == 1 then na else if revrcnt == 3 and zz2 == high then high else r3_line[1];
def s1_line = if bn == 1 then na else if revscnt == 1 and zz2 == low then low else s1_line[1];
def s2_line = if bn == 1 then na else if revscnt == 2 and zz2 == low then low else s2_line[1];
def s3_line = if bn == 1 then na else if revscnt == 3 and zz2 == low then low else s3_line[1];
plot z1 = r1_line;
plot z2 = r2_line;
plot z3 = r3_line;
z1.setdefaultcolor(color.pink);
z1.SetStyle(Curve.MEDIUM_DASH);
# z1.setlineweight(1);
z1.hidebubble();
z2.setdefaultcolor(color.pink);
z2.SetStyle(Curve.MEDIUM_DASH);
# z2.setlineweight(1);
z2.hidebubble();
z3.setdefaultcolor(color.pink);
z3.SetStyle(Curve.MEDIUM_DASH);
# z3.setlineweight(1);
z3.hidebubble();
plot w1 = s1_line;
plot w2 = s2_line;
plot w3 = s3_line;
w1.setdefaultcolor(color.lime);
w1.SetStyle(Curve.MEDIUM_DASH);
# w1.setlineweight(1);
w1.hidebubble();
w2.setdefaultcolor(color.lime);
w2.SetStyle(Curve.MEDIUM_DASH);
# w2.setlineweight(1);
w2.hidebubble();
w3.setdefaultcolor(color.lime);
w3.SetStyle(Curve.MEDIUM_DASH);
# w3.setlineweight(1);
w3.hidebubble();
# ----------------------------
input test1_labels = no;
addlabel(test1_labels, "Rs " + rttl + " peaks", color.red);
addlabel(1, "Ss " + sttl + " valleys", color.green);
input test2_bubbles = no;
addchartbubble(test2_bubbles, low*0.98,
zz2 + "\n" +
high + "\n" +
low + "\n" +
rcnt + " r\n" +
revrcnt + " revr\n" +
scnt + " s\n" +
revscnt + "revs\n"
, ( if !isnan(zz) then color.yellow else color.gray), no);
#