Library · Pine Script v6 · Library

PriceAction

by alvinng214· code credited to mickes

PriceAction is a Pine Script v6 library designed to calculate and track market structure elements based on customizable pivot lengths.

View on GitHub

Repaints

GitHub stars2on the repository
Pine versionv6current
Lines of code660
Settings0inputs
LicenceNone statedfile: MPL-2.0
Last update2 months ago5 Aug 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new library, select all of the template text and paste. Press Save and give it a name.
  4. 4Publish or import itA library draws nothing. Publish it from the editor, then import its functions in your own scripts.

Source Code

660 lines of Pine Script v6 from Liquidity & Inducements/mickesPriceAction4.txt, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

mickesPriceAction4.txt
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © mickes

//@version=6

// @description Will draw out the market structure for the disired pivot length.
library("PriceAction")

//@type Holds drawings for a structure break.
//@field Line The line object.
//@field Label The label object.
export type StructureBreak
    line Line
    label Label
//@type Holds all the values for a found pivot.
//@field Price The price of the pivot.
//@field BarIndex The bar_index where the pivot occured.
//@field Type The type of the pivot (-1 = low, 1 = high).
//@field Time The time where the pivot occured.
//@field BreakOfStructureBroken Sets to true if a break of structure has happened.
//@field LiquidityBroken Sets to true if a liquidity of the price level has happened.
//@field ChangeOfCharacterBroken Sets to true if a change of character has happened.
export type Pivot
    float Price
    int BarIndex
    int Type // -1 = low, 1 = high
    int Time
    bool BreakOfStructureBroken
    bool LiquidityBroken
    bool ChangeOfCharacterBroken
//@type Enum for the type of market structure.
//@field Intenal represents the internal (orderflow) market structure.
//@field Swing represents the swing market structure.
export enum Type
    Internal = "internal"
    Swing = "swing"
//@type Holds all the values for the market structure.
//@field LeftLength Define the left length of the pivots used.
//@field RightLength Define the right length of the pivots used.
//@field Type Set the type of the market structure. Two types can be used, 'internal' and 'swing' (0 = internal, 1 = swing).
//@field Trend This will be set internally and can be -1 = downtrend, 1 = uptrend.
//@field EqualPivotsFactor Set how the limits are for an equal pivot. This is a factor of the Average True Length (ATR) of length 14. If a low pivot is considered to be equal if it doesn't break the low pivot (is at a lower value) and is inside the previous low pivot + this limit.
//@field ExtendEqualPivotsZones Set to true if you want the equal pivots zones to be extended.
//@field ExtendEqualPivotsStyle Set the style of equal pivot zones.
//@field ExtendEqualPivotsColor Set the color of equal pivot zones.
//@field EqualHighs Holds the boxes for zones that contains equal highs.
//@field EqualLows Holds the boxes for zones that contains equal lows.
//@field BreakOfStructures Holds all the break of structures within the trend (before a change of character).
//@field Pivots All the pivots in the current trend, added with the latest first, this is cleared when the trend changes.
//@field FontSize Holds the size of the font displayed.
//@field AlertChangeOfCharacter Holds true or false if a change of character should be alerted or not.
//@field AlertBreakOfStructure Holds true or false if a break of structure should be alerted or not.
//@field AlerEqualPivots Holds true or false if equal highs/lows should be alerted or not.
export type Structure
    int LeftLength
    int RightLength
    Type Type
    int Trend // -1 = downtrend, 1 = uptrend
    float EqualPivotsFactor
    bool ExtendEqualPivotsZones
    string ExtendEqualPivotsStyle
    color ExtendEqualPivotsColor
    array<box> EqualHighs
    array<box> EqualLows
    array<StructureBreak> BreakOfStructures
    array<Pivot> Pivots // All the pivots in the current trend, added with the latest first, this is cleared when the trend changes
    int FontSize
    bool AlertChangeOfCharacter
    bool AlertBreakOfStructure
    bool AlerEqualPivots
//@type Holds all the values for liquidity.
//@field LiquidityPivotsHigh All high pivots for liquidity.
//@field LiquidityPivotsLow All low pivots for liquidity.
//@field LiquidityConfirmationBars The number of bars to confirm that a liquidity is valid.
//@field LiquidityPivotsLookback A number of pivots to look back for.
//@field FontSize Holds the size of the font displayed.
export type Liquidity
    array<Pivot> LiquidityPivotsHigh
    array<Pivot> LiquidityPivotsLow
    int LiquidityConfirmationBars
    int LiquidityPivotsLookback
    int FontSize
//@type Holds all the values for the general price action and the market structures.
//@field Liqudity Placeholder for all objects used for liquidity.
//@field Swing Placeholder for all objects used for the swing market structure.
//@field Internal Placeholder for all objects used for the internal market structure.
export type PriceAction
    Liquidity Liquidity

    Structure Swing
    Structure Internal
