Repaints Harmonic Patterns Indicator for ThinkorSwim (ZigZag, Bat, Butterfly, ABCD)

Repaints
View attachment 4938

@chillc15 Ok here is the other version. Has some other features. If you can make a consistent strategy out of these various zigzag types please let me know.

Code:
## START CODE
## ZigZagSign TOMO modification, v0.2 written by Linus @Thinkscripter Lounge adapted from
## Thinkorswim ZigZagSign Script
## Mods by Larry to add chart bubbles & horizontal lines
## Mod by Larry to add Chart Bubble  for HH/LL indication
## 7.1.13 Added Volume Wave (similar looking to other Wave Volume studies) as a lower study. To use this, just load 2 versions of this study and designate one for the upper panel and one for the lower panel. For the lower panel, select input showvolumewave == yes. For the upper panel input showvolumewave ==no and then select the other options as usual.
##7.27.13 Added 2nd Zigzag from new TOS ZigZagHighLow indicator (can see smaller zigzags if used)
##8.24.13 Mod by Lar to add Supply/Demand Levels (Red Zones are Supply, Green are Demand), ability to enter percentage, amount or atr for reversalAmount (using the greater of the three at any reversal)

def   price               = close;
def   priceH              = high;    # swing high
def   priceL              = low;     # swing low
input ATRreversalfactor   = 3.0;#Hint ATRreversalfactor: 3 is standard, adjust to whatever instrument/timeframe you are trading.
input ATRlength           = 5;#Hint ATRlength: 5 is standard, adjust to whatever instrument/timeframe you are trading
input useatr              = yes;#Hint useatr: set to no to use manual zigzagamount for reversalamount before a new zigzag is drawn. The ATR will still be used for auto fibs.
input zigzagpercent       = 0.20;
input zigzagamount        = .15;
def ATR                   = reference ATR(length = ATRlength);
#def reversalAmount        = if useatr == yes then ATRreversalfactor * ATR else zigzagamount;
def reversalAmount        = if (close * zigzagpercent / 100) > Max(zigzagamount < ATRreversalfactor * ATR, zigzagamount) then (close * zigzagpercent / 100) else if zigzagamount < ATRreversalfactor * ATR then ATRreversalfactor * ATR else zigzagamount;
#addlabel(yes,(zigzagpercent*close/100)+"   "+zigzagamount+"  "+(atrreversalfactor*ATR));
input showsupplydemand    = no;
input showhorizontal      = no;#Hint showhorizontal: set yes to display horizontal lines at low/high of each zigzag high/low reversal bar to use for possible entry point
input bubbleoffset        = .0005;
input pricecolor          = no;
input showVolumeWave      = no;#Hint showvolumewave: set all other bubbles to no if showvolumeWave is selected yes
input showcombinedbubble  = no;#Hint showcombinedbubble: set other bubbles contained in combined to no if combined selected yes
input showcombinedbubble2 = no;#Hint showcombinedbubble2: shorter version. set other bubbles contained in combined to no if combined selected yes
input showBubbleshhll     = no;
input showBubblesprice    = no;
input showBubbleschange   = no;
input showBubblesbarcount = no;
input showBubblesVolume   = no;
input showFibLines        = no;
input showFibExtLines     = yes;
input usemanualfibskip    = no;#Hint usemanualfibskip: Select no to use preprogrammed fibskip amounts. Select no, to use the amount entered at input fibskip.
input fibskip             = .50;#Hint fibskip: Set input usemanualfibskip == yes to use this amount versus preprogrammed amounts. Standard is 1.0. This is percentage difference between fib high and low before a new fib grid created.
input showBubblesfibratio = no;
input showFibLabel        = no;#Hint showfibLabel: Select yes to show label of current fib level as of last price
input fib1level           = .236;
input fib2level           = .382;
input fibMlevel           = .500;
input fib3level           = .618;
input fib4level           = .786;
input showArrows          = no;
input useAlerts           = no;
input showconfirmedLabel  = yes;#Hint showconfirmedLabel: Select yes to see current status of ZigZag, either unconfirmed or confirmed
input showBubblewaveC     = no;#Hint showbubblewave123: Not complete, work in progress

#Assert(reversalAmount > 0, "'reversal amount' should be positive: " + reversalAmount);

