Repaints ZigZag High Low Stats for ThinkorSwim

Repaints
@Madison If you haven't already done this, here is one way to use code to count the number of Highs and Lows displayed on the chart.
Thank you, yes this is part of what I am looking for. Now I just need to figure out how to total all the up percentage numbers and down percentages.
 

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

I'm very well aware of the repainting issues with zigzag. I want to use this for historical data not real time trading.
 
Last edited:
Thank you, yes this is part of what I am looking for. Now I just need to figure out how to total all the up percentage numbers and down percentages.

To add other stats, you just need to modify the stats code in the script I provided above. Here is the adjusted code to add to your chart for totals of price at the highs/lows. For example, def xh, which used xh[1] + 1, to get the price, def xhp used xhp[1] + price to accumulate the prices.

@rad14733 posted that the bubbles in the code will show how many times the study repaints. However, if the zigzag study repaints, there is no way to capture the missing repaints as the condition that causes a zigzag is no longer true and disappears. As you indicated, you are aware of how this indicator works and its' limitations.
.
Code:
def xhp = CompoundValue(1, if isUp and !IsNaN("ZZ%") then xhp[1] + price else xhp[1], 0);
AddLabel(show_stats_labels, "#Highs: " + asdollars(xhp), Color.GREEN);
def xlp = CompoundValue(1, if !isUp and !IsNaN("ZZ%") then xlp[1] + price else xlp[1], 0);
AddLabel(show_stats_labels, "#Lows: " + asdollars(xlp), Color.RED);

AddChartBubble(showbubbles_stats and !IsNaN("ZZ%") and barNumber != 1 and isUp, price, "H: " + asdollars(xhp), Color.GREEN, isUp);
AddChartBubble(showbubbles_stats and !IsNaN("ZZ%") and barNumber != 1 and !isUp, price, "L: " + asdollars(xlp), Color.RED, isUp);
 
@SeattleTrader20 The zig-zag indicators such as the one in the 1st post and the many variations in this thread as well as, the other zigzag indicators on the forum, the harmonics, all the wave studies, all the trend reversals and some pivot studies all "plot a zigzag graph that connects high, low, high, low".

PS: They also all
repaint
 
Extracted idea from RDMercer's post #369 of a variant of a massive Zig Zag High Low Supply Demand study that comprises many different components

https://usethinkscript.com/threads/...-signals-for-thinkorswim.183/page-19#post-369
I heavily modified, cleaned up and extracted some interesting Zig Zag statistical information resulting in this study called Zig Zag High Low Stats. It displays the following information represented via bubbles at each of the Zig zag turning points

Label for Confirmed/Unconfirmed Status of Current Zigzag
Price Change between Zigzags
Price at Zigzag High/Low
Bar Count between Zigzags
Volume at Zigzag Reversals

Here's the study - you might like to load this study on a Daily chart of AAPL, AMZN or your favorite ticker
You can turn off any information you don't want via the user interface

Code:
# ZigZag High Low Stats
# tomsk
# 11.16.2019

# V1.0 - 11.16.2019 - tomsk - Initial release of ZigZag High Low Stats

# Extracted idea from RDMercer's post #369 of a variant of a massive
# Zig Zag High Low Supply Demand study that comprises many different
# components
#
# https://usethinkscript.com/threads/trend-reversal-indicator-with-signals-for-thinkorswim.183/page-19#post-369
#
# I heavily modified, cleaned up and extracted some interesting Zig Zag statistical information resulting in this study called Zig Zag High
# Low Stats. It displays the following information represented via bubbles at each of the Zig zag turning points
#
# Label for Confirmed/Unconfirmed Status of Current Zigzag
# Price Change between Zigzags
# Price at Zigzag High/Low
# Bar Count between Zigzags
# Volume at Zigzag Reversals

input showBubblesChange = no;   # Price Change between Zigzags
input showBubblesPrice = no;    # Price at Zigzag High/Low
input showBubblesBarCount = no; # Bar Count between Zigzags
input showBubblesVolume = no;   # Volume at Zigzag Reversals

input BubbleOffset = .0005;
input PercentAmount = .01;
input RevAmount = .05;
input ATRreversal = 3.0;
input ATRlength = 5;

def zz = ZigZagHighLow("price h" = high, "price l" = low, "percentage reversal" = PercentAmount,
"absolute reversal" = RevAmount, "atr length" = ATRlength, "atr reversal" = ATRreversal);

def ReversalAmount = if (close * PercentAmount / 100) > Max(RevAmount < ATRreversal * reference ATR(ATRlength), RevAmount)
                     then (close * PercentAmount / 100)
                     else if RevAmount < ATRreversal * reference ATR(ATRlength)
                          then ATRreversal * reference ATR(ATRlength)
                          else RevAmount;
# Zig Zag Specific Data

def zzSave = if !IsNaN(zz) then zz else GetValue(zzSave, 1);
def chg = (if zzSave == high then high else low) - GetValue(zzSave, 1);
def isUp = chg >= 0;
def isConf = AbsValue(chg) >= ReversalAmount or (IsNaN(GetValue(zz, 1)) and GetValue(isConf, 1));

# Price Change Specific Data

def xxHigh = if zzSave == high then high else xxHigh[1];
def chgHigh = high - xxHigh[1];
def xxLow = if zzSave == low then low else xxLow[1];
def chgLow = low - xxLow[1];

# Bar Count Specific Data

def zzCount = if zzSave[1] != zzSave then 1 else if zzSave[1] == zzSave then zzCount[1] + 1 else 0;
def zzCountHiLo = if zzCountHiLo[1] == 0 and (zzSave == high or zzSave == low) then 1
                  else if zzSave == high or zzSave == low then zzCountHiLo[1] + 1
                  else zzCountHiLo[1];
def zzHiLo = if zzSave == high or zzSave == low then zzCountHiLo else zzCountHiLo + 1;
def zzCountHigh = if zzSave == high then zzCount[1] else Double.NaN;
def zzCountLow  = if zzSave == low then zzCount[1] else Double.NaN;

# Volume Specific Data

def vol = if BarNumber() == 0 then 0 else volume + vol[1];
def vol1 = if BarNumber() == 1 then volume else vol1[1];
def xxVol = if zzSave == high or zzSave == low then TotalSum(volume) else xxVol[1];
def chgVol =  if xxvol - xxVol[1] + vol1 == vol then vol else xxVol - xxVol[1];

# Zigzag Status Label

AddLabel(BarNumber() != 1, (if isConf then "Confirmed " else "Unconfirmed ") + "ZigZag: " + chg + "  ATRrev " + Round(reference ATR(ATRlength) * ATRreversal, 2) + "  RevAmt " + Round(ReversalAmount, 2), if !isConf then Color.Dark_Orange else if isUp then Color.Green else Color.Red);

# Zig Zag Plot

plot zzp = if isUp <= 1 then zz else Double.NaN;
zzp.AssignValueColor(if isUp then Color.Green else if !isUp then Color.Red else Color.Dark_Orange);
zzp.SetStyle(Curve.FIRM);
zzp.EnableApproximation();
zzp.HideBubble();

# Bubbles

# Price Change between Zigzags

AddChartBubble(showBubblesChange and !IsNaN(zz) and BarNumber() != 1, if isUp then high * (1 + BubbleOffset) else low * (1 - BubbleOffset), "$" + Round(chg, 2), if isUp and chgHigh > 0 then Color.Green else if isUp and chgHigh < 0 then Color.Red else if isUp then Color.Yellow else if !isUp and chgLow > 0 then Color.Green else if !isUp and chgLow < 0 then Color.Red else Color.Yellow, isUp);

