Wyckoff Phases For ThinkOrSwim

british43

Member
VIP
@halcyonguy have helped me get to a good point for this wyckoff indicator I've working on to identify the different phases and locate when a spring occur. I would like to share it and get some feedback on how to make it efficient and scannable.

Ruby:
# seq_peaks_valleys_01d

# https://usethinkscript.com/threads/how-do-i-code-a-sequence-of-events.11956/
# I am trying to code the sequence of events: ST then UR then LS as seen below with horizontal lines. If the sequence does not occur nothing gets plot on the chart. I have post the script and looking for some tips to do this. Thanks!

def bn = barnumber();
def na = double.nan;

def lastbn = HighestAll(If(IsNaN(close), 0, bn));
def lastbar = if (bn == lastbn) then 1 else 0;

def hibn = HighestAll(bn);
#def lastbar = !isnan(close[0]) and isnan(close[-1]);

def priceH = high;
def priceL = low;
def priceC = close;

def o = open;
def h = high;
def l = low;
def c = close;

input percentageReversal = 2;
input absoluteReversal = 0.0;
input atrLength = 2;
input atrReversal = 1;
input tickReversal = 0;

Assert(percentageReversal >= 0, "'percentage reversal' must not be negative: " + percentageReversal);
Assert(absoluteReversal >= 0, "'absolute reversal' must not be negative: " + absoluteReversal);
Assert(atrReversal >= 0, "'atr reversal' must not be negative: " + atrReversal);
Assert(tickReversal >= 0, "'ticks' must not be negative: " + tickReversal);
Assert(percentageReversal != 0 or absoluteReversal != 0 or atrReversal != 0 or tickReversal != 0, "Either 'percentage reversal' or 'absolute reversal' or 'atr reversal' or 'tick reversal' must not be zero");

def absReversal;
if (absoluteReversal != 0) {
    absReversal = absoluteReversal;
} else {
    absReversal =  tickReversal * TickSize();
}

def hlPivot;
if (atrReversal != 0) {
    hlPivot = percentageReversal / 100 + WildersAverage(TrueRange(high, close, low), atrLength) / close * atrReversal;
} else {
    hlPivot = percentageReversal / 100;
}


def state = {default init, undefined, uptrend, downtrend};
def maxPriceH;
def minPriceL;
def newMax;
def newMin;
def prevMaxH = GetValue(maxPriceH, 1);
def prevMinL = GetValue(minPriceL, 1);

if GetValue(state, 1) == GetValue(state.init, 0) {
    maxPriceH = priceH;
    minPriceL = priceL;
    newMax = yes;
    newMin = yes;
    state = state.undefined;
} else if GetValue(state, 1) == GetValue(state.undefined, 0) {
    if priceH >= prevMaxH {
        state = state.uptrend;
        maxPriceH = priceH;
        minPriceL = prevMinL;
        newMax = yes;
        newMin = no;
    } else if priceL <= prevMinL {
        state = state.downtrend;
        maxPriceH = prevMaxH;
        minPriceL = priceL;
        newMax = no;
        newMin = yes;
    } else {
        state = state.undefined;
        maxPriceH = prevMaxH;
        minPriceL = prevMinL;
        newMax = no;
        newMin = no;
    }
} else if GetValue(state, 1) == GetValue(state.uptrend, 0) {
    if priceL <= prevMaxH - prevMaxH * hlPivot - absReversal {
        state = state.downtrend;
        maxPriceH = prevMaxH;
        minPriceL = priceL;
        newMax = no;
        newMin = yes;
    } else {
        state = state.uptrend;
        if (priceH >= prevMaxH) {
            maxPriceH = priceH;
            newMax = yes;
        } else {
            maxPriceH = prevMaxH;
            newMax = no;
        }
        minPriceL = prevMinL;
        newMin = no;
    }
} else {
    if priceH >= prevMinL + prevMinL * hlPivot + absReversal {
        state = state.uptrend;
        maxPriceH = priceH;
        minPriceL = prevMinL;
        newMax = yes;
        newMin = no;
    } else {
        state = state.downtrend;
        maxPriceH = prevMaxH;
        newMax = no;
        if (priceL <= prevMinL) {
            minPriceL = priceL;
            newMin = yes;
        } else {
            minPriceL = prevMinL;
            newMin = no;
        }
    }
}



def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(priceH), 0, barNumber));
def newState = GetValue(state, 0) != GetValue(state, 1);
def offset = barCount - barNumber + 1;
def highPoint = state == state.uptrend and priceH == maxPriceH;
def lowPoint = state == state.downtrend and priceL == minPriceL;