//@type Holds sll the values for the settings for turtle soups.
//@field PivotLeftLenght Define the left length of the pivots used.
//@field PivotRightLenght Define the right length of the pivots used.
//@field Lookback Set how many pivots back that will be used.
//@field Confirmation Set if you want confirmation to be needed for q turtle soup to be formed (e g. a CHoCH).
//@field Color The color of turtle soups.
//@field ScreenerKeep Set the number of bars that the plot 'Turtle soup' will have a value after a turtle soup is found.
//@field AlertFrequency Set the frequency of alerts, possible values are 'alert.freq_all', 'alert.freq_once_per_bar' or 'alert.freq_once_per_bar_close'.
export type TurtleSoupSettings
    int PivotLeftLenght
    int PivotRightLenght
    int Lookback
    bool Confirmation
    color Color
    int ScreenerKeep
    string AlertFrequency
//@type To be used when a turtle soup is found and holds all values needed for it.
//@field Line The line object between the pivot and the turtle soup.
//@field Box The bos for the turtle soup.
//@field Start The first bar of the turtle soup.
//@field End The last bar of the turtle soup.
//@field Pivot The pivot which liquidity was taken by the turtle soup.
export type TurtleSoup
    line Line
    box Box
    int Start
    int End
    Pivot Pivot
//@type Holds all values to be used in the Pine Screener by Tradingview.
//@field TurtleSoupUntilBarIndex Pine Screener value for turtle soups.
export type Screener
    int TurtleSoupUntilBarIndex
//@type TurtleSoups The entire context for all turtle soups.
//@field Highs The high pivots.
//@field Lows The low pivots.
//@field Bullish Bullish turtle soups.
//@field Bearish Bearish turtle soups.
//@field AlertMessages All messages for the current iteration.
export type TurtleSoups
    array<Pivot> Highs
    array<Pivot> Lows
    array<TurtleSoup> Bullish
    array<TurtleSoup> Bearish
    varip array<string> AlertMessages

_atr = ta.atr(14)

method SetBarIndex(Pivot pivot, int barTime) =>
    barIndex = 0
    i = 0
    while true
        timeBack = time[i]
        if timeBack < barTime or na(timeBack) // before creation of pivot
            barIndex := bar_index - (i - 1) // set the creation bar to the first bar inside the pivot
            break
        i += 1
    pivot.BarIndex := barIndex
//@function Sets the 'BarIndex' value of the 'Pivot' object. Useful if the pivot is from an other timeframe.
//@param pivotHigh The 'Pivot' object for the high pivot.
//@param pivotLow The 'Pivot' object for the low pivot.
export SetBarIndices(Pivot pivotHigh, Pivot pivotLow) =>
    if not na(pivotHigh) and na(pivotHigh.BarIndex)
        pivotHigh.SetBarIndex(pivotHigh.Time)
    if not na(pivotLow) and na(pivotLow.BarIndex)
        pivotLow.SetBarIndex(pivotLow.Time)
Alert(string message, string frequency) =>
    switch frequency
        alert.freq_all => alert(message, alert.freq_all)
        alert.freq_once_per_bar => alert(message, alert.freq_once_per_bar)
        alert.freq_once_per_bar_close => alert(message, alert.freq_once_per_bar_close)
TurtleSoupAlert(string message, TurtleSoup turtleSoup, TurtleSoupSettings settings) =>
    direction = switch turtleSoup.Pivot.Type
        -1 => "bullish"
        1 => "bearish"
    fullMessage = str.format("{0} ({1} of {2} bars, {3} bars ago and with a pivot from {4} bars ago (from the turtle soup start))", message, direction, turtleSoup.End - turtleSoup.Start, bar_index - turtleSoup.End, turtleSoup.Start - turtleSoup.Pivot.BarIndex)
    fullMessage
//@function Will fire off an alert if there is one. To be used lastly in the calling script.
//@param turtleSoupsContext The context of all turtle soups.
//@param settings The settings for turtle soups.
export Alert(TurtleSoups turtleSoupsContext, TurtleSoupSettings settings) =>
    if turtleSoupsContext.AlertMessages.size() > 0
        Alert(turtleSoupsContext.AlertMessages.join("\n"), settings.AlertFrequency)
        turtleSoupsContext.AlertMessages.clear()