#Original TOS ZigZag code Modified by Linus
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;
rec isConf =  AbsValue(chg) >= reversalAmount or (IsNaN(GetValue("ZZ$", 1)) and GetValue(isConf, 1)) ;
rec isconfreal = if isConf[1] == 0 and isConf then close else Double.NaN;
"ZZ$".EnableApproximation();
"ZZ$".DefineColor("Up Trend", Color.GREEN);
"ZZ$".DefineColor("Down Trend", Color.RED);
"ZZ$".DefineColor("Undefined", Color.YELLOW);
"ZZ$".AssignValueColor(if !isConf then "ZZ$".Color("Undefined") else if isUp then "ZZ$".Color("Up Trend") else "ZZ$".Color("Down Trend"));
"ZZ$".SetLineWeight(2);
DefineGlobalColor("Unconfirmed", Color.YELLOW);
DefineGlobalColor("Up", Color.GREEN);
DefineGlobalColor("Down", Color.RED);

#Store Previous Data
def zzsave1 = if !IsNaN(zzSave) then zzSave else zzsave1[1];
def zzsave2 = zzsave1;
rec priorzz1 = if zzsave2  != zzsave2[1]  then zzsave2[1]  else priorzz1[1];
rec priorzz2 = if priorzz1 != priorzz1[1] then priorzz1[1] else priorzz2[1];
rec priorzz3 = if priorzz2 != priorzz2[1] then priorzz2[1] else priorzz3[1];
rec priorzz4 = if priorzz3 != priorzz3[1] then priorzz3[1] else priorzz4[1];
rec priorzz5 = if priorzz4 != priorzz4[1] then priorzz4[1] else priorzz5[1];
rec priorzz6 = if priorzz5 != priorzz5[1] then priorzz5[1] else priorzz6[1];

rec upmove = if currentPoints == 0 and upmove[1] == 0 then 1 else if upmove[1] == 1  and currentPoints != 0  then 1 else 0;
rec dnmove = if currentPoints == 0 and upmove[1] == 1 then 1 else if dnmove[1] == 1 and currentPoints != 0  then 1 else 0;

def extfib1 = if zzSave == priceH then high - AbsValue(priorzz2 - priorzz1) * 1 else extfib1[1];
plot extfib100 = if showFibExtLines and currentPoints != 0 and upmove and !IsNaN(extfib1) then extfib1[1] else Double.NaN;
extfib100.SetPaintingStrategy(PaintingStrategy.DASHES);
extfib100.SetDefaultColor(Color.RED);
extfib100.SetLineWeight(1);
def extfib2 = if zzSave == priceH then high - AbsValue(priorzz2 - priorzz1) * 0.618 else extfib2[1];
plot extfib618 = if showFibExtLines and currentPoints != 0 and upmove and !IsNaN(extfib2) then extfib2[1] else Double.NaN;
extfib618.SetPaintingStrategy(PaintingStrategy.DASHES);
extfib618.SetDefaultColor(Color.RED);
extfib618.SetLineWeight(1);
def extfib3 = if zzSave == priceH then high - AbsValue(priorzz2 - priorzz1) * 1.618 else extfib3[1];
plot extfib1618 = if showFibExtLines and currentPoints != 0 and upmove and !IsNaN(extfib3) then extfib3[1] else Double.NaN;
extfib1618.SetPaintingStrategy(PaintingStrategy.DASHES);
extfib1618.SetDefaultColor(Color.RED);
extfib1618.SetLineWeight(1);
def extfib4 = if zzSave == priceH then high - AbsValue(priorzz2 - priorzz1) * 2.618 else extfib4[1];
plot extfib2618 = if showFibExtLines and currentPoints != 0 and upmove and !IsNaN(extfib4) then extfib4[1] else Double.NaN;
extfib2618.SetPaintingStrategy(PaintingStrategy.DASHES);
extfib2618.SetDefaultColor(Color.RED);
extfib2618.SetLineWeight(1);
def extfib1_ = if zzSave == priceL then low + AbsValue(priorzz2 - priorzz1) * 1 else extfib1_[1];
plot extfib100_ = if showFibExtLines and currentPoints != 0 and dnmove and !IsNaN(extfib1_) then extfib1_[1] else Double.NaN;
extfib100_.SetPaintingStrategy(PaintingStrategy.DASHES);
extfib100_.SetDefaultColor(Color.GREEN);
extfib100_.SetLineWeight(1);
def extfib2_ = if zzSave == priceL then low + AbsValue(priorzz2 - priorzz1) * 0.618 else extfib2_[1];
plot extfib618_ = if showFibExtLines and currentPoints != 0 and dnmove and !IsNaN(extfib2_) then extfib2_[1] else Double.NaN;
extfib618_.SetPaintingStrategy(PaintingStrategy.DASHES);
extfib618_.SetDefaultColor(Color.GREEN);
extfib618_.SetLineWeight(1);
def extfib3_ = if zzSave == priceL then low + AbsValue(priorzz2 - priorzz1) * 1.618 else extfib3_[1];
plot extfib1618_ = if showFibExtLines and currentPoints != 0 and dnmove and !IsNaN(extfib3_) then extfib3_[1] else Double.NaN;
extfib1618_.SetPaintingStrategy(PaintingStrategy.DASHES);
extfib1618_.SetDefaultColor(Color.GREEN);
extfib1618_.SetLineWeight(1);
def extfib4_ = if zzSave == priceL then low + AbsValue(priorzz2 - priorzz1) * 2.618 else extfib4_[1];
plot extfib2618_ = if showFibExtLines and currentPoints != 0 and dnmove and !IsNaN(extfib4_) then extfib4_[1] else Double.NaN;
extfib2618_.SetPaintingStrategy(PaintingStrategy.DASHES);
extfib2618_.SetDefaultColor(Color.GREEN);
extfib2618_.SetLineWeight(1);