def lastH;
if highPoint and offset > 1 {
    lastH = fold iH = 1 to offset with tH = priceH while !IsNaN(tH) and !GetValue(newState, -iH) do if GetValue(newMax, -iH) or iH == offset - 1 and GetValue(priceH, -iH) == tH then Double.NaN else tH;
} else {
    lastH = Double.NaN;
}


def lastL;
if lowPoint and offset > 1 {
    lastL = fold iL = 1 to offset with tL = priceL while !IsNaN(tL) and !GetValue(newState, -iL) do if GetValue(newMin, -iL) or iL == offset - 1 and GetValue(priceL, -iL) == tL then Double.NaN else tL;
} else {
    lastL = Double.NaN;
}


plot ZZ;
if barNumber == 1 {
    ZZ = fold iF = 1 to offset with tP = Double.NaN while IsNaN(tP) do if GetValue(state, -iF) == GetValue(state.uptrend, 0) then priceL else if GetValue(state, -iF) == GetValue(state.downtrend, 0) then priceH else Double.NaN;
} else if barNumber == barCount {
    ZZ = if highPoint or state == state.downtrend and priceL > minPriceL then priceH else if lowPoint or state == state.uptrend and priceH < maxPriceH then priceL else Double.NaN;
} else {
    ZZ = if !IsNaN(lastH) then lastH else if !IsNaN(lastL) then lastL else Double.NaN;
}
ZZ.SetDefaultColor(GetColor(1));
ZZ.EnableApproximation();



input toggle = no;
input reversalamount = 8.0;

def ATRSave = if  !IsNaN(ZZ) then ZZ else GetValue(ATRSave, 1);
def ATRSave1 = if ATRSave != ATRSave[1] then ATRSave[1] else GetValue(ATRSave1, 1);
def ATRSave2 = if ATRSave != ATRSave then ATRSave else GetValue(ATRSave1, 1);
def ATRSave3 = if  ATRSave2 != ATRSave2[1] then ATRSave2[1] else GetValue(ATRSave3, 1);
def ATRSave4 = if  ATRSave3 != ATRSave3[1] then ATRSave3[1] else GetValue(ATRSave4, 1);
def ATRSave5 = if  ATRSave4 != ATRSave4[1] then ATRSave4[1] else GetValue(ATRSave5, 1);
def ATRSave6 = if  ATRSave5 != ATRSave5[1] then ATRSave5[1] else GetValue(ATRSave6, 1);
def ATRSave7 = if  ATRSave6 != ATRSave6[1] then ATRSave6[1] else GetValue(ATRSave7, 1);


#########################################################################################
#Sequence 1
#########################################################################################
input length = 20;
input trendSetup = 2;
input error = .90;

def ErrMargin = error * Average(BodyHeight(), length);
def IsWhite = open < close;
def IsAlmostEqual = AbsValue(ATRSave - ATRSave2) <= ErrMargin and IsDescending(ATRSave, trendSetup);

#def LR = isAlmostEqual;
def st1 = isAlmostEqual;


#plot test =  if st1 or st1[1] or st1[2] then (low - 3 * TickSize()) else Double.NaN;
plot test =  if st1 then (low - 3 * TickSize()) else Double.NaN;
Test.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
Test.SetStyle(Curve.POINTS);
Test.SetDefaultColor(Color.white);
Test.HideBubble();
Test.HideTitle();

#########################################################################################
#Sequence 2
#########################################################################################
def Upper_ID = ATRSave > ATRSave1 && ATRSave > ATRSAve2 && ATRSave > ATRSave3 && ATRSave2 > ATRSave1 && ATRSave2 > ATRSave3 && (ATRSave1 > ATRSave3 or ATRSave3 > ATRSave1) ;

plot Upper_Resistance =  if Upper_ID then (high + 3 * TickSize()) else Double.NaN;
Upper_Resistance.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
Upper_Resistance.SetStyle(Curve.POINTS);
Upper_Resistance.SetDefaultColor(Color.RED);
Upper_Resistance.HideBubble();
Upper_Resistance.HideTitle();

#########################################################################################
#Sequence 3
#########################################################################################
def Lower_ID = ATRSave1 > ATRSave && ATRSave1 > ATRSAve2 && ATRSave1 > ATRSave3 && ATRSave1 > ATRSave4 && ATRSave3 > ATRSave && ATRSave3 > ATRSave2 && ATRSave3 > ATRSave4 && ATRSave4 > ATRSave && (ATRSave4 > ATRSave2 or ATRSave2 > ATRSave4) && ATRSave2 > ATRSave;

plot Lower_Range =  if Lower_ID then (low - 3 * TickSize()) else Double.NaN;
Lower_Range.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
Lower_Range.SetStyle(Curve.POINTS);
Lower_Range.SetDefaultColor(Color.GREEN);
Lower_Range.HideBubble();
Lower_Range.HideTitle();