# Price at Zigzag High/Low

AddChartBubble(showBubblesPrice and !IsNaN(zz) and BarNumber() != 1, if isUp then high * (1 + BubbleOffset) else low * (1 - BubbleOffset), if isUp then "$" + high else "$" + low, if isUp and chgHigh > 0 then Color.Green else if isUp and chgHigh < 0 then Color.Red else if isUp then Color.Yellow else if !isUp and chgLow > 0 then Color.Green else if !isUp and chgLow < 0 then Color.Red else Color.Yellow, isUp);

# Bar Count between Zigzags

AddChartBubble(showBubblesBarCount and !IsNaN(zz) and BarNumber() != 1, if isUp then high * (1 + BubbleOffset) else low * (1 - BubbleOffset), if zzSave == high then zzCountHigh else zzCountLow, if isUp and chgHigh > 0 then Color.Green else if isUp and chgHigh < 0 then Color.Red else if isUp then Color.Yellow else if !isUp and chgLow > 0 then Color.Green else if !isUp and chgLow < 0 then Color.Red else Color.Yellow, if isUp then yes else no);

# Volume at Zigzag Reversals

AddChartBubble(showBubblesVolume and !IsNaN(zz) and BarNumber() != 1, if isUp then high * (1 + bubbleoffset) else low * (1 - bubbleoffset), chgVol, if isUp and chghigh > 0 then Color.Green else if isUp and chghigh < 0 then Color.Red else if isUp then Color.Yellow else if !isUp and chglow > 0 then Color.Green else if !isUp and chglow < 0 then Color.Red else Color.Yellow, if isUp then yes else no);

# End ZigZag High Low Stats
Can someone please explain what portion of this code causes the ZZ lines to change from red to green and green to red? What would I need to add to the code so that a red down arrow appears when the ZZ line changes from green to red, and a green up arrow appears when the ZZ line changes from red to green? Thanks in advance!
 
Last edited:
@David45
Add this Arrow Syntax to the bottom of your ZigZag study:
Ruby:
plot BullTrigger = if !isUp[1] and isUp then low else double.NaN ;
BullTrigger.SetPaintingStrategy(paintingStrategy.ARROW_UP) ;
BullTrigger.SetDefaultColor(color.blue);

plot BearTrigger = if !isUp and isUp[1] then high else double.NaN ;
BearTrigger.SetPaintingStrategy(paintingStrategy.ARROW_down) ;
BearTrigger.SetDefaultColor(color.magenta);
a1.png
 
is there a way to have the below code record the last price High and Low of the ZigZap pattern?

Thank you

Code:
## START CODE
## ZigZagSign TOMO modification, v0.2 written by Linus @Thinkscripter Lounge adapted from Thinkorswim ZigZagSign Script

input price             = close;
input priceH            = high;    # swing high
input priceL            = low;     # swing low
input ATRreversalfactor = 3.2;
def ATR                 = reference ATR(length = 5);
def reversalAmount      = ATRreversalfactor * ATR;
input showlines         = yes;
input displace          = 1;
input showBubbleschange = yes;

def X = Highest(open, 12);
def lastbar = HighestAll(if IsNaN(close) then 0 else BarNumber());
plot condition = if BarNumber() <= lastbar - 19 and BarNumber() >= lastbar - 20 then GetValue(X, BarNumber() - lastbar) else Double.NaN;
AddChartBubble(BarNumber() == lastbar - 19, condition, "  ", Color.Yellow, 0);

def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(price), 0, barNumber));

rec state = {default init, undefined, uptrend, downtrend};
rec minMaxPrice;

if (GetValue(state, 1) == GetValue(state.init, 0)) {
    minMaxPrice = price;
    state = state.undefined;
} else if (GetValue(state, 1) == GetValue(state.undefined, 0)) {
    if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
        state = state.downtrend;
        minMaxPrice = priceL;
    } else if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
        state = state.uptrend;
        minMaxPrice = priceH;
    } else {
        state = state.undefined;
        minMaxPrice = GetValue(minMaxPrice, 1);
    }
} else if (GetValue(state, 1) == GetValue(state.uptrend, 0)) {
    if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
        state = state.downtrend;
        minMaxPrice = priceL;
    } else {
        state = state.uptrend;
        minMaxPrice = Max(priceH, GetValue(minMaxPrice, 1));
    }
} else {
    if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
        state = state.uptrend;
        minMaxPrice = priceH;
    } else {
        state = state.downtrend;
        minMaxPrice = Min(priceL, GetValue(minMaxPrice, 1));
    }
}

def isCalculated = GetValue(state, 0) != GetValue(state, 1) and barNumber >= 1;
def futureDepth =  barCount - barNumber;
def tmpLastPeriodBar;
if (isCalculated) {
    if (futureDepth >= 1 and GetValue(state, 0) == GetValue(state, -1)) {
        tmpLastPeriodBar = fold lastPeriodBarI = 2 to futureDepth + 1 with lastPeriodBarAcc = 1
            while lastPeriodBarAcc > 0
            do if (GetValue(state, 0) != GetValue(state, -lastPeriodBarI))
                then -lastPeriodBarAcc
                else lastPeriodBarAcc + 1;
    } else {
        tmpLastPeriodBar = 0;
    }
} else {
    tmpLastPeriodBar = Double.NaN;
}

def lastPeriodBar = if (!IsNaN(tmpLastPeriodBar)) then -AbsValue(tmpLastPeriodBar) else -futureDepth;

rec currentPriceLevel;
rec currentPoints;
if (state == state.uptrend and isCalculated) {
    currentPriceLevel =
        fold barWithMaxOnPeriodI = lastPeriodBar to 1 with barWithMaxOnPeriodAcc = minMaxPrice
            do Max(barWithMaxOnPeriodAcc, GetValue(minMaxPrice, barWithMaxOnPeriodI));
    currentPoints =
        fold maxPointOnPeriodI = lastPeriodBar to 1 with maxPointOnPeriodAcc = Double.NaN
            while IsNaN(maxPointOnPeriodAcc)
            do if (GetValue(priceH, maxPointOnPeriodI) == currentPriceLevel)
                then maxPointOnPeriodI
                else maxPointOnPeriodAcc;
} else if (state == state.downtrend and isCalculated) {
    currentPriceLevel =
        fold barWithMinOnPeriodI = lastPeriodBar to 1 with barWithMinOnPeriodAcc = minMaxPrice
            do Min(barWithMinOnPeriodAcc, GetValue(minMaxPrice, barWithMinOnPeriodI));
    currentPoints =
        fold minPointOnPeriodI = lastPeriodBar to 1 with minPointOnPeriodAcc = Double.NaN
            while IsNaN(minPointOnPeriodAcc)
            do if (GetValue(priceL, minPointOnPeriodI) == currentPriceLevel)
                then minPointOnPeriodI
                else minPointOnPeriodAcc;
} else if (!isCalculated and (state == state.uptrend or state == state.downtrend)) {
    currentPriceLevel = GetValue(currentPriceLevel, 1);
    currentPoints = GetValue(currentPoints, 1) + 1;
} else {
    currentPoints = 1;
    currentPriceLevel = GetValue(price, currentPoints);
}

plot "ZZ$" = if (barNumber == barCount or barNumber == 1) then if state == state.uptrend then priceH else priceL else if (currentPoints == 0) then currentPriceLevel else Double.NaN;

rec zzSave =  if !IsNaN("ZZ$" ) then if (barNumber == barCount or barNumber == 1) then if IsNaN(barNumber[-1]) and  state == state.uptrend then priceH else priceL else currentPriceLevel else GetValue(zzSave, 1);