AddChartBubble(showFibExtLines and !IsNaN(extfib1[7]) and IsNaN(extfib1[6]), extfib1[8], "100%", Color.RED, no);
AddChartBubble(showFibExtLines and !IsNaN(extfib2[7]) and IsNaN(extfib2[6]), extfib2[8], "61.8%", Color.RED, no);
AddChartBubble(showFibExtLines and !IsNaN(extfib3[7]) and IsNaN(extfib3[6]), extfib3[8], "161.8%", Color.RED, no);
AddChartBubble(showFibExtLines and !IsNaN(extfib4[7]) and IsNaN(extfib4[6]), extfib4[8], "261.8%", Color.RED, no);
AddChartBubble(showFibExtLines and !IsNaN(extfib1_[7]) and IsNaN(extfib1_[6]), extfib1_[8], "100%", Color.GREEN, yes);
AddChartBubble(showFibExtLines and !IsNaN(extfib2[7]) and IsNaN(extfib2_[6]), extfib2_[8], "61.8%", Color.GREEN, yes);
AddChartBubble(showFibExtLines and !IsNaN(extfib3_[7]) and IsNaN(extfib3_[6]), extfib3_[8], "161.8%", Color.GREEN, yes);
AddChartBubble(showFibExtLines and !IsNaN(extfib4_[7]) and IsNaN(extfib4_[6]), extfib4_[8], "261.8%", Color.GREEN, yes);
#addlabel(yes,concat("Prior High: ", (if priorzz1>priorzz2 then priorzz1 else priorzz2))+concat(" Prior Low : ", (if priorzz1<priorzz2 then priorzz1 else priorzz2))+concat(" 2 Highs Ago: ", (if priorzz3>priorzz4 then priorzz3 else priorzz4))+concat(" 2 Lows Ago: ", (if priorzz3<priorzz4 then priorzz3 else priorzz4))+concat(" 3 Highs Ago: ", (if priorzz5>priorzz6 then priorzz5 else priorzz6))+concat(" 3 Lows Ago: ", (if priorzz5<priorzz6 then priorzz5 else priorzz6)));

#Horizontal Lines Added
def zzhigh = if zzSave == priceH then low else zzhigh[1];
plot zzupline = if showhorizontal == yes then zzhigh else Double.NaN;
zzupline.SetPaintingStrategy(PaintingStrategy.POINTS);
zzupline.SetDefaultColor(color = Color.RED);
zzupline.SetLineWeight(1);

def zzlow = if zzSave == priceL then high else zzlow[1];
plot zzlowline = if showhorizontal == yes then zzlow else Double.NaN;
zzlowline.SetPaintingStrategy(PaintingStrategy.POINTS);
zzlowline.SetDefaultColor(color = Color.GREEN);
zzlowline.SetLineWeight(1);

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

AddChartBubble(showBubbleshhll and !IsNaN("ZZ$") and barNumber != 1, if isUp then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)  , if isUp and chghigh > 0 then "HH" else if isUp and chghigh < 0 then "LH" else if isUp then "EH" else if !isUp and chglow > 0 then "HL" else if !isUp and chglow < 0 then "LL" else "EL", if isUp and chghigh > 0 then Color.GREEN else if isUp and chghigh < 0 then Color.RED else if isUp then Color.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, isUp);

