find 4 bar wedge pattern, 2 peaks & 2 valleys

halcyonguy

Moderator - Expert
VIP
Lifetime
this study is in response to this request
https://usethinkscript.com/threads/indicator-for-triangles.14372/

find 4 bar wedge pattern,
. peak, lower peak , valley, higher valley
. peaks and valleys defined by x bars on either side of a bar
. may have 2 in a row of same signal , doesn't force alternating signals
. may have 3 or more of 1 signal, during the period of the 2 other signals
. peaks and valleys don't have to be next to each other
. alert when 4th bar appears. different sounds, if a peak or valley


options
..choose a number to define peaks and valleys. default is 2 (does not include the current bar)
..draw cyan wedge (small arrows) on all peaks and valleys
..show a wedge bubble on bar 1 of the pattern
..show a gray shaded rectangle that covers the bars of the pattern
..show diagonal lines that connect, 2 peaks and 2 valleys
..show a gray shaded area, between the 2 diagonal lines
..can show an arrow on the last bar of pattern


notes,
..when a first peak and first valley exist, and the bars after them are within those price levels, it will start to define the pattern
....if the last pattern is near the last bars on the chart, it is possible for future bars to move outside the high , low limits, canceling the pattern.
..the last x bars on the chart won't be included in the pattern
....if length is 4, then the last (length-1), or 3, bars won't be included in the pattern
..valley diagonal line starts at a valley. it doesn't extend backwards to peak bar. same with cloud, so cloud will not cover first few bars

i left my debugging test codes in. not needed to use this study


Code:
# peaks_valleys_triangle_wedge_01

#------------------
# 23-02-09
# halcyonguy
#
# find 4 bar wedge pattern, starts with a peak
#   peak, lower peak ,  valley, higher valley
#     peaks and valleys defined by x bars on either side of a bar
#   may have 2 in a row of same signal , doesn't force alternating signals
#   may have 3 or more of 1 signal, during the period of the 2 other signals
#------------------

# https://usethinkscript.com/threads/indicator-for-triangles.14372/
# Indicator for Triangles

#------------------------
# template_peaks_valleys_off_robert_03_chg
#------------------------
# https://usethinkscript.com/threads/zigzag-high-low-with-supply-demand-zones-for-thinkorswim.172/#post-7048
# original code, bar qty includes current bar
# define swing low points , robert payne
#
# modifified by halcyonguy to ignore last bar , and bar qty does not include current bar
#------------------------
def bn = BarNumber();
def na = double.nan;
input peak_valley_bars = 2;
def length = peak_valley_bars;
def lastbn = HighestAll(if IsNaN(close) then 0 else bn);
def offset = Min(length - 1, lastbn - bn);
input ignore_last_bar = yes;
def ignorelast = if (ignore_last_bar and bn == lastbn) then 0 else 1;
#
# original robert code, bar qty includes current bar
#def peak = ignorelast and high > highest(high[1], length - 1) and high == GetValue(highest(high, length), -offset);
#def valley = ignorelast and low < Lowest(low[1], length - 1) and low == GetValue(Lowest(low, length), -offset);
#
# mod code , bar qty does not include current bar
#def peak = ignorelast and high > highest(high[1], length) and high > GetValue(highest(high, length), -(offset+1));
#def valley = ignorelast and low < Lowest(low[1], length) and low < GetValue(Lowest(low, length), -(offset+1));
#
# chg so 2+ price levels in a row won't be skipped. trigger on the last bar in set, >= prev bars
def peak = ignorelast and high >= highest(high[1], length) and high > GetValue(highest(high, length), -(offset+1));
def valley = ignorelast and low <= Lowest(low[1], length) and low < GetValue(Lowest(low, length), -(offset+1));


#addlabel(1, "peak/valley bars " + peak_valley_bars, color.yellow);


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


# find a peak
# look at future bars for next 3 signals
#   valley, lower peak , higher valley

# does not force  alternating signals 


