Broadening Formation Pattern for ThinkorSwim

MrDrB

New member
Hello All, I've spent several nights trying to re-create this without any success: http://www.patternsmart.com/cart/index.php?route=product/product&product_id=430&search=broadening

Perhaps I'm missing something obvious. I've tried applying techniques from mobius' scalper alerts and tried re-tooling the built-in zig-zag code. Any offers to help would be appreciated. I would've just paid for it if the site looked legit and at least had an SSL cert. If anyone knows if this is available for purchase from a reputable site, I would happy to know that as well. Thanks!

BTW, I've also went over this forum post multiple times (https://usethinkscript.com/threads/second-highest-lowest-high-low-in-same-range.2064/) as it is trying to do something fundamentally similar: find the two highest highs and two lowest lows in a range of bars.
 
Last edited by a moderator:
1709388478388.png
I'm trying to use this code as a condition for a SCAN (one that finds broadening formations in addition to other parameters).

I have the code imported and applied to charts, and that is working fine.

When I copy/paste the code into CUSTOM (thinkscript) on the SCAN definition page, it posts and error about 'AddLabel not allowed in this context'. I suspect this has to do with drawing and labeling the chart, but I don't know what or how to edit the script so that it will work in the SCAN. Any help or guidance?

They idea I have here, is I want to have a 'dynamic watchlist' that shows only those symbols where the broadening pattern is being found.

I also wonder.... if it would be possible to incorporate some additional level of fidelity into this script.
The fidelity I refer to here, has to do with 'symmetry' of broadening, and 'angle' of upper and lower lines.

First, would be to focus on 'angle'. The angles of the upper and lower lines need to be within a user-specified value; with a default of 45-degrees.

Symmetry; would be that both upper and lower angles are within a user-specified 'threshold' of each other, say, +/- 1% to 50% variance of the angle with the lower-angled slope of the two slopes.

To become truly 'actionable' for setups, we want to find broadening patterns based on the most recent candle, going backward upto a user-specified number of candles (width) of the pattern. Finding a broadening pattern in history is not actionable.

Lastly, would be able to specify the height, or the 'delta' (or delta-range) between the highest-high price, and the lowest-low price, thus... find only broadening patterns where the height of the broadening pattern is at least 'z-high' (or, is between z1 and z2 in height).


