Second Highest/Lowest High/Low in same range



New member
Hi All,

Trying to extract the high and low price for the 2nd highest volume bar. Finding it for the highest is easy enough. i'm using a fold statement to iterate thought the range comparing the volume bars to each other. If there is a better way i'm all ears. Appreciate the help.

declare lower;
input length = 100;

# highest volume bar used to help compare for 2nd highest volume bar
def vol = highest(volume, length);

#2nd highest volume bar need to extract the high and low values. 
def vol2 = fold i = 0 to length with v do if volume[ i ] < vol and volume[ i ] > v then volume[ i ]  else v;

# get the high and low values for the highest volume bar. 
def highPriceVolhigh = GetValue(high, GetMaxValueOffset(volume, length), length);
def lowPriceVolhigh = GetValue(low, GetMaxValueOffset(volume, length), length);

Last edited by a moderator:


New member
I've searched around the forum and found code that leverages highestall and barnumber to get the highest/lowest values. My ask is bit more complex i'm tying to find the 2nd and 3rd highest volume values x bar before and after the swing high of the volume bar.

I leveraged the swing high swing low code to get the bar number and volume of the first highest volume but now I'll looking from that point to look to find the 2nd highest swing high in that same range. I'm assuming the using the barNumber of the highest volume is the key but i'm not sure how you pass that to HighestAll but not sure how you make a range of it. Any help would be appreciated. Link to image below showing the highest and second highest volume with the price highs and lows for a 5 period lookback and lookforward swing high.

### taken for Robert Paynes swing high low code.
input length = 10;
def bn = BarNumber();
def lastBar = HighestAll(if IsNaN(close) then 0 else bn);
def offset = Min(length - 1, lastBar - bn);

# i get this defines the swing high looking back 10 and foward  10 periods  changed it for volume
def swingHigh = volume > Highest(volume[1], length - 1) and high == GetValue(Highest(volume, length), -offset);
# identify the very last swing high point
def highPointOneBarNumber = HighestAll(if swingHigh then bn else 0);
Last edited by a moderator:


New member
So i gave it a shot and was able to get the next highest value prior to the swing high but not the highest value after the swing high. Instead I get some weird number I think it has to do with the -offset calculation but can't seem to figure why it give a weird number for vol2 plot. Any help would be greatly appreciated.

input length = 10;

def bn = BarNumber();
def lastBar = HighestAll(if IsNaN(close) then 0 else bn);
def offset = Min(length - 1, lastBar - bn);
def swingHigh = volume > Highest(volume[1], length - 1) and volume == GetValue(Highest(volume, length), -offset);
def volHighBefore = volume > Highest(volume[1], length - 1);
def volHighAfter = volume == GetValue(Highest(volume, length), -offset);

# identify the very last swing high point
def volHighBarNum = HighestAll(if swingHigh then bn else 0);
def volHighValue = if bn == volHighBarNum then high else volHighValue[1];
plot volHighPrior = if bn < volHighBarNum then Double.NaN else volHighValue;

# identify the  highest volume for the last X periods before the last swing high point
def volHighBeforeBarNum = HighestAll(if volHighBefore and bn < volHighBarNum then bn else 0);
def volHighBeforeValue = if bn ==  volHighBeforeBarNum then high else volHighBeforeValue[1];
plot vol1 = if bn < volHighBeforeBarNum then Double.NaN else volHighBeforeValue;

# identify the  highest volume for the last X periods after the last swing high point
def volHighAfterBarNum = HighestAll(if volHighAfter and bn > volHighBarNum then bn else 0);
def volHighAfterValue = if bn ==  volHighAfterBarNum then high else volHighAfterValue[1];
plot vol2 = if bn < volHighAfterBarNum then Double.NaN else volHighAfterValue;


Active member
I feel your pain. I'm trying to write a script to connect a high to the next highest high and a low to the next lowest low, but no dice


New member
Here is my attempt/compiled code for a Broadening Pattern. I am new to thinkscript but not new to programming. Please see if this can help you. Also, I would appreciate it if you can review/test and provide comments. Reminded me of middle school/high school math :)

Rich (BB code):
#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 indepedent values
# 20201020 Raj B. Added initial column/watchlist alerts, needs testing
# TODO complete alert part

# Inputs

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

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

plot lowerLine = if !isAlertSetup and 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(debug, "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);

#AddLabel(debug, "LastPrice:" + last, Color.YELLOW);
Last edited:


New member
Hey @RajB. Thank you so much for the formula. I'm having trouble seeing the yellow and purple lines on my chart. Is there something I need to fix in the settings of the formula or does it only work on certain time frames? Any help would be appreciated. Thanks


New member
The script works on all different timeframes. However, it will ONLY draw the lines when conditions for broadening formation are valid. It needs 2 higher/increasing peaks and two lower decreasing valleys and the highs/lows interlaced.

If you edit the settings for the script and set debug=yes, then it will show you the values for highs/lows and its overall assessment. If you find a bug, do let me know and I will attempt to fix it. What does it say for the value of BroadPattern? 0 or 1?



@RajB this is simply amazing work RajB... very very nice, thanks for sharing.


New member
:) Thank you. If you find any issues, please let me know. It would be great if you like the post with script above and also post 1-2 images of you using it on your stock of choice. I may learn something about trading/watching it.

Similar threads