def peakbn = if peak then bn else 0;
def valleybn = if valley then bn else 0;

# loop length, qty bars to look for next peak/valley
def t = 100;

def temp1;
def temp2;
def bars1;
def bars2;
def bars3;
def peak1bn;
def peak2bn;
def valley1bn;
def valley2bn;
def wedge;
def lastpvbn;
def hislope;
def loslope;

if bn == 1 then {
 temp1 = 0;
 temp2 = 0;
 bars1 = 0;
 bars2 = 0;
 bars3 = 0;
 peak1bn = 0;
 peak2bn = 0;
 valley1bn = 0;
 valley2bn = 0;
 wedge = 0;
 lastpvbn = 0;
 hislope = 0;
 loslope = 0;

} else if bn > lastpvbn[1] and !peak then {
 # after a wedge  reset values
 temp1 = 0;
 temp2 = 0;
 bars1 = 0;
 bars2 = 0;
 bars3 = 0;
 peak1bn = 0;
 peak2bn = 0;
 valley1bn = 0;
 valley2bn = 0;
 wedge = 0;
 lastpvbn = 0;
 hislope = 0;
 loslope = 0;

} else if peak and getvalue(wedge, 1) == 0 then {
#  check if already in a wedge before recalculating new values

# start with a peak
# look for next peak, get offset to it
 bars1 = fold i1 = 1 to t
  with p1 = 1
  while getvalue(peak, -i1) == 0 and !isnan(getvalue(close, -i1))
  do p1 + 1;

# is next peak lower than current peak?
 temp1 = if isnan(getvalue(high, -bars1)) then 0
  else if (bars1 > 0 and bars1 < t and getvalue(high, -bars1) < high) then 1
  else 0;
 peak1bn = if temp1 then bn else 0;
 peak2bn = if temp1 then (bn + bars1) else 0;

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

# find valley1
 bars2 = fold i2 = 1 to t
  with p2 = 1
  while (!isnan(getvalue(close, -i2)) and getvalue(valley, -i2) == 0)
  do p2 + 1;

# find valley2
 bars3 = fold i3 = 1 to t
#  with p3 = bars2 + 1
  with p3 = 1
  while (!isnan(getvalue(close, -(bars2 + i3))) and getvalue(valley, -(bars2 + i3)) == 0)
  do p3 + 1;

# is 1st valley lower than 2nd valley?
 temp2 = if (isnan(getvalue(low, -bars2)) or isnan(getvalue(low, -(bars2 + bars3)))) then 0
  else if (bars2 > 0 and bars2 < t) and (getvalue(low, -bars2) < getvalue(low, -(bars2 + bars3))) then 1
  else 0;
 valley1bn = if temp2 then (bn + bars2) else 0;
 valley2bn = if temp2 then (bn + bars2 + bars3) else 0;

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

# do 2 peaks and 2 valleys form a wedge?
 wedge = (temp1 and temp2);

# find last bn , pk or val.  may have 2 in a row of same signal , not alternating. 1 side may have more than 2 signals
 lastpvbn = max(peak2bn, valley2bn);

# calc slopes of diag lines, connecting peaks, and valleys
 hislope = (getvalue(high, -bars1) - high)/bars1;
 loslope = (getvalue(low, -(bars2 + bars3)) - getvalue(low, -bars2)) / bars3;

} else {
# during a wedge, keep values
 temp1 = 0;
 temp2 = 0;
 bars1 = 0;
 bars2 = 0;
 bars3 = 0;
 peak1bn = peak1bn[1];
 peak2bn = peak2bn[1];
 valley1bn = valley1bn[1];
 valley2bn = valley2bn[1];
 wedge = wedge[1];
 lastpvbn = lastpvbn[1];
 hislope = hislope[1];
 loslope = loslope[1];
}

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




def pv = (peak1bn == bn or peak2bn == bn or valley1bn == bn or valley2bn == bn);