So, in summary (in total), find broadening patterns that 'starting for today/yesterday' and looking backward, are at least x-candles wide between at the last 2 (ideally 3) highest highs and lowest lows, and are at least y-price high (between the highest high and lowest low, and the slopes of the upper lower lines are within d-degrees, and have v% variance of degrees between the 2 slopes. (where x, y, d, v and z(1,2) are user-specified.

This would be PERFECT...


Here's a great post on calculating slopes.

It almost feels like there's one more parameter needed; to skip over and find the 'next low (or high) back.. if the next lower-low/high is within 't-bars'. For example, if moving backward from now, the 2nd lowest low, or 2nd highest high is within t-bars of the first, then ignore it, and find the next lower low or higher high after that one, and use THAT one, as the 2nd point.

And to be truly truly actionable, the price needs to be within the 'highest high, and lowest low'. (thus, a toggle, 'Price is within the highest high, and lowest low of the broadening? Y/N'

I'll post some examples, being done by site and manually drawn.

I'll post some examples, being done by sight and manually drawn.

1709397095759.png


1709397256148.png


1709398062331.png


1709397451306.png


Thank you so much! You are awesome!

Were you able to get this code to work in a SCAN ?

I have the script loaded and applied to a chart and it works there, but when I copy the script into a CUSTOM Filter Condition as part of a SCAN ( Ideal was to scan for symbols that have the broadening formation present); I get the same error you mentioned about 'Add Label not allowed in this Context', and I have now idea how or what to do to fix this.
 
Last edited by a moderator:
I'm trying to use this code as a condition for a SCAN (one that finds broadening formations in addition to other parameters).

I have the code imported and applied to charts, and that is working fine.

When I copy/paste the code into CUSTOM (thinkscript) on the SCAN definition page, it posts and error about 'AddLabel not allowed in this context'. I suspect this has to do with drawing and labeling the chart, but I don't know what or how to edit the script so that it will work in the SCAN. Any help or guidance?

They idea I have here, is I want to have a 'dynamic watchlist' that shows only those symbols where the broadening pattern is being found.

I also wonder.... if it would be possible to incorporate some additional level of fidelity into this script.
The fidelity I refer to here, has to do with 'symmetry' of broadening, and 'angle' of upper and lower lines.

First, would be to focus on 'angle'. The angles of the upper and lower lines need to be within a user-specified value; with a default of 45-degrees.

Symmetry; would be that both upper and lower angles are within a user-specified 'threshold' of each other, say, +/- 1% to 50% variance of the angle with the lower-angled slope of the two slopes.

To become truly 'actionable' for setups, we want to find broadening patterns based on the most recent candle, going backward upto a user-specified number of candles (width) of the pattern. Finding a broadening pattern in history is not actionable.

Lastly, would be able to specify the height, or the 'delta' (or delta-range) between the highest-high price, and the lowest-low price, thus... find only broadening patterns where the height of the broadening pattern is at least 'z-high' (or, is between z1 and z2 in height).


So, in summary (in total), find broadening patterns that 'starting for today/yesterday' and looking backward, are at least x-candles wide between at the last 2 (ideally 3) highest highs and lowest lows, and are at least y-price high (between the highest high and lowest low, and the slopes of the upper lower lines are within d-degrees, and have v% variance of degrees between the 2 slopes. (where x, y, d, v and z(1,2) are user-specified.

This would be PERFECT...


Here's a great post on calculating slopes.

It almost feels like there's one more parameter needed; to skip over and find the 'next low (or high) back.. if the next lower-low/high is within 't-bars'. For example, if moving backward from now, the 2nd lowest low, or 2nd highest high is within t-bars of the first, then ignore it, and find the next lower low or higher high after that one, and use THAT one, as the 2nd point.

And to be truly truly actionable, the price needs to be within the 'highest high, and lowest low'. (thus, a toggle, 'Price is within the highest high, and lowest low of the broadening? Y/N'

I'll post some examples, being done by site and manually drawn.


Were you able to get this code to work in a SCAN ?

I have the script loaded and applied to a chart and it works there, but when I copy the script into a CUSTOM Filter Condition as part of a SCAN ( Ideal was to scan for symbols that have the broadening formation present); I get the same error you mentioned about 'Add Label not allowed in this Context', and I have now idea how or what to do to fix this.

to use this for scanning,
try changing all the plots to def , disable all the addlabels.

this already exists , inBroadeningPattern . so set it = to a plot variable
plot z = inBroadeningPattern;


a lower study that should work as a scan

Code:
#Broadening_Pattern_lines_00b_lower

#Broadening Pattern lines
#Broadening Formation Pattern for ThinkorSwim
#https://usethinkscript.com/threads/broadening-formation-pattern-for-thinkorswim.2732/page-2#posts

# true if a broadening wedge on last bars

declare lower;

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

# Inputs
input LeftBarsThreshold = 5;
input RightBarsThreshold = 5;
#input isAlertSetup = no;
input debug = no;

# Calculate values for peaks
def peak = high > Highest(high[1], LeftBarsThreshold) and high >= Highest(high[-RightBarsThreshold], RightBarsThreshold);
#plot peakBoolean = peak;

def peakValue = if peak then high else peakValue[1];
def peakBar = if peak then BarNumber() else Double.NaN;

# Calculate barNumbers for previous 2 peaks
def lastPeakBarNumber = HighestAll(if peak then bn else 0);
def prevPeakBarNumber = HighestAll(if peak and bn < lastPeakBarNumber then bn else 0);

# Get values for previous 2 peaks
def lastPeakValue = GetValue(high, bn - HighestAll(peakBar));
def prevPeakValue = GetValue(peakValue[1], bn - HighestAll(peakBar));

#  Calculate values for valleys/low points
def valley = low < Lowest(low[1], LeftBarsThreshold) and low <= Lowest(low[-RightBarsThreshold], RightBarsThreshold);
#plot valleyBoolean = valley;

def valleyValue = if valley then low else valleyValue[1];
def valleyBar = if valley then BarNumber() else Double.NaN;

# Get barNumbers for previous 2 valleys
def lastValleyBarNumber = HighestAll(if valley then bn else 0);
def prevValleyBarNumber = HighestAll(if valley and bn < lastValleyBarNumber then bn else 0);

# Get values for previous 2 valleys
def lastValleyValue = GetValue(low, bn - HighestAll(valleyBar));
def prevValleyValue = GetValue(valleyValue[1], bn - HighestAll(valleyBar));


# Do we have valid values for peaks/valleys and
# are they  increasing peaks and decreasing valleys
def areLast2PeaksIncreasing =  !IsNaN(lastPeakValue) and !IsNaN(prevPeakValue) and lastPeakValue > prevPeakValue;
def areLast2ValleysDecreasing = !IsNaN(lastValleyValue) and !IsNaN(prevValleyValue) and lastValleyValue < prevValleyValue;

# Do we have interlaced peaks/valleys
def peaksValleysInterlaced = (prevValleyBarNumber > prevPeakBarNumber and prevValleyBarNumber < lastPeakBarNumber)
   or (prevPeakBarNumber > prevValleyBarNumber and prevPeakBarNumber < lastValleyBarNumber);

def inBroadeningPattern = areLast2PeaksIncreasing and areLast2ValleysDecreasing and peaksValleysInterlaced;


def peakScalePerBar = (lastPeakValue - prevPeakValue) / (lastPeakBarNumber - prevPeakBarNumber );
def valleyScalePerBar = (lastValleyValue - prevValleyValue) / (lastValleyBarNumber - prevValleyBarNumber );

def peakExtendedValue = lastPeakValue + (bn - lastPeakBarNumber) * peakScalePerBar;
def valleyExtendedValue = lastValleyValue + (bn - lastValleyBarNumber) * valleyScalePerBar;

#Draw UpperLine, initial with 2 points, then extend with scaling factor
def upperLine = if isnan(close) then na
   else if inBroadeningPattern and bn > lastPeakBarNumber then peakExtendedValue
   else if inBroadeningPattern and peak and bn >= prevPeakBarNumber then high
   else Double.NaN;
#upperLine.EnableApproximation();
#upperLine.SetDefaultColor(Color.LIME);
#upperLine.SetLineWeight(2);

def lowerLine = if isnan(close) then na
   else if inBroadeningPattern and bn > lastValleyBarNumber then valleyExtendedValue
   else if inBroadeningPattern and valley and bn >= prevValleyBarNumber then low
   else Double.NaN;
#lowerLine.EnableApproximation();
#lowerLine.SetDefaultColor(Color.PLUM);
#lowerLine.SetLineWeight(2);

def scan_above = inBroadeningPattern and high > peakExtendedValue;
def scan_below = inBroadeningPattern and low < valleyExtendedValue;
def scan_between = inBroadeningPattern and high < peakExtendedValue and low  > valleyExtendedValue;

plot z = inBroadeningPattern;
#


----------------------

here is an updated upper study.
i removed the boolean plots.
add wedges on peaks and valleys.
add a mid line in middle of wedge.

test on AMD day chart

Code:
#Broadening_Pattern_lines_00

#Broadening Pattern lines
#Broadening Formation Pattern for ThinkorSwim
#MrDrB  Jun 7, 2020  #1
#Hello All, I've spent several nights trying to re-create this without any success: #http://www.patternsmart.com/cart/index.php?route=product/product&product_id=430&search=broadening

#Perhaps I'm missing something obvious. I've tried applying techniques from mobius' scalper alerts and tried re-tooling the built-in zig-zag code. Any offers to help would be appreciated. I would've just paid for it if the site looked legit and at least had an SSL cert. If anyone knows if this is available for purchase from a reputable site, I would happy to know that as well. Thanks!

#BTW, I've also went over this forum post multiple times
#(https://usethinkscript.com/threads/second-highest-lowest-high-low-in-same-range.2064/) as it is trying to do something fundamentally similar: find the two highest highs and two lowest lows in a range of bars.



#post5
#RajB
#Oct 20, 2020
#@MrDrB I am new to thinkscript ( few weeks of experience but programmer by trade). I am also new to this forum. I made an initial attempt at this. Are you still interested in working on this? I can send the script over. I would appreciate someone else looking over and verifying my logic. I am not done with the alerts part. I am not familiar with the best practices on think scripts.



#post7
#answer , but good ??
#RajB
#oct 21, 2020  #7
#@MrDrB
#Nice, looking forward to working together
#I think that scenario you are referring to is done. I took the approach of listing valleys/peaks and then using the last 2 valleys/peaks if present
#Alerts are partially coded and I may get to it this weekend, they are partially coded and can't be relied on
#toggle the debug flag input value for params etc. will give you my step by step decision-making process


#Broadening Pattern
#Multiple Sources
# Fun with thinkscript: https://researchtrade.com/forum/read.php?7,2258,page=31
# UseThinkScript: https://usethinkscript.com/threads/create-column-based-on-peak-and-valley-indicator.901/
# https://funwiththinkscript.com/count-the-number-of-bars-between-successive-highs/
# Idea source: https://www.patternsmart.com/cart/index.php?route=product/product&product_id=430&search=broadening

# 20201019 Raj B, initial code upto calculating peaks/valleys, getting barNumbers , checking if broadening pattern conditions exist
# 20201020 Raj B. Added ability for separate left/right threshold to allow independent values
# 20201020 Raj B. Added initial column/watchlist alerts, needs testing
# TODO complete alert part
# 20210803 Raj B. Cay7man identified a bug, removed logic that depends on isAlertSetup yes/no https://usethinkscript.com/threads/broadening-formation-pattern-for-thinkorswim.2732/post-71684  re

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

# Inputs
input LeftBarsThreshold = 5;
input RightBarsThreshold = 5;
#input isAlertSetup = no;
input debug = no;

# Calculate values for peaks
def peak = high > Highest(high[1], LeftBarsThreshold) and high >= Highest(high[-RightBarsThreshold], RightBarsThreshold);
#plot peakBoolean = peak;

def peakValue = if peak then high else peakValue[1];
def peakBar = if peak then BarNumber() else Double.NaN;

# Calculate barNumbers for previous 2 peaks
def lastPeakBarNumber = HighestAll(if peak then bn else 0);
def prevPeakBarNumber = HighestAll(if peak and bn < lastPeakBarNumber then bn else 0);

# Get values for previous 2 peaks
def lastPeakValue = GetValue(high, bn - HighestAll(peakBar));
def prevPeakValue = GetValue(peakValue[1], bn - HighestAll(peakBar));

#  Calculate values for valleys/low points
def valley = low < Lowest(low[1], LeftBarsThreshold) and low <= Lowest(low[-RightBarsThreshold], RightBarsThreshold);
#plot valleyBoolean = valley;

def valleyValue = if valley then low else valleyValue[1];
def valleyBar = if valley then BarNumber() else Double.NaN;

# Get barNumbers for previous 2 valleys
def lastValleyBarNumber = HighestAll(if valley then bn else 0);
def prevValleyBarNumber = HighestAll(if valley and bn < lastValleyBarNumber then bn else 0);

# Get values for previous 2 valleys
def lastValleyValue = GetValue(low, bn - HighestAll(valleyBar));
def prevValleyValue = GetValue(valleyValue[1], bn - HighestAll(valleyBar));


#plot zp = if peak then high else na;
#plot zv = if valley then low else na;
plot zp = peak;
plot zv = valley;
zp.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_up);
zv.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
zp.setdefaultcolor(color.cyan);
zv.setdefaultcolor(color.cyan);


# Do we have valid values for peaks/valleys and
# are they  increasing peaks and decreasing valleys
def areLast2PeaksIncreasing =  !IsNaN(lastPeakValue) and !IsNaN(prevPeakValue) and lastPeakValue > prevPeakValue;
def areLast2ValleysDecreasing = !IsNaN(lastValleyValue) and !IsNaN(prevValleyValue) and lastValleyValue < prevValleyValue;

# Do we have interlaced peaks/valleys
def peaksValleysInterlaced = (prevValleyBarNumber > prevPeakBarNumber and prevValleyBarNumber < lastPeakBarNumber)
   or (prevPeakBarNumber > prevValleyBarNumber and prevPeakBarNumber < lastValleyBarNumber);

def inBroadeningPattern = areLast2PeaksIncreasing and areLast2ValleysDecreasing and peaksValleysInterlaced;

# if we have a broadening pattern, get last 2 values and draw a line with extension


# get scaling factor for high side, low side
# initial line is drawn using last 2 peaks/valleys
# However, after those 2 points, we need to use scaling factors to extend the line y=mx+c
# Thank you to my middle school math teachers in India :)
# Expect valleyScalePerBar to be negative number

def peakScalePerBar = (lastPeakValue - prevPeakValue) / (lastPeakBarNumber - prevPeakBarNumber );
def valleyScalePerBar = (lastValleyValue - prevValleyValue) / (lastValleyBarNumber - prevValleyBarNumber );

def peakExtendedValue = lastPeakValue + (bn - lastPeakBarNumber) * peakScalePerBar;
def valleyExtendedValue = lastValleyValue + (bn - lastValleyBarNumber) * valleyScalePerBar;

#Draw UpperLine, initial with 2 points, then extend with scaling factor
plot upperLine = if isnan(close) then na
   else if inBroadeningPattern and bn > lastPeakBarNumber then peakExtendedValue
   else if inBroadeningPattern and peak and bn >= prevPeakBarNumber then high
   else Double.NaN;
upperLine.EnableApproximation();
upperLine.SetDefaultColor(Color.LIME);
upperLine.SetLineWeight(2);

plot lowerLine = if isnan(close) then na
   else if inBroadeningPattern and bn > lastValleyBarNumber then valleyExtendedValue
   else if inBroadeningPattern and valley and bn >= prevValleyBarNumber then low
   else Double.NaN;
lowerLine.EnableApproximation();
lowerLine.SetDefaultColor(Color.PLUM);
lowerLine.SetLineWeight(2);

# create a line in middle, between 2 lines

def midline = if isnan(close) then na
 else if (!isnan(upperLine) and !isnan(lowerLine)) then (upperLine + lowerLine)/2
 else na;

plot z3 = midline;
z3.SetDefaultColor(Color.light_gray);



addchartbubble(0, low,
upperline + " up\n"+
lowerline + " lo"
, color.yellow, no);


# alert when crosses over/above line?
#get highestPrice after last peak

#def highValueAfterLastPeak = Highest(high[-(bn-lastPeakBarNumber)], RightBarsThreshold);

# scantype=1; for price cross above upper line
#def scantype_1 = inBroadeningPattern and high >

# scantype=2; for price cross below lower line
# scantype=3; for price is below lower line
def scantype_3 = inBroadeningPattern and high > peakExtendedValue;
# scantype=4; for price is above upper line
def scantype_4 = inBroadeningPattern and low < valleyExtendedValue;
# scantype=5; for price is inside two lines.
def scantype_5 = inBroadeningPattern and high < peakExtendedValue
                                     and low  > valleyExtendedValue;


# getDisplayValue for alerts/scans
AddLabel(scantype_3, "Above BF", Color.CYAN);
AddLabel(scantype_4, "Below BF", Color.CYAN);
AddLabel(scantype_5, "Between BF", Color.CYAN);

AddLabel(debug, "BarNumber:" + bn, Color.WHITE);
AddLabel(debug, "lastpeakbar:" + lastPeakBarNumber, Color.WHITE);
AddLabel(debug, "prevPeakGetValue:" + prevPeakBarNumber, Color.WHITE);
AddLabel(debug, "lastpeakvalue:" + lastPeakValue, Color.WHITE);
AddLabel(debug, "previouspeakvalue:" + prevPeakValue, Color.WHITE);

AddLabel(debug, "lastvalleybar:" + lastValleyBarNumber, Color.YELLOW);
AddLabel(debug, "prevValleyGetValue:" + prevValleyBarNumber, Color.YELLOW);
AddLabel(debug, "lastvalleyvalue:" + lastValleyValue, Color.YELLOW);
AddLabel(debug, "previousvalleyvalue:" + prevValleyValue, Color.YELLOW);

AddLabel(debug, "IncPeaks?:" + areLast2PeaksIncreasing, Color.WHITE);
AddLabel(debug, "DecPeaks?:" + areLast2ValleysDecreasing, Color.WHITE);
AddLabel(debug, "ValuesInterlaced?:" + peaksValleysInterlaced, Color.WHITE);
AddLabel(inBroadeningPattern, "BroadPattern?:" + inBroadeningPattern, if inBroadeningPattern then Color.LIGHT_GREEN else Color.LIGHT_RED);

AddLabel(debug, "peakSideScaleFactor:" + peakScalePerBar, Color.YELLOW);
AddLabel(debug, "valleySideScaleFactor:" + valleyScalePerBar, Color.YELLOW);

AddLabel(debug, "peakExtendedValue:" + peakExtendedValue, Color.YELLOW);
AddLabel(debug, "valleyExtendedValue:" + valleyExtendedValue, Color.YELLOW);
###End Code

#
 

Attachments

  • img1-amd.JPG
    img1-amd.JPG
    32.9 KB · Views: 183
to use this for scanning,
try changing all the plots to def , disable all the addlabels.

this already exists , inBroadeningPattern . so set it = to a plot variable
plot z = inBroadeningPattern;


a lower study that should work as a scan

Code:
#Broadening_Pattern_lines_00b_lower

#Broadening Pattern lines
#Broadening Formation Pattern for ThinkorSwim
#https://usethinkscript.com/threads/broadening-formation-pattern-for-thinkorswim.2732/page-2#posts

# true if a broadening wedge on last bars

declare lower;

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

# Inputs
input LeftBarsThreshold = 5;
input RightBarsThreshold = 5;
#input isAlertSetup = no;
input debug = no;

# Calculate values for peaks
def peak = high > Highest(high[1], LeftBarsThreshold) and high >= Highest(high[-RightBarsThreshold], RightBarsThreshold);
#plot peakBoolean = peak;

def peakValue = if peak then high else peakValue[1];
def peakBar = if peak then BarNumber() else Double.NaN;

# Calculate barNumbers for previous 2 peaks
def lastPeakBarNumber = HighestAll(if peak then bn else 0);
def prevPeakBarNumber = HighestAll(if peak and bn < lastPeakBarNumber then bn else 0);

# Get values for previous 2 peaks
def lastPeakValue = GetValue(high, bn - HighestAll(peakBar));
def prevPeakValue = GetValue(peakValue[1], bn - HighestAll(peakBar));

#  Calculate values for valleys/low points
def valley = low < Lowest(low[1], LeftBarsThreshold) and low <= Lowest(low[-RightBarsThreshold], RightBarsThreshold);
#plot valleyBoolean = valley;

def valleyValue = if valley then low else valleyValue[1];
def valleyBar = if valley then BarNumber() else Double.NaN;

# Get barNumbers for previous 2 valleys
def lastValleyBarNumber = HighestAll(if valley then bn else 0);
def prevValleyBarNumber = HighestAll(if valley and bn < lastValleyBarNumber then bn else 0);

# Get values for previous 2 valleys
def lastValleyValue = GetValue(low, bn - HighestAll(valleyBar));
def prevValleyValue = GetValue(valleyValue[1], bn - HighestAll(valleyBar));


# Do we have valid values for peaks/valleys and
# are they  increasing peaks and decreasing valleys
def areLast2PeaksIncreasing =  !IsNaN(lastPeakValue) and !IsNaN(prevPeakValue) and lastPeakValue > prevPeakValue;
def areLast2ValleysDecreasing = !IsNaN(lastValleyValue) and !IsNaN(prevValleyValue) and lastValleyValue < prevValleyValue;

# Do we have interlaced peaks/valleys
def peaksValleysInterlaced = (prevValleyBarNumber > prevPeakBarNumber and prevValleyBarNumber < lastPeakBarNumber)
   or (prevPeakBarNumber > prevValleyBarNumber and prevPeakBarNumber < lastValleyBarNumber);

def inBroadeningPattern = areLast2PeaksIncreasing and areLast2ValleysDecreasing and peaksValleysInterlaced;


def peakScalePerBar = (lastPeakValue - prevPeakValue) / (lastPeakBarNumber - prevPeakBarNumber );
def valleyScalePerBar = (lastValleyValue - prevValleyValue) / (lastValleyBarNumber - prevValleyBarNumber );

def peakExtendedValue = lastPeakValue + (bn - lastPeakBarNumber) * peakScalePerBar;
def valleyExtendedValue = lastValleyValue + (bn - lastValleyBarNumber) * valleyScalePerBar;

#Draw UpperLine, initial with 2 points, then extend with scaling factor
def upperLine = if isnan(close) then na
   else if inBroadeningPattern and bn > lastPeakBarNumber then peakExtendedValue
   else if inBroadeningPattern and peak and bn >= prevPeakBarNumber then high
   else Double.NaN;
#upperLine.EnableApproximation();
#upperLine.SetDefaultColor(Color.LIME);
#upperLine.SetLineWeight(2);

def lowerLine = if isnan(close) then na
   else if inBroadeningPattern and bn > lastValleyBarNumber then valleyExtendedValue
   else if inBroadeningPattern and valley and bn >= prevValleyBarNumber then low
   else Double.NaN;
#lowerLine.EnableApproximation();
#lowerLine.SetDefaultColor(Color.PLUM);
#lowerLine.SetLineWeight(2);

def scan_above = inBroadeningPattern and high > peakExtendedValue;
def scan_below = inBroadeningPattern and low < valleyExtendedValue;
def scan_between = inBroadeningPattern and high < peakExtendedValue and low  > valleyExtendedValue;

plot z = inBroadeningPattern;
#


----------------------

here is an updated upper study.
i removed the boolean plots.
add wedges on peaks and valleys.
add a mid line in middle of wedge.

test on AMD day chart

Code:
#Broadening_Pattern_lines_00

#Broadening Pattern lines
#Broadening Formation Pattern for ThinkorSwim
#MrDrB  Jun 7, 2020  #1
#Hello All, I've spent several nights trying to re-create this without any success: #http://www.patternsmart.com/cart/index.php?route=product/product&product_id=430&search=broadening

#Perhaps I'm missing something obvious. I've tried applying techniques from mobius' scalper alerts and tried re-tooling the built-in zig-zag code. Any offers to help would be appreciated. I would've just paid for it if the site looked legit and at least had an SSL cert. If anyone knows if this is available for purchase from a reputable site, I would happy to know that as well. Thanks!

#BTW, I've also went over this forum post multiple times
#(https://usethinkscript.com/threads/second-highest-lowest-high-low-in-same-range.2064/) as it is trying to do something fundamentally similar: find the two highest highs and two lowest lows in a range of bars.



#post5
#RajB
#Oct 20, 2020
#@MrDrB I am new to thinkscript ( few weeks of experience but programmer by trade). I am also new to this forum. I made an initial attempt at this. Are you still interested in working on this? I can send the script over. I would appreciate someone else looking over and verifying my logic. I am not done with the alerts part. I am not familiar with the best practices on think scripts.



#post7
#answer , but good ??
#RajB
#oct 21, 2020  #7
#@MrDrB
#Nice, looking forward to working together
#I think that scenario you are referring to is done. I took the approach of listing valleys/peaks and then using the last 2 valleys/peaks if present
#Alerts are partially coded and I may get to it this weekend, they are partially coded and can't be relied on
#toggle the debug flag input value for params etc. will give you my step by step decision-making process


#Broadening Pattern
#Multiple Sources
# Fun with thinkscript: https://researchtrade.com/forum/read.php?7,2258,page=31
# UseThinkScript: https://usethinkscript.com/threads/create-column-based-on-peak-and-valley-indicator.901/
# https://funwiththinkscript.com/count-the-number-of-bars-between-successive-highs/
# Idea source: https://www.patternsmart.com/cart/index.php?route=product/product&product_id=430&search=broadening

# 20201019 Raj B, initial code upto calculating peaks/valleys, getting barNumbers , checking if broadening pattern conditions exist
# 20201020 Raj B. Added ability for separate left/right threshold to allow independent values
# 20201020 Raj B. Added initial column/watchlist alerts, needs testing
# TODO complete alert part
# 20210803 Raj B. Cay7man identified a bug, removed logic that depends on isAlertSetup yes/no https://usethinkscript.com/threads/broadening-formation-pattern-for-thinkorswim.2732/post-71684  re

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

# Inputs
input LeftBarsThreshold = 5;
input RightBarsThreshold = 5;
#input isAlertSetup = no;
input debug = no;

# Calculate values for peaks
def peak = high > Highest(high[1], LeftBarsThreshold) and high >= Highest(high[-RightBarsThreshold], RightBarsThreshold);
#plot peakBoolean = peak;

def peakValue = if peak then high else peakValue[1];
def peakBar = if peak then BarNumber() else Double.NaN;

# Calculate barNumbers for previous 2 peaks
def lastPeakBarNumber = HighestAll(if peak then bn else 0);
def prevPeakBarNumber = HighestAll(if peak and bn < lastPeakBarNumber then bn else 0);

# Get values for previous 2 peaks
def lastPeakValue = GetValue(high, bn - HighestAll(peakBar));
def prevPeakValue = GetValue(peakValue[1], bn - HighestAll(peakBar));

#  Calculate values for valleys/low points
def valley = low < Lowest(low[1], LeftBarsThreshold) and low <= Lowest(low[-RightBarsThreshold], RightBarsThreshold);
#plot valleyBoolean = valley;

def valleyValue = if valley then low else valleyValue[1];
def valleyBar = if valley then BarNumber() else Double.NaN;

# Get barNumbers for previous 2 valleys
def lastValleyBarNumber = HighestAll(if valley then bn else 0);
def prevValleyBarNumber = HighestAll(if valley and bn < lastValleyBarNumber then bn else 0);

# Get values for previous 2 valleys
def lastValleyValue = GetValue(low, bn - HighestAll(valleyBar));
def prevValleyValue = GetValue(valleyValue[1], bn - HighestAll(valleyBar));


#plot zp = if peak then high else na;
#plot zv = if valley then low else na;
plot zp = peak;
plot zv = valley;
zp.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_up);
zv.SetPaintingStrategy(PaintingStrategy.BOOLEAN_WEDGE_DOWN);
zp.setdefaultcolor(color.cyan);
zv.setdefaultcolor(color.cyan);


# Do we have valid values for peaks/valleys and
# are they  increasing peaks and decreasing valleys
def areLast2PeaksIncreasing =  !IsNaN(lastPeakValue) and !IsNaN(prevPeakValue) and lastPeakValue > prevPeakValue;
def areLast2ValleysDecreasing = !IsNaN(lastValleyValue) and !IsNaN(prevValleyValue) and lastValleyValue < prevValleyValue;

# Do we have interlaced peaks/valleys
def peaksValleysInterlaced = (prevValleyBarNumber > prevPeakBarNumber and prevValleyBarNumber < lastPeakBarNumber)
   or (prevPeakBarNumber > prevValleyBarNumber and prevPeakBarNumber < lastValleyBarNumber);

def inBroadeningPattern = areLast2PeaksIncreasing and areLast2ValleysDecreasing and peaksValleysInterlaced;

# if we have a broadening pattern, get last 2 values and draw a line with extension


# get scaling factor for high side, low side
# initial line is drawn using last 2 peaks/valleys
# However, after those 2 points, we need to use scaling factors to extend the line y=mx+c
# Thank you to my middle school math teachers in India :)
# Expect valleyScalePerBar to be negative number

def peakScalePerBar = (lastPeakValue - prevPeakValue) / (lastPeakBarNumber - prevPeakBarNumber );
def valleyScalePerBar = (lastValleyValue - prevValleyValue) / (lastValleyBarNumber - prevValleyBarNumber );

def peakExtendedValue = lastPeakValue + (bn - lastPeakBarNumber) * peakScalePerBar;
def valleyExtendedValue = lastValleyValue + (bn - lastValleyBarNumber) * valleyScalePerBar;

#Draw UpperLine, initial with 2 points, then extend with scaling factor
plot upperLine = if isnan(close) then na
   else if inBroadeningPattern and bn > lastPeakBarNumber then peakExtendedValue
   else if inBroadeningPattern and peak and bn >= prevPeakBarNumber then high
   else Double.NaN;
upperLine.EnableApproximation();
upperLine.SetDefaultColor(Color.LIME);
upperLine.SetLineWeight(2);

plot lowerLine = if isnan(close) then na
   else if inBroadeningPattern and bn > lastValleyBarNumber then valleyExtendedValue
   else if inBroadeningPattern and valley and bn >= prevValleyBarNumber then low
   else Double.NaN;
lowerLine.EnableApproximation();
lowerLine.SetDefaultColor(Color.PLUM);
lowerLine.SetLineWeight(2);

# create a line in middle, between 2 lines

def midline = if isnan(close) then na
 else if (!isnan(upperLine) and !isnan(lowerLine)) then (upperLine + lowerLine)/2
 else na;

plot z3 = midline;
z3.SetDefaultColor(Color.light_gray);



addchartbubble(0, low,
upperline + " up\n"+
lowerline + " lo"
, color.yellow, no);


# alert when crosses over/above line?
#get highestPrice after last peak

#def highValueAfterLastPeak = Highest(high[-(bn-lastPeakBarNumber)], RightBarsThreshold);

# scantype=1; for price cross above upper line
#def scantype_1 = inBroadeningPattern and high >

# scantype=2; for price cross below lower line
# scantype=3; for price is below lower line
def scantype_3 = inBroadeningPattern and high > peakExtendedValue;
# scantype=4; for price is above upper line
def scantype_4 = inBroadeningPattern and low < valleyExtendedValue;
# scantype=5; for price is inside two lines.
def scantype_5 = inBroadeningPattern and high < peakExtendedValue
                                     and low  > valleyExtendedValue;


# getDisplayValue for alerts/scans
AddLabel(scantype_3, "Above BF", Color.CYAN);
AddLabel(scantype_4, "Below BF", Color.CYAN);
AddLabel(scantype_5, "Between BF", Color.CYAN);

AddLabel(debug, "BarNumber:" + bn, Color.WHITE);
AddLabel(debug, "lastpeakbar:" + lastPeakBarNumber, Color.WHITE);
AddLabel(debug, "prevPeakGetValue:" + prevPeakBarNumber, Color.WHITE);
AddLabel(debug, "lastpeakvalue:" + lastPeakValue, Color.WHITE);
AddLabel(debug, "previouspeakvalue:" + prevPeakValue, Color.WHITE);

AddLabel(debug, "lastvalleybar:" + lastValleyBarNumber, Color.YELLOW);
AddLabel(debug, "prevValleyGetValue:" + prevValleyBarNumber, Color.YELLOW);
AddLabel(debug, "lastvalleyvalue:" + lastValleyValue, Color.YELLOW);
AddLabel(debug, "previousvalleyvalue:" + prevValleyValue, Color.YELLOW);

AddLabel(debug, "IncPeaks?:" + areLast2PeaksIncreasing, Color.WHITE);
AddLabel(debug, "DecPeaks?:" + areLast2ValleysDecreasing, Color.WHITE);
AddLabel(debug, "ValuesInterlaced?:" + peaksValleysInterlaced, Color.WHITE);
AddLabel(inBroadeningPattern, "BroadPattern?:" + inBroadeningPattern, if inBroadeningPattern then Color.LIGHT_GREEN else Color.LIGHT_RED);

AddLabel(debug, "peakSideScaleFactor:" + peakScalePerBar, Color.YELLOW);
AddLabel(debug, "valleySideScaleFactor:" + valleyScalePerBar, Color.YELLOW);

AddLabel(debug, "peakExtendedValue:" + peakExtendedValue, Color.YELLOW);
AddLabel(debug, "valleyExtendedValue:" + valleyExtendedValue, Color.YELLOW);
###End Code

#

@halcyonguy Is there any way to adjust the script so as to look at the broadening pattern on different time frames? As of now if I set the scan to Monthly, when I look at Weekly, Daily and Hourly the broadening pattern does not show up. It only shows up on the original scan of the Monthly. Thank you appreciate it.






Also thanks for including the thread address bar info at the top of the script!!
 
Last edited:

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
205 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