#########################################################################################
#Chartbubble
#########################################################################################
addchartBubble(toggle, Test, "ST", color.WHITE, no);
addchartBubble(toggle, Upper_Resistance, "UR", color.RED, yes);
addchartBubble(toggle, Lower_Range, "LS", color.GREEN, no);

#########################################################################################


#
#

#   chg , disable these plots
#########################################################################################
#Horizontal Lines , most recent
#########################################################################################
input lineLength = 5;
#def BN = BarNumber();
def barCount1 = Highestall(If(IsNaN(test), 0.0, BN));
def closeLine = if BN == 1 then Double.NaN
                else if BN == barCount1 - linelength
                then test[-lineLength]
                else closeLine[1];
#plot x = closeline;


def barCount2 = Highestall(If(IsNaN(Upper_Resistance), 0.0, BN));
def closeLine2 = if BN == 1 then Double.NaN
                else if BN == barCount2 - linelength
                then Upper_Resistance[-lineLength]
                else closeLine2[1];
#plot x2 = closeline2;

def barCount3 = Highestall(If(IsNaN(Lower_Range), 0.0, BN));
def closeLine3 = if BN == 1 then Double.NaN
                else if BN == barCount3 - linelength
                then Lower_Range[-lineLength]
                else closeLine3[1];
#plot x3 = closeline3;


#-------------------------------------------------------------------
#-------------------------------------------------------------------
#-------------------------------------------------------------------

# check for the seq of 3 vars , ST , then UR, then LS

#chg vars
def st = test;
def ur = Upper_Resistance;
def ls = Lower_Range;

def st_bn = barCount1;
def ur_bn = barCount2;
def ls_bn = barCount3;

def st_lvl = closeLine;
def ur_lvl = closeLine2;
def ls_lvl = closeLine3;

#---------------------------

def st_bn2 = if st_bn != st_bn[1] then st_bn else st_bn[1];

def signal_bn = if st then st_bn
  else if ur then ur_bn
  else if ls then ls_bn
  else signal_bn[1];

def sigchg = if signal_bn[1] != signal_bn then 1 else 0;


def lines_en = if bn == 1 then 0
  else if bn == st_bn then
  fold i = 1 to (lastbn - bn +1)
    with p
    do p + (if (bn == getvalue(ur_bn, -i) or bn == getvalue(ls_bn, -i)) then 1 else 0)
  else lines_en[1];


def st2 = st1;

def ur2 = if bn == 1 then 0
  else if isnan(ur) then 0
  else if ur then 1
  else ur2[1];

def ls2 = if bn == 1 then 0
  else if isnan(ls) then 0
  else if ls then 1
  else ls2[1];


# cyan line peaks/valleys
def zz2 = if bn == 1 then 0
  else if isnan(zz) then 0
  else zz;

# var with values, that determine when a pattern is found
# when a value of 3 occurs, a full pattern exists , ST, UR, LS
def signals = if bn == 1 then 0
  else if st2 and signals[1] != 0 then 0
  else if ur2 and signals[1] != 1 then 0
  else if ls2 and signals[1] != 2 then 0
  else if signals[1] == 3 then 0
  else if st2 then 1
  else if ur2 and signals[1] == 1 then 2
  else if ls2 and signals[1] == 2 then 3
# if a non labeled peak or valley then 0
  else if (zz2 > 0 and (!st2 or !ur2 or !ls2)) then 0
  else signals[1];


def ls2_off = if bn == 1 then 0
  else if lastbar then 0
  else if st2 then fold j = 1 to ( (hibn+1) - bn)
    with q
    while !isnan(getvalue(close, -j)) and getvalue(signals, -j) > 0
    do ( if getvalue(signals, -(j-1)) == 2 and getvalue(signals, -j) == 3 then j else q)
  else if ls2_off[1] == 0 then 0
  else ls2_off[1] - 1;


def st2_bn = if bn == 1 then 0
  else if st2 and ls2_off > 0 then bn
  else if signals > 0 then st2_bn[1]
  else 0;

def ur2_bn = If bn == 1 then 0
  else if ur2 and ls2_off > 0 then bn
  else if signals > 0 then ur2_bn[1]
  else 0;

def ls2_bn = if st2 then (bn + ls2_off)
  else if signals > 0 then ls2_bn[1]
  else 0;

def pattern = if bn == 1 then 0
  else if (bn >= st2_bn and bn <= ls2_bn) then 1
  else 0;

#-----------------------------

# find high of pattern rng
def rnghi = if (bn == st2_bn and ls2_bn > 0) then
  Fold k = 0 to 100
  with r
  while getvalue(pattern, -k) > 0
  do if getvalue(high, -k) > r  then getvalue(high, -k) else r