def chg = (if barNumber == barCount and currentPoints < 0 then priceH else if barNumber == barCount and currentPoints > 0 then priceL else currentPriceLevel) - GetValue(zzSave, 1);

def isUp = chg >= 0;

#Higher/Lower/Equal High, Higher/Lower/Equal Low
def xxhigh = if zzSave == priceH then Round(high, 2) else Round(xxhigh[1], 2);
def chghigh = Round(Round(high, 2) - Round(xxhigh[1], 2), 2);
def xxlow = if zzSave == priceL then Round(low, 2) else Round(xxlow[1], 2);
def chglow = Round(Round(low, 2) - Round(xxlow[1], 2), 2);


rec isConf = AbsValue(chg) >= reversalAmount or (IsNaN(GetValue("ZZ$", 1)) and GetValue(isConf, 1));

"ZZ$".EnableApproximation();
"ZZ$".DefineColor("Up Trend", Color.UPTICK);
"ZZ$".DefineColor("Down Trend", Color.DOWNTICK);
"ZZ$".DefineColor("Undefined", Color.WHITE);
"ZZ$".AssignValueColor(if !isConf then "ZZ$".Color("Undefined" ) else if isUp then "ZZ$".Color("Up Trend" ) else "ZZ$".Color("Down Trend" ));

DefineGlobalColor("Unconfirmed", Color.WHITE);
DefineGlobalColor("Up", Color.UPTICK);
DefineGlobalColor("Down", Color.DOWNTICK);

AddChartBubble(showBubbleschange and !IsNaN("ZZ$" ) and barNumber != 1, if isUp then high else low , Round(chg, 2) , if barCount == barNumber or !isConf then GlobalColor("Unconfirmed" ) else if isUp then GlobalColor("Up" ) else GlobalColor("Down" ), isUp);

## END CODE
 
Last edited:
The code below with some changes worked from what i need....

Code:
rec closeAtBuy = if buy then close else closeAtBuy[1];
rec closeAtSell = if sell then close else closeAtSell[1];
rec state = if buy then 1 else if sell then -1 else state[1];
 
is there a way to have the below code record the last price High and Low of the ZigZap pattern?

Thank you

Capture.jpg
Code:
## START CODE
## ZigZagSign TOMO modification, v0.2 written by Linus @Thinkscripter Lounge adapted from Thinkorswim ZigZagSign Script

input price             = close;
input priceH            = high;    # swing high
input priceL            = low;     # swing low
input ATRreversalfactor = 3.2;
def ATR                 = reference ATR(length = 5);
def reversalAmount      = ATRreversalfactor * ATR;
input showlines         = yes;
input displace          = 1;
input showBubbleschange = yes;

def X = Highest(open, 12);
def lastbar = HighestAll(if IsNaN(close) then 0 else BarNumber());
plot condition = if BarNumber() <= lastbar - 19 and BarNumber() >= lastbar - 20 then GetValue(X, BarNumber() - lastbar) else Double.NaN;
AddChartBubble(BarNumber() == lastbar - 19, condition, "  ", Color.Yellow, 0);

def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(price), 0, barNumber));

rec state = {default init, undefined, uptrend, downtrend};
rec minMaxPrice;

if (GetValue(state, 1) == GetValue(state.init, 0)) {
    minMaxPrice = price;
    state = state.undefined;
} else if (GetValue(state, 1) == GetValue(state.undefined, 0)) {
    if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
        state = state.downtrend;
        minMaxPrice = priceL;
    } else if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
        state = state.uptrend;
        minMaxPrice = priceH;
    } else {
        state = state.undefined;
        minMaxPrice = GetValue(minMaxPrice, 1);
    }
} else if (GetValue(state, 1) == GetValue(state.uptrend, 0)) {
    if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
        state = state.downtrend;
        minMaxPrice = priceL;
    } else {
        state = state.uptrend;
        minMaxPrice = Max(priceH, GetValue(minMaxPrice, 1));
    }
} else {
    if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
        state = state.uptrend;
        minMaxPrice = priceH;
    } else {
        state = state.downtrend;
        minMaxPrice = Min(priceL, GetValue(minMaxPrice, 1));
    }
}

def isCalculated = GetValue(state, 0) != GetValue(state, 1) and barNumber >= 1;
def futureDepth =  barCount - barNumber;
def tmpLastPeriodBar;
if (isCalculated) {
    if (futureDepth >= 1 and GetValue(state, 0) == GetValue(state, -1)) {
        tmpLastPeriodBar = fold lastPeriodBarI = 2 to futureDepth + 1 with lastPeriodBarAcc = 1
            while lastPeriodBarAcc > 0
            do if (GetValue(state, 0) != GetValue(state, -lastPeriodBarI))
                then -lastPeriodBarAcc
                else lastPeriodBarAcc + 1;
    } else {
        tmpLastPeriodBar = 0;
    }
} else {
    tmpLastPeriodBar = Double.NaN;
}

def lastPeriodBar = if (!IsNaN(tmpLastPeriodBar)) then -AbsValue(tmpLastPeriodBar) else -futureDepth;

rec currentPriceLevel;
rec currentPoints;
if (state == state.uptrend and isCalculated) {
    currentPriceLevel =
        fold barWithMaxOnPeriodI = lastPeriodBar to 1 with barWithMaxOnPeriodAcc = minMaxPrice
            do Max(barWithMaxOnPeriodAcc, GetValue(minMaxPrice, barWithMaxOnPeriodI));
    currentPoints =
        fold maxPointOnPeriodI = lastPeriodBar to 1 with maxPointOnPeriodAcc = Double.NaN
            while IsNaN(maxPointOnPeriodAcc)
            do if (GetValue(priceH, maxPointOnPeriodI) == currentPriceLevel)
                then maxPointOnPeriodI
                else maxPointOnPeriodAcc;
} else if (state == state.downtrend and isCalculated) {
    currentPriceLevel =
        fold barWithMinOnPeriodI = lastPeriodBar to 1 with barWithMinOnPeriodAcc = minMaxPrice
            do Min(barWithMinOnPeriodAcc, GetValue(minMaxPrice, barWithMinOnPeriodI));
    currentPoints =
        fold minPointOnPeriodI = lastPeriodBar to 1 with minPointOnPeriodAcc = Double.NaN
            while IsNaN(minPointOnPeriodAcc)
            do if (GetValue(priceL, minPointOnPeriodI) == currentPriceLevel)
                then minPointOnPeriodI
                else minPointOnPeriodAcc;
} else if (!isCalculated and (state == state.uptrend or state == state.downtrend)) {
    currentPriceLevel = GetValue(currentPriceLevel, 1);
    currentPoints = GetValue(currentPoints, 1) + 1;
} else {
    currentPoints = 1;
    currentPriceLevel = GetValue(price, currentPoints);
}

plot "ZZ$" = if (barNumber == barCount or barNumber == 1) then if state == state.uptrend then priceH else priceL else if (currentPoints == 0) then currentPriceLevel else Double.NaN;

rec zzSave =  if !IsNaN("ZZ$" ) then if (barNumber == barCount or barNumber == 1) then if IsNaN(barNumber[-1]) and  state == state.uptrend then priceH else priceL else currentPriceLevel else GetValue(zzSave, 1);

def chg = (if barNumber == barCount and currentPoints < 0 then priceH else if barNumber == barCount and currentPoints > 0 then priceL else currentPriceLevel) - GetValue(zzSave, 1);

def isUp = chg >= 0;

