Broadening Formation Pattern for ThinkorSwim


New member
Hello All, I've spent several nights trying to re-create this without any success:

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 ( 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:


20:17 Vimes: Was browsing some old public thinkscript forums and came across a very old snippet from Robert Payne that looked interesting, I modified it to plot peak to peak and valley to valley moves together. Likely not practical yet for trading but perhaps an interesting snippet (at least for me:))

#Snippet only
#idea taken from a public robert payne snippet on valley lines
#extended to plot valley to valley and peak to peak lines together
#and made lookback adjustable
#perhaps useful for broadening formation or other potential extensions of price action
input len = 3;
input showBubble = no;

#valley section
def Valley = low < Lowest(low[1], len) and low < Lowest(low[-len], len);
plot ArrowUP = Valley;
plot line_v = if ArrowUP then low else Double.NaN;
def run_v = if Valley then 1 else run_v[1] + 1;
def rise_v = if Valley then low - GetValue(low, run_v[1]) else Double.NaN;
def slope_v = rise_v / run_v[1];
AddChartBubble(showBubble and Valley, low, slope_v, if slope_v > 0 then Color.LIGHT_GREEN else Color.PINK);

def slopeV = if Valley then slope_v else slopeV[1];
def lineV = if Valley then low else lineV[1] + slopeV;
plot LineExtension_V = lineV;

#peak section
def Peak = high > highest(high[1], len) and high > highest(high[-len], len);
plot ArrowDN = Peak;

plot line_p = if ArrowDN then high else Double.NaN;
def run_p = if Peak then 1 else run_p[1] + 1;
def rise_p = if Peak then high - GetValue(high, run_p[1]) else Double.NaN;
def slope_p = rise_p / run_p[1];
AddChartBubble(showBubble and Peak, high, slope_p, if slope_p > 0 then Color.LIGHT_GREEN else Color.PINK);
def slopeX_p = if Peak then slope_p else slopeX_p[1];
def lineX_p = if Peak then high else lineX_p[1] + slopeX_p;
plot LineExtension_p = lineX_p;

If I share a chart, will you guys look at it? I use triangles/broadening formations to find support and resistance and inside/outside bars to look for signals. Todays 3 min chart on the /ES will show you how using just that would have had you nailing all the big moves today.


@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.

Last edited:


New member
@RajB sure, i also have something similar completed but without logic that deals with some scenarios like when a prior lower-hi/higher-low can't be found, etc. If you've dealt with some of those cases, let me know, would love to work together!


  • 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:,2258,page=31
# UseThinkScript:
# Idea source:

# 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  re

# Inputs

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

# Setup
def bn = BarNumber();

# 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)
                              (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 inBroadeningPattern and bn > lastPeakBarNumber
                 then peakExtendedValue
                 else if inBroadeningPattern and peak and bn >= prevPeakBarNumber
                 then high
                 else Double.NaN;

plot lowerLine = if inBroadeningPattern and bn > lastValleyBarNumber
                 then valleyExtendedValue
                 else if inBroadeningPattern and valley and bn >= prevValleyBarNumber
                 then low
                 else Double.NaN;


# 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
Last edited:


New member
@RajB looks good so far. i'll take a fuller look tonight. it looks like we've gotten about as far as each other on this except i never intended on coding alerts. we can continue iterating from your code...any specific issues/features that i can help look into?


@MrDrB Sounds good.
  • If you can sanity check my logic that would be great.
  • also, any do's/don't on TS coding would be appreciated, I am still relatively new to this space
  • I had performed limited testing and things seem to work. Did you have any edge/test cases that you have used before?
  • wanted to share this with the rest of the community as part of the effort
Last edited:


New member
Hi there. This is my first post. I'd love to use this script. Is there a finished version? The last one above gives me an error that I do not understand how to fix "AddLabel is not allowed in this context". Any help is greatly appreciated.


Staff member


New member
@JG123 Nope, I am not getting any errors. You may not have copy & pasted correctly? I actually got the same error on a different indicator. Turned out, when I copied and pasted, I left off the ; at the very end. The last line in your study label might be missing a ;

Maybe you aren't using the script from post#7?
Thanks for replying. Yes, I did copy #7, tried putting it in directly, then tried to drop it in notepad to remove any web formatting, and double checked for the ; at the end. Same error. "AddLabel is not allowed in this context". That's all it says, nothing to point further. Any ideas are welcomed. Thanks!


Well-known member
@JG123 There is no "web formatting" in the code block from Post #7 and that is the reason we stress posting within code tags using the </> icon in the formatting toolbar or manually using code tags... I just Copied and Pasted that code and it works flawlessly...

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.