else if pattern > 0 then rnghi[1]
else na;
#plot yy = rnghi;
#yy.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);


def rnglo = if (bn == st2_bn and ls2_bn > 0) then
  fold m = 0 to 100
  with s = 99999
  while getvalue(pattern, -m) > 0
  do if getvalue(low, -m) < s  then getvalue(low, -m) else s
else if pattern > 0 then rnglo[1]
else na;
#plot ww = rnglo;
#ww.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);


input show_clouds = yes;
def factor_percent = 4.0;
def top = if show_clouds then (1+(factor_percent/100))*rnghi else na;
def bot = if show_clouds then (1-(factor_percent/100))*rnglo else na;
addcloud(top, bot, color.light_gray, color.light_gray);


#plot zp = if pattern then high * 1.05 else na;
#zp.setdefaultcolor(color.cyan);
#zp.setlineweight(4);

# ---------------------------------------


#########################################################################################
#Horizontal Lines , most recent
#   chg to be when a pattern happens
#########################################################################################
#input lineLength = 5;
#def BN = BarNumber();
#def barCount1 = Highestall(If(IsNaN(test), 0.0, BN));


# plot test =  if st1 then (low - 3 * TickSize()) else Double.NaN;
def diplvl = low - (3 * TickSize());
def peaklvl = high + (3 * TickSize());

def st_line = if BN == 1 then 0
  else if bn == st2_bn and ls2_bn > 0 then diplvl
  else st_line[1];
plot stx = if st_line > 0 then st_line else na;
stx.setdefaultcolor(color.cyan);
#stx.setlineweight(4);
stx.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

Def ur_Line = if BN == 1 then Double.NaN
  else if BN == ur2_bn and ls2_bn > 0 then peaklvl
  else ur_line[1];
plot urx = if ur_line > 0 then ur_line else na;
urx.setdefaultcolor(color.violet);
urx.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

def ls_line = if BN == 1 then Double.NaN
  else if BN == ls2_bn and signals[1] == 2 then diplvl
  else ls_line[1];
plot lsx = if ls_line > 0 then ls_line else na;
lsx.setdefaultcolor(color.orange);
lsx.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);


#--------------------------------------------

#  LR = true on st valley
input test1 = no;
addchartbubble(test1, 100,
st1 + " LR\n" +
(low - 3 * TickSize()) + "\n" +
ticksize()
#+
#test
, (if st1 then color.yellow else color.gray), no);


addchartbubble(0, low*0.88,
bn + "\n" +
st2_bn + "\n" +
st_line + "\n" +

ur2_bn + "\n" +
ls2_bn + "\n" +
signals  + "\n" +

# na
#test[-lineLength] + "\n" +
pattern + "\n" +
diplvl
# cause fold error
#pattern[-lineLength]
, color.yellow, no);


#-----------------------------------------------

addchartbubble(0, low*0.96 ,
#addchartbubble(signals > 0, low*0.96 ,
bn + " \n" +
( lastbn - bn) + "\n" +
ls2_off + " off\n" +
(bn + ls2_off) + " LS bn\n" +
zz2 + " zz\n" +
st2 + " st2\n" +
ur2 + " ur2\n" +
ls2 + " ls2\n" +
signals + "\n" +
ls2_bn
, color.yellow, no);

#addverticalline( signals == 3 , "-", color.cyan);
 
This is how it looks so far and it looks very interesting. I will keep watching it. Does it has a preferred timeframe? It looks like 1h timeframe works well.

Good for swing trading, since it seems there can be no signals for a few days. This would make a scan for the UR/ST/LS points very useful.

Whoops, sorry, I see the scan question was already on the table.

Screenshot-2022-11-06-17-30-39.png

Image Link
 
Last edited:
@Yello It works on all timeframes. I think the code can be much better (i.e. the code for the ST and LS can be better). The indicator does repaint bc it is using the zigzag indicator however if you use it in conjunction with volume analysis. It can be power.
 
@halcyonguy have helped me get to a good point for this wyckoff indicator I've working on to identify the different phases and locate when a spring occur. I would like to share it and get some feedback on how to make it efficient and scannable.

if you want an efficient and maybe simpler version, that might be usable in a scanner, try to describe the conditions in simpler terms and make a new study. maybe a simpler version would be close enough to this ?
load the study and look at many stocks , and stare at the named bubbles and look for patterns that define why they on some peaks but not on others.


i didn't study the programming math, i just stared at many charts,

ST, not sure what defines it. maybe when a valley is near the level of a previous valley?
maybe within 3% ?

UR, seems to be, a higher peak than several previous peaks

LS, seems to be, a lower valley, lower than several previous valleys.
 