input show_all_small_arrows_on_peaks_valleys = no;
def arr = if show_all_small_arrows_on_peaks_valleys then 1
  else if (wedge and pv) then 1
  else 0;


def vert = 0.002;
#plot zv = if show_peak_valley_arrows and valley then low*(1-vert) else na;
#zv.SetPaintingStrategy(PaintingStrategy.ARROW_UP);
plot zv = if arr and valley then 1 else 0;
zv.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_down);
zv.SetDefaultColor(Color.cyan);
#zv.setlineweight(2);
zv.hidebubble();

#plot zp = if show_peak_valley_arrows and peak then high*(1+vert) else na;
#zp.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN);
plot zp = if arr and peak then 1 else 0;
zp.SetPaintingStrategy(PaintingStrategy.boolean_wedge_up);
zp.SetDefaultColor(Color.cyan);
#zp.setlineweight(2);
zp.hidebubble();


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


input show_wedge_bubble = yes;
#addchartbubble(bubble1 and peak and wedge, high*1.001,
# adding , and wedge[1] == 0 ,  removes 2nd  bubble
addchartbubble(show_wedge_bubble and peak and wedge and wedge[1] == 0, high*1.0004,
"wedge"
, color.yellow, yes);
#-------------------------

# draw a rectangular cloud over the wedge
def hi1 = if wedge and peak1bn == bn then high
# else if wedge then hi1[1]
 else if bn <= lastpvbn then hi1[1]
 else na;

def lo1 = if wedge and peak1bn == bn then getvalue(low, -bars2)
# else if wedge then lo1[1]
 else if bn <= lastpvbn then lo1[1]
 else na;


input show_rectangular_wedge_cloud = yes;
plot zh1 = if show_rectangular_wedge_cloud then hi1 else na;
zh1.SetDefaultColor(Color.white);
zh1.setlineweight(1);
zh1.hidebubble();
plot zl1 = if show_rectangular_wedge_cloud then lo1 else na;
zl1.SetDefaultColor(Color.white);
zl1.setlineweight(1);
zl1.hidebubble();

addcloud(zh1, zl1, color.gray);

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

# diag lines , 2 peaks, 2 valleys
input show_diagonal_lines = no;
def hiline = if wedge and peak1bn == bn then high
# else if wedge then hiline[1] + hislope
 else if bn <= lastpvbn then hiline[1] + hislope
 else na;

def loline = if wedge and valley1bn == bn then low
# else if wedge then loline[1] + loslope
 else if bn <= lastpvbn then loline[1] + loslope
 else na;

plot zhiline = if show_diagonal_lines and wedge then hiline else na;
zhiline.SetDefaultColor(Color.white);
zhiline.setlineweight(1);
zhiline.hidebubble();

plot zloline = if show_diagonal_lines and wedge then loline else na;
zloline.SetDefaultColor(Color.white);
zloline.setlineweight(1);
zloline.hidebubble();

input show_wedge_cloud = no;
def zhi2 = if show_wedge_cloud then zhiline else na;
addcloud(zhi2, zloline, color.gray, color.red);


input show_arrow_on_last_bar = no;
plot pattern_end = if show_arrow_on_last_bar and valley2bn == bn then low else na;
pattern_end.SetPaintingStrategy(PaintingStrategy.arrow_up);
pattern_end.SetDefaultColor(Color.cyan);
pattern_end.setlineweight(2);
pattern_end.hidebubble();


#-------------------
# alerts

# Sound.Ding , higher pitch , up sound
# Sound.Bell , lower pitch , down sound
def upalert = (bn == valley2bn);
def dwnalert = (bn == peak2bn);
alert(upalert, "valley" ,alert.BAR, sound.DING);
alert(dwnalert, "peak" ,alert.BAR, sound.bell);

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



#------------------------------------------
# test stuff

input ooooooooooo = 0;

input test1_bubbles_all_bars = no;
input test2_bubbles_just_peak_valley = no;
def t1 = if test1_bubbles_all_bars then 1
  else if test2_bubbles_just_peak_valley then (peak or valley)
  else 0; 