#Price at High/Low
AddChartBubble(showBubblesprice and !IsNaN("ZZ$") and barNumber != 1, if isUp then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)  , (if barNumber == barCount and currentPoints < 0 then "$" + priceH else if barNumber == barCount and currentPoints > 0 then "$" + priceL else "$" + currentPriceLevel)  , if isUp and chghigh > 0 then Color.GREEN else if isUp and chghigh < 0 then Color.RED else if isUp then Color.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, isUp);

#Price Change between zigzags
AddChartBubble(showBubbleschange and !IsNaN("ZZ$") and barNumber != 1, if isUp then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)   , "$" + chg , if isUp and chghigh > 0 then Color.GREEN else if isUp and chghigh < 0 then Color.RED else if isUp then Color.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, isUp);

#Bar Count between zigzags
#Bar Count
rec 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 == priceH or zzSave == priceL) then 1 else if zzSave == priceH or zzSave == priceL then zzcounthilo[1] + 1 else zzcounthilo[1];
def zzhilo = if zzSave == priceH or zzSave == priceL then zzcounthilo else zzcounthilo + 1;

def zzcounthigh = if zzSave == priceH then zzcount[1] else Double.NaN;
def zzcountlow =  if zzSave == priceL then zzcount[1] else Double.NaN;

AddChartBubble(showBubblesbarcount and !IsNaN("ZZ$") and barNumber != 1, if isUp then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)  , if zzSave == priceH 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.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, if isUp then yes else no );

#Supply Demand Areas
def cp = if currentPoints == 0 then 1 else if currentPoints != 0 then cp[1] + 1 else 0;
#def zzhigh = if zzSave == priceH  and (sum(close[-1]>close[-2],10)>=5 or cp[-30]>=30) then l else zzhigh[1];
def sdhigh = if zzSave == priceH then low else sdhigh[1];
plot sdupline = if showsupplydemand == no then Double.NaN else sdhigh[1];
sdupline.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
sdupline.SetDefaultColor(color = Color.RED);
sdupline.SetLineWeight(1);
#def zzhigh1 = if zzsave == priceH and (sum(close[-1]>close[-2],10)>=5 or cp[-30]>=30) then h else zzhigh1[1];
def sdhigh1 = if zzSave == priceH then high else sdhigh1[1];
plot sdupline1 = if showsupplydemand == no then Double.NaN else sdhigh1[1];
sdupline1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
sdupline1.SetDefaultColor(color = Color.RED);
sdupline1.SetLineWeight(1);
AddCloud(if showsupplydemand then sdupline1 else Double.NaN, sdupline, Color.GRAY, Color.GRAY);

#def zzlow = if zzSave == priceL and (sum(close[-1]<close[-2],10)>=5 or or cp[-30]>=30) then h else zzlow[1];
def sdlow = if zzSave == priceL then high else sdlow[1];
plot sdlowline = if showsupplydemand == no then Double.NaN else sdlow[1];
sdlowline.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
sdlowline.SetDefaultColor(color = Color.GREEN);
sdlowline.SetLineWeight(1);
#def zzlow1 = if zzSave == priceL and (sum(close[-1]<close[-2],10)>=5 or or cp[-30]>=30) then l else zzlow1[1];
def sdlow1 = if zzSave == priceL then low else sdlow1[1];
plot sdlowline1 = if showsupplydemand == no then Double.NaN else sdlow1[1];
sdlowline1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
sdlowline1.SetDefaultColor(color = Color.GREEN);
sdlowline1.SetLineWeight(1);
AddCloud(if showsupplydemand then sdlowline1 else Double.NaN, sdlowline, Color.GRAY, Color.GRAY);

#Fibs
def fibskipit = if usemanualfibskip == no then if close > 800 then .25 else .5 else fibskip;
def zzfibh    = if zzSave == priceH and AbsValue(zzSave - zzSave[1]) > close * fibskipit * .01 then high  else zzfibh[1];
def zzfibl    = if zzSave == priceL and AbsValue(zzSave - zzSave[1]) > close * fibskipit * .01 then low  else zzfibl[1];
def range = zzfibh - zzfibl;
plot fibH = if showFibLines == no then Double.NaN else zzfibh;
plot fibL = if showFibLines == no then Double.NaN else zzfibl;
plot fibM = if showFibLines == no then Double.NaN else zzfibl + range * fibMlevel;
plot fib1 = if showFibLines == no then Double.NaN else zzfibl + range * fib1level;
plot fib2 = if showFibLines == no then Double.NaN else zzfibl + range * fib2level;
plot fib3 = if showFibLines == no then Double.NaN else zzfibl + range * fib3level;
plot fib4 = if showFibLines == no then Double.NaN else zzfibl + range * fib4level;
fibH.SetPaintingStrategy(PaintingStrategy.DASHES);
fibL.SetPaintingStrategy(PaintingStrategy.DASHES);
fibH.SetLineWeight(2);
fibL.SetLineWeight(2);
fibM.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
fib1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
fib2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
fib3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
fib4.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
fibH.SetDefaultColor(Color.GREEN);
fibL.SetDefaultColor(Color.RED);
fibM.SetDefaultColor(Color.WHITE);
fib1.SetDefaultColor(Color.CYAN);
fib2.SetDefaultColor(Color.YELLOW);
fib3.SetDefaultColor(Color.YELLOW);
fib4.SetDefaultColor(Color.CYAN);