@halcyonguy I want to scan when close crosses above and below LS line and same for UR line. The idea for this study is to identify when smart money is (re)accumulation or (re)distribution a stock. I define ST using 3 points. point#3 close have to be greater than point#1 low or equal. I use 5 points to define UR and UR is the highest peak of the 5 points. The opposite hold true for LS. Picture1 below is NFLX accumulation and Picture2 is what I'm trying to accomplish. If would be awesome to get the phases with vertical lines and able to scan for phases. Would you be open to having a zoom call?

16395[/ATTACH]']
8GmMZXE.png

16397[/ATTACH]']
9sxHREz.png
 

Attachments

  • 8GmMZXE.png
    8GmMZXE.png
    223.3 KB · Views: 117
  • 9sxHREz.png
    9sxHREz.png
    210.3 KB · Views: 228
Last edited:
Just a note: I looked up some charts over the weekend and found a lot of UR markings last Friday (last day in the scan for D timeframe). That was rather random and on Monday after close they where gone. IMHO, a UR flag (same of ST or LS) needs a following bar for confirmation to keep last bar errors down.
 
Just a note: I looked up some charts over the weekend and found a lot of UR markings last Friday (last day in the scan for D timeframe). That was rather random and on Monday after close they where gone. IMHO, a UR flag (same of ST or LS) needs a following bar for confirmation to keep last bar errors down.
Zigzag is a repaint indicator. This is why volume analysis is important. If volume does not correlate with the area in which LS, UR, ST is located you should use your judgement before trading it
 
@halcyonguy I'm trying to code phase A of the Wyckoff method using the code you did but failed. Can you see what I'm doing wrong. The sequence I'm looking for is SC then AR then ST.

Ruby:
# seq_peaks_valleys_01d

# https://usethinkscript.com/threads/how-do-i-code-a-sequence-of-events.11956/
# I am trying to code the sequence of events: SC then AR then ST as seen below with horizontal lines. If the sequence does not occur nothing gets plot on the chart. I have post the script and looking for some tips to do this. Thanks!
# Internal Script Reference
# User Inputs
input n = 21; #hint n: periods used for pivot calculations.
script LinePlot {
    input BarID = 0;
    input Value = 0;
    input BarOrigin = 0;
    def ThisBar = HighestAll(BarOrigin);
    def ValueLine = if BarOrigin == ThisBar
                then Value
                else Double.NaN;
    plot P = if ThisBar - BarID <= BarOrigin
             then HighestAll(ValueLine)
             else Double.NaN;
}


def l = low;
def h = high;
def bar = BarNumber();
# Parent Low
def ParentLow = LowestAll(l);
def ParentLBarOrigin = if l == ParentLow
                       then bar
                       else ParentLBarOrigin[1];
def ParentLBarID = bar - HighestAll(ParentLBarOrigin);
# S1
def ll = fold j = 1 to n + 1
         with q = 1
         while q
         do l < GetValue(l, -j);
def PivotL = if (bar > n and
                 l == Lowest(l, n) and
                 ll)
             then l
             else Double.NaN;

def PivotLH = if (bar > n and
                 l == Lowest(l, n) and
                 ll)
             then h
             else Double.NaN;

def PLValue = if !IsNaN(PivotL)
              then PivotL
              else PLValue[1];

def PLHValue = if !IsNaN(PivotLH)
              then PivotLH
              else PLHValue[1];

def PLBarOrigin = if !IsNaN(PivotL)
                  then bar
                  else PLBarOrigin[1];

def PLHBarOrigin = if !IsNaN(PivotLH)
                  then bar
                  else PLHBarOrigin[1];

def PLBarID = bar - PLBarOrigin;
def PLHBarID = bar - PLHBarOrigin;

plot PS1 = LinePlot(BarID = ParentLBarID,
                   Value = ParentLow,
                   BarOrigin = HighestAll(ParentLBarOrigin));
PS1.SetDefaultColor(Color.RED);

def bn = BarNumber();
def na = Double.NaN;

def lastbn = HighestAll(If(IsNaN(close), 0, bn));
def lastbar = if (bn == lastbn) then 1 else 0;

def hibn = HighestAll(bn);
#def lastbar = !isnan(close[0]) and isnan(close[-1]);

def priceH = high;
def priceL = low;
def priceC = close;

def o = open;

def c = close;

input percentageReversal = 2;
input absoluteReversal = 0.0;
input atrLength = 2;
input atrReversal = 1;
input tickReversal = 0;

