structure with limit lines

You might also like

Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 76

// This source code is subject to the terms of the Mozilla Public License 2.

0 at
https://mozilla.org/MPL/2.0/
// ┬й sevencampbell

//@version=5
//trategy(title = "Zazzamira 50-25-25 Trend System W Alerts", overlay = true,
default_qty_value = 4, initial_capital=10000,default_qty_type=strategy.fixed,
pyramiding=3, process_orders_on_close=true, max_lines_count=500)

indicator("THE MASTER PATTERN",overlay = true,max_boxes_count = 500,


max_lines_count = 500, max_bars_back = 5000)

Major_Box_Color = input.color(color.rgb(81, 55, 226),"Major Box Color")


show_minor_boxes = input.bool(false,"Show Minor Boxes")
Minor_Box_Color = input.color(color.rgb(163, 160, 160),"Minor Box Color")
Major_Expansion_Line_Color = input.color(color.rgb(238, 238, 238),"Major Expansion
Line Color")
Major_Expansion_Line_Style = input.string("Solid","Major Expansion Line Style",
["Solid","Dotted","Dashed"])
Major_Expansion_Line_Thickness = input.int(2,"Major Expansion Line Thickness")
show_minor_expansion = input.bool(true,"Show Minor Expansion Lines")
Minor_Expansion_Line_Color = input.color(color.rgb(241, 238, 239),"Minor Expansion
Line Color")
Minor_Expansion_Line_Style = input.string("Dashed","Minor Expansion Line Style",
["Solid","Dotted","Dashed"])
Minor_Expansion_Line_Thickness = input.int(1,"Minor Expansion Line Thickness")
Sell_Line_Color = input.color(color.red,"Sell Side Liquidity Line Color")
Sell_Line_Style = input.string("Dotted","Sell Side Liquidity Line Style",
["Solid","Dotted","Dashed"])
Sell_Line_Thickness = input.int(1,"Sell Side Liquidity Line Thickness")
Buy_Line_Color = input.color(color.green,"Buy Side Liquidity Line Color")
Buy_Line_Style = input.string("Dotted","Buy Side Liquidity Line Style",
["Solid","Dotted","Dashed"])
Buy_Line_Thickness = input.int(1,"Buy Side Liquidity Line Thickness")
max_bars = input.int(500,"Max Bars Back")
indi_type = input.int(1,"Type")
alert_major_line_confirm = input.bool(true,"Major Line Confirmation",group =
"Alerts")
alert_major_line_cross = input.bool(true,"Major Line Crossing",group = "Alerts")
alert_liquidity_line_touch = input.bool(true,"Liquidity Line Touching",group =
"Alerts")
//n = input.int(title="Fractals Periods", defval=2, minval=2)
repaint = true

// // UpFractal
// bool upflagDownFrontier = true
// bool upflagUpFrontier0 = true
// bool upflagUpFrontier1 = true
// bool upflagUpFrontier2 = true
// bool upflagUpFrontier3 = true
// bool upflagUpFrontier4 = true

// for i = 1 to n
// upflagDownFrontier := upflagDownFrontier and (high[n-i] < high[n])
// upflagUpFrontier0 := upflagUpFrontier0 and (high[n+i] < high[n])
// upflagUpFrontier1 := upflagUpFrontier1 and (high[n+1] <= high[n] and
high[n+i + 1] < high[n])
// upflagUpFrontier2 := upflagUpFrontier2 and (high[n+1] <= high[n] and
high[n+2] <= high[n] and high[n+i + 2] < high[n])
// upflagUpFrontier3 := upflagUpFrontier3 and (high[n+1] <= high[n] and
high[n+2] <= high[n] and high[n+3] <= high[n] and high[n+i + 3] < high[n])
// upflagUpFrontier4 := upflagUpFrontier4 and (high[n+1] <= high[n] and
high[n+2] <= high[n] and high[n+3] <= high[n] and high[n+4] <= high[n] and high[n+i
+ 4] < high[n])
// flagUpFrontier = upflagUpFrontier0 or upflagUpFrontier1 or upflagUpFrontier2 or
upflagUpFrontier3 or upflagUpFrontier4

// upFractal = (upflagDownFrontier and flagUpFrontier)

// // downFractal
// bool downflagDownFrontier = true
// bool downflagUpFrontier0 = true
// bool downflagUpFrontier1 = true
// bool downflagUpFrontier2 = true
// bool downflagUpFrontier3 = true
// bool downflagUpFrontier4 = true

// for i = 1 to n
// downflagDownFrontier := downflagDownFrontier and (low[n-i] > low[n])
// downflagUpFrontier0 := downflagUpFrontier0 and (low[n+i] > low[n])
// downflagUpFrontier1 := downflagUpFrontier1 and (low[n+1] >= low[n] and
low[n+i + 1] > low[n])
// downflagUpFrontier2 := downflagUpFrontier2 and (low[n+1] >= low[n] and
low[n+2] >= low[n] and low[n+i + 2] > low[n])
// downflagUpFrontier3 := downflagUpFrontier3 and (low[n+1] >= low[n] and
low[n+2] >= low[n] and low[n+3] >= low[n] and low[n+i + 3] > low[n])
// downflagUpFrontier4 := downflagUpFrontier4 and (low[n+1] >= low[n] and
low[n+2] >= low[n] and low[n+3] >= low[n] and low[n+4] >= low[n] and low[n+i + 4] >
low[n])
// flagDownFrontier = downflagUpFrontier0 or downflagUpFrontier1 or
downflagUpFrontier2 or downflagUpFrontier3 or downflagUpFrontier4

// downFractal = (downflagDownFrontier and flagDownFrontier)

// var zz = array.new_float()
// var yy = array.new_int()

// if upFractal
// array.push(zz, high)
// array.push(yy,bar_index)

// if downFractal
// array.push(zz, low)
// array.push(yy,bar_index)

var Depth = 3
var Deviation = 1
var Backstep = 1

if(indi_type==2)
Depth := 2

var last_h = 1, last_h := last_h + 1


var last_l = 1, last_l := last_l + 1
var lw = 1, var hg = 1
lw := lw + 1, hg := hg + 1
p_lw = -ta.lowestbars(Depth), p_hg = -ta.highestbars(Depth)
lowing = lw == p_lw or low - low[p_lw] > Deviation*syminfo.mintick
highing = hg == p_hg or high[p_hg] - high > Deviation*syminfo.mintick
lh = ta.barssince(not highing[1]), ll = ta.barssince(not lowing[1])
down = ta.barssince(not (lh > ll)) >= Backstep, lower = low[lw] > low[p_lw], higher
= high[hg] < high[p_hg]
if lw != p_lw and (not down[1] or lower)
lw := p_lw < hg ? p_lw : 0
if hg != p_hg and (down[1] or higher)
hg := p_hg < lw ? p_hg : 0

var zz = array.new_float()
var yy = array.new_int()
x1 = down ? lw : hg
y1 = down ? low[lw] : high[hg]

if down == down[1]
if repaint
if(array.size(zz)>0)
array.pop(zz)
array.pop(yy)
down
if down != down[1]
if down
last_h := hg
else
last_l := lw
if not repaint
nx = down?last_h:last_l
array.push(zz, (down ? low[last_l] : high[last_h]))
array.push(yy,bar_index-(down?last_l:last_h))
down
if repaint
array.push(zz, y1)
array.push(yy,bar_index-x1)

allowPlot()=>
(last_bar_index-bar_index<=max_bars)

checkTrigger()=>
value1 = 0.0, value2 = 0.0, value3 = 0.0, value4 = 0.0, counter = 0, res =
false, pos = 0
if(array.size(zz)>=4 and array.size(yy)>=4)
for x = array.size(zz)-1 to 0
if(x<array.size(zz))
price = array.get(zz,x)
counter += 1
if(counter == 1)
value1 := price
if(counter == 2)
value2 := price
pos := array.get(yy,x)
if(counter == 3)
value3 := price
if(counter == 4)
value4 := price
break
if((value1<value2 and value1>value3 and value4>value2) or
(value1>value2 and value1<value3 and value4<value2))
res := true
[res, math.max(value1,value2), math.min(value1,value2), pos]

var minorBoxes = array.new_box()


var minorBoxNames = array.new_string()
var minorCrossedHigh = array.new_bool()
var minorCrossedLow = array.new_bool()
var expansionLines = array.new_line()
var minorExpansionLines = array.new_line()
[RES,Val1,Val2,POS] = checkTrigger()
if(RES and allowPlot())
array.push(minorBoxes, box.new(time[bar_index-
POS],Val1,time,Val2,xloc=xloc.bar_time,border_color=(show_minor_boxes?
Minor_Box_Color:na),bgcolor=(show_minor_boxes?Minor_Box_Color:na)))
array.push(minorBoxNames, "Active Box")
array.push(minorCrossedHigh, false), array.push(minorCrossedLow, false)

updateExpansionLines(Time,Line,clear,checktimes)=>
if(array.size(Line)>0)
for x = 0 to array.size(Line)-1
if(x < array.size(checktimes) and x < array.size(Line))
if(Time>array.get(checktimes,x))
line.set_x2(array.get(Line,x),Time)
if(clear)
array.remove(Line,x)

var check = array.new_int()


var checkMinor = array.new_int()

updateExpansionLines(time,expansionLines,false,check)
updateExpansionLines(time,minorExpansionLines,false,checkMinor)

var majorBoxLines = array.new_line()


var majorBoxLineType = array.new_int()
var majorBoxLineRef = array.new_int()
var Crossed = array.new_bool()

getHighOffset(Time)=>
x = 1, hi = high, res = 0
while(time[x]>=Time)
if(high[x]>hi)
hi := high[x]
res := x
x += 1
res

getLowOffset(Time)=>
x = 1, lo = low, res = 0
while(time[x]>=Time)
if(low[x]<lo)
lo := low[x]
res := x
x += 1
res

checkCross(line_array, price)=>
result = false
Prices = price
if array.size(line_array) > 0
for x = 0 to array.size(line_array)-1
Price = line.get_y1(array.get(line_array,x))
if (Prices > Price and Prices[1] <= Price) or (Prices < Price and
Prices[1] >= Price)
result := true
result

operateMinorBox(price,hi_price,lo_price,Time)=>
var lastMinorExp = 0
confirm = false

if(array.size(minorBoxes)>0 and array.size(minorCrossedHigh)>0 and


array.size(minorCrossedLow)>0 and array.size(minorBoxNames)>0)
x = array.size(minorBoxes)-1
if array.get(minorBoxNames,x)!="NULL"
top = box.get_top(array.get(minorBoxes,x)), bottom =
box.get_bottom(array.get(minorBoxes,x))
time1 = box.get_left(array.get(minorBoxes,x))
time2 = box.get_right(array.get(minorBoxes,x)), ppp = bottom+(top-
bottom)/2
origCrossedHigh = array.get(minorCrossedHigh,x)
origCrossedLow = array.get(minorCrossedLow,x)
if(not array.get(minorCrossedHigh,x) and not
array.get(minorCrossedLow,x))
if(not barstate.islast or barstate.isconfirmed)
if(price>top)
array.set(minorCrossedHigh,x,true)
if(price<bottom)
array.set(minorCrossedLow,x,true)
else
if(hi_price>top)
array.set(minorCrossedHigh,x,true)
if(lo_price<bottom)
array.set(minorCrossedLow,x,true)
if(array.get(minorCrossedHigh,x) and array.get(minorCrossedLow,x))
box.set_bgcolor(array.get(minorBoxes,x),Major_Box_Color)
array.set(minorBoxNames,x,"NULL")
updateExpansionLines(time2,expansionLines,true,check)
confirm := true
if(show_minor_expansion)
updateExpansionLines(time2,minorExpansionLines,true,checkMinor)

array.push(expansionLines,line.new(time2,ppp,time,ppp,xloc.bar_time,extend.none,Maj
or_Expansion_Line_Color,
(Major_Expansion_Line_Style=="Solid"?
line.style_solid:Major_Expansion_Line_Style=="Dotted"?line.style_dotted:
line.style_dashed),Major_Expansion_Line_Thickness))
array.push(check,time2)
hi_pos = getHighOffset(time2)
lo_pos = getLowOffset(time2)
if(not origCrossedHigh)
rrr = low[lo_pos]
array.push(majorBoxLines,
line.new(time[lo_pos],rrr,Time,rrr,xloc.bar_time,extend.none,Buy_Line_Color,
(Buy_Line_Style=="Solid"?
line.style_solid:Buy_Line_Style=="Dotted"?line.style_dotted:line.style_dashed),
Buy_Line_Thickness))
array.push(majorBoxLineType,0)
else if(not origCrossedLow)
rrr = high[hi_pos]
array.push(majorBoxLines,
line.new(time[hi_pos],rrr,Time,rrr,xloc.bar_time,extend.none,Sell_Line_Color,
(Sell_Line_Style=="Solid"?
line.style_solid:Sell_Line_Style=="Dotted"?line.style_dotted:line.style_dashed),
Sell_Line_Thickness))
array.push(majorBoxLineType,1)
array.push(majorBoxLineRef,time2)
array.push(Crossed,false)
true
else if(not array.get(minorCrossedHigh,x) and not
array.get(minorCrossedLow,x))
box.set_right(array.get(minorBoxes,x),Time)
true
else if(show_minor_expansion and time1!=lastMinorExp)
updateExpansionLines(time2,minorExpansionLines,true,checkMinor)
array.push(minorExpansionLines,
line.new(time2,ppp,time,ppp,xloc.bar_time,extend.none,Minor_Expansion_Line_Color,
(Minor_Expansion_Line_Style=="Solid"?
line.style_solid:Minor_Expansion_Line_Style=="Dotted"?line.style_dotted:
line.style_dashed),Minor_Expansion_Line_Thickness))
array.push(checkMinor,time2)
lastMinorExp := time1
true
confirm

operateLiquidity(hi_price,lo_price,Time)=>
result = false
if(array.size(majorBoxLines)>0 and array.size(majorBoxLineRef)>0 and
array.size(Crossed)>0)
z = array.size(majorBoxLines)-1
for x = 0 to z
line_price = line.get_y2(array.get(majorBoxLines,x))
hi_pos = getHighOffset(array.get(majorBoxLineRef,x))
lo_pos = getLowOffset(array.get(majorBoxLineRef,x))
qq = 0.0
if(array.get(majorBoxLineType,x)==0 and lo_price <= line_price)
if not array.get(Crossed,x)
result := true
qq := high[hi_pos]
if x == z

array.set(majorBoxLines,x,line.new(time[hi_pos],qq,Time,qq,xloc.bar_time,extend.non
e,Sell_Line_Color,(Sell_Line_Style=="Solid"?line.style_solid:
Sell_Line_Style=="Dotted"?
line.style_dotted:line.style_dashed),Sell_Line_Thickness))
array.set(majorBoxLineType,x,1)
else
array.set(Crossed,x,true)
else if(array.get(majorBoxLineType,x)==1 and hi_price >= line_price)
if not array.get(Crossed,x)
result := true
qq := low[lo_pos]
if x == z

array.set(majorBoxLines,x,line.new(time[lo_pos],qq,Time,qq,xloc.bar_time,extend.non
e,Buy_Line_Color,(Buy_Line_Style=="Solid"?line.style_solid:
Buy_Line_Style=="Dotted"?
line.style_dotted:line.style_dashed),Buy_Line_Thickness))
array.set(majorBoxLineType,x,0)
else
array.set(Crossed,x,true)
if not array.get(Crossed,x)
line.set_x2(array.get(majorBoxLines,x),Time)
result

major_line_confirm = operateMinorBox(close,high,low,time)
major_line_cross = checkCross(expansionLines,close)
liquidity_line_touch = operateLiquidity(high,low,time)

if alert_major_line_confirm and major_line_confirm


alert("Major Line Confirmed.")
if alert_major_line_cross and major_line_cross
alert("Major Line Crossed.")
if alert_liquidity_line_touch and liquidity_line_touch
alert("Liquidity Line Touched.")

//@version=5
//ndicator("Smart Money Breakouts [ChartPrime]", overlay=true,
max_labels_count=500, max_lines_count=500)
color GREEN = #1592e6
color TAIL = #673ab7
color RED = #673ab7
color _Green = #1592e6
color OFF = color.new(color.red,100)
string CORE = "�� Core Settings �"
var array<int> score = array.new_int(2,0)
//
var float UpdatedHigh = na
var float UpdatedLow = na
var bool ShortTrade = false
var bool TradeisON = false
var bool LongTrade = false
var int HighIndex = na
var bool phActive = false
var bool plActive = false
var int LowIndex = na
var bool HBreak = false
var line tpLine = na
var label LAB = na
var float TP = 0.0
var float SL = 0.0
int Sync = bar_index
bool BUY = false
bool SELL = false