AddLabel(showFibLabel, Concat( "Current Fib Level ", AsPercent((close - zzfibl) / (range))), if close > zzfibl then Color.GREEN else if zzfibh == close then Color.WHITE else Color.RED);

AddChartBubble(showBubblesfibratio and !IsNaN("ZZ$") and barNumber != 1, if isUp then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)   , if isUp then AsPercent((high - zzfibl) / (range)) else AsPercent((low - zzfibl) / range), if isUp and chghigh > 0 then Color.GREEN else if isUp and chghigh < 0 then Color.RED else if isUp then Color.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, isUp);

#Wave C - This is still in development
def wave    = if chghigh < 0 and isUp or chglow > 0 and !isUp then 2 else 0;

AddChartBubble(showBubblewaveC and !IsNaN("ZZ$") and barNumber != 1 and wave == 2, if isUp then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)  , Concat("Wave C", ""), if isUp and chghigh > 0 then Color.GREEN else if isUp and chghigh < 0 then Color.RED else if isUp then Color.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, isUp);

#Price Color
AssignPriceColor(if pricecolor then if !isConf then "ZZ$".Color("Undefined") else if isUp then "ZZ$".Color("Up Trend") else "ZZ$".Color("Down Trend") else Color.CURRENT);
plot Data = if pricecolor and !isConf then if open > close then low else high else Double.NaN;
Data.SetPaintingStrategy(PaintingStrategy.POINTS);
Data.AssignValueColor(if open > close then Color.RED else Color.GREEN);
Data.SetLineWeight(4);

#Volume at Reversals
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 == priceH or zzSave == priceL then TotalSum(volume) else xxvol[1];
def chgvol =  if xxvol - xxvol[1] + vol1 == vol then vol else xxvol - xxvol[1];
plot cvol = chgvol;
cvol.AssignValueColor(if barCount == barNumber  or !isConf then GlobalColor("Unconfirmed") else if isUp then GlobalColor("Up") else GlobalColor("Down"));
cvol.SetHiding(showVolumeWave == no);
rec zzvol = if zzhilo[1] != zzhilo then 0 else zzvol[1] + volume;
plot zzvolupdn = if showVolumeWave then zzvol else Double.NaN;
zzvolupdn.SetPaintingStrategy(PaintingStrategy.HISTOGRAM);
zzvolupdn.AssignValueColor( if barCount == barNumber  or !isConf then GlobalColor("Unconfirmed") else if isUp then GlobalColor("Up") else GlobalColor("Down"));
plot zzt = if showVolumeWave then if zzSave == priceH or zzSave == priceL then chgvol else Double.NaN else Double.NaN;
zzt.EnableApproximation();
zzt.AssignValueColor( if barCount == barNumber  or !isConf then GlobalColor("Unconfirmed") else if isUp then GlobalColor("Up") else GlobalColor("Down"));
zzt.SetLineWeight(2);

AddChartBubble(showVolumeWave and !IsNaN("ZZ$") and barNumber != 1, chgvol , chgvol, if isUp then Color.GREEN else Color.RED, yes);

AddChartBubble(showVolumeWave and !IsNaN("ZZ$") and barNumber != 1, chgvol  , if zzSave == priceH 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.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, yes );

AddChartBubble(showBubblesVolume and !IsNaN("ZZ$") and barNumber != 1, if isUp then priceH * (1 + bubbleoffset)  else priceL * (1 - bubbleoffset), chgvol, if isUp then Color.GREEN else Color.RED, if isUp then yes else no );