Assert(percentageReversal >= 0, "'percentage reversal' must not be negative: " + percentageReversal);
Assert(absoluteReversal >= 0, "'absolute reversal' must not be negative: " + absoluteReversal);
Assert(atrReversal >= 0, "'atr reversal' must not be negative: " + atrReversal);
Assert(tickReversal >= 0, "'ticks' must not be negative: " + tickReversal);
Assert(percentageReversal != 0 or absoluteReversal != 0 or atrReversal != 0 or tickReversal != 0, "Either 'percentage reversal' or 'absolute reversal' or 'atr reversal' or 'tick reversal' must not be zero");

def absReversal;
if (absoluteReversal != 0) {
    absReversal = absoluteReversal;
} else {
    absReversal =  tickReversal * TickSize();
}

def hlPivot;
if (atrReversal != 0) {
    hlPivot = percentageReversal / 100 + WildersAverage(TrueRange(high, close, low), atrLength) / close * atrReversal;
} else {
    hlPivot = percentageReversal / 100;
}


def state = {default init, undefined, uptrend, downtrend};
def maxPriceH;
def minPriceL;
def newMax;
def newMin;
def prevMaxH = GetValue(maxPriceH, 1);
def prevMinL = GetValue(minPriceL, 1);

if GetValue(state, 1) == GetValue(state.init, 0) {
    maxPriceH = priceH;
    minPriceL = priceL;
    newMax = yes;
    newMin = yes;
    state = state.undefined;
} else if GetValue(state, 1) == GetValue(state.undefined, 0) {
    if priceH >= prevMaxH {
        state = state.uptrend;
        maxPriceH = priceH;
        minPriceL = prevMinL;
        newMax = yes;
        newMin = no;
    } else if priceL <= prevMinL {
        state = state.downtrend;
        maxPriceH = prevMaxH;
        minPriceL = priceL;
        newMax = no;
        newMin = yes;
    } else {
        state = state.undefined;
        maxPriceH = prevMaxH;
        minPriceL = prevMinL;
        newMax = no;
        newMin = no;
    }
} else if GetValue(state, 1) == GetValue(state.uptrend, 0) {
    if priceL <= prevMaxH - prevMaxH * hlPivot - absReversal {
        state = state.downtrend;
        maxPriceH = prevMaxH;
        minPriceL = priceL;
        newMax = no;
        newMin = yes;
    } else {
        state = state.uptrend;
        if (priceH >= prevMaxH) {
            maxPriceH = priceH;
            newMax = yes;
        } else {
            maxPriceH = prevMaxH;
            newMax = no;
        }
        minPriceL = prevMinL;
        newMin = no;
    }
} else {
    if priceH >= prevMinL + prevMinL * hlPivot + absReversal {
        state = state.uptrend;
        maxPriceH = priceH;
        minPriceL = prevMinL;
        newMax = yes;
        newMin = no;
    } else {
        state = state.downtrend;
        maxPriceH = prevMaxH;
        newMax = no;
        if (priceL <= prevMinL) {
            minPriceL = priceL;
            newMin = yes;
        } else {
            minPriceL = prevMinL;
            newMin = no;
        }
    }
}



def barNumber = BarNumber();
def barCount = HighestAll(If(IsNaN(priceH), 0, barNumber));
def newState = GetValue(state, 0) != GetValue(state, 1);
def offset = barCount - barNumber + 1;
def highPoint = state == state.uptrend and priceH == maxPriceH;
def lowPoint = state == state.downtrend and priceL == minPriceL;

def lastH;
if highPoint and offset > 1 {
    lastH = fold iH = 1 to offset with tH = priceH while !IsNaN(tH) and !GetValue(newState, -iH) do if GetValue(newMax, -iH) or iH == offset - 1 and GetValue(priceH, -iH) == tH then Double.NaN else tH;
} else {
    lastH = Double.NaN;
}


def lastL;
if lowPoint and offset > 1 {
    lastL = fold iL = 1 to offset with tL = priceL while !IsNaN(tL) and !GetValue(newState, -iL) do if GetValue(newMin, -iL) or iL == offset - 1 and GetValue(priceL, -iL) == tL then Double.NaN else tL;
} else {
    lastL = Double.NaN;
}


plot ZZ;
if barNumber == 1 {
    ZZ = fold iF = 1 to offset with tP = Double.NaN while IsNaN(tP) do if GetValue(state, -iF) == GetValue(state.uptrend, 0) then priceL else if GetValue(state, -iF) == GetValue(state.downtrend, 0) then priceH else Double.NaN;
} else if barNumber == barCount {
    ZZ = if highPoint or state == state.downtrend and priceL > minPriceL then priceH else if lowPoint or state == state.uptrend and priceH < maxPriceH then priceL else Double.NaN;
} else {
    ZZ = if !IsNaN(lastH) then lastH else if !IsNaN(lastL) then lastL else Double.NaN;
}
ZZ.SetDefaultColor(GetColor(1));
ZZ.EnableApproximation();


input toggle = no;
input reversalamount = 8.0;