//@function Will visulize found turtle soups and add alert messages for it.
//@param pivots All current pivots (high or low).
//@param turtleSoups All bullish or bearish turtle soups.
//@param turtleSoupsContext The context of all turtle soups.
//@param settings The settings for turtle soups.
export VisualizeTurtleSoups(array<Pivot> pivots, array<TurtleSoup> turtleSoups, TurtleSoups turtleSoupsContext, TurtleSoupSettings settings) =>
    reversedPivots = pivots.copy()
    reversedPivots.reverse()
    for pivot in reversedPivots
        if not pivot.LiquidityBroken
            confirmed = switch pivot.Type
                -1 => low > pivot.Price and low[1] <= pivot.Price // turtle soup confimed
                1 => high < pivot.Price and high[1] >= pivot.Price // turtle soup confimed
            if confirmed
                i = 2
                deepest = switch pivot.Type
                    -1 => low[1]
                    1 => high[1]
                while true
                    price = switch pivot.Type
                        -1 => low[i]
                        1 => high[i]
                    swept = switch pivot.Type
                        -1 => price <= pivot.Price
                        1 => price >= pivot.Price
                    if swept
                        i += 1
                        newDeepest = switch pivot.Type
                            -1 => price < deepest
                            1 => price > deepest
                        if newDeepest
                            deepest := price
                    else
                        break // before liquidity sweep
                if i == 2
                    continue // no turtle soup, regular liquidity sweep
                pivot.LiquidityBroken := true
                start = bar_index - i
                end = bar_index - 1
                boxColor = if settings.Confirmation
                    na
                else
                    settings.Color
                lineColor = if settings.Confirmation
                    na
                else
                    color.new(settings.Color, 0)
                turtleSoup = TurtleSoup.new(
                  line.new(pivot.Time, pivot.Price, time[1], pivot.Price, xloc = xloc.bar_time, color = lineColor, style = line.style_dotted),
                  box.new(bar_index - i, pivot.Price, bar_index - 1, deepest, border_width = 0, bgcolor = boxColor, text = "🐢", text_color = boxColor),//color.new(color.white, 50)),
                  start,
                  end,
                  pivot)
                removeTurtleSoupIndices = array.new<int>()
                for [j, previousTurtleSoup] in turtleSoups
                    if previousTurtleSoup.Start >= turtleSoup.Start and previousTurtleSoup.End <= turtleSoup.End
                        removeTurtleSoupIndices.unshift(j)
                for removeTurtleSoupIndex in removeTurtleSoupIndices
                    removeTurtleSoup = turtleSoups.get(removeTurtleSoupIndex)
                    removeTurtleSoup.Box.set_text("")//.delete()
                    if turtleSoup.Start > removeTurtleSoup.Start
                        removeTurtleSoup.Line.set_x2(turtleSoup.Start)

                if turtleSoups.size() >= 5
                    turtleSoups.pop()
                turtleSoups.unshift(turtleSoup)

                if not settings.Confirmation
                    turtleSoupsContext.AlertMessages.unshift(TurtleSoupAlert("Turtle soup (NOT confirmed)", turtleSoup, settings))
//@function Will get available pivots. Can be called from another timeframe.
//@param settings The settings for turtle soups.
//@returns A tuple of high and then low pivots.
export GetPivots(TurtleSoupSettings settings) =>
    Pivot pivotHigh = na
    Pivot pivotLow = na
    pivotHighPrice = ta.pivothigh(settings.PivotLeftLenght, settings.PivotRightLenght)
    pivotLowPrice = ta.pivotlow(settings.PivotLeftLenght, settings.PivotRightLenght)
    if not na(pivotHighPrice)
        pivotHigh := Pivot.new(pivotHighPrice, Type = 1, Time = time[settings.PivotRightLenght])
    if not na(pivotLowPrice)
        pivotLow := Pivot.new(pivotLowPrice, Type = -1, Time = time[settings.PivotRightLenght])
    [pivotHigh, pivotLow]
//@function Will set the new pivots in turtleSoupsContext.
//@param turtleSoupsContext The context of all turtle soups.
//@param settings The settings for turtle soups.
//@param pivotHigh The 'Pivot' object for the high pivot.
//@param pivotLow The 'Pivot' object for the low pivot.
export SetPivots(TurtleSoups turtleSoupsContext, TurtleSoupSettings settings, Pivot pivotHigh, Pivot pivotLow) =>
    if not na(pivotHigh)
        if turtleSoupsContext.Highs.size() >= settings.Lookback
            turtleSoupsContext.Highs.pop()
        turtleSoupsContext.Highs.unshift(pivotHigh)
    if not na(pivotLow)
        if turtleSoupsContext.Lows.size() >= settings.Lookback
            turtleSoupsContext.Lows.pop()
        turtleSoupsContext.Lows.unshift(pivotLow)