#Higher/Lower/Equal High, Higher/Lower/Equal Low
def xxhigh = if zzSave == priceH then Round(high, 2) else Round(xxhigh[1], 2);
def chghigh = Round(Round(high, 2) - Round(xxhigh[1], 2), 2);
def xxlow = if zzSave == priceL then Round(low, 2) else Round(xxlow[1], 2);
def chglow = Round(Round(low, 2) - Round(xxlow[1], 2), 2);


rec isConf = AbsValue(chg) >= reversalAmount or (IsNaN(GetValue("ZZ$", 1)) and GetValue(isConf, 1));

"ZZ$".EnableApproximation();
"ZZ$".DefineColor("Up Trend", Color.UPTICK);
"ZZ$".DefineColor("Down Trend", Color.DOWNTICK);
"ZZ$".DefineColor("Undefined", Color.WHITE);
"ZZ$".AssignValueColor(if !isConf then "ZZ$".Color("Undefined" ) else if isUp then "ZZ$".Color("Up Trend" ) else "ZZ$".Color("Down Trend" ));

DefineGlobalColor("Unconfirmed", Color.WHITE);
DefineGlobalColor("Up", Color.UPTICK);
DefineGlobalColor("Down", Color.DOWNTICK);

AddChartBubble(showBubbleschange and !IsNaN("ZZ$" ) and barNumber != 1, if isUp then high else low , Round(chg, 2) , if barCount == barNumber or !isConf then GlobalColor("Unconfirmed" ) else if isUp then GlobalColor("Up" ) else GlobalColor("Down" ), isUp);

## END CODE

Added below is the above code with bubbles that show high/low and price change at each zigzag.

Ruby:
## START CODE
## ZigZagSign TOMO modification, v0.2 written by Linus @Thinkscripter Lounge adapted from Thinkorswim ZigZagSign Script

input price             = close;
input priceH            = high;    # swing high
input priceL            = low;     # swing low
input ATRreversalfactor = 3.2;
def ATR                 = reference ATR(length = 5);
def reversalAmount      = ATRreversalfactor * ATR;
input showlines         = yes;
input displace          = 1;
input showBubbleschange = yes;

def X = Highest(open, 12);
def lastbar = HighestAll(if IsNaN(close) then 0 else BarNumber());
plot condition = if BarNumber() <= lastbar - 19 and BarNumber() >= lastbar - 20 then GetValue(X, BarNumber() - lastbar) else Double.NaN;
AddChartBubble(BarNumber() == lastbar - 19, condition, "  ", Color.Yellow, 0);

def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(price), 0, barNumber));

rec state = {default init, undefined, uptrend, downtrend};
rec minMaxPrice;

if (GetValue(state, 1) == GetValue(state.init, 0)) {
    minMaxPrice = price;
    state = state.undefined;
} else if (GetValue(state, 1) == GetValue(state.undefined, 0)) {
    if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
        state = state.downtrend;
        minMaxPrice = priceL;
    } else if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
        state = state.uptrend;
        minMaxPrice = priceH;
    } else {
        state = state.undefined;
        minMaxPrice = GetValue(minMaxPrice, 1);
    }
} else if (GetValue(state, 1) == GetValue(state.uptrend, 0)) {
    if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
        state = state.downtrend;
        minMaxPrice = priceL;
    } else {
        state = state.uptrend;
        minMaxPrice = Max(priceH, GetValue(minMaxPrice, 1));
    }
} else {
    if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
        state = state.uptrend;
        minMaxPrice = priceH;
    } else {
        state = state.downtrend;
        minMaxPrice = Min(priceL, GetValue(minMaxPrice, 1));
    }
}

def isCalculated = GetValue(state, 0) != GetValue(state, 1) and barNumber >= 1;
def futureDepth =  barCount - barNumber;
def tmpLastPeriodBar;
if (isCalculated) {
    if (futureDepth >= 1 and GetValue(state, 0) == GetValue(state, -1)) {
        tmpLastPeriodBar = fold lastPeriodBarI = 2 to futureDepth + 1 with lastPeriodBarAcc = 1
            while lastPeriodBarAcc > 0
            do if (GetValue(state, 0) != GetValue(state, -lastPeriodBarI))
                then -lastPeriodBarAcc
                else lastPeriodBarAcc + 1;
    } else {
        tmpLastPeriodBar = 0;
    }
} else {
    tmpLastPeriodBar = Double.NaN;
}

def lastPeriodBar = if (!IsNaN(tmpLastPeriodBar)) then -AbsValue(tmpLastPeriodBar) else -futureDepth;

rec currentPriceLevel;
rec currentPoints;
if (state == state.uptrend and isCalculated) {
    currentPriceLevel =
        fold barWithMaxOnPeriodI = lastPeriodBar to 1 with barWithMaxOnPeriodAcc = minMaxPrice
            do Max(barWithMaxOnPeriodAcc, GetValue(minMaxPrice, barWithMaxOnPeriodI));
    currentPoints =
        fold maxPointOnPeriodI = lastPeriodBar to 1 with maxPointOnPeriodAcc = Double.NaN
            while IsNaN(maxPointOnPeriodAcc)
            do if (GetValue(priceH, maxPointOnPeriodI) == currentPriceLevel)
                then maxPointOnPeriodI
                else maxPointOnPeriodAcc;
} else if (state == state.downtrend and isCalculated) {
    currentPriceLevel =
        fold barWithMinOnPeriodI = lastPeriodBar to 1 with barWithMinOnPeriodAcc = minMaxPrice
            do Min(barWithMinOnPeriodAcc, GetValue(minMaxPrice, barWithMinOnPeriodI));
    currentPoints =
        fold minPointOnPeriodI = lastPeriodBar to 1 with minPointOnPeriodAcc = Double.NaN
            while IsNaN(minPointOnPeriodAcc)
            do if (GetValue(priceL, minPointOnPeriodI) == currentPriceLevel)
                then minPointOnPeriodI
                else minPointOnPeriodAcc;
} else if (!isCalculated and (state == state.uptrend or state == state.downtrend)) {
    currentPriceLevel = GetValue(currentPriceLevel, 1);
    currentPoints = GetValue(currentPoints, 1) + 1;
} else {
    currentPoints = 1;
    currentPriceLevel = GetValue(price, currentPoints);
}

plot "ZZ$" = if (barNumber == barCount or barNumber == 1) then if state == state.uptrend then priceH else priceL else if (currentPoints == 0) then currentPriceLevel else Double.NaN;

rec zzSave =  if !IsNaN("ZZ$" ) then if (barNumber == barCount or barNumber == 1) then if IsNaN(barNumber[-1]) and  state == state.uptrend then priceH else priceL else currentPriceLevel else GetValue(zzSave, 1);

def chg = (if barNumber == barCount and currentPoints < 0 then priceH else if barNumber == barCount and currentPoints > 0 then priceL else currentPriceLevel) - GetValue(zzSave, 1);

def isUp = chg >= 0;

#Higher/Lower/Equal High, Higher/Lower/Equal Low
def xxhigh = if zzSave == priceH then Round(high, 2) else Round(xxhigh[1], 2);
def chghigh = Round(Round(high, 2) - Round(xxhigh[1], 2), 2);
def xxlow = if zzSave == priceL then Round(low, 2) else Round(xxlow[1], 2);
def chglow = Round(Round(low, 2) - Round(xxlow[1], 2), 2);


rec isConf = AbsValue(chg) >= reversalAmount or (IsNaN(GetValue("ZZ$", 1)) and GetValue(isConf, 1));