def ATRSave = if  !IsNaN(ZZ) then ZZ else GetValue(ATRSave, 1);
def ATRSave1 = if ATRSave != ATRSave[1] then ATRSave[1] else GetValue(ATRSave1, 1);
def ATRSave2 = if ATRSave != ATRSave then ATRSave else GetValue(ATRSave1, 1);
def ATRSave3 = if  ATRSave2 != ATRSave2[1] then ATRSave2[1] else GetValue(ATRSave3, 1);
def ATRSave4 = if  ATRSave3 != ATRSave3[1] then ATRSave3[1] else GetValue(ATRSave4, 1);
def ATRSave5 = if  ATRSave4 != ATRSave4[1] then ATRSave4[1] else GetValue(ATRSave5, 1);
def ATRSave6 = if  ATRSave5 != ATRSave5[1] then ATRSave5[1] else GetValue(ATRSave6, 1);
def ATRSave7 = if  ATRSave6 != ATRSave6[1] then ATRSave6[1] else GetValue(ATRSave7, 1);



#Standard Test
input length = 20;
input trendSetup = 2;
input error = 2;

def ErrMargin = error * Average(BodyHeight(), length);
def IsAlmostEqual = AbsValue(ATRSave - ATRSave2) <= ErrMargin and IsDescending(ATRSave, trendSetup);

#def LR = isAlmostEqual;
def st = IsAlmostEqual;

#plot test =  if st1 or st1[1] or st1[2] then (low - 3 * TickSize()) else Double.NaN;
plot test =  if st then (low - 3 * TickSize()) else Double.NaN;
test.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
test.SetStyle(Curve.POINTS);
test.SetDefaultColor(Color.WHITE);
test.HideBubble();
test.HideTitle();

#Selling Climax
def Selling_Climax = ATRSave1 > ATRSave && ATRSave1 > ATRSave2 && ATRSave2 > ATRSave;

plot SC =  if Selling_Climax  then (low - 3 * TickSize()) else Double.NaN;
SC.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
SC.SetStyle(Curve.POINTS);
SC.SetDefaultColor(Color.GREEN);
SC .HideBubble();
SC.HideTitle();

#Automatic Reaction
def Automatic_Reaction = (ATRSave2 > ATRSave && ATRSave2 > ATRSave1 && ATRSave2 > ATRSave3 &&  ATRSave3 > ATRSave && ATRSave3 > ATRSave1 &&  ATRSave > ATRSave1) or (ATRSave2 > ATRSave && ATRSave2 > ATRSave1 && ATRSave2 > ATRSave3 &&  ATRSave > ATRSave3 && ATRSave > ATRSave1 &&  ATRSave3 > ATRSave1);

plot AR =  if Automatic_Reaction then (high + 3 * TickSize()) else Double.NaN;
AR.SetPaintingStrategy(PaintingStrategy.LINE_VS_POINTS);
AR.SetStyle(Curve.POINTS);
AR.SetDefaultColor(Color.RED);
AR .HideBubble();
AR.HideTitle();

#   chg , disable these plots
#########################################################################################
#Horizontal Lines , most recent
#########################################################################################
input lineLength = 5;
#def BN = BarNumber();
def barCount1 = Highestall(If(IsNaN(sc), 0.0, BN));
def closeLine = if BN == 1 then Double.NaN
                else if BN == barCount1 - linelength
                then sc[-lineLength]
                else closeLine[1];
#plot x = closeline;

def barCount2 = Highestall(If(IsNaN(ar), 0.0, BN));
def closeLine2 = if BN == 1 then Double.NaN
                else if BN == barCount2 - linelength
                then ar[-lineLength]
                else closeLine2[1];
#plot x2 = closeline2;

def barCount3 = Highestall(If(IsNaN(test), 0.0, BN));
def closeLine3 = if BN == 1 then Double.NaN
                else if BN == barCount3 - linelength
                then test[-lineLength]
                else closeLine3[1];
#plot x3 = closeline3;

# check for the seq of 3 vars , ST , then UR, then LS

#chg vars
def sc1 = sc;
def ar1 = ar;
def st1 = test;

def sc_bn = barCount1;
def ar_bn = barCount2;
def st_bn = barCount3;

def sc_lvl = closeLine;
def ar_lvl = closeLine2;
def st1_lvl = closeLine3;

#---------------------------

def st_bn2 = if sc_bn != sc_bn[1] then sc_bn else sc_bn[1];

def signal_bn = if sc then sc_bn
  else if ar then ar_bn
  else if st then st_bn
  else signal_bn[1];

def sigchg = if signal_bn[1] != signal_bn then 1 else 0;