#Combined Bubbles
AddChartBubble(showcombinedbubble and !IsNaN("ZZ$") and barNumber != 1, if isUp then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)  , Concat("", if isUp and chghigh > 0 then "HH" else if isUp and chghigh < 0 then "LH" else if isUp then "EH" else if !isUp and chglow > 0 then "HL" else if !isUp and chglow < 0 then "LL" else "EL") + "\n" + Concat("", if barNumber == barCount and currentPoints < 0 then "$" + priceH else if barNumber == barCount and currentPoints > 0 then "$" + priceL else "$" + currentPriceLevel) + "\n$" + chg + "\n" + Concat("", if chgvol != 0 or IsNaN(chgvol) then if isUp and chghigh > 0 then chgvol else if isUp and chghigh < 0 then chgvol else if isUp then chgvol else if !isUp and chglow > 0 then chgvol else if !isUp and chglow < 0 then chgvol else chgvol else Double.NaN) + "\n" + Concat("", if zzSave == priceH then zzcounthigh else zzcountlow) + "\n" + if isUp then AsPercent((high - zzfibl) / (range)) else AsPercent((low - zzfibl) / range), if isUp and chghigh > 0 then Color.GREEN else if isUp and chghigh < 0 then Color.RED else if isUp then Color.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, if isUp then yes else no );

AddChartBubble(showcombinedbubble2 and !IsNaN("ZZ$") and barNumber != 1, if isUp then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)  , "$" + chg + "\n" + Concat("", if barNumber == barCount and currentPoints < 0 then "$" + priceH else if barNumber == barCount and currentPoints > 0 then "$" + priceL else "$" + currentPriceLevel) , if isUp and chghigh > 0 then Color.GREEN else if isUp and chghigh < 0 then Color.RED else if isUp then Color.GREEN else if !isUp and chglow > 0 then Color.GREEN else if !isUp and chglow < 0 then Color.RED else Color.RED, if isUp then yes else no );

#Showlabel for Confirmed/Unconfirmed Status of Current Zigzag
AddLabel(showconfirmedLabel and barNumber != 1, (if isConf then "Confirmed " else "Unconfirmed ") + "ZigZag: " + chg, if !isConf then GlobalColor("Unconfirmed") else if isUp then GlobalColor("Up") else GlobalColor("Down"));

#Arrows
def zzL = if !IsNaN("ZZ$") and state == state.downtrend then priceL else GetValue(zzL, 1);
def zzH = if !IsNaN("ZZ$") and state == state.uptrend then priceH else GetValue(zzH, 1);
def dir = CompoundValue(1, if zzL != zzL[1] then 1 else if zzH != zzH[1] then -1 else dir[1], 0);
def signal = CompoundValue(1,
    if dir > 0 and low > zzL then
        if signal[1] <= 0 then 1 else signal[1]
    else if dir < 0 and high < zzH then
        if signal[1] >= 0 then -1 else signal[1]
    else signal[1]
, 0);
plot U1 = showArrows and signal > 0 and signal[1] <= 0;
U1.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
U1.SetDefaultColor(Color.GREEN);
U1.SetLineWeight(5);

plot isconfdn = if showArrows and !isUp and isconfreal then high + .05 else Double.NaN;
isconfdn.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
isconfdn.SetLineWeight(5);
isconfdn.SetDefaultColor(Color.WHITE);

plot isconfup = if showArrows and isUp and isconfreal then low - .05 else Double.NaN;
isconfup.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
isconfup.SetLineWeight(5);
isconfup.SetDefaultColor(Color.WHITE);

plot D1 = showArrows and signal < 0 and signal[1] >= 0;
D1.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
D1.SetDefaultColor(Color.RED);
D1.SetLineWeight(5);

#Alerts
def EH_EL = if isUp and chghigh > 0 then 1 else if isUp and chghigh < 0 then 1 else if isUp then 2 else if !isUp and chglow > 0 then 1 else if !isUp and chglow < 0 then 1 else 3;
Alert(useAlerts and EH_EL == 2, "Even High", Alert.BAR, Sound.Ding);
Alert(useAlerts and EH_EL == 3, "Even Low", Alert.BAR, Sound.Ding);
Alert(useAlerts and U1, "ZIG-UP", Alert.BAR, Sound.Bell);
Alert(useAlerts and D1, "ZAG-DOWN", Alert.BAR, Sound.Chimes);
Alert(useAlerts and U1, "ZIG-UP", Alert.BAR, Sound.Bell);