"ZZ$".EnableApproximation();
"ZZ$".DefineColor("Up Trend", Color.UPTICK);
"ZZ$".DefineColor("Down Trend", Color.DOWNTICK);
"ZZ$".DefineColor("Undefined", Color.WHITE);
"ZZ$".AssignValueColor(if !isConf then "ZZ$".Color("Undefined" ) else if isUp then "ZZ$".Color("Up Trend" ) else "ZZ$".Color("Down Trend" ));

DefineGlobalColor("Unconfirmed", Color.WHITE);
DefineGlobalColor("Up", Color.UPTICK);
DefineGlobalColor("Down", Color.DOWNTICK);

AddChartBubble(showBubbleschange and !IsNaN("ZZ$" ) and barNumber != 1, if isUp then high else low , Round(chg, 2) , if barCount == barNumber or !isConf then GlobalColor("Unconfirmed" ) else if isUp then GlobalColor("Up" ) else GlobalColor("Down" ), isUp);

AddChartBubble(showBubbleschange and !IsNaN("ZZ$" ) and barNumber != 1, if isUp then high else low , if isup then high else low , if barCount == barNumber or !isConf then GlobalColor("Unconfirmed" ) else if isUp then GlobalColor("Up" ) else GlobalColor("Down" ), isUp);
 
Added below is the above code with bubbles that show high/low and price change at each zigzag.
@SleepyZ Is there a way to use the the condition for when a ZigZag Chart Bubble occurs and match it with the conditions in the code below for when up signal and down signal are created to create 1 combined condition? I am using Donchian Channel (script below, the actual channel is hidden to make for an easier read) to help trigger the up/down signals, and would like to have the up/down signals trigger at a ZigZag point. Attached is a chart (chart below) with both scripts in separate conditions showing a few of the areas (not all) where the zigzag bubble and the arrows both match in the light blue ovals (these are the ones I'd like to keep) and a few of the areas (not all) where the zigzag and arrows do not match in the shadow boxes (these are the ones I am trying to remove).

Code:
#Name:             DonchianChannel
#Programmed By:    Chris Ball ([email protected]) on 10/23/08
#Posted At:        http://chartingwithchris.blogspot.com
#Description:      This is a channel system that is used frequently for trend trading.  Google the term "turtle trader" for more information.
#Updated 9/15/21 by Stoneybucks to add upsignal when price fails to make a new Lower Low (value from the last 25 periods) in the current period compared to the previous period, and add a downsignal when when price failes to make a new Higher Higher (value from the last 25 periods) in the current period compared to the previous period. These are minimum conditions for spotting potential trend reversals.
######################################################################
##DonchianChannel
input length = 25;

plot upperBand = Highest(high[1], length);
plot lowerBand = Lowest(low[1], length);
plot middleBand = (upperBand + lowerBand) / 2;

upperBand.SetDefaultColor(Color.WHITE);
lowerBand.SetDefaultColor(Color.WHITE);
middleBand.SetDefaultColor(Color.WHITE);

#DefineScenarios

def H = high;
def L = low;
def longentry = (L > L[1] and L[1] <= lowerBand[1]);
def shortentry = (H < H[1] and H[1] >= upperBand[1]);

plot downsignal = if shortentry and !longentry  then high else Double.NaN;
downsignal.setpaintingstrategy(paintingstrategy.arrow_down);
downsignal.setdefaultcolor(color.red);
downsignal.setlineweight(5);

plot upsignal = if longentry and !shortentry then low else Double.NaN;
upsignal.setpaintingstrategy(paintingstrategy.arrow_up);
upsignal.setdefaultcolor(color.green);
upsignal.setlineweight(5);
Screen-Shot-2021-09-25-at-23-58-44.png
 
Last edited:
@SleepyZ Is there a way to use the the condition for when a ZigZag Chart Bubble occurs and match it with the conditions in the code below for when up signal and down signal are created to create 1 combined condition? I am using Donchian Channel (script below, the actual channel is hidden to make for an easier read) to help trigger the up/down signals, and would like to have the up/down signals trigger at a ZigZag point. Attached is a chart (chart below) with both scripts in separate conditions showing a few of the areas (not all) where the zigzag bubble and the arrows both match in the light blue ovals (these are the ones I'd like to keep) and a few of the areas (not all) where the zigzag and arrows do not match in the shadow boxes (these are the ones I am trying to remove).

Code:
#Name:             DonchianChannel
#Programmed By:    Chris Ball ([email protected]) on 10/23/08
#Posted At:        http://chartingwithchris.blogspot.com
#Description:      This is a channel system that is used frequently for trend trading.  Google the term "turtle trader" for more information.
#Updated 9/15/21 by Stoneybucks to add upsignal when price fails to make a new Lower Low (value from the last 25 periods) in the current period compared to the previous period, and add a downsignal when when price failes to make a new Higher Higher (value from the last 25 periods) in the current period compared to the previous period. These are minimum conditions for spotting potential trend reversals.
######################################################################
##DonchianChannel
input length = 25;

plot upperBand = Highest(high[1], length);
plot lowerBand = Lowest(low[1], length);
plot middleBand = (upperBand + lowerBand) / 2;

upperBand.SetDefaultColor(Color.WHITE);
lowerBand.SetDefaultColor(Color.WHITE);
middleBand.SetDefaultColor(Color.WHITE);

#DefineScenarios

def H = high;
def L = low;
def longentry = (L > L[1] and L[1] <= lowerBand[1]);
def shortentry = (H < H[1] and H[1] >= upperBand[1]);

plot downsignal = if shortentry and !longentry  then high else Double.NaN;
downsignal.setpaintingstrategy(paintingstrategy.arrow_down);
downsignal.setdefaultcolor(color.red);
downsignal.setlineweight(5);

plot upsignal = if longentry and !shortentry then low else Double.NaN;
upsignal.setpaintingstrategy(paintingstrategy.arrow_up);
upsignal.setdefaultcolor(color.green);
upsignal.setlineweight(5);
Screen-Shot-2021-09-25-at-23-58-44.png

Here is the combined codes with limited plots of arrows.

Capture.jpg
Ruby:
#Combined ZigZagSign and Donchian Channel Signals-----------------------------------

#ZigZag Code Used-------------------------------------------------------------------
## START CODE
## ZigZagSign TOMO modification, v0.2 written by Linus @Thinkscripter Lounge adapted from Thinkorswim ZigZagSign Script

input price             = close;
input priceH            = high;    # swing high
input priceL            = low;     # swing low
input ATRreversalfactor = 3.2;
def ATR                 = reference ATR(length = 5);
def reversalAmount      = ATRreversalfactor * ATR;
input showlines         = yes;
input displace          = 1;
input showBubbleschange = yes;

def X = Highest(open, 12);
def lastbar = HighestAll(if IsNaN(close) then 0 else BarNumber());
plot condition = if BarNumber() <= lastbar - 19 and BarNumber() >= lastbar - 20 then GetValue(X, BarNumber() - lastbar) else Double.NaN;
AddChartBubble(BarNumber() == lastbar - 19, condition, "  ", Color.YELLOW, 0);

def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(price), 0, barNumber));

rec state = {default init, undefined, uptrend, downtrend};
rec minMaxPrice;

