mickesPriceAction4.txt
Copy
// 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])
Show all 660 lines