def lines_en = if bn == 1 then 0
  else if bn == sc_bn then
  fold i = 1 to (lastbn - bn +1)
    with p
    do p + (if (bn == getvalue(ar_bn, -i) or bn == getvalue(st_bn, -i)) then 1 else 0)
  else lines_en[1];




#Phase 1

def SC2 = if bn == 1 then 0
  else if IsNaN(SC) then 0
  else if SC then 1
  else SC2[1];

def AR2 = if bn == 1 then 0
  else if IsNaN(AR) then 0
  else if AR then 1
  else AR2[1];

def st2 = st1;

# cyan line peaks/valleys
def zz2 = if bn == 1 then 0
  else if IsNaN(ZZ) then 0
  else ZZ;

# var with values, that determine when a pattern is found
# when a value of 3 occurs, a full pattern exists , SC, AR, ST

def signals = if bn == 1 then 0
  else if SC2 and signals[1] != 0 then 0
  else if AR2 and signals[1] != 1 then 0
  else if ST2 and signals[1] != 2 then 0
  else if signals[1] == 3 then 0
  else if SC2 then 1
  else if AR2 and signals[1] == 1 then 2
  else if ST2 and signals[1] == 2 then 3
# if a non labeled peak or valley then 0
  else if (zz2 > 0 and (!SC2 or !AR2 or !ST2)) then 0
  else signals[1];

def ST2_off = if bn == 1 then 0
  else if lastbar then 0
  else if SC2 then fold k = 1 to ( (hibn+1) - bn)
    with b
    while !isnan(getvalue(close, -k)) and getvalue(signals, -k) > 0
    do ( if getvalue(signals, -(k-1)) == 2 and getvalue(signals, -k) == 3 then b else k)
  else if ST2_off[1] == 0 then 0
  else ST2_off[1] - 1;


def SC2_bn = if bn == 1 then 0
  else if SC2 and ST2_off > 0 then bn
  else if signals > 0 then SC2_bn[1]
  else 0;

def ar2_bn = If bn == 1 then 0
  else if ar2 and st2_off > 0 then bn
  else if signals > 0 then ar2_bn[1]
  else 0;

def st2_bn = if st2 then (bn + st2_off)
  else if signals > 0 then st2_bn[1]
  else 0;

def pattern = if bn == 1 then 0
  else if (bn >= sc2_bn and bn <= st2_bn) then 1
  else 0;

# find high of pattern rng
def rnghi = if (bn == sc2_bn and st2_bn > 0) then
  Fold z = 0 to 100
  with r
  while getvalue(pattern, -z) > 0
  do if getvalue(high, -z) > r  then getvalue(high, -z) else r
else if pattern > 0 then rnghi[1]
else na;
#plot yy = rnghi;
#yy.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);


def rnglo = if (bn == sc2_bn and st2_bn > 0) then
  fold m = 0 to 100
  with s = 99999
  while getvalue(pattern, -m) > 0
  do if getvalue(low, -m) < s  then getvalue(low, -m) else s
else if pattern > 0 then rnglo[1]
else na;
#plot ww = rnglo;
#ww.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);


input show_clouds = yes;
def factor_percent = 4.0;
def top = if show_clouds then (1+(factor_percent/100))*rnghi else na;
def bot = if show_clouds then (1-(factor_percent/100))*rnglo else na;
addcloud(top, bot, color.light_gray, color.light_gray);

#########################################################################################
#Horizontal Lines , most recent
#   chg to be when a pattern happens
#########################################################################################
#input lineLength = 5;
#def BN = BarNumber();
#def barCount1 = Highestall(If(IsNaN(test), 0.0, BN));


# plot test =  if st1 then (low - 3 * TickSize()) else Double.NaN;
def diplvl = low - (3 * TickSize());
def peaklvl = high + (3 * TickSize());

def sc_line = if BN == 1 then 0
  else if bn == sc2_bn and st2_bn > 0 then diplvl
  else sc_line[1];
plot scx = if sc_line > 0 then sc_line else na;
scx.setdefaultcolor(color.cyan);
#stx.setlineweight(4);
scx.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

Def ar_Line = if BN == 1 then Double.NaN
  else if BN == sc2_bn and st2_bn > 0 then peaklvl
  else ar_line[1];
plot arx = if ar_line > 0 then ar_line else na;
arx.setdefaultcolor(color.violet);
arx.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

def st_line = if BN == 1 then Double.NaN
  else if BN == st2_bn and signals[1] == 3 then diplvl
  else st_line[1];
plot stx = if st_line > 0 then st_line else na;
stx.setdefaultcolor(color.orange);
stx.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);




AddVerticalLine( signals==3 , "Phase A ends                                                             Phase B Starts", Color.CYAN);
 

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

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
465 Online
Create Post

Similar threads

Similar threads

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