type Vol
array<float> Total
array<float> Green
array<float> Red
array<float> SCR
Volume = Vol.new(
array.new_float(),
array.new_float(),
array.new_float(),
array.new_float()

int period = input.int(20, 'Length',group = CORE,tooltip = "Swing


Length")
int period2 =input.int(2, "Right Length", group=CORE, tooltip="Swing
Length Right")
bool CandleType = input.string(title = "Type ��",
defval='Wicks',
options=['Wicks', 'Body'],
group = CORE,
tooltip = "Calculation Price : Wicks or Body of the candle")
== 'Wicks'
float Tar = input.float(2,"Target ",step = 0.1 , tooltip = "Target
Multiplyer ",group = CORE) * 10
string Linestyle = input.string('Dashed',
'Line Style', ['Solid', 'Dashed', 'Dotted'], group=CORE,inline= "Line")

color Bull = input.color(GREEN,"",group=CORE,inline= "Line")


color Bear = input.color(RED,"",group=CORE,inline= "Line")

StyleSwitch = switch Linestyle


'Dashed' => line.style_dashed ,
'Dotted' => line.style_dotted ,
=> line.style_solid

method volAdj(int len)=>


math.min(ta.atr(len) * 0.3, close * (0.3/100)) [20] /2

Adj = volAdj(30)

VolCal(Index,Sync) =>
Bars = math.abs(Index - Sync)
for i = 0 to Bars -1
Volume.SCR.push(close[i])

for i = 0 to Volume.SCR.size() -1

if Volume.SCR.get(i) > open[i]


Volume.Green.push(volume[i])

if Volume.SCR.get(i) < open[i]


Volume.Red.push(volume[i])

Volume.Total.push(volume[i])

GreenRatio = math.round(Volume.Green.sum() / Volume.Total.sum()* 100,2)


RedRatio = math.round(Volume.Red.sum() / Volume.Total.sum()* 100,2)
Out = GreenRatio > 55 ? "" : RedRatio > 55 ? "" : ""
Out
PH = ta.pivothigh(high, period, period2)
PL = ta.pivotlow(low, period, period2)
ScrHigh = CandleType ? high : close
ScrLow = CandleType ? low : close

if ta.change(fixnan(PH)) != 0
UpdatedHigh := PH
phActive := true
HighIndex := Sync - period

if ta.change(fixnan(PL)) != 0
UpdatedLow := PL
plActive := true
LowIndex := Sync - period

// LONG
if ScrHigh > UpdatedHigh and plActive
BUY := true
phActive := false

//Sell
if ScrLow < UpdatedLow and phActive
SELL := true
plActive := false

// lets Draw

if BUY and not TradeisON


sign = VolCal(HighIndex,Sync)
line.new(HighIndex,
UpdatedHigh,
Sync,
UpdatedHigh,
color=Bull,
style=StyleSwitch,
width=1)
label.new(math.floor(Sync - (Sync - HighIndex) / 2),
UpdatedHigh,
not HBreak ? 'CHoCH\n' + sign : 'BOS\n' + sign,
color=OFF,
textcolor=color.white,
size=size.tiny)
label.new(Sync,
low,
"",
yloc = yloc.belowbar,
color = #1592e6,
size = size.small,
style = label.style_label_up)
HBreak := true

if SELL and not TradeisON


sign = VolCal(LowIndex,Sync)
line.new(LowIndex,
UpdatedLow,
Sync,
UpdatedLow,
color=Bear,
style=StyleSwitch,
width=1)
label.new(math.floor(Sync - (Sync - LowIndex) / 2),
UpdatedLow,
HBreak ? 'CHoCH\n' + sign : 'BOS\n' + sign,
color=OFF,
textcolor=color.white,
style=label.style_label_up,
size=size.tiny)
label.new(Sync,
low,
"",
yloc = yloc.abovebar,
color =RED,
size = size.small,
style = label.style_label_down)
HBreak := false

Long = BUY and not TradeisON


Short = SELL and not TradeisON
TradeFire = Long or Short

if Long and not TradeisON


LongTrade:= true
ShortTrade:= false

if Short and not TradeisON


LongTrade:= false
ShortTrade:= true

if true
if TradeFire and not TradeisON
TP := switch
Long => high + (Adj * Tar)
Short => low - (Adj * Tar)

SL := switch
Long => low - (Adj * Tar)
Short => high + (Adj * Tar)

TradeisON:= true
if true
line.new(bar_index,
Long ? high : low,
bar_index,
TP,
width=1,
color = TAIL,
style= line.style_dashed)

tpLine:= line.new(bar_index,
TP,
bar_index+2,
TP,
style= line.style_dashed,
color = TAIL
)
LAB:=label.new(bar_index,
TP,
"Target",
color = TAIL,
style= label.style_label_left,
size=size.small,
textcolor = color.white
)
if TradeisON
line.set_x2(tpLine,bar_index)
label.set_x(LAB,bar_index+1)

if LongTrade and TradeisON


if high >= TP
label.set_color(LAB,GREEN)
score.set(0,score.get(0)+1)
TradeisON:=false
if close <= SL
score.set(1,score.get(1)+1)
label.set_color(LAB,color.new(RED,70))
label.set_tooltip(LAB,"Stoploss Hit : "+
str.tostring(math.round_to_mintick(SL)))
TradeisON:=false

else if ShortTrade and TradeisON


if low <= TP
label.set_color(LAB,GREEN)
score.set(0,score.get(0)+1)
TradeisON:=false

if close >= SL
score.set(1,score.get(1)+1)
label.set_color(LAB,color.new(RED,70))
label.set_tooltip(LAB,"Stoploss Hit : "+
str.tostring(math.round_to_mintick(SL)))
TradeisON:=false

BearCon = TradeisON and ShortTrade


BullCon = TradeisON and LongTrade

barcolor(BearCon ? RED : BullCon ? _Green : color.rgb(52, 52, 54) )

plotcandle(open, high, low, close, color = BearCon ? RED : BullCon ? _Green :


color.rgb(52, 52, 54),
wickcolor = color.rgb(103, 99, 99),bordercolor = BearCon ? RED : BullCon ?
_Green : color.rgb(52, 52, 54))

bgcolor(BearCon ? color.rgb(136, 4, 15, 90) : BullCon ? color.rgb(8, 191, 158,90) :


na )

// where is my table ?!
var tb = table.new(position.top_right, 3, 3,
bgcolor= color.new(color.gray,80))
if barstate.islast

table.cell(tb, 0, 0, "Winning Trades"


, text_color = #a3a3b1)
table.cell(tb, 1, 0, str.tostring(score.get(0))
, text_color = #08c09b)
table.cell(tb, 0, 1, "Losing Trades"
, text_color = #a3a3b1)
table.cell(tb, 1, 1, str.tostring(score.get(1))
, text_color = #cd0202)

//-- END --
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0
International (CC Dy-NC-SA 4.0) https://creativecommons.org/licenses/Dy-nc-sa/4.0/
// © LuxAlgo

//@version=5
//indicator("Breaker Blocks with Signals [LuxAlgo]", max_lines_count=500,
max_boxes_count=500, max_labels_count=500, max_bars_back=3000, overlay=true)
//------------------------------------------------------------------------------
//Settings
//-----------------------------------------------------------------------------{
shZZ = false
len = input.int ( 5 ,
title=' Length' , inline='MS' , group='Market Structure'
, minval=1, maxval=10
)
//Breaker block
breakerCandleOnlyBody = input.bool ( false , title='Use only candle body'
, group='Breaker Block' )
breakerCandle_2Last = input.bool ( false , title='Use 2 candles instead of 1'
, group='Breaker Block', tooltip='In the same direction')
tillFirstBreak = input.bool ( true , title='Stop at first break of
center line' , group='Breaker Block' )

//PD array
onlyWhenInPDarray = input.bool ( false , title='Only when E is in
Premium/Discount Array', group='PD array' )
showPDarray = input.bool ( false , title='show Premium/Discount Zone'
, group='PD array' )
showBreaks = input.bool ( false , title='Highlight Swing Breaks'
, group='PD array' )
showSPD = input.bool ( true , title='Show Swings/PD Arrays'
, group='PD array' )
PDtxtCss = input.color ( color.silver, 'Text Color' , group='PD
array' )
PDSCss = input.color ( color.silver, 'Swing Line Color', group='PD
array' )

//Take profit
iTP = input.bool ( false , title='Enable
TP' , inline='RR' , group='TP'
)
tpCss = input.color ( #2157f3, title='' ,
inline='RR', group='TP' )
R1a = input.float ( 1 , title='R:R 1', minval= 1,
maxval=1, inline='RR1', group='TP' )
R2a = input.float ( 2 , title= ':' , minval=.2,
step= .1, inline='RR1', group='TP' )
R1b = input.float ( 1 , title='R:R 2', minval= 1,
maxval=1, inline='RR2', group='TP' )
R2b = input.float ( 3 , title= ':' , minval=.2,
step= .1, inline='RR2', group='TP' )
R1c = input.float ( 1 , title='R:R 3', minval= 1,
maxval=1, inline='RR3', group='TP' )
R2c = input.float ( 4 , title= ':' , minval=.2,
step= .1, inline='RR3', group='TP' )

//Colors
cBBplusA = input.color (color.rgb(12, 181, 26, 93)
,
title=' ' , inline='bl' , group='Colours
+BB Last Swings' )
cBBplusB = input.color (color.rgb(12, 181, 26, 85)
,
title='' , inline='bl' , group='Colours
+BB Last Swings' )
cSwingBl = input.color (color.rgb(255, 82, 82, 85)
,
title=' ' , inline='bl' , group='Colours
+BB Last Swings' )
cBB_minA = input.color (color.rgb(255, 17, 0, 95)
,
title=' ' , inline='br' , group='Colours -
BB Last Swings' )
cBB_minB = input.color (color.rgb(255, 17, 0, 85)
,
title='' , inline='br' , group='Colours -
BB Last Swings' )
cSwingBr = input.color (color.rgb(0, 137, 123, 85)
,
title=' ' , inline='br' , group='Colours -
BB Last Swings' )

_arrowup = '▲'
_arrowdn = '▼'
_c = '●'
_x = '❌'

//-----------------------------------------------------------------------------}
//General Calculations
//-----------------------------------------------------------------------------{
per = last_bar_index - bar_index <= 2000
mx = math.max(close , open )
mn = math.min(close , open )
atr = ta.atr (10 )
n = bar_index
hi = high
lo = low
mCxSize = 50

//-----------------------------------------------------------------------------}
//User Defined Types
//-----------------------------------------------------------------------------{
type ZZ
int [] d
int [] x
float [] y
line [] l
bool [] b

type mss
int dir
line [] l_mssBl
line [] l_mssBr
line [] l_bosBl
line [] l_bosBr
label[] lbMssBl
label[] lbMssBr
label[] lbBosBl
label[] lbBosBr

type block
int dir
bool Broken
bool Mitigated
box BB_boxA
box BB_boxB
line BB_line
box FVG_box
line line_1
line line_2
bool Broken_1
bool Broken_2
box PDa_boxA
box PDa_boxB
box PDa_box1
line PDaLine1
label PDaLab_1
box PDa_box2
line PDaLine2
label PDaLab_2
bool PDbroken1
bool PDbroken2
line TP1_line
line TP2_line
line TP3_line
bool TP1_hit
bool TP2_hit
bool TP3_hit
bool scalp
label HL
label[] aLabels

//-----------------------------------------------------------------------------}
//Variables
//-----------------------------------------------------------------------------{
BBplus = 0, signUP = 1, cnclUP = 2, LL1break = 3, LL2break = 4, SW1breakUP = 5
, SW2breakUP = 6, tpUP1 = 7, tpUP2 = 8, tpUP3 = 9, BB_endBl =10
BB_min =11, signDN =12, cnclDN =13, HH1break =14, HH2break =15, SW1breakDN =16
, SW2breakDN =17, tpDN1 =18, tpDN2 =19, tpDN3 =20, BB_endBr =21

signals =
array.from(
false // BBplus
, false // signUP
, false // cnclUP
, false // LL1break
, false // LL2break
, false // SW1breakUP
, false // SW2breakUP
, false // tpUP1
, false // tpUP2
, false // tpUP3
, false // BB_endBl
, false // BB_min
, false // signDN
, false // cnclDN
, false // HH1break
, false // HH2break
, false // SW1breakDN
, false // SW2breakDN
, false // tpDN1
, false // tpDN2
, false // tpDN3
, false // BB_endBr
)

var block [] aBlockBl = array.new< block >( )


var block [] aBlockBr = array.new< block >( )

var ZZ aZZ =
ZZ.new(
array.new < int >(mCxSize, 0),
array.new < int >(mCxSize, 0),
array.new < float >(mCxSize, na),
array.new < line >(mCxSize, na),
array.new < bool >(mCxSize, na))

var mss MSS = mss.new(


0
, array.new < line >()
, array.new < line >()
, array.new < line >()
, array.new < line >()
, array.new < label >()
, array.new < label >()
, array.new < label >()
, array.new < label >()
)

var block BB = block.new(


BB_boxA = box.new (na, na, na, na, border_color=color(na))
, BB_boxB = box.new (na, na, na, na, border_color=color(na)
, text_size=size.small
, text_halign=text.align_right
, text_font_family=font.family_monospace
)
, BB_line = line.new (na, na, na, na
, style=line.style_dashed
, color=color.silver
)
, PDa_box1 = box.new (na, na, na, na, border_color=color(na))
, PDaLine1 = line.new (na, na, na, na, color=PDSCss)
, PDaLab_1 = label.new(na, na, color=color(na))
, PDa_box2 = box.new (na, na, na, na, border_color=color(na))
, PDaLine2 = line.new (na, na, na, na, color=PDSCss)
, PDaLab_2 = label.new(na, na, color=color(na))
, line_1 = line.new (na, na, na, na, color=PDSCss)
, line_2 = line.new (na, na, na, na, color=PDSCss)
, TP1_line = line.new (na, na, na, na, color=tpCss)
, TP2_line = line.new (na, na, na, na, color=tpCss)
, TP3_line = line.new (na, na, na, na, color=tpCss)
, HL = label.new(na, na, color=color(na)
, textcolor=PDtxtCss
, yloc=yloc.price
)
, aLabels = array.new<label>(1, label(na))
)

//-----------------------------------------------------------------------------}
//Functions/methods
//-----------------------------------------------------------------------------{
method in_out(ZZ aZZ, int d, int x1, float y1, int x2, float y2, color col, bool b)
=>
aZZ.d.unshift(d), aZZ.x.unshift(x2), aZZ.y.unshift(y2), aZZ.b.unshift(b),
aZZ.d.pop(), aZZ.x.pop(), aZZ.y.pop(), aZZ.b.pop()
if shZZ
aZZ.l.unshift(line.new(x1, y1, x2, y2, color= col)), aZZ.l.pop().delete()

method io_box(box[] aB, box b) => aB.unshift(b), aB.pop().delete()

method setLine(line ln, int x1, float y1, int x2, float y2) => ln.set_xy1(x1, y1),
ln.set_xy2(x2, y2)

method notransp(color css) => color.rgb(color.r(css), color.g(css), color.b(css))

createLab(string s, float y, color c, string t, string sz = size.small) =>


label.new(n
, y
, style=s == 'c' ? label.style_label_center
: s == 'u' ? label.style_label_up
: label.style_label_down
, textcolor=c
, color=color(na)
, size=sz
, text=t
)

draw(left, col) =>

max_bars_back(time, 1000)
var int dir= na, var int x1= na, var float y1= na, var int x2= na, var float
y2= na

sz = aZZ.d.size( )
x2 := bar_index -1
ph = ta.pivothigh(hi, left, 1)
pl = ta.pivotlow (lo, left, 1)
if ph
dir := aZZ.d.get (0)
x1 := aZZ.x.get (0)
y1 := aZZ.y.get (0)
y2 := nz(hi[1])

if dir < 1 // if previous point was a pl, add, and change direction ( 1)
aZZ.in_out( 1, x1, y1, x2, y2, col, true)
else
if dir == 1 and ph > y1
aZZ.x.set(0, x2), aZZ.y.set(0, y2)
if shZZ
aZZ.l.get(0).set_xy2(x2, y2)

if pl
dir := aZZ.d.get (0)
x1 := aZZ.x.get (0)
y1 := aZZ.y.get (0)
y2 := nz(lo[1])

if dir > -1 // if previous point was a ph, add, and change direction (-1)
aZZ.in_out(-1, x1, y1, x2, y2, col, true)
else
if dir == -1 and pl < y1
aZZ.x.set(0, x2), aZZ.y.set(0, y2)
if shZZ
aZZ.l.get(0).set_xy2(x2, y2)

iH = aZZ.d.get(2) == 1 ? 2 : 1
iL = aZZ.d.get(2) == -1 ? 2 : 1

switch
// MSS Bullish
close > aZZ.y.get(iH) and aZZ.d.get(iH) == 1 and MSS.dir < 1 and per =>

Ex = aZZ.x.get(iH -1), Ey = aZZ.y.get(iH -1)


Dx = aZZ.x.get(iH ), Dy = aZZ.y.get(iH ), DyMx = mx[n - Dx]
Cx = aZZ.x.get(iH +1), Cy = aZZ.y.get(iH +1)
Bx = aZZ.x.get(iH +2), By = aZZ.y.get(iH +2), ByMx = mx[n - Bx]
Ax = aZZ.x.get(iH +3), Ay = aZZ.y.get(iH +3), AyMn = mn[n - Ax]
_y = math.max(ByMx, DyMx)
mid = AyMn + ((_y - AyMn) / 2) // 50% fib A- min(B, D)
isOK = onlyWhenInPDarray ? Ay < Cy and Ay < Ey and Ey < mid : true

float green1prT = na
float green1prB = na
float avg = na

if Ey < Cy and Cx != Dx and isOK


// latest HH to 1 HH further -> search first green bar
for i = n - Dx to n - Cx
if close[i] > open[i]
// reset previous swing box's
BB.PDa_box1.set_lefttop(na, na), BB.PDaLine1.set_xy1(na,
na), BB.PDaLab_1.set_xy(na, na)
BB.PDa_box2.set_lefttop(na, na), BB.PDaLine2.set_xy1(na,
na), BB.PDaLab_2.set_xy(na, na)

green1idx = n - i
green1prT := breakerCandleOnlyBody ? mx[i] : high[i]
green1prB := breakerCandleOnlyBody ? mn[i] : low [i]
if breakerCandle_2Last
if close[i +1] > open[i +1]
green2prT = breakerCandleOnlyBody ? mx[i +1] :
high[i +1]
green2prB = breakerCandleOnlyBody ? mn[i +1] : low
[i +1]
if green2prT > green1prT or green2prB < green1prB
green1idx -= 1
green1prT := math.max(green1prT, green2prT)
green1prB := math.min(green1prB, green2prB)

// Breaker Block +
avg := math.avg(green1prB, green1prT)
while BB.aLabels.size() > 0
BB.aLabels.pop().delete()
BB.PDa_boxA.delete(), BB.PDa_boxB.delete(), BB.dir := 1
BB.BB_boxA.set_left (green1idx)
BB.BB_boxA.set_top (green1prT)
BB.BB_boxA.set_right ( n )
BB.BB_boxA.set_bottom (green1prB)
BB.BB_boxA.set_bgcolor(cBBplusA )

BB.BB_boxB.set_left ( n )
BB.BB_boxB.set_top (green1prT)
BB.BB_boxB.set_right ( n + 8)
BB.BB_boxB.set_bottom (green1prB)
BB.BB_boxB.set_bgcolor(cBBplusB )
BB.BB_boxB.set_text('+BB')
BB.BB_boxB.set_text_color(cBBplusB.notransp())
BB.BB_boxB.set_text_valign(text.align_bottom)

BB.BB_line.set_xy1(n, avg), BB.BB_line.set_xy2(n , avg)

if showSPD
BB.line_1.set_xy1(Cx, Cy), BB.line_1.set_xy2(n , Cy),
BB.Broken_1 := false
BB.line_2.set_xy1(Ex, Ey), BB.line_2.set_xy2(n , Ey),
BB.Broken_2 := false
BB.HL.set_xy(Ex, Ey),
BB.HL.set_style(label.style_label_up), BB.HL.set_text('LL')

BB.TP1_hit := false
BB.TP2_hit := false
BB.TP3_hit := false
BB.Broken := false
BB.Mitigated := false
BB.scalp := false
BB.PDbroken1 := false
BB.PDbroken2 := false

if onlyWhenInPDarray and showPDarray


BB.PDa_boxA := box.new(Ax, mid, Ex +1, AyMn,
bgcolor=color.rgb(132, 248, 171, 90), border_color=color(na)
, text = 'Discount PD Array', text_size = size.small,
text_color = color.rgb(132, 248, 171, 25)
, text_halign = text.align_right, text_valign =
text.align_center, text_font_family = font.family_monospace) // , text_wrap=
text.wrap_auto
BB.PDa_boxB := box.new(Ax, _y, Ex +1, mid,
bgcolor=color.rgb(248, 153, 132, 90), border_color=color(na))
// Previous swings
cnt = 0, hh1 = high
for c = 0 to sz -2
getX = aZZ.x.get(c)
getY = aZZ.y.get(c)
if getY > hh1 and aZZ.d.get(c) == 1 and showSPD
getY2 = (high[n - getX] - mn[n - getX]) / 4
switch cnt
0 =>
BB.PDa_box1.set_lefttop (getX,
getY )
BB.PDaLine1.set_xy1 (getX,
getY )
BB.PDa_box1.set_rightbottom(n , getY -
getY2)
BB.PDaLine1.set_xy2 (n , getY
)
BB.PDa_box1.set_bgcolor ( cSwingBl
)
BB.PDaLab_1.set_xy ( getX,
getY )
BB.PDaLab_1.set_size
( size.small )
BB.PDaLab_1.set_textcolor ( PDtxtCss )
BB.PDaLab_1.set_text ('Premium PD
Array')

BB.PDaLab_1.set_style(label.style_label_lower_left)
cnt := 1
hh1 := getY
1 =>
if getY - getY2 > hh1
BB.PDa_box2.set_lefttop (getX,
getY )
BB.PDaLine2.set_xy1 (getX,
getY )
BB.PDa_box2.set_rightbottom(n , getY
- getY2)
BB.PDaLine2.set_xy2 (n , getY
)
BB.PDa_box2.set_bgcolor
( cSwingBl )
BB.PDaLab_2.set_xy
( getX, getY )
BB.PDaLab_2.set_size
( size.small )
BB.PDaLab_2.set_textcolor
( PDtxtCss )
BB.PDaLab_2.set_text ('Premium PD
Array')

BB.PDaLab_2.set_style(label.style_label_lower_left)
cnt := 2
if cnt == 2
break

I = green1prT - green1prB
E1 = green1prT + (I * R2a / R1a)
E2 = green1prT + (I * R2b / R1b)
E3 = green1prT + (I * R2c / R1c)

if iTP
if not BB.TP1_hit
BB.TP1_line.set_xy1(n, E1)
BB.TP1_line.set_xy2(n + 20, E1)
if not BB.TP2_hit
BB.TP2_line.set_xy1(n, E2)
BB.TP2_line.set_xy2(n + 20, E2)
if not BB.TP3_hit
BB.TP3_line.set_xy1(n, E3)
BB.TP3_line.set_xy2(n + 20, E3)

signals.set(BBplus, true)
alert('+BB', alert.freq_once_per_bar_close)
BB.aLabels.unshift(createLab('u', low, cBBplusB.notransp(),
_arrowup, size.large))

break

MSS.dir := 1

// MSS Bearish
close < aZZ.y.get(iL) and aZZ.d.get(iL) == -1 and MSS.dir > -1 and per =>
Ex = aZZ.x.get(iL -1), Ey = aZZ.y.get(iL -1)
Dx = aZZ.x.get(iL ), Dy = aZZ.y.get(iL ), DyMn = mn[n - Dx]
Cx = aZZ.x.get(iL +1), Cy = aZZ.y.get(iL +1)
Bx = aZZ.x.get(iL +2), By = aZZ.y.get(iL +2), ByMn = mn[n - Bx]
Ax = aZZ.x.get(iL +3), Ay = aZZ.y.get(iL +3), AyMx = mx[n - Ax]
_y = math.min(ByMn, DyMn)
//_x = _y == ByMn ? Bx : Dx
mid = AyMx - ((AyMx - _y) / 2) // 50% fib A- min(B, D)
isOK = onlyWhenInPDarray ? Ay > Cy and Ay > Ey and Ey > mid : true
//
float red_1_prT = na
float red_1_prB = na
float avg = na
if Ey > Cy and Cx != Dx and isOK
// latest LL to LL further -> search first red bar
for i = n - Dx to n - Cx
if close[i] < open[i]
// reset previous swing box's
BB.PDa_box1.set_lefttop(na, na), BB.PDaLine1.set_xy1(na,
na), BB.PDaLab_1.set_xy(na, na)
BB.PDa_box2.set_lefttop(na, na), BB.PDaLine2.set_xy1(na,
na), BB.PDaLab_2.set_xy(na, na)

red_1_idx = n - i
red_1_prT := breakerCandleOnlyBody ? mx[i] : high[i]
red_1_prB := breakerCandleOnlyBody ? mn[i] : low [i]
if breakerCandle_2Last
if close[i +1] < open[i +1]
red_2_prT = breakerCandleOnlyBody ? mx[i +1] :
high[i +1]
red_2_prB = breakerCandleOnlyBody ? mn[i +1] : low
[i +1]
if red_2_prT > red_1_prT or red_2_prB < red_1_prB
red_1_idx -= 1
red_1_prT := math.max(red_1_prT, red_2_prT)
red_1_prB := math.min(red_1_prB, red_2_prB)

// Breaker Block -
avg := math.avg(red_1_prB, red_1_prT)
while BB.aLabels.size() > 0
BB.aLabels.pop().delete()
BB.PDa_boxA.delete(), BB.PDa_boxB.delete(), BB.dir := -1
BB.BB_boxA.set_left (red_1_idx)
BB.BB_boxA.set_top (red_1_prT)
BB.BB_boxA.set_right ( n )
BB.BB_boxA.set_bottom (red_1_prB)
BB.BB_boxA.set_bgcolor(cBB_minA )

BB.BB_boxB.set_left (n)
BB.BB_boxB.set_top (red_1_prT)
BB.BB_boxB.set_right ( n + 8)
BB.BB_boxB.set_bottom (red_1_prB)
BB.BB_boxB.set_bgcolor(cBB_minB )
BB.BB_boxB.set_text('-BB')
BB.BB_boxB.set_text_color(cBB_minB.notransp())
BB.BB_boxB.set_text_valign(text.align_top)

BB.BB_line.set_xy1(n, avg), BB.BB_line.set_xy2(n , avg)

if showSPD
BB.line_1.set_xy1(Cx, Cy), BB.line_1.set_xy2(n , Cy),
BB.Broken_1 := false
BB.line_2.set_xy1(Ex, Ey), BB.line_2.set_xy2(n , Ey),
BB.Broken_2 := false
BB.HL.set_xy(Ex, Ey),
BB.HL.set_style(label.style_label_down), BB.HL.set_text('HH'),
BB.HL.set_textcolor(PDtxtCss)

BB.TP1_hit := false
BB.TP2_hit := false
BB.TP3_hit := false
BB.Broken := false
BB.Mitigated := false
BB.scalp := false
BB.PDbroken1 := false
BB.PDbroken2 := false

if onlyWhenInPDarray and showPDarray


BB.PDa_boxA := box.new(Ax, AyMx, Ex +1, mid,
bgcolor=color.rgb(248, 153, 132, 90), border_color=color(na)
, text = 'Premium PD Array', text_size = size.small,
text_color = color.rgb(248, 153, 132, 25)
, text_halign = text.align_right, text_valign =
text.align_center, text_font_family = font.family_monospace) // , text_wrap=
text.wrap_auto
BB.PDa_boxB := box.new(Ax, mid , Ex +1, _y,
bgcolor=color.rgb(132, 248, 171, 90), border_color=color(na))

// Previous swings
cnt = 0, ll1 = low
for c = 0 to sz -2
getX = aZZ.x.get(c)
getY = aZZ.y.get(c)
if getY < ll1 and aZZ.d.get(c) == -1 and showSPD
getY2 = (mx[n - getX] - low[n - getX]) / 4
switch cnt
0 =>
BB.PDa_box1.set_lefttop (getX, getY +
getY2)
BB.PDaLine1.set_xy1 (getX,
getY )
BB.PDa_box1.set_rightbottom( n ,
getY )
BB.PDaLine1.set_xy2 ( n ,
getY )
BB.PDa_box1.set_bgcolor ( cSwingBr
)
BB.PDaLab_1.set_xy ( getX,
getY )
BB.PDaLab_1.set_size
( size.small )
BB.PDaLab_1.set_textcolor ( PDtxtCss )
BB.PDaLab_1.set_text ('Discount PD
Array')

BB.PDaLab_1.set_style(label.style_label_upper_left)

cnt := 1
ll1 := getY
1 =>
if getY + getY2 < ll1
BB.PDa_box2.set_lefttop (getX, getY
+ getY2)
BB.PDaLine2.set_xy1 (getX,
getY )

BB.PDa_box2.set_rightbottom( n , getY )
BB.PDaLine2.set_xy2
( n , getY )
BB.PDa_box2.set_bgcolor
( cSwingBr )
BB.PDaLab_2.set_xy
( getX, getY )
BB.PDaLab_2.set_size
( size.small )
BB.PDaLab_2.set_textcolor
( PDtxtCss )
BB.PDaLab_2.set_text ('Discount PD
Array')

BB.PDaLab_2.set_style(label.style_label_upper_left)
cnt := 2
if cnt == 2
break

I = red_1_prT - red_1_prB
E1 = red_1_prB - (I * R2a / R1a)
E2 = red_1_prB - (I * R2b / R1b)
E3 = red_1_prB - (I * R2c / R1c)

if iTP
if not BB.TP1_hit
BB.TP1_line.set_xy1(n, E1)
BB.TP1_line.set_xy2(n + 20, E1)
if not BB.TP2_hit
BB.TP2_line.set_xy1(n, E2)
BB.TP2_line.set_xy2(n + 20, E2)
if not BB.TP3_hit
BB.TP3_line.set_xy1(n, E3)
BB.TP3_line.set_xy2(n + 20, E3)

signals.set(BB_min, true)
alert('-BB', alert.freq_once_per_bar_close)
BB.aLabels.unshift(createLab('d', high,
cBB_minB.notransp(), _arrowdn, size.large))

break

MSS.dir := -1

//-----------------------------------------------------------------------------}
//Calculations
//-----------------------------------------------------------------------------{
draw(len, tpCss)

lft = BB.BB_boxB.get_left ()
top = BB.BB_boxB.get_top ()
btm = BB.BB_boxB.get_bottom()
avg = BB.BB_line.get_y2 ()
l_1 = BB.line_1.get_y2 ()
l_2 = BB.line_2.get_y2 ()
TP1 = BB.TP1_line.get_y2 ()
TP2 = BB.TP2_line.get_y2 ()
TP3 = BB.TP3_line.get_y2 ()

switch BB.dir
1 =>
if not BB.Mitigated
if close < btm
BB.Mitigated := true
signals.set(BB_endBl, true)
alert('+BB Mitigated', alert.freq_once_per_bar_close)

BB.aLabels.unshift(createLab('u', low, color.yellow, _c))

BB.BB_boxB.set_right(n)
BB.BB_line.set_x2 (n)
else
BB.BB_boxB.set_right(n + 8)
BB.BB_line.set_x2 (n + 8)

BB.TP1_line.set_x2 (n)
BB.TP2_line.set_x2 (n)
BB.TP3_line.set_x2 (n)

if n > BB.BB_boxB.get_left()
if not BB.Broken
if BB.scalp
if not BB.TP1_hit and open < TP1 and high > TP1
BB.TP1_hit := true
signals.set(tpUP1, true)
alert('TP UP 1', alert.freq_once_per_bar)
BB.aLabels.unshift(createLab('c', TP1, #ff00dd, _c))
if not BB.TP2_hit and open < TP2 and high > TP2
BB.TP2_hit := true
signals.set(tpUP2, true)
alert('TP UP 2', alert.freq_once_per_bar)
BB.aLabels.unshift(createLab('c', TP2, #ff00dd, _c))
if not BB.TP3_hit and open < TP3 and high > TP3
BB.TP3_hit := true
signals.set(tpUP3, true)
alert('TP UP 3', alert.freq_once_per_bar)
BB.aLabels.unshift(createLab('c', TP3, #ff00dd, _c))
switch
open > avg and open < top and close > top =>
BB.TP1_hit := false
BB.TP2_hit := false
BB.TP3_hit := false
BB.scalp := true
signals.set(signUP, true)
alert('signal UP', alert.freq_once_per_bar_close)
BB.aLabels.unshift(createLab('u', low, color.lime,
_arrowup, size.normal))
close < avg and close > btm =>
BB.Broken := true
BB.scalp := false
signals.set(cnclUP, true)
alert('cancel UP', alert.freq_once_per_bar_close)
BB.aLabels.unshift(createLab('u', low, color.orange,
_x))
else
// reset
if not tillFirstBreak and close > top
BB.Broken := false
BB.scalp := true
signals.set(BBplus, true)
alert('+BB (R)', alert.freq_once_per_bar_close)
BB.aLabels.unshift(createLab('u', low, color.blue, 'R',
size.normal))

if not BB.Broken_1
BB.line_1.set_x2(n)
if close < l_1
BB.Broken_1 := true
signals.set(LL1break, true)
alert('LL 1 break', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('c', low, #c00000, _c))
if not BB.Broken_2
BB.line_2.set_x2(n)
if close < l_2
BB.Broken_2 := true
signals.set(LL2break, true)
alert('LL 2 break', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('c', low, #c00000, _c))

if not BB.PDbroken1
BB.PDa_box1.set_right(n)
BB.PDaLine1.set_x2 (n)
if close > BB.PDa_box1.get_top() and n > BB.PDa_box1.get_left()
BB.PDbroken1 := true
signals.set(SW1breakUP, true)
alert('Swing UP 1 break', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('c', high, #c00000, _c))
if not BB.PDbroken2
BB.PDa_box2.set_right(n)
BB.PDaLine2.set_x2 (n)
if close > BB.PDa_box2.get_top() and n > BB.PDa_box2.get_left()
BB.PDbroken2 := true
signals.set(SW2breakUP, true)
alert('Swing UP 2 break', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('c', high, #c00000, _c))

-1 =>
if not BB.Mitigated
if close > top
BB.Mitigated := true
signals.set(BB_endBr, true)
alert('-BB Mitigated', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('d', high, cBB_minB.notransp(),
_c))
BB.BB_boxB.set_right(n)
BB.BB_line.set_x2 (n)
else
BB.BB_boxB.set_right(n + 8)
BB.BB_line.set_x2 (n + 8)

BB.TP1_line.set_x2 (n)
BB.TP2_line.set_x2 (n)
BB.TP3_line.set_x2 (n)

if n > BB.BB_boxB.get_left()
if not BB.Broken
if BB.scalp
if not BB.TP1_hit and open > TP1 and low < TP1
BB.TP1_hit := true
signals.set(tpDN1, true)
alert('TP DN 1', alert.freq_once_per_bar)
BB.aLabels.unshift(createLab('c', TP1, #ff00dd, _c))
if not BB.TP2_hit and open > TP2 and low < TP2
BB.TP2_hit := true
signals.set(tpDN2, true)
alert('TP DN 2', alert.freq_once_per_bar)
BB.aLabels.unshift(createLab('c', TP2, #ff00dd, _c))
if not BB.TP3_hit and open > TP3 and low < TP3
BB.TP3_hit := true
signals.set(tpDN3, true)
alert('TP DN 3', alert.freq_once_per_bar)
BB.aLabels.unshift(createLab('c', TP3, #ff00dd, _c))
switch
open < avg and open > btm and close < btm =>
BB.TP1_hit := false
BB.TP2_hit := false
BB.TP3_hit := false
BB.scalp := true
signals.set(signDN, true)
alert('signal DN', alert.freq_once_per_bar_close)
BB.aLabels.unshift(createLab('d', high, color.orange,
_arrowdn, size.normal))
close > avg and close < top =>
BB.Broken := true
BB.scalp := false
signals.set(cnclDN, true)
alert('cancel DN', alert.freq_once_per_bar_close)
BB.aLabels.unshift(createLab('d', high, color.red ,
_x))
else
// reset
if not tillFirstBreak and close < btm
BB.Broken := false
BB.scalp := true
signals.set(BB_min, true)
alert('-BB (R)', alert.freq_once_per_bar_close)
BB.aLabels.unshift(createLab('d', high, color.blue, 'R',
size.normal))

if not BB.Broken_1
BB.line_1.set_x2(n)
if close > l_1
BB.Broken_1 := true
signals.set(HH1break, true)
alert('HH 1 break', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('c', high, #c00000, _c))
if not BB.Broken_2
BB.line_2.set_x2(n)
if close > l_2
BB.Broken_2 := true
signals.set(HH2break, true)
alert('HH 2 break', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('c', high, #c00000, _c))

if not BB.PDbroken1
BB.PDa_box1.set_right(n)
BB.PDaLine1.set_x2 (n)
if close < BB.PDa_box1.get_bottom() and n > BB.PDa_box1.get_left()
BB.PDbroken1 := true
signals.set(SW1breakDN, true)
alert('Swing DN 1 break', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('c', low, #c00000, _c))
if not BB.PDbroken2
BB.PDa_box2.set_right(n)
BB.PDaLine2.set_x2 (n)
if close < BB.PDa_box2.get_bottom() and n > BB.PDa_box2.get_left()
BB.PDbroken2 := true
signals.set(SW2breakDN, true)
alert('Swing DN 2 break', alert.freq_once_per_bar_close)
if showBreaks
BB.aLabels.unshift(createLab('c', low, #c00000, _c))
}

// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0


International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo

//@version=5
//ndicator("Buyside & Sellside Liquidity [LuxAlgo]", "LuxAlgo - Buyside & Sellside
Liquidity", overlay = true, max_lines_count = 500, max_boxes_count = 500,
max_bars_back = 3000)
//------------------------------------------------------------------------------
//Settings
//-----------------------------------------------------------------------------{
liqGrp = 'Liquidity Detection'
liqLen = input.int (7, title = 'Detection Length', minval = 3, maxval = 13,
inline = 'LIQ', group = liqGrp)
liqMar = 10 / input.float (6.9, 'Margin', minval = 4, maxval = 9, step = 0.1,
inline = 'LIQ', group = liqGrp)

liqBuy = input.bool (true, 'Buyside Liquidity Zones, Margin', inline = 'Buyside',


group = liqGrp)
marBuy = input.float(2.3, '', minval = 1.5, maxval = 10, step = .1, inline =
'Buyside', group = liqGrp)
cLIQ_B = input.color (color.new(#4caf50, 0), '', inline = 'Buyside', group =
liqGrp)

liqSel = input.bool (true, 'Sellside Liquidity Zones, Margin', inline = 'Sellside',


group = liqGrp)
marSel = input.float(2.3, '', minval = 1.5, maxval = 10, step = .1, inline =
'Sellside', group = liqGrp)
cLIQ_S = input.color (color.new(#f23645, 0), '', inline = 'Sellside', group =
liqGrp)

lqVoid = input.bool (false, 'Liquidity Voids, Bullish', inline = 'void', group =


liqGrp)
cLQV_B = input.color (color.new(#4caf50, 0), '', inline = 'void', group = liqGrp)
cLQV_S = input.color (color.new(#f23645, 0), 'Bearish', inline = 'void', group =
liqGrp)
lqText = input.bool (false, 'Label', inline = 'void', group = liqGrp)

mode = input.string('Present', title = 'Mode', options =['Present',


'Historical'], inline = 'MOD', group = liqGrp)
visLiq = input.int (3, ' # Visible Levels', minval = 1, maxval = 50, inline =
'MOD', group = liqGrp)

//-----------------------------------------------------------------------------}
//General Calculations
//-----------------------------------------------------------------------------{
maxSize = 50
atr = ta.atr(10)
atr200 = ta.atr(200)
per = mode == 'Present' ? last_bar_index - bar_index <= 500 : true

//-----------------------------------------------------------------------------}
//User Defined Types
//-----------------------------------------------------------------------------{
// @type used to store pivot high/low data
//
// @field d (array<int>) The array where the trend direction is to be
maintained
// @field x (array<int>) The array where the bar index value of pivot high/low
is to be maintained
// @field y (array<float>) The array where the price value of pivot high/low is
to be maintained

type ZZ
int [] d
int [] x
float [] y

// @type bar properties with their values


//
// @field o (float) open price of the bar
// @field h (float) high price of the bar
// @field l (float) low price of the bar
// @field c (float) close price of the bar
// @field i (int) index of the bar

type bar
float o = open
float h = high
float l = low
float c = close
int i = bar_index

// @type liquidity object definition


//
// @field bx (box) box maitaing the liquity level margin extreme levels
// @field bxz (box) box maitaing the liquity zone margin extreme levels
// @field bxt (box) box maitaing the labels
// @field brZ (bool) mainains broken zone status
// @field brL (bool) mainains broken level status
// @field ln (line) maitaing the liquity level line
// @field lne (line) maitaing the liquity extended level line

type liq
box bx
box bxz
box bxt
bool brZ
bool brL
line ln
line lne

//-----------------------------------------------------------------------------}
//Variables
//-----------------------------------------------------------------------------{
var ZZ aZZ = ZZ.new(
array.new <int> (maxSize, 0),
array.new <int> (maxSize, 0),
array.new <float>(maxSize, na)
)

bar b = bar.new()

var liq[] b_liq_B = array.new<liq> (1, liq.new(box(na), box(na), box(na), false,


false, line(na), line(na)))
var liq[] b_liq_S = array.new<liq> (1, liq.new(box(na), box(na), box(na), false,
false, line(na), line(na)))

var b_liq_V = array.new_box()


var int dir = na, var int x1 = na, var float y1 = na, var int x2 = na, var float y2
= na

//-----------------------------------------------------------------------------}
//Functions/methods
//-----------------------------------------------------------------------------{
// @function maintains arrays
// it prepends a `value` to the arrays and removes their oldest
element at last position
// @param aZZ (UDT<array<int>, array<int>, array<float>>) The UDT obejct of
arrays
// @param _d (array<int>) The array where the trend direction is maintained
// @param _x (array<int>) The array where the bar index value of pivot
high/low is maintained
// @param _y (array<float>) The array where the price value of pivot
high/low is maintained
//
// @returns none

method in_out(ZZ aZZ, int _d, int _x, float _y) =>
aZZ.d.unshift(_d), aZZ.x.unshift(_x), aZZ.y.unshift(_y), aZZ.d.pop(),
aZZ.x.pop(), aZZ.y.pop()

// @function (build-in) sets the maximum number of bars that is available


for historical reference

max_bars_back(time, 1000)

//-----------------------------------------------------------------------------}
//Calculations
//-----------------------------------------------------------------------------{
x2 := b.i - 1
ph = ta.pivothigh(liqLen, 1)
pl = ta.pivotlow (liqLen, 1)

if ph
dir := aZZ.d.get(0)
x1 := aZZ.x.get(0)
y1 := aZZ.y.get(0)
y2 := nz(b.h[1])

if dir < 1
aZZ.in_out(1, x2, y2)
else
if dir == 1 and ph > y1
aZZ.x.set(0, x2), aZZ.y.set(0, y2)

if per
count = 0
st_P = 0.
st_B = 0
minP = 0.
maxP = 10e6

for i = 0 to maxSize - 1
if aZZ.d.get(i) == 1
if aZZ.y.get(i) > ph + (atr / liqMar)
break
else
if aZZ.y.get(i) > ph - (atr / liqMar) and aZZ.y.get(i) < ph +
(atr / liqMar)
count += 1
st_B := aZZ.x.get(i)
st_P := aZZ.y.get(i)
if aZZ.y.get(i) > minP
minP := aZZ.y.get(i)
if aZZ.y.get(i) < maxP
maxP := aZZ.y.get(i)

if count > 2
getB = b_liq_B.get(0)

if st_B == getB.bx.get_left()
getB.bx.set_top(math.avg(minP, maxP) + (atr / liqMar))
getB.bx.set_rightbottom(b.i + 10, math.avg(minP, maxP) - (atr /
liqMar))
else
b_liq_B.unshift(
liq.new(
box.new(st_B, math.avg(minP, maxP) + (atr / liqMar), b.i + 10,
math.avg(minP, maxP) - (atr / liqMar), bgcolor=color(na), border_color=color(na)),
box.new(na, na, na, na, bgcolor = color(na), border_color =
color(na)),
box.new(st_B, st_P, b.i + 10, st_P, text = 'Buyside liquidity',
text_size = size.tiny, text_halign = text.align_left, text_valign =
text.align_bottom, text_color = color.new(cLIQ_B, 25), bgcolor = color(na),
border_color = color(na)),
false,
false,
line.new(st_B , st_P, b.i - 1, st_P, color = color.new(cLIQ_B,
0)),
line.new(b.i - 1, st_P, na , st_P, color = color.new(cLIQ_B,
0), style = line.style_dotted))
)

alert('buyside liquidity level detected/updated for ' +


syminfo.ticker)

if b_liq_B.size() > visLiq


getLast = b_liq_B.pop()
getLast.bx.delete()
getLast.bxz.delete()
getLast.bxt.delete()
getLast.ln.delete()
getLast.lne.delete()

if pl
dir := aZZ.d.get (0)
x1 := aZZ.x.get (0)
y1 := aZZ.y.get (0)
y2 := nz(b.l[1])

if dir > -1
aZZ.in_out(-1, x2, y2)
else
if dir == -1 and pl < y1
aZZ.x.set(0, x2), aZZ.y.set(0, y2)

if per
count = 0
st_P = 0.
st_B = 0
minP = 0.
maxP = 10e6

for i = 0 to maxSize - 1
if aZZ.d.get(i) == -1
if aZZ.y.get(i) < pl - (atr / liqMar)
break
else
if aZZ.y.get(i) > pl - (atr / liqMar) and aZZ.y.get(i) < pl +
(atr / liqMar)
count += 1
st_B := aZZ.x.get(i)
st_P := aZZ.y.get(i)
if aZZ.y.get(i) > minP
minP := aZZ.y.get(i)
if aZZ.y.get(i) < maxP
maxP := aZZ.y.get(i)

if count > 2
getB = b_liq_S.get(0)

if st_B == getB.bx.get_left()
getB.bx.set_top(math.avg(minP, maxP) + (atr / liqMar))
getB.bx.set_rightbottom(b.i + 10, math.avg(minP, maxP) - (atr /
liqMar))
else
b_liq_S.unshift(
liq.new(
box.new(st_B, math.avg(minP, maxP) + (atr / liqMar), b.i + 10,
math.avg(minP, maxP) - (atr / liqMar), bgcolor=color(na), border_color=color(na)),
box.new(na, na, na, na, bgcolor=color(na),
border_color=color(na)),
box.new(st_B, st_P, b.i + 10, st_P, text = 'Sellside liquidity',
text_size = size.tiny, text_halign = text.align_left, text_valign = text.align_top,
text_color = color.new(cLIQ_S, 25), bgcolor=color(na), border_color=color(na)),
false,
false,
line.new(st_B , st_P, b.i - 1, st_P, color = color.new(cLIQ_S,
0)),
line.new(b.i - 1, st_P, na , st_P, color = color.new(cLIQ_S,
0), style = line.style_dotted))
)

alert('sellside liquidity level detected/updated for ' +


syminfo.ticker)

if b_liq_S.size() > visLiq


getLast = b_liq_S.pop()
getLast.bx.delete()
getLast.bxz.delete()
getLast.bxt.delete()
getLast.ln.delete()
getLast.lne.delete()
for i = 0 to b_liq_B.size() - 1
x = b_liq_B.get(i)

if not x.brL
x.lne.set_x2(b.i)

if b.h > x.bx.get_top()


x.brL := true
x.brZ := true
alert('buyside liquidity level breached for ' + syminfo.ticker)

x.bxz.set_lefttop(b.i - 1, math.min(x.ln.get_y1() + marBuy * (atr),


b.h))
x.bxz.set_rightbottom(b.i + 1, x.ln.get_y1())
x.bxz.set_bgcolor(color.new(cLIQ_B, liqBuy ? 73 : 100))

else if x.brZ
if b.l > x.ln.get_y1() - marBuy * (atr) and b.h < x.ln.get_y1() + marBuy *
(atr)
x.bxz.set_right(b.i + 1)
x.bxz.set_top(math.max(b.h, x.bxz.get_top()))
if liqBuy
x.lne.set_x2(b.i + 1)
else
x.brZ := false

for i = 0 to b_liq_S.size() - 1
x = b_liq_S.get(i)

if not x.brL
x.lne.set_x2(b.i)

if b.l < x.bx.get_bottom()


x.brL := true
x.brZ := true
alert('sellside liquidity level breached for ' + syminfo.ticker)

x.bxz.set_lefttop(b.i - 1, x.ln.get_y1())
x.bxz.set_rightbottom(b.i + 1, math.max(x.ln.get_y1() - marSel * (atr),
b.l))
x.bxz.set_bgcolor(color.new(cLIQ_S, liqSel ? 73 : 100))

else if x.brZ
if b.l > x.ln.get_y1() - marSel * (atr) and b.h < x.ln.get_y1() + marSel *
(atr)
x.bxz.set_rightbottom(b.i + 1, math.min(b.l, x.bxz.get_bottom()))
if liqSel
x.lne.set_x2(b.i + 1)
else
x.brZ := false

if lqVoid and per


bull = b.l - b.h[2] > atr200 and b.l > b.h[2] and b.c[1] > b.h[2]
bear = b.l[2] - b.h > atr200 and b.h < b.l[2] and b.c[1] < b.l[2]

if bull
l = 13
if bull[1]
st = math.abs(b.l - b.l[1]) / l
for i = 0 to l - 1
array.push(b_liq_V, box.new(b.i - 2, b.l[1] + i * st, b.i, b.l[1] +
(i + 1) * st, border_color = na, bgcolor = color.new(cLQV_B, 90) ))
else
st = math.abs(b.l - b.h[2]) / l
for i = 0 to l - 1
if lqText and i == 0
array.push(b_liq_V, box.new(b.i - 2, b.h[2] + i * st, b.i,
b.h[2] + (i + 1) * st, text = 'Liquidity Void ', text_size = size.tiny,
text_halign = text.align_right, text_valign = text.align_bottom, text_color = na,
border_color = na, bgcolor = color.new(cLQV_B, 90) ))
else
array.push(b_liq_V, box.new(b.i - 2, b.h[2] + i * st, b.i,
b.h[2] + (i + 1) * st, border_color = na, bgcolor = color.new(cLQV_B, 90) ))

if bear
l = 13
if bear[1]
st = math.abs(b.h[1] - b.h) / l
for i = 0 to l - 1
array.push(b_liq_V, box.new(b.i - 2, b.h + i * st, b.i, b.h + (i +
1) * st, border_color = na, bgcolor = color.new(cLQV_S, 90) ))
else
st = math.abs(b.l[2] - b.h) / l
for i = 0 to l - 1
if lqText and i == l - 1
array.push(b_liq_V, box.new(b.i - 2, b.h + i * st, b.i, b.h +
(i + 1) * st, text = 'Liquidity Void ', text_size = size.tiny, text_halign =
text.align_right, text_valign = text.align_top, text_color = na, border_color = na,
bgcolor = color.new(cLQV_S, 90) ))
else
array.push(b_liq_V, box.new(b.i - 2, b.h + i * st, b.i, b.h +
(i + 1) * st, border_color = na, bgcolor = color.new(cLQV_S, 90) ))

if b_liq_V.size() > 0
qt = b_liq_V.size()
for bn = qt - 1 to 0
if bn < b_liq_V.size()
cb = b_liq_V.get(bn)
ba = math.avg(cb.get_bottom(), cb.get_top())

if math.sign(b.c[1] - ba) != math.sign(b.c - ba) or math.sign(b.c[1] -


ba) != math.sign(b.l - ba) or math.sign(b.c[1] - ba) != math.sign(b.h - ba)
b_liq_V.remove(bn)
else
cb.set_right(b.i + 1)

if b.i - cb.get_left() > 21


cb.set_text_color(color.new(color.gray, 25))

//-----------------------------------------------------------------------------}

// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0


International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/

// ~~ © Zeiierman {
//@version=5
//ndicator("Golden Swap
(Zeiierman)",overlay=true,max_labels_count=500,max_lines_count=500)
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Tooltips {
t1="Select the timeframe for the Golden Swap signals. Changing this affects the
period over which the signals are calculated and displayed on the chart."
t2="Toggle the display of Golden Swap signals"
t3="Enable or disable the display of pre-signals for Golden Swaps. These are
preliminary signals that indicate a potential upcoming Golden Swap signal."
t4="Turn on/off the Symmetry Precision filter. This filter adds an additional layer
of precision to the signals by considering the symmetry of price movements. \n\nSet
the level of precision for Symmetry Signals. A higher value allows for greater
variation in symmetry, while a lower value demands closer symmetry."
t5="Enable or disable the BaselineBound Threshold. This setting acts as a filter
for signals, where only those meeting the threshold criteria are considered
valid. \n\nAdjust the range factor for the BaselineBound pattern. Increasing this
value widens the threshold range, potentially allowing more signals to pass through
the filter."
t7="Enable or disable the display of Open, High, and Low levels for the selected
timeframe. Adjusting this affects the visibility of these price levels on the
chart. \n\nSelect the timeframe for displaying Open, High, and Low levels. Changing
this setting will adjust the period over which these levels are calculated and
shown."
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Input Golden Swap


tf = input.timeframe("", title="", group="Golden Swap Signals",inline="0",
tooltip=t1)
Signal = input.bool(true, title="Golden Swap", group="Golden Swap
Signals",inline="s2", tooltip=t2)
Up = input.color(color.lime, title="", group="Golden Swap Signals",inline="s2",
tooltip="")
Dn = input.color(color.red, title="", group="Golden Swap Signals",inline="s2",
tooltip="")

Presignal = input.bool(false, title="Pre Golden Swap", group="Golden Swap


Signals",inline="s1", tooltip=t3)
PreUp = input.color(color.green, title="", group="Golden Swap
Signals",inline="s1", tooltip="")
PreDn = input.color(color.maroon, title="", group="Golden Swap
Signals",inline="s1", tooltip="")

filterCombination = input.string("Symmetry + BaselineBound", "Golden Swap Filters",


options=[
"None",
"Symmetry",
"BaselineBound",
"PrecisionPinBar",
"Symmetry + BaselineBound",
"Symmetry + PrecisionPinBar",
"BaselineBound + PrecisionPinBar",
"Symmetry + BaselineBound + PrecisionPinBar"
], group="Bloom & Precision PinBar Filters",inline="", tooltip="Select Filters")
precision = input.int(7, step= 1, minval= 1, title="Symetry Precision",
group="Bloom & Precision PinBar Filters",inline="", tooltip=t4)
rangeFactor = input.float(0.2, title="BaselineBound Threshold" ,minval=0.01,
maxval=1, step=0.01, group="Bloom & Precision PinBar Filters",inline="",
tooltip=t5)
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Inputs Open High Low


Level_1 = input.bool(true, title="", group="Open, High, Low - Timeframe",
inline="1", tooltip="")
tfq = input.timeframe("240", title="", group="Open, High, Low - Timeframe",
inline="1", tooltip=t7)
style = input.string("solid", title="", options= ["solid", "dotted", "dashed"],
group="Open, High, Low - Timeframe", inline="1", tooltip="")
clr = input(color.new(#69bcff, 0), title="", group="Open, High, Low -
Timeframe", inline="1", tooltip="")
labels_ = input.bool(true, title="Price Labels", group="Open, High, Low -
Timeframe", inline="1", tooltip="")

Level_2 = input.bool(true, title="", group="Open, High, Low - Timeframe",


inline="2", tooltip="")
tf1 = input.timeframe("D", title="", group="Open, High, Low - Timeframe",
inline="2", tooltip="")
style1 = input.string("dotted", title="", options= ["solid", "dotted", "dashed"],
group="Open, High, Low - Timeframe", inline="2", tooltip="")
clr1 = input(color.new(#41ffa3, 0), title="", group="Open, High, Low -
Timeframe", inline="2", tooltip="")
labels_1 = input.bool(true, title="Price Labels", group="Open, High, Low -
Timeframe", inline="2", tooltip="")

Level_3 = input.bool(false, title="", group="Open, High, Low - Timeframe",


inline="3", tooltip="")
tf2 = input.timeframe("W", title="", group="Open, High, Low - Timeframe",
inline="3", tooltip="")
style2 = input.string("dotted", title="", options= ["solid", "dotted", "dashed"],
group="Open, High, Low - Timeframe", inline="3", tooltip="")
clr2 = input(color.new(#ffd024, 0), title="", group="Open, High, Low -
Timeframe", inline="3", tooltip="")
labels_2 = input.bool(false, title="Price Labels", group="Open, High, Low -
Timeframe", inline="3", tooltip="")

Level_4 = input.bool(false, title="", group="Open, High, Low - Timeframe",


inline="4", tooltip="")
tf3 = input.timeframe("M", title="", group="Open, High, Low - Timeframe",
inline="4", tooltip="")
style3 = input.string("dotted", title="", options= ["solid", "dotted", "dashed"],
group="Open, High, Low - Timeframe", inline="4", tooltip="")
clr3 = input(color.new(#ff5420, 0), title="", group="Open, High, Low -
Timeframe", inline="4", tooltip="")
labels_3 = input.bool(false, title="Price Labels", group="Open, High, Low -
Timeframe", inline="4", tooltip="")

Level_5 = input.bool(false, title="", group="Open, High, Low - Timeframe",


inline="5", tooltip="")
tf4 = input.timeframe("12M", title="", group="Open, High, Low - Timeframe",
inline="5", tooltip="")
style4 = input.string("dotted", title="", options= ["solid", "dotted", "dashed"],
group="Open, High, Low - Timeframe", inline="5", tooltip="")
clr4 = input(color.new(#fc39ff, 0), title="", group="Open, High, Low -
Timeframe", inline="5", tooltip="")
labels_4 = input.bool(false, title="Price Labels", group="Open, High, Low -
Timeframe", inline="5", tooltip="")
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Function to check for Symetry Signals


SymmetrySignal(precision)=>
max = math.max(high,high[1])
min = math.min(low,low[1])
high_ = (math.abs(high - high[1])/(max-min))*100
low_ = (math.abs(low - low[1])/(max-min))*100
SymmetryHigh = high_<= precision
SymmetryLow = low_<= precision
[SymmetryHigh,SymmetryLow]
[SymmetryHigh,SymmetryLow] = SymmetrySignal(precision)
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Function to check for BaselineBound


BaselineBoundPattern(rangeFactor) =>
bullish = close >= high - math.abs(high[1] - low[1]) * rangeFactor
bearish = close <= low + math.abs(high[1] - low[1]) * rangeFactor
[bullish, bearish]
[bullishBaselineBound, bearishBaselineBound] = BaselineBoundPattern(rangeFactor)
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Function to check for PrecisionPinBar


PrecisionPinBar() =>
barRange = high - low
threshold = barRange / 3
bodyLen = math.abs(close - open)
tailLen = open > close ? close - low : open - low
longTail = tailLen > 3 * bodyLen
bullish = (open >= high - threshold) and (close >= high - threshold) and
(longTail or close > open)
bearish = (open <= low + threshold) and (close <= low + threshold) and
(longTail or close < open)
[bullish, bearish]
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Get PrecisionPinBar patterns


[BullishPrecisionPinBar, BearishPrecisionPinBar] = PrecisionPinBar()
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Golden Swap Pattern


[o, c, l, h] = request.security(syminfo.tickerid, tf, [open, close, low, high])
longcond = c[2]>o[2] and c[1]>c[2] and c[1]>o[1] and l<math.max(c[2],o[2])
shortcond = c[2]<o[2] and c[1]<c[2] and c[1]<o[1] and h>math.min(c[2],o[2])
// ~~ Apply filters based on selected combination
if filterCombination == "Symmetry"
longcond := longcond and SymmetryLow
shortcond := shortcond and SymmetryHigh
if filterCombination == "BaselineBound"
longcond := longcond and bullishBaselineBound
shortcond := shortcond and bearishBaselineBound
if filterCombination == "PrecisionPinBar"
longcond := longcond and BullishPrecisionPinBar
shortcond := shortcond and BearishPrecisionPinBar
if filterCombination == "Symmetry + BaselineBound"
longcond := longcond and SymmetryLow and bullishBaselineBound
shortcond := shortcond and SymmetryHigh and bearishBaselineBound
if filterCombination == "Symmetry + PrecisionPinBar"
longcond := longcond and SymmetryLow and BullishPrecisionPinBar
shortcond := shortcond and SymmetryHigh and BearishPrecisionPinBar
if filterCombination == "BaselineBound + PrecisionPinBar"
longcond := longcond and bullishBaselineBound and BullishPrecisionPinBar
shortcond := shortcond and bearishBaselineBound and BearishPrecisionPinBar
if filterCombination == "Symmetry + BaselineBound + PrecisionPinBar"
longcond := longcond and SymmetryLow and bullishBaselineBound and
BullishPrecisionPinBar
shortcond := shortcond and SymmetryHigh and bearishBaselineBound and
BearishPrecisionPinBar

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Plot Golden Swap Lines


l1 = line(na)
var cond = 0
prevup = 0
prevdn = 0
up = 0
dn = 0
if longcond
l1 := line.new(bar_index[1],low[1],bar_index,low[1],color=Presignal?PreUp:na,
width = 5)
cond := 1
prevup := 1
if shortcond
l1 := line.new(bar_index[1],high[1],bar_index,high[1], color=Presignal?
PreDn:na, width = 5)
cond := -1
prevdn := -1

if cond>0 and close>close[1]


cond := 0
up := 1
line.new(bar_index[1],low[1],bar_index,low[1], color=Signal?Up:na, width = 4)
l1.delete()
if cond<0 and close<close[1]
cond := 0
dn := -1
line.new(bar_index[1],high[1],bar_index,high[1], color=Signal?Dn:na, width = 4)
l1.delete()
else
cond := 0
PreShort = prevdn == -1
PreLong = prevup == 1
Short = dn == -1
Long = up == 1
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Line style function


sty(type_) =>
switch type_
"dotted" => line.style_dotted
"dashed" => line.style_dashed
=> line.style_solid
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Label style function


labelStyle(clr) =>
label.style_label_left
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Line creation and update function


lineUpdate(ln, t, p, clr, sty) =>
if na(ln)
line.new(t, p, last_bar_time, p, xloc.bar_time, extend.none, clr, sty)
else
ln.set_xy1(t, p)
ln.set_xy2(last_bar_time, p)
ln
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Label creation and update function


labelUpdate(lbl, t, p, text_, clr) =>
var label lbl_var = na
if na(lbl)
lbl_var := label.new(bar_index, p, text_, style=labelStyle(clr),
color=color.new(clr,100), textcolor=clr, yloc=yloc.price, size=size.normal)
else
lbl.set_xy(bar_index, p)
lbl.set_text(text_)
lbl_var := lbl
lbl_var
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Fetch Data
[oq, hq, lq, tq] = request.security(syminfo.tickerid, tfq, [open, high, low,
time])
[o1q, h1q, l1q, t1q] = request.security(syminfo.tickerid, tf1, [open[1], high[1],
low[1], time[1]])
[o2, h2, l2, t2_] = request.security(syminfo.tickerid, tf2, [open[1], high[1],
low[1], time[1]])
[o3, h3, l3, t3_] = request.security(syminfo.tickerid, tf3, [open[1], high[1],
low[1], time[1]])
[o4, h4, l4, t4_] = request.security(syminfo.tickerid, tf4, [open[1], high[1],
low[1], time[1]])
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Variables
var line[] lines = array.new_line(30)
var label[] labels = array.new_label(30)
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Update lines based on the number of periods


if barstate.islast
if Level_1
lines.set(0, lineUpdate(lines.get(0), tq, oq, clr, sty(style)))
lines.set(1, lineUpdate(lines.get(1), tq, hq, clr, sty(style)))
lines.set(2, lineUpdate(lines.get(2), tq, lq, clr, sty(style)))
if Level_2
lines.set(3, lineUpdate(lines.get(3), t1q, o1q, clr1, sty(style1)))
lines.set(4, lineUpdate(lines.get(4), t1q, h1q, clr1, sty(style1)))
lines.set(5, lineUpdate(lines.get(5), t1q, l1q, clr1, sty(style1)))
if Level_3
lines.set(6, lineUpdate(lines.get(6), t2_, o2, clr2, sty(style2)))
lines.set(7, lineUpdate(lines.get(7), t2_, h2, clr2, sty(style2)))
lines.set(8, lineUpdate(lines.get(8), t2_, l2, clr2, sty(style2)))
if Level_4
lines.set(9, lineUpdate(lines.get(9), t3_, o3, clr3, sty(style3)))
lines.set(10, lineUpdate(lines.get(10), t3_, h3, clr3, sty(style3)))
lines.set(11, lineUpdate(lines.get(11), t3_, l3, clr3, sty(style3)))
if Level_5
lines.set(12, lineUpdate(lines.get(12), t4_, o4, clr4, sty(style4)))
lines.set(13, lineUpdate(lines.get(13), t4_, h4, clr4, sty(style4)))
lines.set(14, lineUpdate(lines.get(14), t4_, l4, clr4, sty(style4)))
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Update labels based on the number of periods


if barstate.islast
if Level_1 and labels_
labels.set(0, labelUpdate(labels.get(0), tq, oq, "Prev: " + tfq + " Open: "
+ str.tostring(oq), clr))
labels.set(1, labelUpdate(labels.get(1), tq, hq, "Prev: " + tfq + " High: "
+ str.tostring(hq), clr))
labels.set(2, labelUpdate(labels.get(2), tq, lq, "Prev: " + tfq + " Low: "
+ str.tostring(lq), clr))
if Level_2 and labels_1
labels.set(3, labelUpdate(labels.get(3), t1q, o1q, "Prev: " + tf1 + " Open:
" + str.tostring(o1q), clr1))
labels.set(4, labelUpdate(labels.get(4), t1q, h1q, "Prev: " + tf1 + " High:
" + str.tostring(h1q), clr1))
labels.set(5, labelUpdate(labels.get(5), t1q, l1q, "Prev: " + tf1 + " Low:
" + str.tostring(l1q), clr1))
if Level_3 and labels_2
labels.set(6, labelUpdate(labels.get(6), t2_, o2, "Prev: " + tf2 + " Open:
" + str.tostring(o2), clr2))
labels.set(7, labelUpdate(labels.get(7), t2_, h2, "Prev: " + tf2 + " High:
" + str.tostring(h2), clr2))
labels.set(8, labelUpdate(labels.get(8), t2_, l2, "Prev: " + tf2 + " Low: "
+ str.tostring(l2), clr2))
if Level_4 and labels_3
labels.set(9, labelUpdate(labels.get(9), t3_, o3, "Prev: " + tf3 + " Open:
" + str.tostring(o3), clr3))
labels.set(10, labelUpdate(labels.get(10), t3_, h3, "Prev: " + tf3 + "
High: " +str.tostring(h3), clr3))
labels.set(11, labelUpdate(labels.get(11), t3_, l3, "Prev: " + tf3 + " Low:
" + str.tostring(l3), clr3))
if Level_5 and labels_4
labels.set(12, labelUpdate(labels.get(12), t4_, o4, "Prev: " + tf4 + "
Open: " + str.tostring(o4), clr4))
labels.set(13, labelUpdate(labels.get(13), t4_, h4, "Prev: " + tf4 + "
High: " + str.tostring(h4), clr4))
labels.set(14, labelUpdate(labels.get(14), t4_, l4, "Prev: " + tf4 + " Low:
" + str.tostring(l4), clr4))
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

// ~~ Plot Golden Swap


plotshape(Presignal and PreShort and not Short?
high:na,color=PreDn,style=shape.triangledown,size=size.tiny,
location=location.abovebar, title="Golden Swap Pre Short")
plotshape(Presignal and PreLong and not Long?
low:na,color=PreUp,style=shape.triangleup,size=size.tiny,
location=location.belowbar, title="Golden Swap Pre Long")

plotshape(Signal and Short?


high:na,color=Dn,style=shape.triangledown,size=size.small,
location=location.abovebar, title="Golden Swap Short")
plotshape(Signal and Long?low:na,color=Up,style=shape.triangleup,size=size.small,
location=location.belowbar, title="Golden Swap Long")
//
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}

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

//@

//
-----------------------------------------------------------------------------------
----------------------------------}
// 𝙄𝙉𝙋𝙐𝙏𝙎
//
-----------------------------------------------------------------------------------
----------------------------------{
extension = input.int(50, "Extension to the right of High and Low", group =
"Settings")
timeframe = input.timeframe("D", "timeframe", tooltip = "Use Higher Timeframe then
Current", group = "Settings")

separator = input.bool(false, "Period Separator")


show_trend = input.bool(false, "Show Trend?")
show_break = input.bool(false, "Show Breakout Labels?")

// Variables Declaration
var color color = na
color color1 = na
var bool check = na

color colorDn = #d41919


color colorUp = #13b818

//
-----------------------------------------------------------------------------------
----------------------------------}
// 𝘾𝘼𝙇𝘾𝙐𝙇𝘼𝙏𝙄𝙊𝙉𝙎
//
-----------------------------------------------------------------------------------
----------------------------------{
// To avoid differences on historical and realtime bars:
// returns a value from the higher timeframe on the bar after it completes:
indexHighTF = barstate.isrealtime ? 1 : 0
indexCurrTF = barstate.isrealtime ? 0 : 1

pricehigh = request.security(syminfo.tickerid, timeframe, high[indexHighTF])


[indexCurrTF]
pricelow = request.security(syminfo.tickerid, timeframe, low[indexHighTF])
[indexCurrTF]
price_avg = math.avg(pricelow, pricehigh)

high_break = ta.crossover(close, pricehigh)


low_break = ta.crossunder(close, pricelow)

// BreakOuts Checker (to avoid multiple labels) and color change


switch
high_break => check := true, color1 := colorUp, color := colorUp
low_break => check := false, color1 := colorDn, color := colorDn

//
-----------------------------------------------------------------------------------
----------------------------------}
// 𝙑𝙄𝙎𝙐𝘼𝙇𝙄𝙕𝘼𝙏𝙄𝙊𝙉
//
-----------------------------------------------------------------------------------
----------------------------------{
// BreakOut labels
if high_break and check[1] == false and show_break

label.new(x = bar_index, y = low*0.99,


text = timeframe + "\nHigh Break",
style = label.style_label_up,
textcolor = chart.fg_color,
color = #0e4e11,
size = size.small
)

if low_break and check[1] == true and show_break

label.new(x = bar_index, y = high*1.01,


text = timeframe + "\nLow Break",
style = label.style_label_down,
textcolor = chart.fg_color,
color = #6e1414,
size = size.small
)

// High and Low plots from HTF


change_hl = not ta.change(pricehigh) or not ta.change(pricelow)

ph = plot(series = change_hl and not show_trend ? pricehigh : show_trend ?


pricehigh : na,
title ='High',
style = plot.style_linebr,
linewidth = 2,
color = not show_trend ? colorDn : color.new(colorDn, 80)
)

pm = plot(series = change_hl and not show_trend ? price_avg : show_trend ?


price_avg : na,
title ='L & H Avg',
style = show_trend ? plot.style_stepline_diamond : plot.style_circles,
linewidth = 1,
color = show_trend ? color.new(chart.fg_color, 90) :
color.new(chart.fg_color, 50)
)

pl = plot(series = change_hl and not show_trend ? pricelow : show_trend ?


pricelow : na,
title = 'Low',
style = plot.style_linebr,
linewidth = 2,
color = not show_trend ? colorUp : color.new(colorUp, 80)
)

// Plot triangles if High or Low weren't broken


plotchar(series = ta.crossunder(high, pricehigh),
title = "Resistance",
char = "◆",
location = location.abovebar,
offset = -1,
color = colorDn,
size = size.tiny
)

plotchar(series = ta.crossover(low, pricelow),


title = "Support",
char = "◆",
location = location.belowbar,
offset = -1,
color = colorUp,
size = size.tiny
)

// Extension High and Low to a future


if barstate.islast

label.new(point = chart.point.from_index(bar_index + extension, pricehigh),

text = "⮪ " + timeframe + " High",


style = label.style_label_left,
textcolor = chart.fg_color,
color = colorDn,
size = size.normal
)

label.new(point = chart.point.from_index(bar_index + extension, pricelow),

text = "⮨ " + timeframe + " Low",


style = label.style_label_left,
textcolor = chart.fg_color,
color = #158d19,
size = size.normal
)

if change_hl and barstate.islast

h_Left = chart.point.from_index(bar_index, pricehigh)


h_Right = chart.point.from_index(bar_index+extension, pricehigh)

line.new(h_Left, h_Right, color = colorDn, style = line.style_solid, width = 2)

l_Left = chart.point.from_index(bar_index, pricelow)


l_Right = chart.point.from_index(bar_index+extension, pricelow)

line.new(l_Left, l_Right, color = colorUp, width = 2)

m_Left = chart.point.from_index(bar_index, math.avg(pricelow,


pricehigh))
m_Right = chart.point.from_index(bar_index+extension, math.avg(pricelow,
pricehigh))

line.new(m_Left, m_Right,
color = chart.fg_color,
width = show_trend ? 1 : 2,
style = show_trend ? line.style_solid : line.style_dotted
)

// BreakOut Bar Color of Trend Color


barcolor(show_trend ? color : color1)

bgcolor(separator ? (not change_hl


? color.new(chart.fg_color, 90): na)
: na
)
// Fill OB and OS Zones
fill(plot1 = ph,
plot2 = pl,
top_value = pricehigh,
bottom_value = pricelow,
top_color = not show_trend ? color.new(colorDn, chart.bg_color ==
color.white ? 80 : 92) : na,
bottom_color = not show_trend ? color.new(colorUp, chart.bg_color ==
color.white ? 80 : 92) : na
)

//
-----------------------------------------------------------------------------------
----------------------------------}
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0
International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo
//@version=5

//ndicator("ICT Immediate Rebalance [LuxAlgo]", "LuxAlgo - ICT Immediate


Rebalance", overlay = true, max_lines_count = 500, max_labels_count = 500)

//------------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------{

disp = display.all - display.status_line

irGR = 'Immediate Rebalances'


irTF = input.string('Chart', 'Timeframe', options = ['Chart', '5 Minutes', '15
Minutes', '1 Hour', '4 Hours', '1 Day', '1 Week'], group = irGR, display = disp)
irBC = input.color(color.new(#2962ff, 07), 'Bullish Immediate Rebalance', group =
irGR)
irSC = input.color(color.new(#ff9800, 07), 'Bearish Immediate Rebalance', group =
irGR)
irL75 = input.color(color.new(#b2b5be, 1), 'Wicks 75%', inline = 'IR' , group =
irGR)
irL50 = input.color(color.new(#d1d4dc, 1), '50%', inline = 'IR' , group = irGR)
irL25 = input.color(color.new(#b2b5be, 1), '25%', inline = 'IR' , group = irGR)
itCTT = 'Specifies the number of bars required to confirm the validation of the
detected immediate rebalance. Please note that, in case higher timeframe is
selected then higher timeframe bars will be assumed\n\n' +
'It\'s important to highlight that both failed and successful immediate
rebalances, when considered within a context, are significant signatures in
trading.'
irCFR = input.int(2, 'Confirmation (Bars)', minval = 1, maxval = 5, group = irGR,
tooltip = itCTT, display = disp)
irCTT = 'applicable when higher timeframe detection is enabled.'
irCDL = input.bool(false, 'Immediate Rebalance Candles', inline = 'COL', group =
irGR, tooltip = irCTT)
irCCb = input(color.teal, "", inline = 'COL', group = irGR)
irCCa = input(color.red, "", inline = 'COL', group = irGR)
irSZ = input.string('Normal', 'Immediate Rebalance Icon', options = ['Small',
'Normal', 'Large'], group = irGR, display = disp)

dbSH = input(false, 'Dashboard', group = 'Dashboard', inline = 'DB')


dbLOC = input.string('Top Right', '', options = ['Top Right', 'Bottom Right',
'Bottom Left'], group = 'Dashboard', inline = 'DB', display = disp)
dbSZ = input.string('Small', '', options = ['Tiny', 'Small', 'Normal'], group =
'Dashboard', inline = 'DB', display = disp)

//-----------------------------------------------------------------------------}
// User Defined Types
//-----------------------------------------------------------------------------{

type BAR
float o = open
float h = high
float l = low
float c = close
int i = bar_index

type htfBar
float price = na
int index = na

type htfBarArray
htfBar opn
htfBar top
htfBar btm
htfBar prc

type ImmediateRebalance
label lb
line ln
int idx
int count

type STAT
int bullTotal = 0
int bullFailed = 0
int bearTotal = 0
int bearFailed = 0

//-----------------------------------------------------------------------------}
// Variables
//-----------------------------------------------------------------------------{

BAR b = BAR.new()
var STAT stat = STAT.new()

//-----------------------------------------------------------------------------}
// Functions / Methods
//-----------------------------------------------------------------------------{

plotImmediateRebalances(x1, y, x2, color, bull, body, irArray, lastIdxO, lastIdxC,


irSZ, irWTH) =>

line.new(x1, y, x2, y, color = color, width = irWTH)


line.new(x1, math.avg(y, body), x2, math.avg(y, body), color = irL50, width =
1)
line.new(x1, math.avg(y, math.avg(y, body)), x2, math.avg(y, math.avg(y,
body)), color = irL75, width = 1, style = line.style_dotted)
line.new(x1, math.avg(math.avg(y, body), body), x2, math.avg(math.avg(y, body),
body), color = irL25, width = 1, style = line.style_dotted)
label.new(x1, y, '▶ ', textcolor = color, color = color(na), style =
label.style_label_center, size = size.small, tooltip = bull ? 'Bullish Immediate
Rebalance' : 'Bearish Immediate Rebalance')

irArray.unshift(
ImmediateRebalance.new(
label.new(x2, y, bull ? '◥' : '◢', textcolor = color, color = color(na),
style = label.style_label_center, size = irSZ, tooltip = bull ? 'Bullish Immediate
Rebalance' : 'Bearish Immediate Rebalance'),
line.new(x2, y, x2, y, color = color, width = 1, style =
line.style_dotted),
lastIdxC, (lastIdxC - lastIdxO + 1)
)
)

plotCandles(x1, x2, o, h, l, c) =>


box.new(x1, o, x2, c, o < c ? irCCb : irCCa, 2, line.style_solid , extend.none,
xloc.bar_index, o < c ? color.new(irCCb, 80) : color.new(irCCa, 80))
line.new(math.floor(math.avg(x1, x2)), l, math.floor(math.avg(x1, x2)), o < c ?
o : c, xloc.bar_index, extend.none, o < c ? irCCb : irCCa, line.style_solid, 2)
line.new(math.floor(math.avg(x1, x2)), h, math.floor(math.avg(x1, x2)), o < c ?
c : o, xloc.bar_index, extend.none, o < c ? irCCb : irCCa, line.style_solid, 2)

setCells(tb, column, bull_filled, bull_count, bear_filled, bear_count,


table_size)=>
table.cell(tb, column, 1, str.tostring(bull_count), text_color = #089981,
text_size = table_size, text_halign = text.align_left)
table.cell(tb, column, 2, str.format('{0,number,percent}', bull_filled /
bull_count), text_color = #089981, text_size = table_size, text_halign =
text.align_left)
table.cell(tb, column, 3, str.tostring(bear_count), text_color = #f23645,
text_size = table_size, text_halign = text.align_left)
table.cell(tb, column, 4, str.format('{0,number,percent}', bear_filled /
bear_count), text_color = #f23645, text_size = table_size, text_halign =
text.align_left)

//-----------------------------------------------------------------------------}
// Calculations
//-----------------------------------------------------------------------------{

var barArray = array.new<htfBarArray>()

var htfBar barOpen = htfBar.new(b.o, b.i)


var htfBar barHigh = htfBar.new(b.h, b.i)
var htfBar barLow = htfBar.new(b.l, b.i)
var htfBar barClose = htfBar.new(b.c, b.i)

var barHist = htfBarArray.new(barOpen, barHigh, barLow, barClose)

var int bullBarIndexEnd = na, var int bullBarIndexEnd1 = na


var int bearBarIndexEnd = na, var int bearBarIndexEnd1 = na

var bool bullProcess = na, var bool bullCondition = na


var bool bearProcess = na, var bool bearCondition = na

var aIR = array.new<ImmediateRebalance>()


var bIR = array.new<ImmediateRebalance>()

string tf = switch
irTF == "5 Minutes" and timeframe.isintraday and timeframe.multiplier <= 5
=> '5'
irTF == "15 Minutes" and timeframe.isintraday and timeframe.multiplier <= 15
=> '15'
irTF == "1 Hour" and timeframe.isintraday and timeframe.multiplier <= 60
=> '60'
irTF == "4 Hours" and timeframe.isintraday and timeframe.multiplier <= 240
=> '240'
irTF == "1 Day" and timeframe.isintraday => 'D'
irTF == "1 Week" and (timeframe.isdaily or timeframe.isintraday) => 'W'
=> timeframe.period

[irSZl, irWTH] = switch irSZ


'Small' => [size.small , 1]
'Normal' => [size.normal, 2]
=> [size.large, 3]

if timeframe.change(tf)
bullProcess := false
bearProcess := false

if barArray.size() > 2
barArray.pop()

barArray.unshift(barHist)

barOpen := htfBar.new(b.o, b.i)


barHigh := htfBar.new(b.h, b.i)
barLow := htfBar.new(b.l, b.i)
barClose := htfBar.new(b.c, b.i)

barHist := htfBarArray.new(barOpen, barHigh, barLow, barClose)

bullBarIndexEnd1 := bullBarIndexEnd, bullBarIndexEnd := b.i


bearBarIndexEnd1 := bearBarIndexEnd, bearBarIndexEnd := b.i

else
if b.h > barHigh.price
barHigh.price := b.h
barHigh.index := b.i

if b.l < barLow.price


barLow.price := b.l
barLow.index := b.i

barClose.price := b.c
barClose.index := b.i

if barArray.size() > 2
if b.l < barArray.get(1).top.price
bullBarIndexEnd := b.i

if b.h > barArray.get(1).btm.price


bearBarIndexEnd := b.i

if barArray.size() > 2
bullCondition := barArray.get(0).btm.price < barArray.get(2).top.price and
barArray.get(0).btm.price > barArray.get(2).prc.price and
barArray.get(0).prc.price > barArray.get(2).top.price and
barArray.get(1).prc.price > barArray.get(2).top.price and
barArray.get(0).prc.price > barArray.get(1).prc.price

bearCondition := barArray.get(0).top.price > barArray.get(2).btm.price and


barArray.get(0).top.price < barArray.get(2).prc.price and
barArray.get(0).prc.price < barArray.get(2).btm.price and
barArray.get(1).prc.price < barArray.get(2).btm.price and
barArray.get(0).prc.price < barArray.get(1).prc.price

if bullCondition and not bullProcess


bullProcess := true
stat.bullTotal += 1

plotImmediateRebalances(barArray.get(2).top.index, barArray.get(2).top.price,
bullBarIndexEnd1, irBC, true, math.max(barArray.get(2).opn.price,
barArray.get(2).prc.price), bIR, barArray.get(0).opn.index,
barArray.get(0).prc.index, irSZl, irWTH)

if irCDL and tf != timeframe.period


plotCandles(barArray.get(2).opn.index, barArray.get(2).prc.index,
barArray.get(2).opn.price, barArray.get(2).top.price, barArray.get(2).btm.price,
barArray.get(2).prc.price)
plotCandles(barArray.get(1).opn.index, barArray.get(1).prc.index,
barArray.get(1).opn.price, barArray.get(1).top.price, barArray.get(1).btm.price,
barArray.get(1).prc.price)
plotCandles(barArray.get(0).opn.index, barArray.get(0).prc.index,
barArray.get(0).opn.price, barArray.get(0).top.price, barArray.get(0).btm.price,
barArray.get(0).prc.price)

if bearCondition and not bearProcess


bearProcess := true
stat.bearTotal += 1

plotImmediateRebalances(barArray.get(2).btm.index, barArray.get(2).btm.price,
bearBarIndexEnd1, irSC, false, math.min(barArray.get(2).opn.price,
barArray.get(2).prc.price), aIR, barArray.get(0).opn.index,
barArray.get(0).prc.index, irSZl, irWTH)

if irCDL and tf != timeframe.period


plotCandles(barArray.get(2).opn.index, barArray.get(2).prc.index,
barArray.get(2).opn.price, barArray.get(2).top.price, barArray.get(2).btm.price,
barArray.get(2).prc.price)
plotCandles(barArray.get(1).opn.index, barArray.get(1).prc.index,
barArray.get(1).opn.price, barArray.get(1).top.price, barArray.get(1).btm.price,
barArray.get(1).prc.price)
plotCandles(barArray.get(0).opn.index, barArray.get(0).prc.index,
barArray.get(0).opn.price, barArray.get(0).top.price, barArray.get(0).btm.price,
barArray.get(0).prc.price)

if aIR.size() > 0
for i = aIR.size() - 1 to 0
lF = aIR.get(i)

if b.i > (lF.idx + lF.count * (irCFR - 1)) and b.h > lF.lb.get_y()
lF.lb.set_text('❌')
lF.lb.set_tooltip('Failed Bearish Immediate Rebalance')
lF.lb.set_size(size.normal)
lF.ln.set_x2(b.i)
stat.bearFailed += 1

aIR.remove(i)
break

if b.i >= (lF.idx + lF.count * irCFR)


aIR.remove(i)

if bIR.size() > 0
for i = bIR.size() - 1 to 0
lF = bIR.get(i)

if b.i > (lF.idx + lF.count * (irCFR - 1)) and b.l < lF.lb.get_y()
lF.lb.set_text('❌')
lF.lb.set_tooltip('Failed Bullish Immediate Rebalance')
lF.lb.set_size(size.normal)
lF.ln.set_x2(b.i)

stat.bullFailed += 1

bIR.remove(i)
break

if b.i >= (lF.idx + lF.count * irCFR)


bIR.remove(i)

//-----------------------------------------------------------------------------}
// Calculations - Dashboard
//-----------------------------------------------------------------------------{

var table_position = dbLOC == 'Bottom Left' ? position.bottom_left


: dbLOC == 'Top Right' ? position.top_right
: position.bottom_right

var table_size = dbSZ == 'Tiny' ? size.tiny


: dbSZ == 'Small' ? size.small
: size.normal

var table tb = na

if barstate.isfirst and dbSH


tb := table.new(table_position, 5, 7, bgcolor = #1e222d, border_color =
#373a46, border_width = 1, frame_color = #373a46, frame_width = 1)

table.cell(tb, 0, 1, 'Bullish', text_color = #089981, text_size = table_size)


table.cell(tb, 1, 1, 'Total', text_color = #089981, text_size = table_size,
text_halign = text.align_left)
table.cell(tb, 1, 2, 'Confirmed', text_color = #089981, text_size = table_size,
text_halign = text.align_left)
table.merge_cells(tb, 0, 1, 0, 2)

table.cell(tb, 0, 3, 'Bearish', text_color = #f23645, text_size = table_size)


table.cell(tb, 1, 3, 'Total', text_color = #f23645, text_size = table_size,
text_halign = text.align_left)
table.cell(tb, 1, 4, 'Confirmed', text_color = #f23645, text_size = table_size,
text_halign = text.align_left)
table.merge_cells(tb, 0, 3, 0, 4)

if barstate.islast and dbSH


setCells(tb, 2, stat.bullTotal - stat.bullFailed, stat.bullTotal,
stat.bearTotal - stat.bearFailed, stat.bearTotal, table_size)

//-----------------------------------------------------------------------------}
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0
International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo

//@version=5
//indicator("Market Structure CHoCH/BOS (Fractal) [LuxAlgo]", "LuxAlgo - Market
Structure (Fractal)", overlay = true, max_lines_count = 500, max_labels_count =
500)
//------------------------------------------------------------------------------
// Settings
//-----------------------------------------------------------------------------{
length = input.int(5, minval = 3)

//Colors
showBull = input(true, 'Bullish Structures', inline = 'bull', group = 'Style')
bullCss = input.color(#089981, '', inline = 'bull', group = 'Style')

showBear = input(true, 'Bearish Structures', inline = 'bear', group = 'Style')


bearCss = input.color(#f23645, '', inline = 'bear', group = 'Style')

showSupport = input(false, 'Support', inline = 's', group = 'Style')


supCss = input.color(#089981, '', inline = 's', group = 'Style')

showResistance = input(false, 'Resistance', inline = 'r', group = 'Style')


resCss = input.color(#f23645, '', inline = 'r', group = 'Style')

//Dashboard
showDash = input(false, 'Show Dashboard', group = 'Dashboard')
dashLoc = input.string('Top Right', 'Location', options = ['Top Right', 'Bottom
Right', 'Bottom Left'], group = 'Dashboard')
textSize = input.string('Small', 'Size' , options = ['Tiny', 'Small',
'Normal'] , group = 'Dashboard')

//-----------------------------------------------------------------------------}
//Types
//-----------------------------------------------------------------------------{
type fractal
float value
int loc
bool iscrossed

//-----------------------------------------------------------------------------}
//Fractal Detection
//-----------------------------------------------------------------------------{
var p = int(length/2)
n = bar_index

dh = math.sum(math.sign(high - high[1]), p)
dl = math.sum(math.sign(low - low[1]), p)

bullf = dh == -p and dh[p] == p and high[p] == ta.highest(length)


bearf = dl == p and dl[p] == -p and low[p] == ta.lowest(length)

bullf_count = ta.cum(bullf ? 1 : 0)
bearf_count = ta.cum(bearf ? 1 : 0)
//-----------------------------------------------------------------------------}
//Bullish market structure
//-----------------------------------------------------------------------------{
var upper = fractal.new()
var line lower_lvl = na
var label ms_lbl = na
var bull_ms_count = 0
var broken_sup = false
var os = 0

if bullf
upper.value := high[p]
upper.loc := n-p
upper.iscrossed := false

if ta.crossover(close, upper.value) and not upper.iscrossed


line.new(upper.loc, upper.value, n, upper.value, color = showBull ? bullCss :
na)

ms_lbl := label.new(int(math.avg(n, upper.loc)), upper.value, os == -1 ?


'ChoCH' : 'BOS'
, color = color(na)
, textcolor = showBull ? bullCss : na
, style = label.style_label_down
, size = size.tiny)

//Set support
k = 2
min = low[1]
for i = 2 to (n - upper.loc)-1
min := math.min(low[i], min)
k := low[i] == min ? i : k

if showSupport
lower_lvl := line.new(n-k, min, n, min, color = bullCss, style =
line.style_dashed)
broken_sup := false

upper.iscrossed := true
bull_ms_count += 1
os := 1

else if showSupport and not broken_sup


lower_lvl.set_x2(n)

if close < lower_lvl.get_y2()


broken_sup := true

//-----------------------------------------------------------------------------}
//Bearish market structure
//-----------------------------------------------------------------------------{
var lower = fractal.new()
var line upper_lvl = na
var broken_res = false
var bear_ms_count = 0

if bearf
lower.value := low[p]
lower.loc := n-p
lower.iscrossed := false

if ta.crossunder(close, lower.value) and not lower.iscrossed


line.new(lower.loc, lower.value, n, lower.value, color = showBear ? bearCss :
na)

label.new(int(math.avg(n, lower.loc)), lower.value, os == 1 ? 'ChoCH' : 'BOS'


, color = color(na)
, textcolor = showBear ? bearCss : na
, style = label.style_label_up
, size = size.tiny)

//Set resistance
k = 2
max = high[1]
for i = 2 to (n - lower.loc)-1
max := math.max(high[i], max)
k := high[i] == max ? i : k

if showResistance
upper_lvl := line.new(n-k, max, n, max, color = bearCss, style =
line.style_dashed)
broken_res := false

lower.iscrossed := true
bear_ms_count += 1
os := -1

else if showResistance and not broken_res


upper_lvl.set_x2(n)

if close > upper_lvl.get_y2()


broken_res := true

//-----------------------------------------------------------------------------}
//Dashboard
//-----------------------------------------------------------------------------{
var table_position = dashLoc == 'Bottom Left' ? position.bottom_left
: dashLoc == 'Top Right' ? position.top_right
: position.bottom_right

var table_size = textSize == 'Tiny' ? size.tiny


: textSize == 'Small' ? size.small
: size.normal

var tb = table.new(table_position, 2, 3
, bgcolor = #1e222d
, border_color = #373a46
, border_width = 1
, frame_color = #373a46
, frame_width = 1)

if showDash
if barstate.isfirst
tb.cell(0, 0, 'Structure To Fractal %', text_color = color.white, text_size
= table_size)
tb.merge_cells(0,0,1,0)
tb.cell(0, 1, 'Bullish', text_color = #089981, text_size = table_size)
tb.cell(1, 1, 'Bearish', text_color = #f23645, text_size = table_size)

if barstate.islast
tb.cell(0, 2, str.tostring(bull_ms_count / bullf_count * 100,
format.percent), text_color = #089981, text_size = table_size)
tb.cell(1, 2, str.tostring(bear_ms_count / bearf_count * 100,
format.percent), text_color = #f23645, text_size = table_size)

//-----------------------------------------------------------------------------}
//Plots
//-----------------------------------------------------------------------------{
plot(broken_res and not broken_res[1] ? low : na, 'Resistance Breakout', #089981,
2, plot.style_circles)
plot(broken_sup and not broken_sup[1] ? high : na, 'Support Breakout', #f23645, 2,
plot.style_circles)

//-----------------------------------------------------------------------------}
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0
International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo

//@version=5
//ndicator("Market Structure with Inducements & Sweeps [LuxAlgo]", "LuxAlgo -
Market Structure with Inducements & Sweeps", overlay = true, max_lines_count = 500,
max_labels_count = 500)
//---------------------------------------------------------------------------------
------------------------------------}
//Settings
//---------------------------------------------------------------------------------
------------------------------------{
len = input(50, 'CHoCH Detection Period')
shortLen = input(3, 'IDM Detection Period')

//Styling
bullCss = input(#089981, 'Bullish Elements', group = 'Style')
bearCss = input(#ff5252, 'Bearish Elements', group = 'Style')

showChoch = input(true, "Show CHoCH", group = 'Style')


showBos = input(true, "Show BOS", group = 'Style')

showIdm = input(true, "Show Inducements", inline = 'idm', group = 'Style')


idmCss = input(color.gray, "", inline = 'idm', group = 'Style')

showSweeps = input(true, "Show Sweeps", inline = 'sweeps', group = 'Style')


sweepsCss = input(color.gray, "", inline = 'sweeps', group = 'Style')

showCircles = input(true, "Show Swings", group = 'Style')

//---------------------------------------------------------------------------------
------------------------------------}
//Functions
//---------------------------------------------------------------------------------
------------------------------------{
//Swings detection/measurements
n = bar_index

swings(len)=>
var os = 0
var int topx = na
var int btmx = na

upper = ta.highest(len)
lower = ta.lowest(len)

os := high[len] > upper ? 0 : low[len] < lower ? 1 : os[1]

top = os == 0 and os[1] != 0 ? high[len] : na


topx := os == 0 and os[1] != 0 ? n[len] : topx

btm = os == 1 and os[1] != 1 ? low[len] : na


btmx := os == 1 and os[1] != 1 ? n[len] : btmx

[top, topx, btm, btmx]

//---------------------------------------------------------------------------------
------------------------------------}
//Swings
//---------------------------------------------------------------------------------
------------------------------------{
[top, topx, btm, btmx] = swings(len)
[stop, stopx, sbtm, sbtmx] = swings(shortLen)

var os = 0
var top_crossed = false
var btm_crossed = false

var float max = na


var float min = na

var int max_x1 = na


var int min_x1 = na

var float topy = na


var float btmy = na
var stop_crossed = false
var sbtm_crossed = false

//---------------------------------------------------------------------------------
------------------------------------}
//CHoCH Detection
//---------------------------------------------------------------------------------
------------------------------------{
if top
topy := top
top_crossed := false
if btm
btmy := btm
btm_crossed := false

//Test for CHoCH


if close > topy and not top_crossed
os := 1
top_crossed := true
if close < btmy and not btm_crossed
os := 0
btm_crossed := true
//Display CHoCH
if os != os[1]
max := high
min := low
max_x1 := n
min_x1 := n
stop_crossed := false
sbtm_crossed := false

if os == 1 and showChoch
line.new(topx, topy, n, topy, color = bullCss, style = line.style_dashed)
label.new(int(math.avg(n, topx)), topy, 'CHoCH', color = color(na), style =
label.style_label_down, textcolor = bullCss, size = size.tiny)
else if showChoch
line.new(btmx, btmy, n, btmy, color = bearCss, style = line.style_dashed)
label.new(int(math.avg(n, btmx)), btmy, 'CHoCH', color = color(na), style =
label.style_label_up, textcolor = bearCss, size = size.tiny)

stopy = fixnan(stop)
sbtmy = fixnan(sbtm)

//---------------------------------------------------------------------------------
------------------------------------}
//Bullish BOS
//---------------------------------------------------------------------------------
------------------------------------{
//IDM
if low < sbtmy and not sbtm_crossed and os == 1 and sbtmy != btmy
if showIdm
line.new(sbtmx, sbtmy, n, sbtmy, color = idmCss, style = line.style_dotted)
label.new(int(math.avg(n, sbtmx)), sbtmy, 'IDM', color = color(na), style =
label.style_label_up, textcolor = idmCss, size = size.tiny)

sbtm_crossed := true

//BOS
if close > max and sbtm_crossed and os == 1
if showBos
line.new(max_x1, max, n, max, color = bullCss)
label.new(int(math.avg(n, max_x1)), max, 'BOS', color = color(na), style =
label.style_label_down, textcolor = bullCss, size = size.tiny)

sbtm_crossed := false

//---------------------------------------------------------------------------------
------------------------------------}
//Bearish BOS
//---------------------------------------------------------------------------------
------------------------------------{
//IDM
if high > stopy and not stop_crossed and os == 0 and stopy != topy
if showIdm
line.new(stopx, stopy, n, stopy, color = color.gray, style =
line.style_dotted)
label.new(int(math.avg(n, stopx)), stopy, 'IDM', color = color(na), style =
label.style_label_down, textcolor = color.gray, size = size.tiny)

stop_crossed := true
//BOS
if close < min and stop_crossed and os == 0
if showBos
line.new(min_x1, min, n, min, color = bearCss)
label.new(int(math.avg(n, min_x1)), min, 'BOS', color = color(na), style =
label.style_label_up, textcolor = bearCss, size = size.tiny)

stop_crossed := false

//---------------------------------------------------------------------------------
------------------------------------}
//Sweeps
//---------------------------------------------------------------------------------
------------------------------------{
if high > max and close < max and os == 1 and n - max_x1 > 1 and showSweeps
line.new(max_x1, max, n, max, color = sweepsCss, style = line.style_dotted)
label.new(int(math.avg(n, max_x1)), max, 'x', color = color(na), style =
label.style_label_down, textcolor = sweepsCss)

if low < min and close > min and os == 0 and n - min_x1 > 1 and showSweeps
line.new(min_x1, min, n, min, color = sweepsCss, style = line.style_dotted)
label.new(int(math.avg(n, min_x1)), min, 'x', color = color(na), style =
label.style_label_up, textcolor = sweepsCss)

//Trailing max/min
max := math.max(high, max)
min := math.min(low, min)

if max > max[1]


max_x1 := n
if min < min[1]
min_x1 := n

//---------------------------------------------------------------------------------
------------------------------------}
//Extensions
//---------------------------------------------------------------------------------
------------------------------------{
var ext_choch = line.new(na,na,na,na, style = line.style_dashed)
var ext_bos = line.new(na,na,na,na)
var ext_idm = line.new(na,na,na,na, style = line.style_dotted, color = idmCss)

var ext_choch_lbl = label.new(na,na, 'CHoCH', color = color(na), size = size.tiny)


var ext_bos_lbl = label.new(na,na, 'BOS' , color = color(na), size = size.tiny)
var ext_idm_lbl = label.new(na,na, 'IDM' , color = color(na), size = size.tiny,
textcolor = idmCss)

if barstate.islast
if os == 1
if showChoch
ext_choch.set_xy1(btmx, btmy), ext_choch.set_xy2(n, btmy),
ext_choch.set_color(bearCss)
ext_choch_lbl.set_xy(n, btmy),
ext_choch_lbl.set_style(label.style_label_up), ext_choch_lbl.set_textcolor(bearCss)

if showBos
ext_bos.set_xy1(max_x1, max), ext_bos.set_xy2(n, max),
ext_bos.set_color(bullCss)
ext_bos_lbl.set_xy(n, max),
ext_bos_lbl.set_style(label.style_label_down), ext_bos_lbl.set_textcolor(bullCss)

if not sbtm_crossed and showIdm


ext_idm.set_xy1(sbtmx, sbtmy), ext_idm.set_xy2(n+15, sbtmy)
ext_idm_lbl.set_xy(n+15, sbtmy),
ext_idm_lbl.set_style(label.style_label_up)
ext_idm.set_color(idmCss), ext_idm_lbl.set_textcolor(idmCss)
else
ext_idm.set_color(na)
ext_idm_lbl.set_textcolor(na)
else
if showChoch
ext_choch.set_xy1(topx, topy), ext_choch.set_xy2(n, topy),
ext_choch.set_color(bullCss)
ext_choch_lbl.set_xy(n, topy),
ext_choch_lbl.set_style(label.style_label_down),
ext_choch_lbl.set_textcolor(bullCss)

if showBos
ext_bos.set_xy1(min_x1, min), ext_bos.set_xy2(n, min),
ext_bos.set_color(bearCss)
ext_bos_lbl.set_xy(n, min),
ext_bos_lbl.set_style(label.style_label_up), ext_bos_lbl.set_textcolor(bearCss)

if not stop_crossed and showIdm


ext_idm.set_xy1(stopx, stopy), ext_idm.set_xy2(n+15, stopy)
ext_idm_lbl.set_xy(n+15, stopy),
ext_idm_lbl.set_style(label.style_label_down)
ext_idm.set_color(idmCss), ext_idm_lbl.set_textcolor(idmCss)
else
ext_idm.set_color(na)
ext_idm_lbl.set_textcolor(na)

//---------------------------------------------------------------------------------
------------------------------------}
//Plots
//---------------------------------------------------------------------------------
------------------------------------{
plot(showCircles ? top : na, 'Swing High', color.new(bearCss, 50), 5,
plot.style_circles, offset = -len)
plot(showCircles ? btm : na, 'Swing Low', color.new(bullCss, 50), 5,
plot.style_circles, offset = -len)

//---------------------------------------------------------------------------------
------------------------------------}
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0
International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © LuxAlgo

//@version=5
//indicator('Range Average Retest Model [LuxAlgo]', 'LuxAlgo - Range Average Retest
Model', overlay=true, max_bars_back = 5000, max_boxes_count = 500, max_lines_count
= 500)

//---------------------------------------------------------------------------------
------------------------------------}
//CONSTANTS & STRINGS & INPUTS
//---------------------------------------------------------------------------------
------------------------------------{
BULLISH_LEG = 1
BEARISH_LEG = 0
ARRAY_MAX_SIZE = 165

BULLISH_AREA = 'BULLISH'
BEARISH_AREA = 'BEARISH'
BOTH_AREA = 'BOTH'

GREEN = #089981
RED = #F23645

SWINGS_GROUP = 'SWINGS'
TRADES_GROUP = 'TRADES'
STYLE_GROUP = 'STYLE'

pivotLengthTooltip = 'How many bars are used to confirm a turn. The


larger this parameter is, the larger and fewer swing areas will be detected.'
areaSelectionModeTooltip = 'Swing area detection mode, detect only bullish
swings, only bearish swings or both.'
areaThresholdMultiplierTooltip = 'Swing area comparator. This threshold is
multiplied by a measure of volatility (average true range over the last 200 bars),
for a new swing area to be detected it must have an average level that is
sufficiently distant from the average level of any untouched swing area, this
parameter controls that distance.'
maximumDistanceFromAreaTooltip = 'Maximum distance allowed between a swing area
and a trade'
minimumDistanceFromAreaTooltip = 'Minimum distance allowed between a swing area
and a trade'
takeProfitMultiplierTooltip = 'The size of the take profit - this threshold is
multiplied by a measure of volatility (the average true range over the last 200
bars).'
stopLossMultiplierTooltip = 'The size of the stop-loss: this threshold is
multiplied by a measure of volatility (the average true range over the last 200
bars).'
showAreasTooltip = 'Activate/deactivate areas, select colours for
bullish and bearish areas.'
overlappingTradesTooltip = 'Activate/deactivate overlapping trades.'

pivotLengthInput = input.int( 20, 'Pivot Length',


group = SWINGS_GROUP, tooltip = pivotLengthTooltip, minval = 1)
areaSelectionModeInput = input.string( BOTH_AREA, 'Selection
Mode', group = SWINGS_GROUP, tooltip = areaSelectionModeTooltip,
options = [BULLISH_AREA, BEARISH_AREA, BOTH_AREA])
areaThresholdMultiplierInput = input.float( 4.0, 'Threshold',
group = SWINGS_GROUP, tooltip = areaThresholdMultiplierTooltip, step=0.25)

maximumDistanceFromAreaInput = input.int( 200, 'Maximum


distance', group = TRADES_GROUP, tooltip = maximumDistanceFromAreaTooltip)
minimumDistanceFromAreaInput = input.int( 10, 'Minimum
distance', group = TRADES_GROUP, tooltip = minimumDistanceFromAreaTooltip)
takeProfitMultiplierInput = input.float( 8.0, 'Take profit',
group = TRADES_GROUP, tooltip = takeProfitMultiplierTooltip)
stopLossMultiplierInput = input.float( 4.0, 'Stop loss',
group = TRADES_GROUP, tooltip = stopLossMultiplierTooltip)

showAreasInput = input.bool( true, 'Show Ranges',


group = STYLE_GROUP, tooltip = showAreasTooltip, inline = '1')
bullAreaColorInput = input.color( GREEN,'',
group = STYLE_GROUP, tooltip = '', inline = '1')
bearAreaColorInput = input.color( RED, '',
group = STYLE_GROUP, tooltip = '', inline = '1')

showAverageInput = input.bool( true, 'Show Average',


group = STYLE_GROUP, tooltip = showAreasTooltip, inline = '2')
bullAvgColorInput = input.color( GREEN,'',
group = STYLE_GROUP, tooltip = '', inline = '2')
bearAvgColorInput = input.color( RED, '',
group = STYLE_GROUP, tooltip = '', inline = '2')

showTPAreasInput = input.bool( true, 'Show TP


Areas', group = STYLE_GROUP, tooltip = showAreasTooltip,
inline = '3')
takeProfitColorInput = input.color( color.new(GREEN,75),'',
group = STYLE_GROUP, tooltip = '', inline = '3')

showSLAreasInput = input.bool( true, 'Show SL


Areas', group = STYLE_GROUP, tooltip = showAreasTooltip,
inline = '4')
stopLossColorInput = input.color( color.new(RED,75), '',
group = STYLE_GROUP, tooltip = '', inline = '4')

overlappingTradesInput = input.bool( false, 'Overlap


trades', group = STYLE_GROUP, tooltip = overlappingTradesTooltip)

//---------------------------------------------------------------------------------
------------------------------------}
//DATA STRUCTURES & VARIABLES
//---------------------------------------------------------------------------------
------------------------------------{
// @type Storage UDT for swing areas
// @field startTime Time of the first barBar
// @field endTime Time of the last barBar
// @field endIndex Bar index of the last bar
// @field areaHigh Highest price
// @field areaLow Lowest price
// @field averagePrice Average price as 0.5*(areaHigh+areaLow)
// @field areaColor Default colour for drawing lines
// @field touched True for swing areas with associated trades, false
otherwise
type area
int startTime
int endTime
int endIndex
float areaHigh
float areaLow
float averagePrice
color areaColor
bool touched = false

// @type Storage UDT for trades


// @field entry Price level for trade entry
// @field top Highest price leve of the trade, can be TP or SL
// @field bottom Lowest price level of the trade, can be TP or SL
// @field topColor Top colour can be RED for SL or GREEN for TP
// @field bottomColor Bottom colour can be RED for SL or GREEN for TP
// @field startTime Time on the first bar of the trade
// @field endTime Time on the last bar of the trade
// @field startLineTime Time on the first bar of the line connecting area and trade
// @field tradeColor Default colour of the trade, RED for shorts, GREEN for
longs
// @field openTrade True for open trades, false for trades that hit TP or SL
levels
type trade
float entry
float top
float bottom
color topColor
color bottomColor
int startTime
int endTime
int startLineTime
color tradeColor
bool openTrade = true
int dir

// @variable storage array for swing areas


var array<area> areas = array.new<area>()
// @variable storage array for trades
var array<trade> trades = array.new<trade>()

// @variable fast volatility measure of 20 periods


fastVolatilityMeasure = ta.atr(20)
// @variable default volatility measure of 200 periods
volatilityMeasure = ta.atr(200)
// @variable threshold to compare areas by volatility
areaThreshold = areaThresholdMultiplierInput * (bar_index < 200 ?
fastVolatilityMeasure : volatilityMeasure)
// @variable take profit in points by volatility
takeProfit = takeProfitMultiplierInput * (bar_index < 200 ?
fastVolatilityMeasure : volatilityMeasure)
// @variable stop loss in points by volatility
stopLoss = stopLossMultiplierInput * (bar_index < 200 ?
fastVolatilityMeasure : volatilityMeasure)
// @variable bar index `pivotLengthInput` bars ago
legIndex = bar_index[pivotLengthInput]
// @variable high `pivotLengthInput` bars ago
legHigh = high[pivotLengthInput]
// @variable low `pivotLengthInput` bars ago
legLow = low[pivotLengthInput]
// @variable time `pivotLengthInput` bars ago
legTime = time[pivotLengthInput]

//---------------------------------------------------------------------------------
------------------------------------}
//USER-DEFINED FUNCTIONS
//---------------------------------------------------------------------------------
------------------------------------{
// @function Get the value of the current leg, it can be 0 (bearish) or
1 (bullish)
// @returns int
leg() =>
var leg = 0
newLegHigh = legHigh > ta.highest(pivotLengthInput)
newLegLow = legLow < ta.lowest( pivotLengthInput)

if newLegHigh
leg := BEARISH_LEG
else if newLegLow
leg := BULLISH_LEG

leg

// @function Identify whether the current value is the start of a new


leg (swing)
// @param leg (int) Current leg value
// @returns bool
startOfNewLeg(int leg) => ta.change(leg) != 0

// @function Identify whether the current level is the start of a new


bearish leg (swing)
// @param leg (int) Current leg value
// @returns bool
startOfBearishLeg(int leg) => ta.change(leg) == -1

// @function Identify whether the current level is the start of a new


bullish leg (swing)
// @param leg (int) Current leg value
// @returns bool
startOfBullishLeg(int leg) => ta.change(leg) == +1

// @function Update highest and/or lowest area values


// @param a_rea (area) area to update
// @param areaHigh (float) new area high, it is used if is not `na`
// @param areaLow (float) new area low, it is used if is not `na`
// @returns float
updateAreaValues(area a_rea,float areaHigh, float areaLow) =>
if not na(areaHigh)
a_rea.areaHigh := areaHigh
if not na(areaLow)
a_rea.areaLow := areaLow

// @function Create a new area and add it to the storage


// @param areaHigh (float) area high
// @param areaLow (float) area low
// @param areaColor (color) Default area colour
// @returns void
createNewArea(float areaHigh = na, float areaLow = na, color areaColor) =>
area a_rea = area.new()
updateAreaValues(a_rea, areaHigh, areaLow)
a_rea.startTime := legTime
a_rea.areaColor := areaColor

if array.size(areas) >= ARRAY_MAX_SIZE


array.shift(areas)
array.push(areas,a_rea)

// @function Check that an average price is valid comparing it with all


the average prices of untouched areas within the parameters defined by the user
// @param averagePrice (float) average price to check
// @returns bool
validAveragePrice(float averagePrice) =>
validAvegare = true
size = array.size(areas)
for [index,eachArea] in areas
if index < size - 1 and not eachArea.touched and bar_index -
eachArea.endIndex <= maximumDistanceFromAreaInput
if math.abs(eachArea.averagePrice - averagePrice) <= areaThreshold
validAvegare := false
break
validAvegare

// @function Update the last area with its final values and if it is not
a valid one, delete it from storage
// @param areaHigh (float) area high
// @param areaLow (float) area low
// @returns area ID
updateLastArea(float areaHigh = na, float areaLow = na) =>
if array.size(areas) > 0
area a_rea = array.last(areas)
updateAreaValues(a_rea, areaHigh, areaLow)
a_rea.endIndex := legIndex
a_rea.endTime := legTime
a_rea.averagePrice :=
math.round_to_mintick(0.5*(a_rea.areaHigh+a_rea.areaLow))
if not validAveragePrice(a_rea.averagePrice)
array.pop(areas)

// @function Check if close is crossing over the provided price level


// @param level Price level to be checked against the close
// @returns bool
crossOver(float level) => close[1] < level and close > level

// @function Check if close is crossing under the provided price level


// @param level Price level to be checked against the close
// @returns bool
crossUnder(float level) => close[1] > level and close < level

// @function Check if current bar has reached the average price of a


given area within the specified parameters
// @param a_rea (area) Swing area to get values from
// @returns bool
reach(area a_rea) =>
openTrade = array.size(trades) > 0 ? array.last(trades).openTrade : false
checkForTradesDisabled = not overlappingTradesInput and openTrade
distanceFromArea = bar_index - a_rea.endIndex
if distanceFromArea <= maximumDistanceFromAreaInput and distanceFromArea >=
minimumDistanceFromAreaInput and bar_index > 20 and not checkForTradesDisabled
crossOver(a_rea.averagePrice) or crossUnder(a_rea.averagePrice)

// @function Create a new short trade and add it to the storage


// @param a_rea (area) Swing area to get values from
// @returns void
addShortTrade(area a_rea) =>
currentTakeProfit = a_rea.averagePrice - takeProfit
currentStopLoss = a_rea.averagePrice + stopLoss

trade t_rade = trade.new(a_rea.averagePrice, currentStopLoss,


math.max(currentTakeProfit,0), stopLossColorInput, takeProfitColorInput, time,
time, a_rea.startTime, tradeColor = bearAvgColorInput, dir = -1)

if array.size(trades) >= ARRAY_MAX_SIZE


array.shift(trades)
array.push(trades,t_rade)
// @function Create a new long trade and add it to the storage
// @param a_rea (area) Swing area to get values from
// @returns void
addLongTrade(area a_rea) =>
currentTakeProfit = a_rea.averagePrice + takeProfit
currentStopLoss = a_rea.averagePrice - stopLoss

trade t_rade = trade.new(a_rea.averagePrice, currentTakeProfit,


math.max(currentStopLoss,0), takeProfitColorInput, stopLossColorInput, time, time,
a_rea.startTime, tradeColor = bullAvgColorInput, dir = 1)

if array.size(trades) >= ARRAY_MAX_SIZE


array.shift(trades)
array.push(trades,t_rade)

// @function Update a trade with its definitive values


// @param t_rade (trade) Trade to update
// @returns bool
updateTrade(trade t_rade) =>
t_rade.endTime := time
t_rade.openTrade := false

// @function Draw area with two lines


// @param a_rea (area) Area to draw
// @returns line ID
drawArea(area a_rea) =>
line.new(a_rea.startTime, a_rea.areaHigh, a_rea.endTime, a_rea.areaHigh,
xloc.bar_time, color=a_rea.areaColor)
line.new(a_rea.startTime, a_rea.areaLow, a_rea.endTime, a_rea.areaLow,
xloc.bar_time, color=a_rea.areaColor)

// @function Draw trade with two boxes and one line


// @param t_rade (trade) Trade to draw
// @returns line ID
drawTrade(trade t_rade) =>
if (t_rade.dir == 1 and showTPAreasInput) or (t_rade.dir == -1 and
showSLAreasInput)
box.new(t_rade.startTime, t_rade.top, t_rade.openTrade ? time :
t_rade.endTime, t_rade.entry, xloc = xloc.bar_time, bgcolor = t_rade.topColor,
border_color = color(na))

if (t_rade.dir == 1 and showSLAreasInput) or (t_rade.dir == -1 and


showTPAreasInput)
box.new(t_rade.startTime, t_rade.entry,t_rade.openTrade ? time :
t_rade.endTime, t_rade.bottom, xloc = xloc.bar_time, bgcolor =
t_rade.bottomColor,border_color = color(na))

if showAverageInput
line.new(t_rade.startLineTime, t_rade.entry, t_rade.openTrade ? time :
t_rade.endTime, t_rade.entry, xloc = xloc.bar_time, color = t_rade.tradeColor,
style = line.style_dashed)

//---------------------------------------------------------------------------------
------------------------------------}
//MUTABLE VARIABLES & EXECUTION
//---------------------------------------------------------------------------------
------------------------------------{
// @variable Get current leg value, this is the leg value on the current
bar
currentLeg = leg()

// we execute the logic only once per bar close


if barstate.isconfirmed

// we get a new swing area


if startOfNewLeg(currentLeg)

// we identify the new area as a bearish one so we create and/or update


areas upon user selection mode
if startOfBearishLeg(currentLeg)
switch areaSelectionModeInput
BULLISH_AREA => updateLastArea(legHigh)
BEARISH_AREA => createNewArea(legHigh, areaColor =
bearAreaColorInput)
BOTH_AREA =>
updateLastArea(legHigh)
createNewArea(legHigh,areaColor = bearAreaColorInput)

// we identify the new area as a bullish one so we create and/or update


areas upon user selection mode
if startOfBullishLeg(currentLeg)
switch areaSelectionModeInput
BULLISH_AREA => createNewArea(areaLow = legLow, areaColor =
bullAreaColorInput)
BEARISH_AREA => updateLastArea(areaLow = legLow)
BOTH_AREA =>
updateLastArea(areaLow = legLow)
createNewArea(areaLow = legLow,areaColor = bullAreaColorInput)

// we check for new trades on all untouched areas average prices


for eachArea in areas
if not eachArea.touched and reach(eachArea)
eachArea.touched := true
if crossOver(eachArea.averagePrice)
addShortTrade(eachArea)
if crossUnder(eachArea.averagePrice)
addLongTrade(eachArea)

// we check for stop loss and take profit hits on all open trades
for eachTrade in trades
if eachTrade.openTrade
if high > eachTrade.top or low < eachTrade.bottom
updateTrade(eachTrade)

// we plot all the drawings (boxes and lines) only once at the end of historical
data, and then once per bar on bar close
if barstate.islastconfirmedhistory or (barstate.isrealtime and
barstate.isconfirmed)
if showAreasInput
// we draw all touched areas
for eachArea in areas
if eachArea.touched
drawArea(eachArea)

// we draw all trades


if showTPAreasInput or showSLAreasInput
for eachTrade in trades
drawTrade(eachTrade)
//---------------------------------------------------------------------------------
------------------------------------}
// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.0
at https://mozilla.org/MPL/2.0/
// © fluxchart

//@version=5
const bool DEBUG = false
const int maxBoxesCount = 500
const float overlapThresholdPercentage = 0.0
int maxDistanceToLastBar = 1250 // Affects Running Time
const int maxSDZones = 30
const int minZoneSize = 10
const int RETEST_COOLDOWN = 5
const int minDistanceBetweenZones = 5
const float maxZoneSizeATR = 1.5

//ndicator(title = 'Supply & Demand (MTF) | Flux Charts', shorttitle = "Supply and
Demand (MTF) | Flux Charts", overlay = true, max_boxes_count = maxBoxesCount,
max_labels_count = maxBoxesCount, max_lines_count = maxBoxesCount, max_bars_back =
2000)

maxDistanceString = input.string("Normal", "Max Distance To Last Bar", options =


["High", "Normal", "Low"], group = "General Configuration", display =
display.none)
sdEndMethod = input.string("Close", "Zone Invalidation", options = ["Wick",
"Close"], group = "General Configuration", display = display.none)
combineSDs = DEBUG ? input.bool(true, "Combine Zones", group = "General
Configuration", display = display.none) : true
momentumBodyMult = DEBUG ? input.float(0.5, "Momentum Body Mult", step = 0.1, group
= "General Configuration") : 0.5
momentumCount = DEBUG ? input.int(4,"Momentum Count", group = "General
Configuration") : 4
momentumSpan = DEBUG ? input.int(4, "Momentum Span", group = "General
Configuration") : 4
//zoneCount = input.string("High", 'Zone Count', options = ["High", "Medium",
"Low", "One"], tooltip = "Number of S&D Zones to be rendered. Higher options will
result in older S&Ds shown.", group = "General Configuration", display =
display.none)
zoneCount = "High"
retestsEnabled = input.bool(true, "Retests", inline = "rb", group = "General
Configuration", display = display.none)
breaksEnabled = input.bool(false, "Breaks", inline = "rb", group = "General
Configuration", display = display.none)
showInvalidated = input.bool(true, "Show Historic Zones", group = "General
Configuration", display = display.none)
bullSDZoneColor = input(#08998180, 'Demand', inline = 'sdColor', group = 'General
Configuration', display = display.none)
bearSDZoneColor = input(#f2364680, 'Supply', inline = 'sdColor', group = 'General
Configuration', display = display.none)

demandZones = zoneCount == "One" ? 1 : zoneCount == "Low" ? 3 : zoneCount ==


"Medium" ? 5 : 30
supplyZones = zoneCount == "One" ? 1 : zoneCount == "Low" ? 3 : zoneCount ==
"Medium" ? 5 : 30

timeframe1Enabled = input.bool(true, title = "", group = "Timeframes", inline =


"timeframe1", display = display.none)
timeframe1 = input.timeframe("", title = "", group = "Timeframes", inline =
"timeframe1", display = display.none)
timeframe2Enabled = input.bool(false, title = "", group = "Timeframes", inline =
"timeframe2", display = display.none)
timeframe2 = input.timeframe("15", title = "", group = "Timeframes", inline =
"timeframe2", display = display.none)
timeframe3Enabled = input.bool(false, title = "", group = "Timeframes", inline =
"timeframe3", display = display.none)
timeframe3 = input.timeframe("30", title = "", group = "Timeframes", inline =
"timeframe3", display = display.none)

textColor = input.color(#ffffffcc, "Text Color", group = "Style")


labelsAtSameLevel = DEBUG ? input.bool(true, "[DBG] Place Labels At Same Level",
group = "Style") : true
labelsAtSameLevelBreak = false

atr = ta.atr(20)
averageBodySize = ta.sma(math.abs(close - open), 20)

maxDistanceToLastBar := maxDistanceString == "Low" ? 150 : maxDistanceString ==


"Normal" ? 500 : 1250

type sdZoneInfo
float top
float bottom
string sdType
int startTime
int breakTime
int guid
string timeframeStr
bool disabled = false
string combinedTimeframesStr = na
bool combined = false

type sdZone
sdZoneInfo info
bool isRendered = false

box sdBox = na

line sdBoxLineTop = na
line sdBoxLineMiddle = na
line sdBoxLineBottom = na
//
box sdBoxText = na

type retestLabelContainer
int guid
array<label> labels

createSDZone (sdZoneInfo sdZoneInfoF) =>


sdZone newSDZone = sdZone.new(sdZoneInfoF)
newSDZone

safeDeleteSDZone (sdZone sdZoneF) =>


sdZoneF.isRendered := false

box.delete(sdZoneF.sdBox)
box.delete(sdZoneF.sdBoxText)
line.delete(sdZoneF.sdBoxLineTop)
line.delete(sdZoneF.sdBoxLineMiddle)
line.delete(sdZoneF.sdBoxLineBottom)

type timeframeInfo
int index = na
string timeframeStr = na
bool isEnabled = false

sdZoneInfo[] demandZonesList = na
sdZoneInfo[] supplyZonesList = na

newTimeframeInfo (index, timeframeStr, isEnabled) =>


newTFInfo = timeframeInfo.new()
newTFInfo.index := index
newTFInfo.isEnabled := isEnabled
newTFInfo.timeframeStr := timeframeStr

newTFInfo

// ____ TYPES END ____

var timeframeInfo[] timeframeInfos = array.from(newTimeframeInfo(1, timeframe1,


timeframe1Enabled), newTimeframeInfo(2, timeframe2, timeframe2Enabled),
newTimeframeInfo(3, timeframe3, timeframe3Enabled))
var demandZonesList = array.new<sdZoneInfo>(0)
var supplyZonesList = array.new<sdZoneInfo>(0)
var breakLabels = map.new<int, label>()
var retestLabels = map.new<int, retestLabelContainer>()

var int oldestBarTime = na


if bar_index == last_bar_index - maxDistanceToLastBar
oldestBarTime := time

var allSDZonesList = array.new<sdZone>(0)

moveLine(_line, _x, _y, _x2) =>


line.set_xy1(_line, _x, _y)
line.set_xy2(_line, _x2, _y)

moveBox (_box, _topLeftX, _topLeftY, _bottomRightX, _bottomRightY) =>


box.set_lefttop(_box, _topLeftX, _topLeftY)
box.set_rightbottom(_box, _bottomRightX, _bottomRightY)

isTimeframeLower (timeframe1F, timeframe2F) =>


timeframe.in_seconds(timeframe1F) < timeframe.in_seconds(timeframe2F)

getMinTimeframe (timeframe1F, timeframe2F) =>


if isTimeframeLower(timeframe1F, timeframe2F)
timeframe1F
else
timeframe2F

getMaxTimeframe (timeframe1F, timeframe2F) =>


if isTimeframeLower(timeframe1F, timeframe2F)
timeframe2F
else
timeframe1F
formatTimeframeString (formatTimeframe) =>
timeframeF = formatTimeframe == "" ? timeframe.period : formatTimeframe

if str.contains(timeframeF, "D") or str.contains(timeframeF, "W") or


str.contains(timeframeF, "S") or str.contains(timeframeF, "M")
timeframeF
else
seconds = timeframe.in_seconds(timeframeF)
if seconds >= 3600
hourCount = int(seconds / 3600)
str.tostring(hourCount) + " Hour" + (hourCount > 1 ? "s" : "")
else
timeframeF + " Min"

colorWithTransparency (colorF, transparencyX) =>


color.new(colorF, color.t(colorF) * transparencyX)

createSDBox (boxColor, transparencyX = 1.0, xlocType = xloc.bar_time) =>


box.new(na, na, na, na, xloc = xlocType, extend = extend.none, bgcolor =
colorWithTransparency(boxColor, transparencyX), text_color = textColor, text_halign
= text.align_right, text_valign = text.align_bottom, text_size = size.small,
border_color = boxColor)

renderSDZone (sdZone sd) =>


sdZoneInfo info = sd.info

sd.isRendered := true

sdColor = sd.info.sdType == "Demand" ? bullSDZoneColor : bearSDZoneColor

int zoneSize = na
if na(info.breakTime)
zoneSize := (time + 1) - info.startTime
else
zoneSize := (info.breakTime - info.startTime)

render = true
if zoneSize < timeframe.in_seconds(info.timeframeStr) * minZoneSize * 1000
render := false
if info.startTime < nz(oldestBarTime, time)
render := false

if render and (showInvalidated or (na(sd.info.breakTime)))


sd.sdBox := createSDBox(sdColor, 1.5)
if sd.info.combined
sd.sdBox.set_bgcolor(colorWithTransparency(sdColor, 1.1))

startX = info.startTime
maxEndX = info.startTime + zoneSize / 2

float middlePoint = (info.top + info.bottom) / 2


moveBox(sd.sdBox, info.startTime, info.top, info.startTime + zoneSize,
info.bottom)

sd.sdBoxLineMiddle := line.new(info.startTime, middlePoint, info.startTime


+ zoneSize, middlePoint, xloc = xloc.bar_time, color = textColor, style =
line.style_dashed)
sd.sdBoxText := createSDBox(color.new(color.white, 100))
moveBox(sd.sdBoxText, maxEndX, middlePoint, info.startTime + zoneSize,
info.bottom)
SDText = (na(sd.info.combinedTimeframesStr) ?
formatTimeframeString(sd.info.timeframeStr) : sd.info.combinedTimeframesStr) + " "
+ sd.info.sdType
//box.set_text(sd.sdBoxText, SDText)
boxText = na(sd.info.combinedTimeframesStr) ?
formatTimeframeString(sd.info.timeframeStr) : sd.info.combinedTimeframesStr
if DEBUG
boxText += " | " + str.tostring(sd.info.guid)
box.set_text(sd.sdBoxText, boxText)

areaOfSD (sdZoneInfo SDInfoF) =>


float XA1 = SDInfoF.startTime
float XA2 = na(SDInfoF.breakTime) ? time + 1 : SDInfoF.breakTime
float YA1 = SDInfoF.top
float YA2 = SDInfoF.bottom
float edge1 = math.sqrt((XA2 - XA1) * (XA2 - XA1) + (YA2 - YA2) * (YA2 - YA2))
float edge2 = math.sqrt((XA2 - XA2) * (XA2 - XA2) + (YA2 - YA1) * (YA2 - YA1))
float totalArea = edge1 * edge2
totalArea

doSDsTouch (sdZoneInfo SDInfo1, sdZoneInfo SDInfo2) =>


float XA1 = SDInfo1.startTime
float XA2 = na(SDInfo1.breakTime) ? (time + 1) : SDInfo1.breakTime
float YA1 = SDInfo1.top + atr / 100
float YA2 = SDInfo1.bottom - atr / 100

float XB1 = SDInfo2.startTime


float XB2 = na(SDInfo2.breakTime) ? (time + 1) : SDInfo2.breakTime
float YB1 = SDInfo2.top + atr / 100
float YB2 = SDInfo2.bottom - atr / 100
float intersectionArea = math.max(0, math.min(XA2, XB2) - math.max(XA1, XB1)) *
math.max(0, math.min(YA1, YB1) - math.max(YA2, YB2))
float unionArea = areaOfSD(SDInfo1) + areaOfSD(SDInfo2) - intersectionArea

float overlapPercentage = (intersectionArea / unionArea) * 100.0

if overlapPercentage > overlapThresholdPercentage


true
else
false

isSDValid (sdZoneInfo SDInfo) =>


valid = true
if SDInfo.disabled
valid := false
valid

clampSDZone (sdZoneInfo sdZoneF) =>


sdZoneSize = sdZoneF.top - sdZoneF.bottom
if sdZoneSize > atr * maxZoneSizeATR
diff = sdZoneSize - (atr * maxZoneSizeATR)
sdZoneF.top -= diff / 2
sdZoneF.bottom += diff / 2
combineSDsFunc () =>
if allSDZonesList.size() > 0
lastCombinations = 999
while lastCombinations > 0
lastCombinations := 0
for i = 0 to allSDZonesList.size() - 1
curSD1 = allSDZonesList.get(i)
for j = 0 to allSDZonesList.size() - 1
curSD2 = allSDZonesList.get(j)
if i == j
continue
if not isSDValid(curSD1.info) or not isSDValid(curSD2.info)
continue
if curSD1.info.sdType != curSD2.info.sdType
continue
if doSDsTouch(curSD1.info, curSD2.info)
curSD1.info.disabled := true
curSD2.info.disabled := true

sdZone newSD =
createSDZone(sdZoneInfo.new(math.max(curSD1.info.top, curSD2.info.top),
math.min(curSD1.info.bottom, curSD2.info.bottom), curSD1.info.sdType))
newSD.info.startTime := math.min(curSD1.info.startTime,
curSD2.info.startTime)
newSD.info.breakTime := math.max(nz(curSD1.info.breakTime),
nz(curSD2.info.breakTime))
newSD.info.breakTime := newSD.info.breakTime == 0 ? na :
newSD.info.breakTime
newSD.info.guid := newSD.info.startTime
newSD.info.timeframeStr := curSD1.info.timeframeStr
clampSDZone(newSD.info)

newSD.info.combined := true
if timeframe.in_seconds(curSD1.info.timeframeStr) !=
timeframe.in_seconds(curSD2.info.timeframeStr)
newSD.info.combinedTimeframesStr :=
(na(curSD1.info.combinedTimeframesStr) ?
formatTimeframeString(curSD1.info.timeframeStr) :
curSD1.info.combinedTimeframesStr) + " & " + (na(curSD2.info.combinedTimeframesStr)
? formatTimeframeString(curSD2.info.timeframeStr) :
curSD2.info.combinedTimeframesStr)
allSDZonesList.unshift(newSD)
lastCombinations += 1

reqSeq (timeframeStr) =>


[demandZonesListF, supplyZonesListF] = request.security(syminfo.tickerid,
timeframeStr, [demandZonesList, supplyZonesList])
[demandZonesListF, supplyZonesListF]

getTFData (timeframeInfo timeframeInfoF, timeframeStr) =>


if not isTimeframeLower(timeframeInfoF.timeframeStr, timeframe.period) and
timeframeInfoF.isEnabled
[demandZonesListF, supplyZonesListF] = reqSeq(timeframeStr)
[demandZonesListF, supplyZonesListF]
else
[na, na]

handleTimeframeInfo (timeframeInfo timeframeInfoF, demandZonesListF,


supplyZonesListF) =>
if not isTimeframeLower(timeframeInfoF.timeframeStr, timeframe.period) and
timeframeInfoF.isEnabled
timeframeInfoF.demandZonesList := demandZonesListF
timeframeInfoF.supplyZonesList := supplyZonesListF

handleSDZonesFinal () =>
if DEBUG
log.info("Demand Count " + str.tostring(demandZonesList.size()))
log.info("Supply Count " + str.tostring(supplyZonesList.size()))
log.info("All " + str.tostring(allSDZonesList.size()))
log.info("Max " + str.tostring(demandZones))

if allSDZonesList.size () > 0
for i = 0 to allSDZonesList.size() - 1
safeDeleteSDZone(allSDZonesList.get(i))
allSDZonesList.clear()

for i = 0 to timeframeInfos.size() - 1
curTimeframe = timeframeInfos.get(i)
if not curTimeframe.isEnabled
continue
if curTimeframe.demandZonesList.size() > 0
for j = 0 to math.min(curTimeframe.demandZonesList.size() - 1,
demandZones - 1)
sdZoneInfoF = curTimeframe.demandZonesList.get(j)
sdZoneInfoF.timeframeStr := curTimeframe.timeframeStr
allSDZonesList.unshift(createSDZone(sdZoneInfo.copy(sdZoneInfoF)))

if curTimeframe.supplyZonesList.size() > 0
for j = 0 to math.min(curTimeframe.supplyZonesList.size() - 1,
supplyZones - 1)
sdZoneInfoF = curTimeframe.supplyZonesList.get(j)
sdZoneInfoF.timeframeStr := curTimeframe.timeframeStr
allSDZonesList.unshift(createSDZone(sdZoneInfo.copy(sdZoneInfoF)))

if combineSDs
combineSDsFunc()

if allSDZonesList.size() > 0
for i = 0 to allSDZonesList.size() - 1
curSD = allSDZonesList.get(i)
if isSDValid(curSD.info)
renderSDZone(curSD)

bodySize = math.abs(close - open)


getMomentumCandleCount (lastBars, reqMult) =>
bearishCnt = 0
bullishCnt = 0
for i = 0 to lastBars - 1
if bodySize[i] >= averageBodySize * reqMult
if close[i] > open[i]
bullishCnt += 1
else
bearishCnt += 1
[bullishCnt, bearishCnt]

[bullishMomentum, bearishMomentum] = getMomentumCandleCount(momentumSpan,


momentumBodyMult)
var int lastDemandZone = 0
var int lastSupplyZone = 0
// Find Supply & Demand
if bar_index > last_bar_index - maxDistanceToLastBar
if bullishMomentum >= momentumCount and bar_index - lastDemandZone >
minDistanceBetweenZones
lastDemandZone := bar_index
newSDZone = sdZoneInfo.new(high[momentumSpan + 1], low[momentumSpan + 1],
"Demand", time[momentumSpan + 1], na, time[momentumSpan + 1])
clampSDZone(newSDZone)
demandZonesList.unshift(newSDZone)
if demandZonesList.size() > maxSDZones
demandZonesList.pop()
if bearishMomentum >= momentumCount and bar_index - lastSupplyZone >
minDistanceBetweenZones
lastSupplyZone := bar_index
newSDZone = sdZoneInfo.new(high[momentumSpan + 1], low[momentumSpan + 1],
"Supply", time[momentumSpan + 1], na, time[momentumSpan + 1])
clampSDZone(newSDZone)
supplyZonesList.unshift(newSDZone)
if supplyZonesList.size() > maxSDZones
supplyZonesList.pop()

// Invalidation
if demandZonesList.size() > 0
for i = demandZonesList.size() - 1 to 0
currentSD = demandZonesList.get(i)

if na(currentSD.breakTime)
if (sdEndMethod == "Wick" ? low : math.min(open, close)) <
currentSD.bottom
currentSD.breakTime := time

if supplyZonesList.size() > 0
for i = supplyZonesList.size() - 1 to 0
currentSD = supplyZonesList.get(i)

if na(currentSD.breakTime)
if (sdEndMethod == "Wick" ? high : math.max(open, close)) >
currentSD.top
currentSD.breakTime := time

[demandZonesListTimeframe1, supplyZonesListTimeframe1] =
getTFData(timeframeInfos.get(0), timeframe1)
[demandZonesListTimeframe2, supplyZonesListTimeframe2] =
getTFData(timeframeInfos.get(1), timeframe2)
[demandZonesListTimeframe3, supplyZonesListTimeframe3] =
getTFData(timeframeInfos.get(2), timeframe3)

var lastRetestIndexSupply = 0
var lastRetestIndexDemand = 0

float renderRetestLabelBuyside = na
int renderRetestLabelBuysideGUID = na

float renderRetestLabelSellside = na
int renderRetestLabelSellsideGUID = na
float renderBreakLabelBuyside = na
int renderBreakLabelBuysideGUID = na

float renderBreakLabelSellside = na
int renderBreakLabelSellsideGUID = na

if barstate.isconfirmed and bar_index > last_bar_index - maxDistanceToLastBar


// Disable Duplicate Timeframes
for i = 0 to timeframeInfos.size() - 1
for j = 0 to timeframeInfos.size() - 1
if i == j
continue
timeframeInfo1 = timeframeInfos.get(i)
timeframeInfo2 = timeframeInfos.get(j)
if timeframeInfo1.isEnabled and timeframeInfo2.isEnabled and
timeframe.in_seconds(timeframeInfo1.timeframeStr) ==
timeframe.in_seconds(timeframeInfo2.timeframeStr)
timeframeInfo1.isEnabled := false

handleTimeframeInfo(timeframeInfos.get(0), demandZonesListTimeframe1,
supplyZonesListTimeframe1)
handleTimeframeInfo(timeframeInfos.get(1), demandZonesListTimeframe2,
supplyZonesListTimeframe2)
handleTimeframeInfo(timeframeInfos.get(2), demandZonesListTimeframe3,
supplyZonesListTimeframe3)
handleSDZonesFinal()

// Breaks

if allSDZonesList.size() > 0
for i = 0 to allSDZonesList.size() - 1
curZone = allSDZonesList.get(i)
if curZone.info.disabled
continue
if not showInvalidated and not na(curZone.info.breakTime)
continue
if na(curZone.info.breakTime)
continue
if time - curZone.info.startTime < minZoneSize *
timeframe.in_seconds(curZone.info.timeframeStr) * 1000
continue
if curZone.info.startTime < nz(oldestBarTime, time)
continue

if time == curZone.info.breakTime
if curZone.info.sdType == "Supply"
if curZone.info.breakTime - curZone.info.startTime >
minZoneSize * timeframe.in_seconds() * 1000
renderBreakLabelBuyside := curZone.info.bottom
renderBreakLabelBuysideGUID := curZone.info.guid
else
if curZone.info.breakTime - curZone.info.startTime >
minZoneSize * timeframe.in_seconds() * 1000
renderBreakLabelSellside := curZone.info.top
renderBreakLabelSellsideGUID := curZone.info.guid

// Retests
if allSDZonesList.size() > 0
for i = 0 to allSDZonesList.size() - 1
curZone = allSDZonesList.get(i)

if curZone.info.disabled
continue
if not showInvalidated and not na(curZone.info.breakTime)
continue
if not na(curZone.info.breakTime)
continue
if time - curZone.info.startTime < minZoneSize *
timeframe.in_seconds(curZone.info.timeframeStr) * 1000
continue
if curZone.info.startTime < nz(oldestBarTime, time)
continue

middleLine = (curZone.info.bottom + curZone.info.top) / 2.0


if curZone.info.sdType == "Supply" and bar_index -
lastRetestIndexSupply > RETEST_COOLDOWN
if high > curZone.info.bottom
renderRetestLabelBuyside := curZone.info.top
renderRetestLabelBuysideGUID := curZone.info.guid
lastRetestIndexSupply := bar_index
else if curZone.info.sdType == "Demand" and bar_index -
lastRetestIndexDemand > RETEST_COOLDOWN
if low < curZone.info.top
renderRetestLabelSellside := curZone.info.bottom
renderRetestLabelSellsideGUID := curZone.info.guid
lastRetestIndexDemand := bar_index

//plotshape(not na(renderRetestLabelBuyside) and retestsEnabled ?


renderRetestLabelBuyside : na, "", shape.labeldown, color = bearSDZoneColor, text =
"R", location = labelsAtSameLevel ? location.absolute : location.abovebar,
textcolor = color.white, size = size.small)
//plotshape(not na(renderRetestLabelSellside) and retestsEnabled ?
renderRetestLabelSellside : na, "", shape.labelup, color = bullSDZoneColor, text =
"R", location = labelsAtSameLevel ? location.absolute : location.belowbar,
textcolor = color.white, size = size.small)

// Retests

if not na(renderRetestLabelBuyside) and retestsEnabled


newLabel = label.new(bar_index, renderRetestLabelBuyside, style =
label.style_label_down, color = bearSDZoneColor, text = "R", textcolor =
color.white, size = size.small)
//label.new(bar_index, renderRetestLabelSellside, style = label.style_label_up,
color = bullSDZoneColor, text = "R", textcolor = color.white, size = size.small)
if na(retestLabels.get(renderRetestLabelBuysideGUID))
newContainer = retestLabelContainer.new(renderRetestLabelBuysideGUID)
newContainer.labels := array.new<label>()
newContainer.labels.push(newLabel)
retestLabels.put(renderRetestLabelBuysideGUID, newContainer)
else
retestLabels.get(renderRetestLabelBuysideGUID).labels.push(newLabel)

if not na(renderRetestLabelSellside) and retestsEnabled


newLabel = label.new(bar_index, renderRetestLabelSellside, style =
label.style_label_up, color = bullSDZoneColor, text = "R", textcolor = color.white,
size = size.small)
if na(retestLabels.get(renderRetestLabelSellsideGUID))
newContainer = retestLabelContainer.new(renderRetestLabelSellsideGUID)
newContainer.labels := array.new<label>()
newContainer.labels.push(newLabel)
retestLabels.put(renderRetestLabelSellsideGUID, newContainer)
else
retestLabels.get(renderRetestLabelSellsideGUID).labels.push(newLabel)

if retestLabels.keys().size() > 0
for i = 0 to retestLabels.keys().size() - 1
curKey = retestLabels.keys().get(i)
foundKey = false
if allSDZonesList.size() > 0
for j = 0 to allSDZonesList.size() - 1
if allSDZonesList.get(j).info.guid == curKey
if allSDZonesList.get(j).info.disabled
continue
if not showInvalidated and not
na(allSDZonesList.get(j).info.breakTime)
continue
if time - allSDZonesList.get(j).info.startTime < minZoneSize *
timeframe.in_seconds(allSDZonesList.get(j).info.timeframeStr) * 1000
continue
if allSDZonesList.get(j).info.startTime < nz(oldestBarTime,
time)
continue
foundKey := true
break
if not foundKey
for j = 0 to retestLabels.get(curKey).labels.size() - 1
label.delete(retestLabels.get(curKey).labels.get(j))

// Breaks
if not na(renderBreakLabelBuyside) and breaksEnabled
breakLabels.put(renderBreakLabelBuysideGUID, label.new(bar_index,
renderBreakLabelBuyside, style = label.style_label_up, color = color.blue, text =
"B", textcolor = color.white, size = size.small))

if not na(renderBreakLabelSellside) and breaksEnabled


breakLabels.put(renderBreakLabelSellsideGUID, label.new(bar_index,
renderBreakLabelSellside, style = label.style_label_down, color = color.blue, text
= "B", textcolor = color.white, size = size.small))

if breakLabels.keys().size() > 0
for i = 0 to breakLabels.keys().size() - 1
curKey = breakLabels.keys().get(i)
foundKey = false
if allSDZonesList.size() > 0
for j = 0 to allSDZonesList.size() - 1
if allSDZonesList.get(j).info.guid == curKey
if allSDZonesList.get(j).info.disabled
continue
foundKey := true
break
if not foundKey
label.delete(breakLabels.get(curKey))

alertcondition(not na(renderRetestLabelBuyside) and barstate.isconfirmed, "Supply


Zone Retest @ {{ticker}}", "Supply Zone Retest @ {{ticker}}")
alertcondition(not na(renderRetestLabelSellside) and barstate.isconfirmed, "Demand
Zone Retest @ {{ticker}}", "Demand Zone Retest @ {{ticker}}")

alertcondition(not na(renderBreakLabelBuyside) and barstate.isconfirmed, "Supply


Zone Break @ {{ticker}}", "Supply Zone Break @ {{ticker}}")
alertcondition(not na(renderBreakLabelSellside) and barstate.isconfirmed, "Demand
Zone Break @ {{ticker}}", "Demand Zone Break @ {{ticker}}")

You might also like