//@function Will visualize turtle soups. To be called if 'TurtleSoupSettings.Confirmation' is true.
//@param turtleSoups All bullish or bearish turtle soups.
//@param turtleSoupsContext The context of all turtle soups.
//@param settings The settings for turtle soups.
//@param previousStructureBreakBarIndex The bar index of the previous structure break (BOS/CHoCH/CHoCH+).
//@param screener The 'Screener' object to be used for Pine Screening by Tradingview. The function will set 'TurtleSoupUntilBarIndex' if there's a confirmed turtle soup.
export Confirm(array<TurtleSoup> turtleSoups, TurtleSoups turtleSoupsContext, TurtleSoupSettings settings, int previousStructureBreakBarIndex, Screener screener) =>
    for turtleSoup in turtleSoups
        if turtleSoup.End > previousStructureBreakBarIndex
            turtleSoup.Line.set_color(color.new(settings.Color, 0))
            turtleSoup.Box.set_bgcolor(settings.Color)
            turtleSoup.Box.set_text_color(settings.Color)
            turtleSoupsContext.AlertMessages.unshift(TurtleSoupAlert("Turtle soup (confirmed)", turtleSoup, settings))
            screener.TurtleSoupUntilBarIndex := bar_index + settings.ScreenerKeep


Liquidation(Liquidity liquidity, Pivot pivot) =>
    switch pivot.Type
        -1 =>
            if low[liquidity.LiquidityConfirmationBars] <= pivot.Price and close[liquidity.LiquidityConfirmationBars] >= pivot.Price
                if liquidity.LiquidityConfirmationBars > 0
                    confirmed = true
                    for i = liquidity.LiquidityConfirmationBars - 1 to 0
                        if close[i] < pivot.Price
                            confirmed := false
                            break
                    confirmed
                else
                    true
        1 =>
            if high[liquidity.LiquidityConfirmationBars] >= pivot.Price and close[liquidity.LiquidityConfirmationBars] <= pivot.Price
                if liquidity.LiquidityConfirmationBars > 0
                    confirmed = true
                    for i = liquidity.LiquidityConfirmationBars - 1 to 0
                        if close[i] > pivot.Price
                            confirmed := false
                            break
                    confirmed
                else
                    true
method VisualizeLiquidations(array<Pivot> pivots, Liquidity liquidity) =>
    for pivot in pivots
        if bar_index < pivot.BarIndex + liquidity.LiquidityConfirmationBars + 1
            continue // only continue if the pivot was at a bar after prIce can take tHe liquidity
        if not pivot.LiquidityBroken
            if Liquidation(liquidity, pivot)
                limitLine = line.new(pivot.BarIndex, pivot.Price, bar_index - liquidity.LiquidityConfirmationBars, pivot.Price, color = color.orange, style = line.style_dotted)
                breakLine = switch pivot.Type
                    -1 => line.new(pivot.BarIndex, low[liquidity.LiquidityConfirmationBars], bar_index - liquidity.LiquidityConfirmationBars, low[liquidity.LiquidityConfirmationBars], color = na)
                    1 => line.new(pivot.BarIndex, high[liquidity.LiquidityConfirmationBars], bar_index - liquidity.LiquidityConfirmationBars, high[liquidity.LiquidityConfirmationBars], color = na)
                linefill.new(limitLine, breakLine, color.new(color.orange, 80))
                switch pivot.Type
                    -1 => label.new(bar_index - liquidity.LiquidityConfirmationBars - ((bar_index - liquidity.LiquidityConfirmationBars - pivot.BarIndex) / 2), pivot.Price, "$$$", size = liquidity.FontSize, color = color(na), textcolor = color.new(color.orange, 30), style = label.style_label_up)
                    1 => label.new(bar_index - liquidity.LiquidityConfirmationBars - ((bar_index - liquidity.LiquidityConfirmationBars - pivot.BarIndex) / 2), pivot.Price, "$$$", size = liquidity.FontSize, color = color(na), textcolor = color.new(color.orange, 30))
                pivot.LiquidityBroken := true
            else
                switch pivot.Type
                    -1 =>
                        if close < pivot.Price // invalid liquidation
                            pivot.LiquidityBroken := true
                    1 =>
                        if close > pivot.Price // invalid liquidation
                            pivot.LiquidityBroken := true
// @function Will draw liquidity.
// @param liquidity The 'PriceAction.Liquidity' object.
export Liqudity(Liquidity liquidity) =>
    if barstate.isconfirmed // only if the bar is closed
        liquidity.LiquidityPivotsHigh.VisualizeLiquidations(liquidity)
        liquidity.LiquidityPivotsLow.VisualizeLiquidations(liquidity)
    pivotHigh = ta.pivothigh(1, 1)
    pivotLow = ta.pivotlow(1, 1)
    if not na(pivotHigh)
        if liquidity.LiquidityPivotsHigh.size() >= liquidity.LiquidityPivotsLookback
            liquidity.LiquidityPivotsHigh.pop()
        liquidity.LiquidityPivotsHigh.unshift(Pivot.new(pivotHigh, bar_index - 1, 1))
    if not na(pivotLow)
        if liquidity.LiquidityPivotsLow.size() >= liquidity.LiquidityPivotsLookback
            liquidity.LiquidityPivotsLow.pop()
        liquidity.LiquidityPivotsLow.unshift(Pivot.new(pivotLow, bar_index - 1, -1))