if (GetValue(state, 1) == GetValue(state.init, 0)) {
    minMaxPrice = price;
    state = state.undefined;
} else if (GetValue(state, 1) == GetValue(state.undefined, 0)) {
    if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
        state = state.downtrend;
        minMaxPrice = priceL;
    } else if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
        state = state.uptrend;
        minMaxPrice = priceH;
    } else {
        state = state.undefined;
        minMaxPrice = GetValue(minMaxPrice, 1);
    }
} else if (GetValue(state, 1) == GetValue(state.uptrend, 0)) {
    if (price <= GetValue(minMaxPrice, 1) - reversalAmount) {
        state = state.downtrend;
        minMaxPrice = priceL;
    } else {
        state = state.uptrend;
        minMaxPrice = Max(priceH, GetValue(minMaxPrice, 1));
    }
} else {
    if (price >= GetValue(minMaxPrice, 1) + reversalAmount) {
        state = state.uptrend;
        minMaxPrice = priceH;
    } else {
        state = state.downtrend;
        minMaxPrice = Min(priceL, GetValue(minMaxPrice, 1));
    }
}

def isCalculated = GetValue(state, 0) != GetValue(state, 1) and barNumber >= 1;
def futureDepth =  barCount - barNumber;
def tmpLastPeriodBar;
if (isCalculated) {
    if (futureDepth >= 1 and GetValue(state, 0) == GetValue(state, -1)) {
        tmpLastPeriodBar = fold lastPeriodBarI = 2 to futureDepth + 1 with lastPeriodBarAcc = 1
            while lastPeriodBarAcc > 0
            do if (GetValue(state, 0) != GetValue(state, -lastPeriodBarI))
                then -lastPeriodBarAcc
                else lastPeriodBarAcc + 1;
    } else {
        tmpLastPeriodBar = 0;
    }
} else {
    tmpLastPeriodBar = Double.NaN;
}

def lastPeriodBar = if (!IsNaN(tmpLastPeriodBar)) then -AbsValue(tmpLastPeriodBar) else -futureDepth;

rec currentPriceLevel;
rec currentPoints;
if (state == state.uptrend and isCalculated) {
    currentPriceLevel =
        fold barWithMaxOnPeriodI = lastPeriodBar to 1 with barWithMaxOnPeriodAcc = minMaxPrice
            do Max(barWithMaxOnPeriodAcc, GetValue(minMaxPrice, barWithMaxOnPeriodI));
    currentPoints =
        fold maxPointOnPeriodI = lastPeriodBar to 1 with maxPointOnPeriodAcc = Double.NaN
            while IsNaN(maxPointOnPeriodAcc)
            do if (GetValue(priceH, maxPointOnPeriodI) == currentPriceLevel)
                then maxPointOnPeriodI
                else maxPointOnPeriodAcc;
} else if (state == state.downtrend and isCalculated) {
    currentPriceLevel =
        fold barWithMinOnPeriodI = lastPeriodBar to 1 with barWithMinOnPeriodAcc = minMaxPrice
            do Min(barWithMinOnPeriodAcc, GetValue(minMaxPrice, barWithMinOnPeriodI));
    currentPoints =
        fold minPointOnPeriodI = lastPeriodBar to 1 with minPointOnPeriodAcc = Double.NaN
            while IsNaN(minPointOnPeriodAcc)
            do if (GetValue(priceL, minPointOnPeriodI) == currentPriceLevel)
                then minPointOnPeriodI
                else minPointOnPeriodAcc;
} else if (!isCalculated and (state == state.uptrend or state == state.downtrend)) {
    currentPriceLevel = GetValue(currentPriceLevel, 1);
    currentPoints = GetValue(currentPoints, 1) + 1;
} else {
    currentPoints = 1;
    currentPriceLevel = GetValue(price, currentPoints);
}

plot "ZZ$" = if (barNumber == barCount or barNumber == 1) then if state == state.uptrend then priceH else priceL else if (currentPoints == 0) then currentPriceLevel else Double.NaN;

rec zzSave =  if !IsNaN("ZZ$" ) then if (barNumber == barCount or barNumber == 1) then if IsNaN(barNumber[-1]) and  state == state.uptrend then priceH else priceL else currentPriceLevel else GetValue(zzSave, 1);

def chg = (if barNumber == barCount and currentPoints < 0 then priceH else if barNumber == barCount and currentPoints > 0 then priceL else currentPriceLevel) - GetValue(zzSave, 1);

def isUp = chg >= 0;

#Higher/Lower/Equal High, Higher/Lower/Equal Low
def xxhigh  = if zzSave == priceH then Round(high, 2) else Round(xxhigh[1], 2);
def chghigh = Round(Round(high, 2) - Round(xxhigh[1], 2), 2);
def xxlow   = if zzSave == priceL then Round(low, 2) else Round(xxlow[1], 2);
def chglow  = Round(Round(low, 2) - Round(xxlow[1], 2), 2);


rec isConf  = AbsValue(chg) >= reversalAmount or (IsNaN(GetValue("ZZ$", 1)) and GetValue(isConf, 1));

"ZZ$".EnableApproximation();
"ZZ$".DefineColor("Up Trend", Color.UPTICK);
"ZZ$".DefineColor("Down Trend", Color.DOWNTICK);
"ZZ$".DefineColor("Undefined", Color.WHITE);
"ZZ$".AssignValueColor(if !isConf then "ZZ$".Color("Undefined" ) else if isUp then "ZZ$".Color("Up Trend" ) else "ZZ$".Color("Down Trend" ));

DefineGlobalColor("Unconfirmed", Color.WHITE);
DefineGlobalColor("Up", Color.UPTICK);
DefineGlobalColor("Down", Color.DOWNTICK);

#Donchian Channel Code Used------------------------------------------------------------------------
#Name:             DonchianChannel
#Programmed By:    Chris Ball ([email protected]) on 10/23/08
#Posted At:        http://chartingwithchris.blogspot.com
#Description:      This is a channel system that is used frequently for trend trading.  Google the term "turtle trader" for more information.
#Updated 9/15/21 by Stoneybucks to add upsignal when price fails to make a new Lower Low (value from the last 25 periods) in the current period compared to the previous period, and add a downsignal when when price failes to make a new Higher Higher (value from the last 25 periods) in the current period compared to the previous period. These are minimum conditions for spotting potential trend reversals.
######################################################################
##DonchianChannel
input showchannel = no;
input displace1   = 0;
input length      = 25;


plot upperBand  = Highest(high[-displace1 + 1], length);
plot lowerBand  = Lowest(low[-displace1 + 1], length);
plot middleBand = (upperBand + lowerBand) / 2;

upperBand.SetDefaultColor(Color.WHITE);
lowerBand.SetDefaultColor(Color.WHITE);
middleBand.SetDefaultColor(Color.WHITE);

upperBand.SetHiding(!showchannel);
lowerBand.SetHiding(!showchannel);
middleBand.SetHiding(!showchannel);

#DefineScenarios - Combined ZZ and Donchian-----------------------------------------------------

def H = high;
def L = low;
def longentry  = (L > L[1] and L[1] <= lowerBand[1]);
def shortentry = (H < H[1] and H[1] >= upperBand[1]);

#Arrows-----------------------------------------------------------------------------------------
plot downsignal = if upperBand == zzSave and isUp and shortentry and !longentry then high else Double.NaN;
downsignal.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
downsignal.SetDefaultColor(Color.RED);
downsignal.SetLineWeight(5);

plot upsignal   = if lowerBand == zzSave and isUp and longentry and !shortentry then low else Double.NaN;
upsignal.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
upsignal.SetDefaultColor(Color.GREEN);
upsignal.SetLineWeight(5);

#Bubbles----------------------------------------------------------------------------
input bubbledisplace = 2.00;
AddChartBubble(showBubbleschange and high == downsignal,  high + bubbledisplace, AsText(high) , GlobalColor("Down" ) , yes);
AddChartBubble(showBubbleschange and low == upsignal,  low - bubbledisplace, AsText(low) , GlobalColor("Up" ) , no);
 