#Additional Zigzag from TOS zigzaghighlow version using different ATR setting
input zzotherpriceh   = high;
input zzotherpricel   = low;
input zzotherperrev   = 0.2;
input zzotherabsrev   = 0.3;
input zzotheratrrev   = 5.0;
input zzotheratrlen   = 5;
input showotherbubble = no;
plot zzother = reference ZigZagHighLow(zzotherpriceh, zzotherpricel,  zzotherperrev, zzotherabsrev, "atr length" = zzotheratrlen, "atr reversal" = zzotheratrrev).ZZ;
zzother.EnableApproximation();
zzother.SetDefaultColor(Color.CYAN);
zzother.SetLineWeight(3);
def zzoth = if !IsNaN(zzother) then zzother else zzoth[1];
def chgzzoth = AbsValue(zzoth[1] - zzoth);
AddChartBubble(showotherbubble and !IsNaN(zzother), if zzother == high then high * (1 + bubbleoffset)  else low * (1 - bubbleoffset)   , "$" + zzother + "\n$" + chgzzoth , Color.CYAN, if zzother == high then yes else no);
## END CODE
HERE IS A STRATEGY that coincides with a phase cycle indicator. the reason for this is that the zig-zag really only had one part of the code that was important and did not repaint.

THE STRATEGY - PST Phase Structure Trigger https://tos.mx/!nfBFl1vY
Off-High Phase Rotation Strategy - Run on 30 minute 1 or 2 hour charts

WHAT is this strategy?
This strategy trades rotation out of deep discount back into trend continuation.

It is NOT a bottom-fishing strategy.
It is NOT a breakout strategy.


It is a mean-reversion → re-acceptance → continuation strategy using the Off-High distance model as the environment filter.

WHY this works (important for us).
Your Off-High study is measuring how far price is from major structural highs
When a stock lives in:
  • the red zone (below −15%)
  • then climbs back above it
you are seeing institutional re-acceptance into the prior distribution.
In market microstructure terms, this is the transition from discount regime → balanced regime
That is exactly where:
  • trend legs re-form
  • options premium becomes directional again
  • mean reversion stops and momentum takes over
This is why it fits the options selling / directional entries so well. (see chart)

WHERE (on the chart) you operate.
You only care about three places on the chart.

① PHASE – Off-High location (the lower pane)
From the script:


Z2 = -15%

This is the boundary.

You are only interested when Off52 has moved back ABOVE −15

In your AMD screenshot we can clearly see:
  • cyan / magenta lines rising out of the red cloud
  • then stabilizing in the yellow/green band
That is the phase shift.
This answers, “Is this even tradable from a structural perspective?”

② STRUCTURE – price behavior

On the price chart we are using:
  • EMA21
  • EMA9
Structure is price is holding above EMA21 and EMA21 is rising.
This tells you the new leg is active.
This prevents
  • fading dead cat bounces
  • trading into compression inside the red zone
③ TRIGGER – execution

Your execution trigger is reclaim / cross above EMA9

This is your:
  • pullback resolution
  • micro-entry
WHEN you trade this, and this is important part.
This is not a “first green bar” strategy.

You trade after the Off-High phase shift has already happened.
Meaning:
  • you do NOT try to catch the turn inside the red zone
  • you wait until the environment flips
So your timeline is:
Step 1 - Off52 moves from:


below -15 → above -15

Step 2 - Price forms a leg:


above EMA21
EMA21 turning up

Step 3 - You wait for:


pullback into EMA9
and reclaim

That reclaim bar is your trade bar.

WHERE you enter (exactly)

On the chart:
Long entry The bar that closes back above EMA9

while:
  • Off52 > -15
  • price > EMA21
  • EMA21 rising
This is exactly what your WL column showed as:


P:1 S:1 T:1

WHAT you trade with this

This fits your style:
  • stocks
  • verticals
  • directional options
  • put spreads
  • call spreads (on shorts)

But most importantly it is directional bias first.

HOW to actually use the watchlist column. This is your daily flow.

Step 1 – run the watchlist
Sort by the column.
Only open symbols that show:


P:1 S:1

Ignore everything else.

Step 2 – open chart
Confirm:
  • Off-High lower pane is above −15
  • price is above EMA21
Step 3 – wait
You wait for EMA9 pullback + reclaim. You do NOT chase.

WHAT you are seeing in the AMD example, (Let’s translate the screenshot.)

Off-High pane:
  • both cyan and magenta lines have climbed from deep red
  • now holding above −15
This tells you phase is bullish

Price:
  • strong impulse leg up
  • consolidation above EMA21
  • EMA21 rising
This tells you structure is bullish

The SELL PUT CS label appears:
That is exactly your system recognizing:
  • directional bias is now positive
  • price is pulling back but not breaking structure
This is not random. This is your rotation strategy in action.

WHEN YOU SHOULD NOT TRADE (This is very important.)

Do NOT trade when:
  • Off-High is still in the red zone
  • price is chopping under EMA21
  • EMA21 is flat