Alert(string message) =>
    alert(message, alert.freq_once_per_bar_close)
method BrokenByBar(Pivot pivot) =>
    broken = false
    for i = 1 to bar_index - 1 - pivot.BarIndex
        switch pivot.Type
            1 =>
                if low[i] > pivot.Price
                    broken := true
                    break
            -1 =>
                if high[i] < pivot.Price
                    broken := true
                    break
    broken
method BrokenByBar(box zone, int type) =>
    broken = false
    for i = 1 to bar_index - 1 - zone.get_left()
        switch type
            1 =>
                if low[i] > zone.get_top()
                    broken := true
                    break
            -1 =>
                if high[i] < zone.get_bottom()
                    broken := true
                    break
    broken
InLimits(float highLimit, float lowLimit, float price) =>
    price >= lowLimit and price <= highLimit
// @function Sets the pivots in the structure.
// @param Structure The market structure value to modify.
export Pivot(Structure structure) =>
    pivotHigh = ta.pivothigh(structure.LeftLength, structure.RightLength)
    pivotLow = ta.pivotlow(structure.LeftLength, structure.RightLength)

    if not na(pivotHigh)
        if structure.Pivots.size() > 5
            structure.Pivots.pop()
        structure.Pivots.unshift(Pivot.new(pivotHigh, bar_index - structure.RightLength, 1, time[structure.RightLength]))
    if not na(pivotLow)
        if structure.Pivots.size() > 5
            structure.Pivots.pop()
        structure.Pivots.unshift(Pivot.new(pivotLow, bar_index - structure.RightLength, -1, time[structure.RightLength]))
// @function Draws labels for the pivots found.
// @param Structure The market structure value to modify.
export PivotLabels(Structure structure) =>
    txt = ""
    for pivot in structure.Pivots
        if pivot.BarIndex == bar_index - structure.RightLength
            for i = 1 to structure.Pivots.size() - 1
                if structure.Pivots.size() == 1
                    break // previous trend pivots high/low
                previousPivot = structure.Pivots.get(i)
                if previousPivot.Type != pivot.Type or previousPivot.BarIndex == pivot.BarIndex
                    continue
                if pivot.Price == previousPivot.Price
                    txt := "EQ"
                else if pivot.Price > previousPivot.Price
                    txt := "H"
                else if pivot.Price < previousPivot.Price
                    txt := "L"
                break
            transparency = switch structure.Type
                Type.Internal => 60
                Type.Swing => 20
            switch pivot.Type
                -1 => txt += "L", label.new(pivot.BarIndex, pivot.Price, txt, size = structure.FontSize, color = color(na), textcolor = color.new(color.teal, transparency), style = label.style_label_up)
                1 => txt += "H", label.new(pivot.BarIndex, pivot.Price, txt, size = structure.FontSize, color = color(na), textcolor = color.new(color.red, transparency))