Here is the combined codes with limited plots of arrows.
@SleepyZ I thought I'd be able to code an alert for when an Upsignal or Downsignal appeared, however I have yet to see it work despite think script accepting the code with no errors. Could you take a look and see if this is correct? What am I missing?

Code:
#Alerts----------------------------------------------------------------------------
def alertlong = low == upsignal;
def alertshort = high == downsignal;

input usealerts = yes;
Alert(usealerts and alertlong, "ZIG-UP", Alert.BAR, Sound.Ding);
Alert(usealerts and alertshort, "ZAG-DOWN", Alert.BAR, Sound.Ding);
 
@SleepyZ I thought I'd be able to code an alert for when an Upsignal or Downsignal appeared, however I have yet to see it work despite think script accepting the code with no errors. Could you take a look and see if this is correct? What am I missing?

Code:
#Alerts----------------------------------------------------------------------------
def alertlong = low == upsignal;
def alertshort = high == downsignal;

input usealerts = yes;
Alert(usealerts and alertlong, "ZIG-UP", Alert.BAR, Sound.Ding);
Alert(usealerts and alertshort, "ZAG-DOWN", Alert.BAR, Sound.Ding);

Since part of the up/downsignal is being displaced, it affects the alert, so the following seems to work in ONDemand

Ruby:
#Alerts----------------------------------------------------------------------------
def alertlong  = low == upsignal;
def alertshort = high == downsignal;

input usealerts = yes;
Alert(usealerts and alertlong[1], "ZIG-UP", Alert.BAR, Sound.Ding);
Alert(usealerts and alertshort[1], "ZAG-DOWN", Alert.BAR, Sound.Ding);
 
Last edited:
Im trying to add labels to this script but for some reason i cant get it to work. Any ideas? Thanks.

Edited for clarification:
I can get the labels to show up but the trigger is not working correctly. Even though i get an arrow within 3 bars, the label still shows black.

Code:
input priceH = high;
input priceL = low;
input percentageReversal = 5.0;
input absoluteReversal = 0.0;
input atrLength = 5;
input atrReversal = 1.5;

def zigZag = reference ZigZagHighLow(priceH, priceL, percentageReversal, absoluteReversal, atrLength, atrReversal).ZZ;

def step1 = open[1] >= open and open >= close[1] and open[1] > close[1];
def step2 = open[1] <= open and open <= close[1] and open[1] < close[1];

def upStep1 = step1 and close > open[1];
def upStep2 = step2 and close > close[1];
def downStep1 = step1 and close < close[1];
def downStep2 = step2 and close < open[1];

plot UpStep = (upStep1 or upStep1[-1] or upStep2 or upStep2[-1]) and zigZag == low;
plot DownStep = (downStep1 or downStep1[-1] or downStep2 or downStep2[-1]) and zigZag == high;

UpStep.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
UpStep.SetDefaultColor(GetColor(0));
UpStep.SetLineWeight(2);
DownStep.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
DownStep.SetDefaultColor(GetColor(1));
DownStep.SetLineWeight(2);



AddLabel ( yes, "zigzag", if upstep within 3 bars then Color.GREEN else color.black );

AddLabel ( yes, "zigzag", if downstep within 3 bars then Color.red else color.black );
 
Ive modified the zig zag sign study a bit to greatly help futures scalping with future specific data- but have one problem Ive been unable to fix- the last bubble often obscures the active candle- Is there somw way to eliminate or hide only the last right hand bubble? My script (this one for /NQ) :

input contracts = 5;
input showBubbles = YES;
input reversalAmount = 10.0;
input offset = 5.0;
input rangeticks = yes;
input showbarvalues = no;

input margin = 17600;
input TICKS = 4;
input tickvalue = 5.00;

def price = close;
def length = 10;
Assert(reversalAmount > 0, "'reversal amount' should be positive: " + reversalAmount);

def "ZZ$" = reference ZigZagSign(price, reversalAmount, 5, 0);

def zzSave = if !IsNaN("ZZ$") then price else GetValue(zzSave, 1);
def chg = price - GetValue(zzSave, 1);
def isUp = chg >= 0;

DefineGlobalColor("Up", CreateColor(50, 200, 250));
DefineGlobalColor("Down", CreateColor (255, 125, 125));

def barNumber = BarNumber();

AddChartBubble(showBubbles and !IsNaN("ZZ$") and barNumber != 1, if (isUp and chg > reversalAmount) then high + offset else low - offset, contracts + "x " + Round((chg * TICKS), 0) + " Ticks=$" + AbsValue(chg) * TICKS * contracts * tickvalue, if isUp then GlobalColor("Up") else GlobalColor("Down"), isUp);

#Legend labels
AddLabel(yes, contracts * TICKS * tickvalue + "x/ " + margin + " mgn ; " + contracts + " contracts : " + TICKS + " @ $ " + tickvalue, CreateColor(0, 0, 150)) ;

#Bar Ticks
def Data = (high - low) * TICKS;
plot range = if rangeticks then Data else Double.NaN;
range.SetPaintingStrategy(PaintingStrategy.VALUES_ABOVE);
range.SetDefaultColor(Color.BLACK);

plot Data2 = if showbarvalues then (high - low) * TICKS * tickvalue * contracts else Double.NaN;
Data2.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);
Data2.SetDefaultColor(Color.DARK_GREEN);

def r = Round(ExpAverage(Data, length), 0) ;
def ll = Lowest(Data[1], length);
AddLabel(yes , length + "ATR= " + r + " ticks ($" + r * tickvalue * contracts + "); low " + ll + "($" + ll * tickvalue * contracts + ") ", Color.DARK_RED);
 
Ive modified the zig zag sign study a bit to greatly help futures scalping with future specific data- but have one problem Ive been unable to fix- the last bubble often obscures the active candle- Is there somw way to eliminate or hide only the last right hand bubble? My script (this one for /NQ) :

input contracts = 5;
input showBubbles = YES;
input reversalAmount = 10.0;
input offset = 5.0;
input rangeticks = yes;
input showbarvalues = no;

input margin = 17600;
input TICKS = 4;
input tickvalue = 5.00;

def price = close;
def length = 10;
Assert(reversalAmount > 0, "'reversal amount' should be positive: " + reversalAmount);

def "ZZ$" = reference ZigZagSign(price, reversalAmount, 5, 0);

def zzSave = if !IsNaN("ZZ$") then price else GetValue(zzSave, 1);
def chg = price - GetValue(zzSave, 1);
def isUp = chg >= 0;

DefineGlobalColor("Up", CreateColor(50, 200, 250));
DefineGlobalColor("Down", CreateColor (255, 125, 125));

def barNumber = BarNumber();

AddChartBubble(showBubbles and !IsNaN("ZZ$") and barNumber != 1, if (isUp and chg > reversalAmount) then high + offset else low - offset, contracts + "x " + Round((chg * TICKS), 0) + " Ticks=$" + AbsValue(chg) * TICKS * contracts * tickvalue, if isUp then GlobalColor("Up") else GlobalColor("Down"), isUp);

#Legend labels
AddLabel(yes, contracts * TICKS * tickvalue + "x/ " + margin + " mgn ; " + contracts + " contracts : " + TICKS + " @ $ " + tickvalue, CreateColor(0, 0, 150)) ;

#Bar Ticks
def Data = (high - low) * TICKS;
plot range = if rangeticks then Data else Double.NaN;
range.SetPaintingStrategy(PaintingStrategy.VALUES_ABOVE);
range.SetDefaultColor(Color.BLACK);