addchartbubble(t1, low*0.995,
 bn + "\n" +
#low + "\n" +
#peak + " P\n" +
 bars1 + " b1\n" +
 peak1bn + " p1\n" +
 peak2bn + " p2\n\n" +
 bars2 + " b2\n" +
 bars3 + " b3\n" +
 valley1bn + " v1\n" +
 valley2bn + " v2\n" +
# temp1 + " t1\n" +
# temp2 + " t2\n" +
 wedge + " w\n" +
 lastpvbn + " last\n" +
 hislope + " hi\n" +
 loslope + " lo"
, (if wedge then color.yellow else color.gray), no);
#, color.yellow, no);


input test2_prices = no;
addchartbubble(test2_prices, low*0.999,
 bn + "\n" +
 high + " hi\n" +
 low + " lo"
, (if wedge then color.yellow else color.gray), no);

#

rectangular cloud
owNFCG6.jpg



diagonal lines, cloud
SpP885d.jpg
 
Great work!!!!! I love it.
Would it be possible to come up with developing M and W patterns using built in ZigZag function?
In the image below, I have your wedge patterns and drew, M and W patterns with zigzag peaks and valleys...

Thank you!!!!!!!.
sstnwl3.png
 
# peaks_valleys_triangle_wedge_01 #------------------ # 23-02-09 # halcyonguy # # find 4 bar wedge pattern, starts with a peak # peak, lower peak , valley, higher valley # peaks and valleys defined by x bars on either side of a bar # may have 2 in a row of same signal , doesn't force alternating signals # may have 3 or more of 1 signal, during the period of the 2 other signals #------------------ # https://usethinkscript.com/threads/indicator-for-triangles.14372/ # Indicator for Triangles #------------------------ # template_peaks_valleys_off_robert_03_chg #------------------------ # https://usethinkscript.com/threads/...y-demand-zones-for-thinkorswim.172/#post-7048 # original code, bar qty includes current bar # define swing low points , robert payne # # modifified by halcyonguy to ignore last bar , and bar qty does not include current bar #------------------------ def bn = BarNumber(); def na = double.nan; input peak_valley_bars = 2; def length = peak_valley_bars; def lastbn = HighestAll(if IsNaN(close) then 0 else bn); def offset = Min(length - 1, lastbn - bn); input ignore_last_bar = yes; def ignorelast = if (ignore_last_bar and bn == lastbn) then 0 else 1; # # original robert code, bar qty includes current bar #def peak = ignorelast and high > highest(high[1], length - 1) and high == GetValue(highest(high, length), -offset); #def valley = ignorelast and low < Lowest(low[1], length - 1) and low == GetValue(Lowest(low, length), -offset); # # mod code , bar qty does not include current bar #def peak = ignorelast and high > highest(high[1], length) and high > GetValue(highest(high, length), -(offset+1)); #def valley = ignorelast and low < Lowest(low[1], length) and low < GetValue(Lowest(low, length), -(offset+1)); # # chg so 2+ price levels in a row won't be skipped. trigger on the last bar in set, >= prev bars def peak = ignorelast and high >= highest(high[1], length) and high > GetValue(highest(high, length), -(offset+1)); def valley = ignorelast and low <= Lowest(low[1], length) and low < GetValue(Lowest(low, length), -(offset+1)); #addlabel(1, "peak/valley bars " + peak_valley_bars, color.yellow); #----------------------------- #----------------------------- # find a peak # look at future bars for next 3 signals # valley, lower peak , higher valley # does not force alternating signals def peakbn = if peak then bn else 0; def valleybn = if valley then bn else 0; # loop length, qty bars to look for next peak/valley def t = 100; def temp1; def temp2; def bars1; def bars2; def bars3; def peak1bn; def peak2bn; def valley1bn; def valley2bn; def wedge; def lastpvbn; def hislope; def loslope; if bn == 1 then { temp1 = 0; temp2 = 0; bars1 = 0; bars2 = 0; bars3 = 0; peak1bn = 0; peak2bn = 0; valley1bn = 0; valley2bn = 0; wedge = 0; lastpvbn = 0; hislope = 0; loslope = 0; } else if bn > lastpvbn[1] and !peak then { # after a wedge reset values temp1 = 0; temp2 = 0; bars1 = 0; bars2 = 0; bars3 = 0; peak1bn = 0; peak2bn = 0; valley1bn = 0; valley2bn = 0; wedge = 0; lastpvbn = 0; hislope = 0; loslope = 0; } else if peak and getvalue(wedge, 1) == 0 then { # check if already in a wedge before recalculating new values # start with a peak # look for next peak, get offset to it bars1 = fold i1 = 1 to t with p1 = 1 while getvalue(peak, -i1) == 0 and !isnan(getvalue(close, -i1)) do p1 + 1; # is next peak lower than current peak? temp1 = if isnan(getvalue(high, -bars1)) then 0 else if (bars1 > 0 and bars1 < t and getvalue(high, -bars1) < high) then 1 else 0; peak1bn = if temp1 then bn else 0; peak2bn = if temp1 then (bn + bars1) else 0; #-------------------------- # find valley1 bars2 = fold i2 = 1 to t with p2 = 1 while (!isnan(getvalue(close, -i2)) and getvalue(valley, -i2) == 0) do p2 + 1; # find valley2 bars3 = fold i3 = 1 to t # with p3 = bars2 + 1 with p3 = 1 while (!isnan(getvalue(close, -(bars2 + i3))) and getvalue(valley, -(bars2 + i3)) == 0) do p3 + 1; # is 1st valley lower than 2nd valley? temp2 = if (isnan(getvalue(low, -bars2)) or isnan(getvalue(low, -(bars2 + bars3)))) then 0 else if (bars2 > 0 and bars2 < t) and (getvalue(low, -bars2) < getvalue(low, -(bars2 + bars3))) then 1 else 0; valley1bn = if temp2 then (bn + bars2) else 0; valley2bn = if temp2 then (bn + bars2 + bars3) else 0; #---------------------------- # do 2 peaks and 2 valleys form a wedge? wedge = (temp1 and temp2); # find last bn , pk or val. may have 2 in a row of same signal , not alternating. 1 side may have more than 2 signals lastpvbn = max(peak2bn, valley2bn); # calc slopes of diag lines, connecting peaks, and valleys hislope = (getvalue(high, -bars1) - high)/bars1; loslope = (getvalue(low, -(bars2 + bars3)) - getvalue(low, -bars2)) / bars3; } else { # during a wedge, keep values temp1 = 0; temp2 = 0; bars1 = 0; bars2 = 0; bars3 = 0; peak1bn = peak1bn[1]; peak2bn = peak2bn[1]; valley1bn = valley1bn[1]; valley2bn = valley2bn[1]; wedge = wedge[1]; lastpvbn = lastpvbn[1]; hislope = hislope[1]; loslope = loslope[1]; } #-------------------------- def pv = (peak1bn == bn or peak2bn == bn or valley1bn == bn or valley2bn == bn); input show_all_small_arrows_on_peaks_valleys = no; def arr = if show_all_small_arrows_on_peaks_valleys then 1 else if (wedge and pv) then 1 else 0; def vert = 0.002; #plot zv = if show_peak_valley_arrows and valley then low*(1-vert) else na; #zv.SetPaintingStrategy(PaintingStrategy.ARROW_UP); plot zv = if arr and valley then 1 else 0; zv.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_down); zv.SetDefaultColor(Color.cyan); #zv.setlineweight(2); zv.hidebubble(); #plot zp = if show_peak_valley_arrows and peak then high*(1+vert) else na; #zp.SetPaintingStrategy(PaintingStrategy.ARROW_DOWN); plot zp = if arr and peak then 1 else 0; zp.SetPaintingStrategy(PaintingStrategy.boolean_wedge_up); zp.SetDefaultColor(Color.cyan); #zp.setlineweight(2); zp.hidebubble(); #------------------------- input show_wedge_bubble = yes; #addchartbubble(bubble1 and peak and wedge, high*1.001, # adding , and wedge[1] == 0 , removes 2nd bubble addchartbubble(show_wedge_bubble and peak and wedge and wedge[1] == 0, high*1.0004, "wedge" , color.yellow, yes); #------------------------- # draw a rectangular cloud over the wedge def hi1 = if wedge and peak1bn == bn then high # else if wedge then hi1[1] else if bn <= lastpvbn then hi1[1] else na; def lo1 = if wedge and peak1bn == bn then getvalue(low, -bars2) # else if wedge then lo1[1] else if bn <= lastpvbn then lo1[1] else na; input show_rectangular_wedge_cloud = yes; plot zh1 = if show_rectangular_wedge_cloud then hi1 else na; zh1.SetDefaultColor(Color.white); zh1.setlineweight(1); zh1.hidebubble(); plot zl1 = if show_rectangular_wedge_cloud then lo1 else na; zl1.SetDefaultColor(Color.white); zl1.setlineweight(1); zl1.hidebubble(); addcloud(zh1, zl1, color.gray); #------------------------- # diag lines , 2 peaks, 2 valleys input show_diagonal_lines = no; def hiline = if wedge and peak1bn == bn then high # else if wedge then hiline[1] + hislope else if bn <= lastpvbn then hiline[1] + hislope else na; def loline = if wedge and valley1bn == bn then low # else if wedge then loline[1] + loslope else if bn <= lastpvbn then loline[1] + loslope else na; plot zhiline = if show_diagonal_lines and wedge then hiline else na; zhiline.SetDefaultColor(Color.white); zhiline.setlineweight(1); zhiline.hidebubble(); plot zloline = if show_diagonal_lines and wedge then loline else na; zloline.SetDefaultColor(Color.white); zloline.setlineweight(1); zloline.hidebubble(); input show_wedge_cloud = no; def zhi2 = if show_wedge_cloud then zhiline else na; addcloud(zhi2, zloline, color.gray, color.red); input show_arrow_on_last_bar = no; plot pattern_end = if show_arrow_on_last_bar and valley2bn == bn then low else na; pattern_end.SetPaintingStrategy(PaintingStrategy.arrow_up); pattern_end.SetDefaultColor(Color.cyan); pattern_end.setlineweight(2); pattern_end.hidebubble(); #------------------- # alerts # Sound.Ding , higher pitch , up sound # Sound.Bell , lower pitch , down sound def upalert = (bn == valley2bn); def dwnalert = (bn == peak2bn); alert(upalert, "valley" ,alert.BAR, sound.DING); alert(dwnalert, "peak" ,alert.BAR, sound.bell); #------------------- #------------------------------------------ # test stuff input ooooooooooo = 0; input test1_bubbles_all_bars = no; input test2_bubbles_just_peak_valley = no; def t1 = if test1_bubbles_all_bars then 1 else if test2_bubbles_just_peak_valley then (peak or valley) else 0; addchartbubble(t1, low*0.995, bn + "\n" + #low + "\n" + #peak + " P\n" + bars1 + " b1\n" + peak1bn + " p1\n" + peak2bn + " p2\n\n" + bars2 + " b2\n" + bars3 + " b3\n" + valley1bn + " v1\n" + valley2bn + " v2\n" + # temp1 + " t1\n" + # temp2 + " t2\n" + wedge + " w\n" + lastpvbn + " last\n" + hislope + " hi\n" + loslope + " lo" , (if wedge then color.yellow else color.gray), no); #, color.yellow, no); input test2_prices = no; addchartbubble(test2_prices, low*0.999, bn + "\n" + high + " hi\n" + low + " lo" , (if wedge then color.yellow else color.gray), no); #

How can you code it to turn off the arrow repaint?
 

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

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

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