// @function Draws the boxes for equal highs/lows. Also creates labels for the pivots included.
// @param Structure The market structure value to modify.
export EqualHighOrLow(Structure structure) =>
    retestHigh = high < high[1] and high[1] > high[2]
    retestLow = low > low[1] and low[1] < low[2]
    // go through previously created zones to add to
    if retestHigh
        for equalPivot in structure.EqualHighs
            price = high[1]
            lowLimit = equalPivot.get_bottom() - (_atr * (structure.EqualPivotsFactor / 100.))
            highLimit = equalPivot.get_top()
            if InLimits(highLimit, lowLimit, price)
                if not equalPivot.BrokenByBar(1)
                    if price < equalPivot.get_bottom() //equalPivot.get_top()
                        equalPivot.set_rightbottom(bar_index - 1, price)
                    else
                        equalPivot.set_right(bar_index - 1)
                        equalPivot.set_top(price)
                    label.new(bar_index - 1, price, style = structure.ExtendEqualPivotsStyle, size = structure.FontSize, color = color.new(structure.ExtendEqualPivotsColor, 70))
                    if structure.AlerEqualPivots
                        Alert("Added bar to existing equal high")
    if retestLow
        for equalPivot in structure.EqualLows
            price = low[1]
            lowLimit = equalPivot.get_bottom()
            highLimit = equalPivot.get_top() + (_atr * (structure.EqualPivotsFactor / 100.))
            if InLimits(highLimit, lowLimit, price)
                if not equalPivot.BrokenByBar(-1)
                    if price < equalPivot.get_bottom()
                        equalPivot.set_rightbottom(bar_index - 1, price)
                    else
                        equalPivot.set_right(bar_index - 1)
                        equalPivot.set_top(price)
                    label.new(bar_index - 1, price, style = structure.ExtendEqualPivotsStyle, size = structure.FontSize, color = color.new(structure.ExtendEqualPivotsColor, 70))
                    if structure.AlerEqualPivots
                        Alert("Added bar to existing equal low")
    // create new zones
    for pivot in structure.Pivots
        price = 0., lowLimit = 0., highLimit = 0.
        switch pivot.Type
            -1 =>
                if not retestLow
                    continue
                price := low[1]
                lowLimit := pivot.Price
                highLimit := pivot.Price + (_atr * (structure.EqualPivotsFactor / 100.))
            1 =>
                if not retestHigh
                    continue
                price := high[1]
                lowLimit := pivot.Price - (_atr * (structure.EqualPivotsFactor / 100.))
                highLimit := pivot.Price
        if InLimits(highLimit, lowLimit, price)
            if not pivot.BrokenByBar()
                left = pivot.BarIndex, right = bar_index - 1, top = math.max(price, pivot.Price), bottom = math.min(price, pivot.Price)
                exactSamePivotPrice = pivot.Price == price
                equalPivotsBox = box.new(left, top, right, bottom, bgcolor = color.new(structure.ExtendEqualPivotsColor, 70), text = "Equal low", text_color = structure.ExtendEqualPivotsColor, border_width = exactSamePivotPrice ? 1 : 0, border_color = structure.ExtendEqualPivotsColor, extend = structure.ExtendEqualPivotsZones ? extend.right : extend.none)
                label.new(bar_index - 1, price, size = structure.FontSize, style = structure.ExtendEqualPivotsStyle, color = color.new(structure.ExtendEqualPivotsColor, 70))
                label.new(pivot.BarIndex, pivot.Price, size = structure.FontSize, style = structure.ExtendEqualPivotsStyle, color = color.new(structure.ExtendEqualPivotsColor, 70))
                switch pivot.Type
                    -1 =>
                        equalPivotsBox.set_text("Equal low")
                        structure.EqualLows.unshift(equalPivotsBox)
                        if structure.AlerEqualPivots
                            Alert("Equal low appeared")
                    1 =>
                        equalPivotsBox.set_text("Equal high")
                        structure.EqualHighs.unshift(equalPivotsBox)
                        if structure.AlerEqualPivots
                            Alert("Equal high appeared")
// @function Will create lines when a break of strycture occures.
// @param Structure The market structure value to modify.
// @returns The 'Pivot' that caused the break of structure, na otherwise.
export BreakOfStructure(Structure structure) =>
    var alerMessageFormat = "BOS on {0} on {1} market structure"
    Pivot breakOfStructureOccured = na
    lineStyle = switch structure.Type
        Type.Swing => line.style_solid
        Type.Internal => line.style_dashed
    for pivot in structure.Pivots
        if structure.Trend == 1 and pivot.Type == 1 and close > pivot.Price and not pivot.BreakOfStructureBroken
            create = true
            for breakOfStructure in structure.BreakOfStructures
                barIndex = breakOfStructure.Line.get_x1()
                if barIndex > pivot.BarIndex
                    price = breakOfStructure.Line.get_y1()
                    if price < pivot.Price
                        breakOfStructure.Line.delete() // remove previous BOS lines
                        breakOfStructure.Label.delete()
                    else // dont create the bos if there was an earlier one with a lower price
                        create := false
                        break
            if create
                structure.BreakOfStructures.unshift(StructureBreak.new(
                  line.new(pivot.BarIndex, pivot.Price, bar_index, pivot.Price, color = color.teal, style = lineStyle),
                  label.new(bar_index - ((bar_index - pivot.BarIndex) / 2), pivot.Price, "BOS", size = structure.FontSize, color = color(na), textcolor = color.new(color.teal, 30))))
                pivot.BreakOfStructureBroken := true
                switch structure.Type
                    Type.Internal =>
                        if structure.AlertBreakOfStructure
                            Alert(str.format(alerMessageFormat, "an uptrend", "internal"))
                    Type.Swing =>
                        if structure.AlertBreakOfStructure
                            Alert(str.format(alerMessageFormat, "an uptrend", "swing"))
                breakOfStructureOccured := pivot
                break
        else if structure.Trend == -1 and pivot.Type == -1 and close < pivot.Price and not pivot.BreakOfStructureBroken
            create = true
            for breakOfStructure in structure.BreakOfStructures
                barIndex = breakOfStructure.Line.get_x1()
                if barIndex > pivot.BarIndex
                    price = breakOfStructure.Line.get_y1()
                    if price > pivot.Price
                        breakOfStructure.Line.delete() // remove previous BOS lines
                        breakOfStructure.Label.delete()
                    else // dont create the bos if there was an earlier one with a lower price
                        create := false
                        break
            if create
                structure.BreakOfStructures.unshift(StructureBreak.new(
                  line.new(pivot.BarIndex, pivot.Price, bar_index, pivot.Price, color = color.red, style = lineStyle),
                  label.new(bar_index - ((bar_index - pivot.BarIndex) / 2), pivot.Price, "BOS", size = structure.FontSize, color = color(na), textcolor = color.new(color.red, 30), style = label.style_label_up)))
                pivot.BreakOfStructureBroken := true
                switch structure.Type
                    Type.Internal =>
                        if structure.AlertBreakOfStructure
                            Alert(str.format(alerMessageFormat, "a downtrend", "internal"))
                    Type.Swing =>
                        if structure.AlertBreakOfStructure
                            Alert(str.format(alerMessageFormat, "a downtrend", "swing"))
                breakOfStructureOccured := pivot
                break
    breakOfStructureOccured