plot Data2 = if showbarvalues then (high - low) * TICKS * tickvalue * contracts else Double.NaN;
Data2.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);
Data2.SetDefaultColor(Color.DARK_GREEN);

def r = Round(ExpAverage(Data, length), 0) ;
def ll = Lowest(Data[1], length);
AddLabel(yes , length + "ATR= " + r + " ticks ($" + r * tickvalue * contracts + "); low " + ll + "($" + ll * tickvalue * contracts + ") ", Color.DARK_RED);

Code is added to make the last bubble optional. It is placed to the right of the last high/low and can be moved left/right by the bubblemover input. Also, added is a '\n" in both the bubble codes to break the bubble display into 2 lines, which might prevent overlapping current candles. It is easy to remove if you do not wish to use it.

Nice modifications that you made.

Capture.jpg
Ruby:
input contracts = 5;
input showBubbles = YES;
input reversalAmount = 10.0;
input offset = 5.0;
input rangeticks = yes;
input showbarvalues = no;

input margin = 17600;
input TICKS = 4;
input tickvalue = 5.00;

def price = close;
def length = 10;
Assert(reversalAmount > 0, "'reversal amount' should be positive: " + reversalAmount);

def "ZZ$" = reference ZigZagSign(price, reversalAmount, 5, 0);

def zzSave = if !IsNaN("ZZ$") then price else GetValue(zzSave, 1);
def chg = price - GetValue(zzSave, 1);
def isUp = chg >= 0;

DefineGlobalColor("Up", CreateColor(50, 200, 250));
DefineGlobalColor("Down", CreateColor (255, 125, 125));

def barNumber = BarNumber();
def last      = highestall(if !isnan(close) and isnan(close[-1]) then barnumber else 0);

AddChartBubble(showBubbles and !IsNaN("ZZ$") and barNumber != 1 and barnumber()!=last, if (isUp and chg > reversalAmount) then high + offset else low - offset, contracts + "x " + Round((chg * TICKS), 0) + " Ticks"+"\n  = $" + AbsValue(chg) * TICKS * contracts * tickvalue, if isUp then GlobalColor("Up") else GlobalColor("Down"), isUp);

#Last Bubble-----------------------------------------------------------------------
input bubblemover = 0;
def   b =bubblemover;
def  b1 = b + 1;
input showlastbubble = yes;
AddChartBubble(showlastBubble and isnan(close[b]) and !isnan(close[b1]), if (isUp[b1] and chg[b1] > reversalAmount) then high[b1]  else low[b1], contracts + "x " + Round((chg[b1] * TICKS), 0) + " Ticks"+"\n  = $" + AbsValue(chg[b1]) * TICKS * contracts * tickvalue, if isUp[b1] then GlobalColor("Up") else GlobalColor("Down"), isUp[b1]);
#------------------------------------------------------------------------------------

#Legend labels
AddLabel(yes, contracts * TICKS * tickvalue + "x/ " + margin + " mgn ; " + contracts + " contracts : " + TICKS + " @ $ " + tickvalue, CreateColor(0, 0, 150)) ;

#Bar Ticks
def Data = (high - low) * TICKS;
plot range = if rangeticks then Data else Double.NaN;
range.SetPaintingStrategy(PaintingStrategy.VALUES_ABOVE);
range.SetDefaultColor(Color.BLACK);

plot Data2 = if showbarvalues then (high - low) * TICKS * tickvalue * contracts else Double.NaN;
Data2.SetPaintingStrategy(PaintingStrategy.VALUES_BELOW);
Data2.SetDefaultColor(Color.DARK_GREEN);

def r = Round(ExpAverage(Data, length), 0) ;
def ll = Lowest(Data[1], length);
AddLabel(yes , length + "ATR= " + r + " ticks ($" + r * tickvalue * contracts + "); low " + ll + "($" + ll * tickvalue * contracts + ") ", Color.DARK_RED);
 
Last edited:
Im trying to add labels to this script but for some reason i cant get it to work. Any ideas? Thanks.

Edited for clarification:
I can get the labels to show up but the trigger is not working correctly. Even though i get an arrow within 3 bars, the label still shows black.

The zigzag is a little tricky as it is most often a 'nan'. So it helps to create code like the zzave below to have a value for it a every bar. The upstep and downstep were revised to produce a barnumber which was used in the addlabel to capture the 3 bars, including the signal bar that you wanted for the label to be colored.

The picture below is a daily chart of AAPL and it shows the signal arrow and the label within 3 bars still showing the red downstep color. In testing the next days bar turned the label black.

See if this helps.

Capture.jpg
Ruby:
input priceH = high;
input priceL = low;
input percentageReversal = 5.0;
input absoluteReversal = 0.0;
input atrLength = 5;
input atrReversal = 1.5;

def zigZag = reference ZigZagHighLow(priceH, priceL, percentageReversal, absoluteReversal, atrLength, atrReversal).ZZ;
def zzsave = if isnan(zigzag) then zzsave[1] else zigzag;

def step1 = open[1] >= open and open >= close[1] and open[1] > close[1];
def step2 = open[1] <= open and open <= close[1] and open[1] < close[1];

def upStep1   = step1 and close > open[1];
def upStep2   = step2 and close > close[1];
def downStep1 = step1 and close < close[1];
def downStep2 = step2 and close < open[1];

def up        = if (upStep1 or upStep1[-1] or upStep2 or upStep2[-1]) and zzsave == low then BarNumber() else up[1];
def down      = if (downStep1 or downStep1[-1] or downStep2 or downStep2[-1]) and zzsave == high then BarNumber() else down[1];
plot UpStep   = barnumber() == up and zzsave[1]!=zzsave and zzsave==low;

plot DownStep = BarNumber() == down and zzsave[1]!=zzsave and zzsave == high;

UpStep.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
UpStep.SetDefaultColor(GetColor(0));
UpStep.SetLineWeight(2);
DownStep.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
DownStep.SetDefaultColor(GetColor(1));
DownStep.SetLineWeight(2);

input bars = 2;
AddLabel (yes, "zigzag", if Between(BarNumber(), up[1], up[1] + bars) then Color.GREEN else if Between(BarNumber(), (down[1]), (down[1] + bars))  then Color.RED else Color.BLACK );

#AddLabel ( yes, "zigzag", if !isnan(downstep[1]) ==1 within 3 bars then Color.red else color.black );
 
Last edited:
The zigzag is a little tricky as it is most often a 'nan'. So it helps to create code like the zzave below to have a value for it a every bar. The upstep and downstep were revised to produce a barnumber which was used in the addlabel to capture the 3 bars, including the signal bar that you wanted for the label to be colored.

The picture below is a daily chart of AAPL and it shows the signal arrow and the label within 3 bars still showing the red downstep color. In testing the next days bar turned the label black.

See if this helps.
Thanks, the script is perfect! I tried to reverse engineer it to turn it into a scan but I believe it is too advanced for my skill level. Any chance you could give it a shot?
 
Thanks, the script is perfect! I tried to reverse engineer it to turn it into a scan but I believe it is too advanced for my skill level. Any chance you could give it a shot?

The zigzag is not the most reliable indicator to use in a scan, as it repaints. Nonetheless, the following seems to produce scan results.

I named the study ZZupstep_downstep. In the scanners study editor, I added a custom study for the downstep ( create a separate one for upstep) and ran a daily scan against the S&P 500. The arrows were either showing on the charts of the results or had/will soon appear.

Ruby:
ZZupstep_downstep()."DownStep" is true within 3 bars
 
Last edited:

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
434 Online
Create Post

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top