That is mean reversion territory. WE already have other tools for that.

WHAT THIS STRATEGY IS NOT

It is not:
  • a top finder
  • a reversal-only strategy
  • a scalping strategy
It is a continuation strategy that waits for structural re-entry

HOW TO ADD SHORTS (symmetry)
Later you can mirror it:
  • Off-Low model
  • structure below EMA21
  • reclaim below EMA9
But right now your data and scripts are built for the long side. That is fine.

THE MOST IMPORTANT RULE (for traders)
Because we tend to be very good at building indicators "Do not add more confirmation to this."

We already solved:
  • environment
  • structure
  • timing
If you add:
  • RSI
  • TMO
  • Hilbert
  • entropy
  • gamma proxy
  • zigzag (repainting)
…you will only delay entries. This is exactly what we warn ourselves about.

Final summary you can keep:

WHAT
Trade rotations out of deep discount into a new bullish regime.

WHY
Off-High shift identifies re-acceptance into prior distribution where trend legs re-form.

WHEN
After Off52 rises above −15 and structure has already formed.

WHERE
On the EMA9 reclaim while holding above a rising EMA21.


SCANNER
Code:
# -------------------------------------------
# Off-High Phase Rotation Scan (LONG)
# antwerks
# Phase -> Structure -> Trigger
# -------------------------------------------

input lookback52w = 251;
input atrLength   = 21;

# --- Off-High (Percent from 52w high)
def high52 = Highest(high, lookback52w);

def off52 =
    if high52 != 0
    then (close - high52) / high52 * 100
    else 0;

# -------------------------------------------
# PHASE
# Must be out of red zone (-15%)
# and recently coming from it
# -------------------------------------------

def phaseBull =
    off52 > -15 and off52[1] <= -15;

# -------------------------------------------
# STRUCTURE
# -------------------------------------------

def ema21 = ExpAverage(close, 21);

def structureBull =
    close > ema21 and
    ema21 > ema21[1];

# -------------------------------------------
# TRIGGER
# EMA9 reclaim
# -------------------------------------------

def ema9 = ExpAverage(close, 9);

def triggerBull =
    close > ema9 and close[1] <= ema9[1];

# -------------------------------------------
# FINAL SCAN
# -------------------------------------------

plot scan =
    phaseBull and
    structureBull and
    triggerBull;

WATCHLIST COLUMN
Code:
# ----------------------------
# antwerks – Phase / Structure / Trigger
# Watchlist column
# ----------------------------

declare lower;

# ----------------------------
# ===== PHASE (Off-High)
# ----------------------------

input phaseThreshold = -15;
input lookback52w = 251;

def high52 = Highest(high, lookback52w);
def off52  = if high52 != 0
             then (close - high52) / high52 * 100
             else 0;

def phaseOK = off52 > phaseThreshold;

# ----------------------------
# ===== STRUCTURE
# (lightweight swing proxy)
# ----------------------------

# This intentionally avoids ZigZag in a column
# and uses your usual trend leg logic

def ema21 = ExpAverage(close, 21);

def structBull =
    close > ema21 and ema21 > ema21[1];

# ----------------------------
# ===== TRIGGER
# ----------------------------

def ema9 = ExpAverage(close, 9);

def triggerLong =
    close crosses above ema9;

# ----------------------------
# ===== SCORE / STATE
# ----------------------------

# 1 = true, 0 = false
def p = if phaseOK then 1 else 0;
def s = if structBull then 1 else 0;
def t = if triggerLong then 1 else 0;

plot State = p + s + t;

# ----------------------------
# ===== Coloring
# ----------------------------

AssignBackgroundColor(
    if p and s and t then Color.DARK_GREEN
    else if p and s then Color.DARK_ORANGE
    else if p then Color.DARK_GRAY
    else Color.DARK_RED
);

# ----------------------------
# ===== Label text
# ----------------------------

AddLabel(yes,
    "P:" + p + " S:" + s + " T:" + t,
    if p and s and t then Color.GREEN
    else if p and s then Color.ORANGE
    else if p then Color.LIGHT_GRAY
    else Color.RED
);
 
Last edited by a moderator:

BenTen's Watchlist + Setup + Trade Recaps

Get access to Ben's watchlist, swing trading strategy, ThinkorSwim setup, and trade examples.

Learn more

New Indicator: Buy the Dip

Check out our Buy the Dip indicator and see how it can help you find profitable swing trading ideas. Scanner, watchlist columns, and add-ons are included.

Download the indicator

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
628 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