// @function Will create lines when a change of character occures. This line will have a label with "CHoCH" or "CHoCH+".
// @param Structure The market structure value to modify.
// @returns The 'Pivot' that caused the change of character, na otherwise.
export ChangeOfCharacter(Structure structure) =>
    var alerMessageFormat = "{0} to {1} on {2} market structure"
    Pivot changeOfCharacterOccured = na
    lineStyle = switch structure.Type
        Type.Internal => line.style_dashed
        Type.Swing => line.style_solid
    for pivot in structure.Pivots
        if structure.Trend <= 0 and pivot.Type == 1 and close > pivot.Price and close[1] < pivot.Price and not(pivot.ChangeOfCharacterBroken)
            pivot.ChangeOfCharacterBroken := true
            txt = "CHoCH"
            if structure.Pivots.size() >= 2 and structure.Trend != 0 // need at leased 2 pivots
                for i = 0 to structure.Pivots.size() - 2
                    latestPivot = structure.Pivots.get(i)
                    if latestPivot.Type == -1
                        for j = i + 1 to structure.Pivots.size() - 2
                            nextLatestPivot = structure.Pivots.get(j)
                            if nextLatestPivot.Type == -1
                                if latestPivot.Price > nextLatestPivot.Price
                                    txt := "CHoCH+"
                                break
                        break
            line.new(pivot.BarIndex, pivot.Price, bar_index, pivot.Price, color = color.teal, style = lineStyle)
            label.new(bar_index - ((bar_index - pivot.BarIndex) / 2), pivot.Price, txt, size = structure.FontSize, color = color(na), textcolor = color.new(color.teal, 30))
            
            structure.Trend := 1
            structure.EqualHighs.clear(), structure.EqualLows.clear()
            structure.BreakOfStructures.clear()
            // Keep all the pivots 'within' the pivot and the break for CHoCHs, disable all for BOSs
            remove = array.new<int>()
            for [i, p] in structure.Pivots
                if p.BarIndex <= pivot.BarIndex
                    remove.push(i)
                else
                    p.BreakOfStructureBroken := true
            for [i, r] in remove
                structure.Pivots.remove(r - i)
            for p in structure.Pivots
                if p.BarIndex != pivot.BarIndex // set all pivots to breakable
                    p.ChangeOfCharacterBroken := false
            switch structure.Type
                Type.Internal =>
                    if structure.AlertChangeOfCharacter
                        Alert(str.format(alerMessageFormat, txt, "an uptrend", "internal"))
                Type.Swing =>
                    if structure.AlertChangeOfCharacter
                        Alert(str.format(alerMessageFormat, txt, "an uptrend", "swing"))
            changeOfCharacterOccured := pivot
            break
        else if structure.Trend >= 0 and pivot.Type == -1 and close < pivot.Price and close[1] > pivot.Price and not(pivot.ChangeOfCharacterBroken)
            pivot.ChangeOfCharacterBroken := true
            txt = "CHoCH"
            if structure.Pivots.size() >= 2 and structure.Trend != 0 // need at leased 2 pivots
                for i = 0 to structure.Pivots.size() - 2
                    latestPivot = structure.Pivots.get(i)
                    if latestPivot.Type == 1
                        for j = i + 1 to structure.Pivots.size() - 2
                            nextLatestPivot = structure.Pivots.get(j)
                            if nextLatestPivot.Type == 1
                                if latestPivot.Price < nextLatestPivot.Price
                                    txt := "CHoCH+"
                                break
                        break
            line.new(pivot.BarIndex, pivot.Price, bar_index, pivot.Price, color = color.red, style = lineStyle)
            label.new(bar_index - ((bar_index - pivot.BarIndex) / 2), pivot.Price, txt, size = structure.FontSize, color = color(na), textcolor = color.new(color.red, 30), style = label.style_label_up)
            
            structure.Trend := -1
            structure.EqualHighs.clear(), structure.EqualLows.clear()
            structure.BreakOfStructures.clear()
            // Keep all the pivots 'within' the pivot and the break for CHoCHs, disable all for BOSs
            remove = array.new<int>()
            for [i, p] in structure.Pivots
                if p.BarIndex <= pivot.BarIndex
                    remove.push(i)
                else
                    p.BreakOfStructureBroken := true
            for [i, r] in remove
                structure.Pivots.remove(r - i)
            for p in structure.Pivots
                if p.BarIndex != pivot.BarIndex // set all pivots to breakable
                    p.ChangeOfCharacterBroken := false
            switch structure.Type
                Type.Internal =>
                    if structure.AlertChangeOfCharacter
                        Alert(str.format(alerMessageFormat, txt, "a downtrend", "internal"))
                Type.Swing =>
                    if structure.AlertChangeOfCharacter
                        Alert(str.format(alerMessageFormat, txt, "a downtrend", "swing"))
            changeOfCharacterOccured := pivot
            break
    changeOfCharacterOccured
// @function Will create a box with a background for between the latest high and low pivots. This can be used as the current trading range (if the pivots broke strucure somehow).
export VisualizeCurrent(Structure structure) =>
    var tradingRange = box.new(bar_index, high, bar_index, high, extend = extend.right, border_width = 0, bgcolor = color.new(color.gray, 70))
    Pivot latestHighPivot = na, Pivot latestLowPivot = na
    for pivot in structure.Pivots
        switch pivot.Type
            -1 =>
                if na(latestLowPivot)
                    latestLowPivot := pivot
            1 =>
                if na(latestHighPivot)
                    latestHighPivot := pivot
    if not na(latestHighPivot) and structure.RightLength == bar_index - latestHighPivot.BarIndex
        tradingRange.set_lefttop(bar_index - (bar_index - latestHighPivot.BarIndex), high[bar_index - latestHighPivot.BarIndex])
    if not na(latestLowPivot) and structure.RightLength == bar_index - latestLowPivot.BarIndex
        tradingRange.set_rightbottom(bar_index - (bar_index - latestLowPivot.BarIndex), low[bar_index - latestLowPivot.BarIndex])

Overview

PriceAction exports custom data structures for pivots, structure breaks, and market trends, categorizing price movement into internal order flow or swing structure. The library manages arrays for breaks of structure, changes of character, liquidity breaks, and equal high or low zones scaled by ATR. Because pivot calculations rely on confirmation bars after the high or low occurs, historical pivot assignments update dynamically.

Details

Published by

alvinng214 on GitHub

Code credit

mickes, as written in the script's header

Draws

Library (no plots)

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

  • Signals can change on the live bar or after it closes (repainting)
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

SFA FlowLiquidity v1

by genesisgrubio39
1 stars

The SFA FlowLiquidity library computes structural flow and liquidity events from price data. It detects sweep ups and downs with associated scores, identifies liquidity levels, and applies session and regime filters. Persistent arrays track liquidity prices, b

Library v6 SMC / ICT / price actionSupport & resistance
Updated 10 months ago · None stated GitHub repository of SFA FlowLiquidity v1

SMC Engine Private

by skipp-dev
1 stars

This Pine Script v6 library serves as an internal engine for Smart Money Concepts (SMC), providing types, tracking, and rendering logic for order blocks, fair value gaps, and market structure. It calculates order block parameters including quality scores, heig

Library v6 SMC / ICT / price actionSupport & resistance
Updated 4 days ago · None stated GitHub repository of SMC Engine Private

AuthLib

by alboogycOdR
6 stars

AuthLib is a Pine Script v5 library that checks a caller username against a fixed list and, when authorized, prepares drawings for six killzone sessions. It stores boxes, labels, trend lines and price labels in a DrawingData type. For each window it tracks the

Library v5 Sessions & timeSMC / ICT / price action
Updated 7 months ago · None stated GitHub repository of AuthLib

Daily Deviation

by Electrified-Trading
2 stars

This library calculates arrays of daily price deviations from the open to the high, low, and close over a user-specified number of days. It optionally filters outliers using a maximum deviation threshold. The fromOpen function returns a normalized value showin

Library v5 Volatility & bandsSupport & resistance
Updated 1 year ago · MPL-2.0 GitHub repository of Daily Deviation

libhl

by ivansoft
1 stars

A Pine Script v5 library that records the open, high, low and close points of successive periods and keeps the latest few in an array. It exports types for period contexts and alignment, a helper that detects when a period such as a week or month changes relat

Library v5 Support & resistance Repaints
Updated 1 year ago · None stated GitHub repository of libhl

Calculates continuous structural market bias by detecting swing high and low pivots (higher highs, higher lows, lower highs, and lower lows) using configurable left and right bar lookbacks. It assigns weighted values to classified pivots within a rolling windo

Indicator v6 SMC / ICT / price actionTrend
Updated 3 days ago · MIT GitHub repository of Market Structure Advanced [WavesUnchained]

More SMC / ICT scripts

Related on ForexR

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers