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

// This Pine Script™ code is subject to the terms of the Mozilla Public License 2.

0
at https://mozilla.org/MPL/2.0/
// © leandrolopezf1920

//@version=5
indicator("Simple System by LEO 2", overlay = true, max_lines_count = 500,
max_labels_count = 500, max_boxes_count = 500, max_bars_back = 1000)
//------------------------------------------------------------------------------
// === Range Detector ===
//------------------------------------------------------------------------------

length3 = input.int(20, 'Minimum Range Length', minval = 2)


mult = input.float(1., 'Range Width', minval = 0, step = 0.1)
atrLen = input.int(500, 'ATR Length', minval = 1)

//Style
upCss = input(#089981, 'Broken Upward', group = 'Style')
dnCss = input(#f23645, 'Broken Downward', group = 'Style')
unbrokenCss = input(#2157f3, 'Unbroken', group = 'Style')

//-----------------------------------------------------------------------------}
//Detect and highlight ranges
//-----------------------------------------------------------------------------{
//Ranges drawings
var box bx = na
var line lvl = na

//Extensions
var float max2 = na
var float min2 = na

var os = 0
color detect_css = na

atr = ta.atr(atrLen) * mult


ma = ta.sma(close, length3)
n = bar_index
count = 0
for i = 0 to length3-1
count += math.abs(close[i] - ma) > atr ? 1 : 0

if count == 0 and count[1] != count


//Test for overlap and change coordinates
if n[length3] <= bx.get_right()
max2 := math.max(ma + atr, bx.get_top())
min2 := math.min(ma - atr, bx.get_bottom())

//Box new coordinates


bx.set_top(max2)
bx.set_rightbottom(n, min2)
bx.set_bgcolor(color.new(unbrokenCss, 80))

//Line new coordinates


avg = math.avg(max2, min2)
lvl.set_y1(avg)
lvl.set_xy2(n, avg)
lvl.set_color(unbrokenCss)
else
max2 := ma + atr
min2 := ma - atr

//Set new box and level


bx := box.new(n[length3], ma + atr, n, ma - atr, na
, bgcolor = color.new(unbrokenCss, 100))

lvl := line.new(n[length3], ma, n, ma


, color = unbrokenCss
, style = line.style_dotted)

detect_css := color.new(#787b86, 80)


os := 0

else if count == 0
bx.set_right(n)
lvl.set_x2(n)

//Set color
if close > bx.get_top()
bx.set_bgcolor(color.new(#ff5252, 100))
lvl.set_color(upCss)
os := 1
else if close < bx.get_bottom()
bx.set_bgcolor(color.new(#ff5252, 100))
lvl.set_color(dnCss)
os := -1

//-----------------------------------------------------------------------------}
//Plots
//-----------------------------------------------------------------------------{
//Range detection bgcolor
bgcolor(detect_css)

plot(max2, 'Range Top'


, max2 != max2[1] ? na : os == 0 ? unbrokenCss : os == 1 ? upCss : dnCss)

plot(min2, 'Range Bottom'


, min2 != min2[1] ? na : os == 0 ? unbrokenCss : os == 1 ? upCss : dnCss)

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

//INPUTS
cooldownPeriod = input.int(10,title="Cooldown Period", minval=0, group =
"Settings")

lbLeft = 20
lbRight = 20

showSwing = input.bool(true,title="Show Swings?", inline="s_1", group = 'Swing


Detaction')
swingClr = input.color(color.new(color.orange, 0), title='', inline="s_1", group =
'Swing Detaction')

bullWidth = input.int(1, title='Line Width:', group='Bullish Sweep')


bullStyle = input.string('Dashed', title='Line Style:', options=['Solid', 'Dotted',
'Dashed'], group='Bullish Sweep')
bullColor = input.color(color.new(color.teal, 0), title='Bullish Color:',
group='Bullish Sweep')
bearWidth = input.int(1, title='Line Width:', group='Bearish Sweep')
bearStyle = input.string('Dashed', title='Line Style:', options=['Solid', 'Dotted',
'Dashed'], group='Bearish Sweep')
bearColor = input.color(color.new(color.maroon, 0), title='Bearish Color:',
group='Bearish Sweep')

//FUNCTIONS
lineStyle(s) =>
if s == 'Solid'
line.style_solid
else if s == 'Dotted'
line.style_dotted
else
line.style_dashed

//VARS
var int bullSignalIndex = 0
var int bearSignalIndex = 0

var line bullLine = na


var line bearLine = na

var line highLine = na


var line lowLine = na

var label swingHighLbl = na


var label swingLowLbl = na
var label swingHighLblTxt = na
var label swingLowLblTxt = na

var float swingLowVal = na


var float swingHighVal = na

//CALCULATIONS
pLow = ta.pivotlow(low, lbLeft, lbRight)
pHigh = ta.pivothigh(high, lbLeft, lbRight)

pLowVal = ta.valuewhen(not na(pLow), low[lbRight], 0)


pHighVal = ta.valuewhen(not na(pHigh), high[lbRight], 0)

prevLowIndex = ta.valuewhen(not na(pLow), bar_index[lbRight], 0)


prevHighIndex = ta.valuewhen(not na(pHigh), bar_index[lbRight], 0)

lp = ta.lowest(low, lbLeft)
hp = ta.highest(high, lbLeft)

highestClose = ta.highest(close, lbLeft)


lowestClose = ta.lowest(close, lbLeft)

bullishSFP = low < pLowVal and close > pLowVal and open > pLowVal and low == lp and
lowestClose >= pLowVal
bearishSFP = high > pHighVal and close < pHighVal and open < pHighVal and high ==
hp and highestClose <= pHighVal

bullCond = bullishSFP[3] and (close > pLowVal) and (close[1] > pLowVal[1]) and
(close[2] > pLowVal[2]) and bar_index >= bullSignalIndex + cooldownPeriod
bearCond = bearishSFP[3] and (close < pHighVal) and (close[1] < pHighVal[1]) and
(close[2] < pHighVal[2]) and bar_index >= bearSignalIndex + cooldownPeriod
//Check Swing H/L Stopper
var int swingLowCounter = 0
var int swingHighCounter = 0
var bool isSwingLowCheck = false
var bool isSwingHighCheck = false
var bool stopPrintingLow = false
var bool stopPrintingHigh = false

if high < swingLowVal and isSwingLowCheck


swingLowCounter := swingLowCounter+1

if low > swingHighVal and isSwingHighCheck


swingHighCounter := swingHighCounter+1

if ta.crossunder(close, swingLowVal) and isSwingLowCheck == false


isSwingLowCheck := true
swingLowCounter := 1

if ta.crossover(close, swingHighVal) and isSwingHighCheck == false


isSwingHighCheck := true
swingHighCounter := 1

if swingLowCounter == 5 and isSwingLowCheck


stopPrintingLow := true
isSwingLowCheck := false
line.set_x2(lowLine,bar_index[4])

if swingHighCounter == 5 and isSwingHighCheck


stopPrintingHigh := true
isSwingHighCheck := false
line.set_x2(highLine,bar_index[4])

//Draw sweep lines


if bullCond
bullSignalIndex := bar_index
bullLine := line.new(prevLowIndex, pLowVal, bar_index-3, pLowVal,
color=bullColor, width=bullWidth, style=lineStyle(bullStyle))

if bearCond
bearSignalIndex := bar_index
bearLine := line.new(prevHighIndex, pHighVal, bar_index-3, pHighVal,
color=bearColor, width=bearWidth, style=lineStyle(bearStyle))

var swingHighArr = array.new_label(0)


var swingHighTextArr = array.new_label(0)

var swingLowArr = array.new_label(0)


var swingLowTextArr = array.new_label(0)

if array.size(swingHighArr) >= 3
label.delete(array.shift(swingHighArr))
label.delete(array.shift(swingHighTextArr))

if array.size(swingLowArr) >= 3
label.delete(array.shift(swingLowArr))
label.delete(array.shift(swingLowTextArr))

//Draw range lines


if showSwing
if stopPrintingHigh == false
line.set_x2(highLine,bar_index+5)
if stopPrintingLow == false
line.set_x2(lowLine,bar_index+5)

if showSwing and not na(pHigh) and bearishSFP[lbRight] == false


stopPrintingHigh := false
swingHighVal := high[lbRight]
line.delete(highLine)
highLine := line.new(bar_index[lbRight], high[lbRight], bar_index+10,
high[lbRight], color = swingClr, width = 2)

swingHighLbl := label.new(bar_index[lbRight], high[lbRight], text="",


yloc=yloc.abovebar, color = swingClr, textcolor = swingClr, style =
label.style_triangledown, size = size.auto)
swingHighLblTxt := label.new(bar_index[lbRight], high[lbRight], text="Swing\
nH", yloc=yloc.abovebar, color = swingClr, textcolor = swingClr, style =
label.style_none, size = size.small)
array.push(swingHighArr, swingHighLbl)
array.push(swingHighTextArr, swingHighLblTxt)

if showSwing and not na(pLow) and bullishSFP[lbRight] == false


stopPrintingLow := false
swingLowVal := low[lbRight]
line.delete(lowLine)
lowLine := line.new(bar_index[lbRight], low[lbRight], bar_index+10,
low[lbRight], color = swingClr, width = 2)

swingLowLbl := label.new(bar_index[lbRight], low[lbRight], text="",


yloc=yloc.belowbar, color = swingClr, textcolor = swingClr, style =
label.style_triangleup, size = size.auto)
swingLowLblTxt := label.new(bar_index[lbRight], low[lbRight], text="Swing\nL",
yloc=yloc.belowbar, color = swingClr, textcolor = swingClr, style =
label.style_none, size = size.small)
array.push(swingLowArr, swingLowLbl)
array.push(swingLowTextArr, swingLowLblTxt)

//PLOTS
plotshape(bullCond, text='Sweep', color=bullColor, textcolor=bullColor,
location=location.belowbar, offset = -3)
plotshape(bearCond, text='Sweep', color=bearColor, textcolor=bearColor,
location=location.abovebar, offset = -3)

//ALERTS
alertcondition(bullishSFP, title='Bullish Sweep', message='{{ticker}} Bullish
Sweep, Price:{{close}}')
alertcondition(bearishSFP, title='Bearish Sweep', message='{{ticker}} Bearish
Sweep, Price:{{close}}')

//------------------------------------------------------------------------------
// === Zig Zag Channels ===
//------------------------------------------------------------------------------

length1 = input(100)
extend = input(true,'Extend To Last Bar')
show_ext = input(true,'Show Extremities')
show_labels = input(true,'Show Labels')
//Style

upcol = input(#ff1100,'Upper Extremity Color',group='Style')


midcol = input(#ff5d00,'Zig Zag Color',group='Style')
dncol = input(#2157f3,'Lower Extremity Color',group='Style')
//------------------------------------------------------------------------------
os1 = 0
src1 = close
var float valtop = na
var float valbtm = na

//------------------------------------------------------------------------------
upper = ta.highest(src1,length1)
lower = ta.lowest(src1,length1)
os1 := src1[length1] > upper ? 0 : src1[length1] < lower ? 1 : os1[1]

btm = os1 == 1 and os1[1] != 1


top = os1 == 0 and os1[1] != 0

//------------------------------------------------------------------------------
btm_n = ta.valuewhen(btm,n,0)
top_n = ta.valuewhen(top,n,0)
len = math.abs(btm_n - top_n)

if btm
max_diff_up = 0.
max_diff_dn = 0.
valbtm := low[length1]

for i = 0 to len-1
point = low[length1] + i/(len-1)*(valtop - low[length1])
max_diff_up := math.max(math.max(src1[length1+i],open[length1+i]) -
point,max_diff_up)
max_diff_dn := math.max(point -
math.min(src1[length1+i],open[length1+i]),max_diff_dn)

line.new(n[len+length1],valtop,n[length1],low[length1],color=midcol)

if show_ext

line.new(n[len+length1],valtop+max_diff_up,n[length1],low[length1]+max_diff_up
,color=upcol,style=line.style_dotted)
line.new(n[len+length1],valtop-max_diff_dn,n[length1],low[length1]-
max_diff_dn
,color=dncol,style=line.style_dotted)
if show_labels

label.new(n[length1],low[length1],str.tostring(low[length1],'#.####'),color=#000000
00
,style=label.style_label_up,textcolor=dncol,textalign=text.align_left,siz
e=size.small)

if top
max_diff_up = 0.
max_diff_dn = 0.
valtop := high[length1]

for i = 0 to len-1
point = high[length1] + i/(len-1)*(valbtm - high[length1])
max_diff_up := math.max(math.max(src1[length1+i],open[length1+i]) -
point,max_diff_up)
max_diff_dn := math.max(point -
math.min(src1[length1+i],open[length1+i]),max_diff_dn)

line.new(n[len+length1],valbtm,n[length1],high[length1],color=midcol)

if show_ext

line.new(n[len+length1],valbtm+max_diff_up,n[length1],high[length1]+max_diff_up
,color=upcol,style=line.style_dotted)
line.new(n[len+length1],valbtm-max_diff_dn,n[length1],high[length1]-
max_diff_dn
,color=dncol,style=line.style_dotted)
if show_labels

label.new(n[length1],high[length1],str.tostring(high[length1],'#.####'),color=#0000
0000
,style=label.style_label_down,textcolor=upcol,textalign=text.align_left,s
ize=size.small)

if barstate.islast and extend


max_diff_up = 0.
max_diff_dn = 0.
x1 = 0
y1 = 0.

if os1 == 1
x1 := btm_n-length1
y1 := valbtm

for i = 0 to n-btm_n+length1-1
point = src1 + i/(n-btm_n+length1-1)*(valbtm - src1)
max_diff_up := math.max(math.max(src1[i],open[i]) - point,max_diff_up)
max_diff_dn := math.max(point - math.min(src1[i],open[i]),max_diff_dn)

else
x1 := top_n-length1
y1 := valtop

for i = 0 to n-top_n+length1-1
point = src1 + i/(n-top_n+length1-1)*(valtop - src1)
max_diff_up := math.max(math.max(src1[i],open[i]) - point,max_diff_up)
max_diff_dn := math.max(point - math.min(src1[i],open[i]),max_diff_dn)

line.delete(line.new(x1,y1,n,src1,color=midcol,extend=extend.right)[1])

if show_ext
line.delete(line.new(x1,y1+max_diff_up,n,src1+max_diff_up
,color=upcol,style=line.style_dotted,extend=extend.right)[1])
line.delete(line.new(x1,y1-max_diff_dn,n,src1-max_diff_dn
,color=dncol,style=line.style_dotted,extend=extend.right)[1])

//------------------------------------------------------------------------------
plot(btm ? low[length1] : top ? high[length1] : na,'Circles'
,color = btm ? dncol : upcol
,style=plot.style_circles
,offset=-length1)
//-----------------------------------------------------------------------------}

C_Len = 14 // ta.ema depth for bodyAvg


C_ShadowPercent = 5.0 // size of shadows
C_ShadowEqualsPercent = 100.0
C_DojiBodyPercent = 5.0
C_Factor = 2.0 // shows the number of times the shadow dominates the candlestick
body

C_BodyHi = math.max(close, open)


C_BodyLo = math.min(close, open)
C_Body = C_BodyHi - C_BodyLo
C_BodyAvg = ta.ema(C_Body, C_Len)
C_SmallBody = C_Body < C_BodyAvg
C_LongBody = C_Body > C_BodyAvg
C_UpShadow = high - C_BodyHi
C_DnShadow = C_BodyLo - low
C_HasUpShadow = C_UpShadow > C_ShadowPercent / 100 * C_Body
C_HasDnShadow = C_DnShadow > C_ShadowPercent / 100 * C_Body
C_WhiteBody = open < close
C_BlackBody = open > close
C_Range = high-low
C_IsInsideBar = C_BodyHi[1] > C_BodyHi and C_BodyLo[1] < C_BodyLo
C_BodyMiddle = C_Body / 2 + C_BodyLo
C_ShadowEquals = C_UpShadow == C_DnShadow or (math.abs(C_UpShadow - C_DnShadow) /
C_DnShadow * 100) < C_ShadowEqualsPercent and (math.abs(C_DnShadow - C_UpShadow) /
C_UpShadow * 100) < C_ShadowEqualsPercent
C_IsDojiBody = C_Range > 0 and C_Body <= C_Range * C_DojiBodyPercent / 100
C_Doji = C_IsDojiBody and C_ShadowEquals

patternLabelPosLow = low - (ta.atr(30) * 0.6)


patternLabelPosHigh = high + (ta.atr(30) * 0.6)

label_color_bearish = input(color.rgb(255, 82, 82, 90), "Label Color Bearish")


label_color_bullish = input(color.rgb(33, 149, 243, 90), "Label Color Bullish")

//--------------//

C_DownTrend = true
C_UpTrend = true
var trendRule1 = "SMA50"
var trendRule2 = "SMA50, SMA200"
var trendRule = input.string(trendRule1, "Detect Trend Based On",
options=[trendRule1, trendRule2, "No detection"])

if trendRule == trendRule1
priceAvg = ta.sma(close, 50)
C_DownTrend := close < priceAvg
C_UpTrend := close > priceAvg

if trendRule == trendRule2
sma200 = ta.sma(close, 200)
sma50 = ta.sma(close, 50)
C_DownTrend := close < sma50 and sma50 < sma200
C_UpTrend := close > sma50 and sma50 > sma200

C_EngulfingBullishNumberOfCandles = 2
C_EngulfingBullish = C_DownTrend and C_WhiteBody and C_LongBody and C_BlackBody[1]
and C_SmallBody[1] and close >= open[1] and open <= close[1] and ( close > open[1]
or open < close[1] )
alertcondition(C_EngulfingBullish, title = "New pattern detected", message = "New
Engulfing – Bullish pattern detected")
if C_EngulfingBullish
var ttBullishEngulfing = "Engulfing\nAt the end of a given downward trend,
there will most likely be a reversal pattern. To distinguish the first day, this
candlestick pattern uses a small body, followed by a day where the candle body
fully overtakes the body from the day before, and closes in the trend’s opposite
direction. Although similar to the outside reversal chart pattern, it is not
essential for this pattern to completely overtake the range (high to low), rather
only the open and the close."
label.new(bar_index, patternLabelPosLow, text="BE", style=label.style_label_up,
color = label_color_bullish, textcolor=color.white, tooltip = ttBullishEngulfing)

C_EngulfingBearishNumberOfCandles = 2
C_EngulfingBearish = C_UpTrend and C_BlackBody and C_LongBody and C_WhiteBody[1]
and C_SmallBody[1] and close <= open[1] and open >= close[1] and ( close < open[1]
or open > close[1] )
alertcondition(C_EngulfingBearish, title = "New pattern detected", message = "New
Engulfing – Bearish pattern detected")
if C_EngulfingBearish
var ttBearishEngulfing = "Engulfing\nAt the end of a given uptrend, a reversal
pattern will most likely appear. During the first day, this candlestick pattern
uses a small body. It is then followed by a day where the candle body fully
overtakes the body from the day before it and closes in the trend’s opposite
direction. Although similar to the outside reversal chart pattern, it is not
essential for this pattern to fully overtake the range (high to low), rather only
the open and the close."
label.new(bar_index, patternLabelPosHigh, text="BE",
style=label.style_label_down, color = label_color_bearish, textcolor=color.white,
tooltip = ttBearishEngulfing)

//-----------------------------------------------------------------------------}
//SUPPORT AND RESISTANCE MTF
//-----------------------------------------------------------------------------{
const bool DEBUG = false
const int timeframeCount = 3
const float touchATR = 1.0 / 30.0
const float retestATR = 1.0 / 30.0
const float labelOffsetY = 1.5
const int labelOffsetsXIndex = 30
const int maxPivotsBackSR = 15
const int retestLabelEveryXBars = 3
const int maxTraverse = 250 // Affects bar history limit. Default value 250.
const int maxRetestLabels = 100
const int maxSupports = 3
const int maxResistances = 3
const int debug_maxPivotLabels = 25

// _____ INPUTS _____


resistanceSupportCount = input.int(3, "Support & Resistance Count", options = [1,
2, 3], group = "General Configuration", display = display.none)
pivotRange = input.int(15, "Pivot Range", options = [5, 15, 30], tooltip =
"Increase for more general pivots, decrease for more private pivots.", group =
"General Configuration", display = display.none)
strength = input.int(1, "Strength", options = [1, 2, 3, 4], tooltip = "X many times
price touched relative price area in order to be considered a support/resistance
zone.", group = "General Configuration", display = display.none)
expandLines = input.bool(true,"Expand Lines & Zones", group = "General
Configuration", display = display.none)

enableZones = input.bool(false, "Enable Zones", group = "Support & Resistance


Zones", display = display.none)
zoneWidthType = input.string("Dynamic", "Zone Width Type", options = ["Fixed",
"Dynamic"], group = "Support & Resistance Zones", display = display.none)
zoneWidth = input.int(1, "Fixed Zone Width", options = [1,2,3], group = "Support &
Resistance Zones", display = display.none)

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(true, title = "", group = "Timeframes", inline =
"timeframe2", display = display.none)
timeframe2 = input.timeframe("240", 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)

showBreaks = input.bool(true,"Show Breaks", group = "Breaks & Retests", inline =


"ShowBR", display = display.none)
showRetests = input.bool(true,"Show Retests", group = "Breaks & Retests", inline =
"ShowBR", display = display.none)
avoidFalseBreaks = input.bool(true, "Avoid False Breaks", group = "Breaks &
Retests", display = display.none)
falseBreakoutVolumeThresholdOpt = input.float(0.3, "Break Volume Threshold",
minval=0.1, maxval=1.0, step=0.1, group = "Breaks & Retests", tooltip = "Only taken
into account if Avoid False Breakouts is enabled.\nHigher values mean it's less
likely to be a break.", display = display.none)
inverseBrokenLineColor = input.bool(true, "Inverse Color After Broken", tooltip =
"Needs Show Breaks & Expand Lines option enabled.", group = "Breaks & Retests",
display = display.none)

falseBreakoutVolumeThreshold = falseBreakoutVolumeThresholdOpt * 100.0

lineStyle = input.string("....", "Line Style", ["____", "----", "...."], group =


"Style", display = display.none)
lineWidth = input.int(1, "Line Width", minval = 1, group = "Style", display =
display.none)
supportColor = input.color(#08998180, "Support Color", group = "Style", inline =
"RScolors", display = display.none)
resistanceColor = input.color(#f2364580, "Resistance Color", group = "Style",
inline = "RScolors", display = display.none)
textColor = input.color(#11101051, "Text Color", group = "Style", inline =
"RScolors", display = display.none)
labelsAlign = input.string("Right", "Align Labels", options = ["Right", "Center"],
group = "Style", tooltip = "Will only work when zones are disabled.", display =
display.none)

enableRetestAlerts = input.bool(true, "Enable Retest Alerts", tooltip = "Needs Show


Retests option enabled.", group = "Alerts", display = display.none)
enableBreakAlerts = input.bool(true, "Enable Break Alerts", group = "Alerts",
display = display.none)
memoryOptimizatonEnabled = input.bool(true, "Enable Memory Optimization", tooltip =
"Enable this option if you encounter memory errors.", group = "Advanced", display =
display.none)
// _____ INPUTS END _____

// _____ DEBUG OPTIONS _____


debug_labelPivots = not DEBUG ? "None" : input.string("None", title = "[DBG] Label
Pivots", group = "DEBUG", options = ["All", "RS", "None"], tooltip = "All -> Debugs
all pivot labels.\nRS -> Debugs RS pivot labels.\nNone -> Debugs none of the last
R&S pivots.")
debug_pivotLabelText = not DEBUG ? false : input.bool(false, title = "[DBG] Pivot
Label Text", group = "DEBUG")
debug_showBrokenOnLabel = not DEBUG ? false : input.bool(false, "[DBG] Show Broken
Text On Label", group = "DEBUG")
debug_removeDuplicateRS = not DEBUG ? true : input.bool(true, "[DBG] Remove
Duplicate RS", group = "DEBUG")
debug_lastXResistances = not DEBUG ? 3 : input.int(3, "[DBG] Show Last X
Resistances", minval = 0, maxval = maxResistances, group = "DEBUG")
debug_lastXSupports = not DEBUG ? 3 : input.int(3, "[DBG] Show Last X Supports",
minval = 0, maxval = maxSupports, group = "DEBUG")
debug_enabledHistory = not DEBUG ? true : input.bool(true, "[DBG] Enable History",
group = "DEBUG")
debug_maxHistoryRecords = not DEBUG ? 10 : input.int(10, "[DBG] Max History
Records", options = [1, 2, 5, 10, 25], group = "DEBUG")
// _____ DEBUG OPTIONS END _____

atr1 = ta.atr(30)

createRSLine (color) =>


line.new(na, na, na, na, extend = expandLines ? extend.both : extend.none,
xloc=xloc.bar_time, color = color, width = lineWidth, style = lineStyle == "----" ?
line.style_dashed : lineStyle == "...." ? line.style_dotted : line.style_solid)

createRSBox (color, xlocType) =>


box.new(na, na, na, na, text_size = size.normal, xloc = xlocType, extend =
extend.both, bgcolor = color, text_color = textColor, text_halign = expandLines ?
text.align_right : text.align_center, border_color = #00000000)

createRSLabel () =>
label.new(na, na, "", style = label.style_none, textcolor = textColor)

createBreakLabel (RSType) =>


var ttBreakResistance = "Breakout\nA breakout of Support or Resistance."
label.new(na,na,"B",style = RSType == "Resistance" ? label.style_label_up :
label.style_label_down, color=color.rgb(33, 149, 243, 50), textcolor = color.white,
xloc = xloc.bar_time, size = size.small,tooltip = ttBreakResistance)

createRetestLabel (RSType) =>


label.new(na,na,"R",style = RSType == "Resistance" ? label.style_label_down :
label.style_label_up, color = RSType == "Resistance" ? resistanceColor :
supportColor, textcolor = color.white, xloc = xloc.bar_time, size = size.small)

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)
moveRSInfoBox (_box, _startPointX, _price, _endPointX) =>
zoneWidthPercent = zoneWidth == 1 ? 0.05 : zoneWidth == 2 ? 0.06 : 0.075
if zoneWidthType == "Dynamic"
zoneWidthPercent := ((atr1) / _price) * 100 / 3.0
topY = _price * (1.0 + (zoneWidthPercent / 2.0 / 100.0))
bottomY = _price * (1.0 - (zoneWidthPercent / 2.0 / 100.0))
moveBox(_box, _startPointX, topY, _endPointX, bottomY)

// _____ TYPES _____

type customPoint
int t
float price

type RSInfo
bool isBroken = na
int brokenTime = na
string RSType = na
float price = na
line line = na
box box = na
label priceLabel = na
customPoint[] points = na
label[] debugPoints = na
label breakLabel = na
label[] retestLabels = na
line breakLine = na
box breakBox = na

curTR = ta.tr(true)
lowPivot = ta.pivotlow(low, pivotRange, pivotRange)
highPivot = ta.pivothigh(high, pivotRange, pivotRange)
pivotTime = time[pivotRange]

newRSInfo (RSType) =>


newRSInfoF = RSInfo.new()
newRSInfoF.RSType := RSType
newRSInfoF.price := na
newRSInfoF.isBroken := false
newRSInfoF.brokenTime := na

newRSInfoF.line := enableZones ? na : createRSLine(RSType == "Resistance" ?


resistanceColor : supportColor)
newRSInfoF.box := enableZones ? createRSBox(RSType == "Resistance" ?
resistanceColor : supportColor, xloc.bar_time) : na
newRSInfoF.priceLabel := enableZones ? na : createRSLabel()
newRSInfoF.points := array.new<customPoint>(0)
newRSInfoF.debugPoints := array.new<label>(0)
newRSInfoF.retestLabels := array.new<label>(0)
newRSInfoF.breakLabel := na
newRSInfoF.breakLine := na
newRSInfoF.breakBox := na

newRSInfoF

histRSInfo (RSInfo RSInfoF) =>


RSType = RSInfoF.RSType
newRS = RSInfo.new()
newRS.RSType := RSType
newRS.price := RSInfoF.price

newRS.debugPoints := array.new<label>(0)
newRS.retestLabels := array.new<label>(0)
newRS.points := array.new<customPoint>(0)

histText = "History | " + str.tostring(newRS.price, format.mintick)

startTime = math.min(time, RSInfoF.points.get(RSInfoF.points.size() - 1).t)


endTime = RSInfoF.isBroken ? RSInfoF.brokenTime : time

if enableZones
newRS.box := createRSBox(RSType == "Resistance" ? resistanceColor :
supportColor, xloc.bar_time)
moveRSInfoBox(newRS.box, startTime, newRS.price, endTime)
box.set_extend(newRS.box, expandLines ? extend.both : extend.none)
box.set_text(newRS.box, histText)
else
newRS.line := line.copy(RSInfoF.line)
moveLine(newRS.line, startTime, newRS.price, endTime)
line.set_extend(newRS.line, expandLines ? extend.both : extend.none)

newRS.priceLabel := label.copy(RSInfoF.priceLabel)
label.set_text(newRS.priceLabel, histText)
label.set_xloc(newRS.priceLabel, (startTime + endTime) / 2, xloc.bar_time)

if not na(newRS.breakLabel)
newRS.breakLabel := label.copy(RSInfoF.breakLabel)

newRS

derenderRSInfo (RSInfo RSInfoF) =>


if not na(RSInfoF)
line.delete(RSInfoF.line)
box.delete(RSInfoF.box)
label.delete(RSInfoF.priceLabel)

if RSInfoF.debugPoints.size() > 0
for i = 0 to RSInfoF.debugPoints.size() - 1
label.delete(RSInfoF.debugPoints.get(i))

if RSInfoF.retestLabels.size() > 0
for i = 0 to RSInfoF.retestLabels.size() - 1
label.delete(RSInfoF.retestLabels.get(i))

label.delete(RSInfoF.breakLabel)
line.delete(RSInfoF.breakLine)
box.delete(RSInfoF.breakBox)

safeDeleteRSInfo (RSInfo RSInfoF) =>


if not na(RSInfoF)
derenderRSInfo(RSInfoF)
RSInfoF.points.clear()
RSInfoF.debugPoints.clear()
RSInfoF.retestLabels.clear()

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

RSInfo[] resistances = na
RSInfo[] supports = na

float[] highPivots = na
float[] highTRs = na
int[] highTimes = na

float[] lowPivots = na
float[] lowTRs = na
int[] lowTimes = na

newTimeframeInfo (index, timeframeStr, isEnabled) =>


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

newTFInfo.resistances := array.new<RSInfo>(debug_lastXResistances)
newTFInfo.supports := array.new<RSInfo>(debug_lastXSupports)

newTFInfo.highPivots := array.new<float>()
newTFInfo.highTRs := array.new<float>()
newTFInfo.highTimes := array.new<int>()

newTFInfo.lowPivots := array.new<float>()
newTFInfo.lowTRs := array.new<float>()
newTFInfo.lowTimes := array.new<int>()

newTFInfo

// _____ TYPES END _____

// _____ VARS _____

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


timeframe1Enabled), newTimeframeInfo(2, timeframe2, timeframe2Enabled),
newTimeframeInfo(3, timeframe3, timeframe3Enabled))
var bool initRun = true

var float[] allLowPivots = array.new<float>(0)


var float[] allHighPivots = array.new<float>(0)

var int[] allLowTimes = array.new<int>(0)


var int[] allHighTimes = array.new<int>(0)

var float[] allHighTR = array.new<float>(0)


var float[] allLowTR = array.new<float>(0)

var RSInfo[] history = array.new<RSInfo>(0)

RSInfo[] curRSList = array.new<RSInfo>(0)


RSInfo[] oldRSList = array.new<RSInfo>(0)

int maxPivotsAllowed = memoryOptimizatonEnabled ? 7 : 15 // Affects memory limit.


Default value 15.
// _____ VARS END _____

doValuesTouch (float value1, float value2, float tr) =>


if math.abs(value1 - value2) <= tr * touchATR
true
else
false

doValuesTouch (float value1, float value2, float tr, float customATRRatio) =>
if math.abs(value1 - value2) <= tr * customATRRatio
true
else
false

findLatestRS (timeframeInfo timeframeInfoF, string RSType, pivots, times, trs,


bannedValues) =>
RSInfo latestRSF = na
pivotsCount = pivots.size()
if pivotsCount > 0
for i = 0 to pivotsCount - 1
if i >= maxTraverse
break

index = pivotsCount - i - 1
occurances = 0
invalidValue = false
pivotValue1 = pivots.get(index)
if bannedValues.size() > 0
for a = 0 to bannedValues.size() - 1
if doValuesTouch(pivotValue1, bannedValues.get(a),
trs.get(index))
invalidValue := true
break

if invalidValue
continue

for j = 0 to pivotsCount - 1
if j >= maxTraverse
break

index2 = pivotsCount - j - 1
pivotValue2 = pivots.get(index2)
if doValuesTouch(pivotValue1, pivotValue2, trs.get(index))
occurances += 1

if occurances >= strength


latestRSF := newRSInfo(RSType)
latestRSF.price := pivotValue1
break

if math.abs(index - index2) > maxPivotsBackSR * strength


break

if not na(latestRSF)
break

if not na(latestRSF)
cnt = 0
if pivotsCount > 0
for i = 0 to pivotsCount - 1
if i >= maxTraverse
break

index = pivotsCount - i - 1
pivotValue = pivots.get(index)
if doValuesTouch(pivotValue, latestRSF.price, trs.get(index))
labelTime = times.get(index)
latestRSF.points.push(customPoint.new(labelTime, pivotValue))
cnt += 1
if cnt == strength
break

if not (debug_labelPivots == "None")


if not (debug_labelPivots == "All")
if not na(latestRSF)
cnt = 0
if pivotsCount > 0
for i = 0 to pivotsCount - 1
index = pivotsCount - i - 1
pivotValue = pivots.get(index)
if doValuesTouch(pivotValue, latestRSF.price,
trs.get(index))
labelTime = times.get(index)
latestRSF.debugPoints.push(RSType == "Resistance" ?
label.new(labelTime,pivotValue,text=debug_pivotLabelText ? str.tostring(pivotValue)
: "",xloc=xloc.bar_time, color=resistanceColor, textcolor=color.white) :
label.new(labelTime,pivotValue,text=debug_pivotLabelText ? str.tostring(pivotValue)
: "",xloc=xloc.bar_time, color=supportColor,style = label.style_label_up,
textcolor=color.white))
cnt += 1
if cnt == strength
break
else
if not na(latestRSF)
if pivotsCount > 0
for i = 0 to pivotsCount - 1
index = pivotsCount - i - 1
pivotValue = pivots.get(index)
labelTime = times.get(index)
latestRSF.debugPoints.push(RSType == "Resistance" ?
label.new(labelTime,pivotValue,text=debug_pivotLabelText ? str.tostring(pivotValue)
: "",xloc=xloc.bar_time, color=resistanceColor, textcolor=color.white) :
label.new(labelTime,pivotValue,text=debug_pivotLabelText ? str.tostring(pivotValue)
: "",xloc=xloc.bar_time, color=supportColor,style = label.style_label_up,
textcolor=color.white))
if latestRSF.debugPoints.size() > debug_maxPivotLabels
break
latestRSF

findLatestNthRS (timeframeInfo timeframeInfoF, string RSType, pivots, times, trs,


n) =>
float[] bannedValues = array.new<float>()
foundRS = 0
RSInfo foundLatestRS = na
while foundRS < n
foundLatestRS := findLatestRS(timeframeInfoF, RSType, pivots, times, trs,
bannedValues)
if not na(foundLatestRS)
foundRS += 1
bannedValues.push(foundLatestRS.price)
else
break
foundLatestRS

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

getFirstBreak (RSInfo rsInfo) =>


if na(rsInfo)
[na, na]

curIndex = 0
float foundBreakLevel = na
int foundBreakTime = na
float foundBreakTR = na

while true
if curIndex >= maxTraverse
break
isBarBreak = rsInfo.RSType == "Resistance" ? (close[curIndex + 1] <=
rsInfo.price and close[curIndex] > rsInfo.price) : (close[curIndex + 1] >=
rsInfo.price and close[curIndex] < rsInfo.price)
if isBarBreak
isTrueBreakout = true
if avoidFalseBreaks
shortTerm = 2
longTerm = 15

shortSum = 0.0
longSum = 0.0

for i = 0 to shortTerm
shortSum += volume[curIndex + i]

for i = 0 to longTerm
longSum += volume[curIndex + i]

shortVolumeAvg = shortSum / shortTerm


longVolumeAvg = longSum / longTerm

volumeRatio = ((shortVolumeAvg - longVolumeAvg) / longVolumeAvg) *


100.0
isTrueBreakout := (volumeRatio >= falseBreakoutVolumeThreshold)
if isTrueBreakout
foundBreakLevel := rsInfo.RSType == "Resistance" ? low[curIndex] :
high[curIndex]
foundBreakTime := time[curIndex]
foundBreakTR := high[curIndex] - low[curIndex]

curIndex += 1
if time[curIndex] <= rsInfo.points.get(rsInfo.points.size() - 1).t
break
[foundBreakLevel, foundBreakTime, foundBreakTR]

getRetests (RSInfo rsInfo) =>


if na(rsInfo)
[na,na]

curIndex = 0
lastRetestIndex = -999
int[] retestTimes = array.new<int>()
float[] retestLevels = array.new<float>()
float[] retestTRs = array.new<float>()

while true
if curIndex >= maxTraverse
break
if retestLevels.size() == maxRetestLabels
break
if rsInfo.isBroken and time[curIndex] >= rsInfo.brokenTime
curIndex += 1
continue

tr = high[curIndex] - low[curIndex]
isRetest = (rsInfo.RSType == "Resistance" ? (doValuesTouch(rsInfo.price,
close[curIndex], tr, retestATR) or doValuesTouch(rsInfo.price, high[curIndex], tr,
retestATR)) : (doValuesTouch(rsInfo.price, close[curIndex], tr, retestATR) or
doValuesTouch(rsInfo.price, low[curIndex], tr, retestATR)))
if isRetest and curIndex - lastRetestIndex >= retestLabelEveryXBars
retestLevels.push(rsInfo.RSType == "Resistance" ? high[curIndex] :
low[curIndex])
retestTimes.push(time[curIndex])
retestTRs.push(high[curIndex] - low[curIndex])
lastRetestIndex := curIndex
curIndex += 1
if time[curIndex] <= rsInfo.points.get(rsInfo.points.size() - 1).t
break
[retestLevels, retestTimes, retestTRs]

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"

handleRSInfo (timeframeInfo timeframeInfoF, RSInfo RSInfoF, int index, string


RSType) =>
if not na(RSInfoF)
if not na(timeframeInfoF)
curRSList.push(RSInfoF)

[foundBreakLevel, foundBreakTime, foundBreakTR] = getFirstBreak(RSInfoF)

RSInfoF.isBroken := na(foundBreakLevel) ? false : true


RSInfoF.brokenTime := na(foundBreakLevel) ? na : foundBreakTime

if not na(foundBreakLevel)
if showBreaks
if na(RSInfoF.breakLabel)
RSInfoF.breakLabel := createBreakLabel(RSInfoF.RSType)
label.set_xy(RSInfoF.breakLabel, foundBreakTime, foundBreakLevel +
(RSInfoF.RSType == "Resistance" ? (-foundBreakTR / labelOffsetY) : foundBreakTR /
labelOffsetY))

if expandLines
if na(RSInfoF.breakLine) and enableZones == false
RSInfoF.breakLine := createRSLine(color.black)

if na(RSInfoF.breakBox) and enableZones == true


RSInfoF.breakBox := createRSBox(color.black, xloc.bar_time)

if not enableZones
line.set_extend(RSInfoF.breakLine, extend.right)
else
box.set_extend(RSInfoF.breakBox, extend.right)

if inverseBrokenLineColor and showBreaks


if not enableZones
line.set_color(RSInfoF.breakLine, RSInfoF.RSType ==
"Resistance" ? supportColor : resistanceColor)
else
box.set_bgcolor(RSInfoF.breakBox, RSInfoF.RSType ==
"Resistance" ? supportColor : resistanceColor)
else
if not enableZones
line.set_color(RSInfoF.breakLine, RSInfoF.RSType ==
"Resistance" ? resistanceColor : supportColor)
else
box.set_bgcolor(RSInfoF.breakBox, RSInfoF.RSType ==
"Resistance" ? resistanceColor : supportColor)

if showRetests
[retestLevels, retestTimes, retestTRs] = getRetests(RSInfoF)

if not na(retestLevels) and retestLevels.size() > 0


for i = 0 to retestLevels.size() - 1
newRetestLabel = createRetestLabel(RSInfoF.RSType)
label.set_xy(newRetestLabel, retestTimes.get(i),
retestLevels.get(i) + (RSInfoF.RSType == "Support" ? (-retestTRs.get(i) /
labelOffsetY) : retestTRs.get(i) / labelOffsetY))
RSInfoF.retestLabels.push(newRetestLabel)
timeSkipOffset = 0
if enableZones
zoneEndX = time + timeSkipOffset +
timeframe.in_seconds(timeframe.period) * 1000 * labelOffsetsXIndex
startTime = math.min(time, RSInfoF.points.get(RSInfoF.points.size() -
1).t)
moveRSInfoBox(RSInfoF.box, startTime, RSInfoF.price, na(foundBreakTime)
? zoneEndX : foundBreakTime)
moveRSInfoBox(RSInfoF.breakBox, foundBreakTime, RSInfoF.price,
zoneEndX)
else
endTime = time + timeSkipOffset +
timeframe.in_seconds(timeframe.period) * 1000
startTime = math.min(time, RSInfoF.points.get(RSInfoF.points.size() -
1).t)
moveLine(RSInfoF.line, startTime, RSInfoF.price, na(foundBreakTime) ?
endTime : foundBreakTime)
moveLine(RSInfoF.breakLine, foundBreakTime, RSInfoF.price, endTime)
//log.info(str.tostring(RSInfoF.price) + " | " +
str.tostring(RSInfoF.points.get(strength - 1).time) + " = " +
str.tostring(line.get_x1(RSInfoF.line)) + " | " + str.tostring(endTime) + " = " +
str.tostring(line.get_x2(RSInfoF.line)))

if expandLines
if not enableZones
line.set_extend(RSInfoF.line, (na(foundBreakTime)) ? extend.both :
extend.left)
else
box.set_extend(RSInfoF.box, (na(foundBreakTime)) ? extend.both :
extend.left)
else
if not enableZones
line.set_extend(RSInfoF.line, na(foundBreakTime) ? extend.right :
extend.none)
else
box.set_extend(RSInfoF.box, na(foundBreakTime) ? extend.right :
extend.none)

//labelTitleOld = formatTimeframeString(timeframeInfoF.timeframeStr) + " "


+ RSInfoF.RSType + " " + str.tostring(index + 1) + " (" +
str.tostring(RSInfoF.price,format.mintick) + ")" + (RSInfoF.isBroken ? "
[Broken]" : "")
labelTitle = formatTimeframeString(timeframeInfoF.timeframeStr) + " | " +
str.tostring(RSInfoF.price,format.mintick) + ((debug_showBrokenOnLabel and
RSInfoF.isBroken) ? " [B]" : "")

if not enableZones
label.set_text(RSInfoF.priceLabel, enableZones ? "" : labelTitle)
label.set_y(RSInfoF.priceLabel, RSInfoF.price)
else
box.set_text(RSInfoF.box, (RSInfoF.isBroken and expandLines) ? "" :
labelTitle)
box.set_text(RSInfoF.breakBox, labelTitle)

if expandLines or not RSInfoF.isBroken


if not enableZones
if labelsAlign == "Right"
label.set_xloc(RSInfoF.priceLabel, bar_index +
labelOffsetsXIndex, xloc.bar_index)
else
label.set_xloc(RSInfoF.priceLabel, labelsAlign == "Center" ?
((chart.right_visible_bar_time + chart.left_visible_bar_time) / 2) : na,
xloc.bar_time)
else
box.set_text_halign(RSInfoF.breakBox, text.align_right)
box.set_text_halign(RSInfoF.box, text.align_right)
else
if not enableZones
label.set_xloc(RSInfoF.priceLabel,
(RSInfoF.points.get(RSInfoF.points.size() - 1).t + RSInfoF.brokenTime) / 2,
xloc.bar_time)
else
box.set_text_halign(RSInfoF.box, text.align_center)
box.set_text_halign(RSInfoF.breakBox, text.align_center)
else
log.error("Couldn't find timeframe " + str.tostring(timeframeInfoF.index) +
" " + str.tostring(index + 1) + "th " + RSType + " . Try decreasing pivot range in
the settings.")

handleTimeframe (timeframeIndex, lowPivots, highPivots, lowTimes, highTimes,


lowTRs, highTRs) =>
timeframeInfoF = timeframeInfos.get(timeframeIndex - 1)

timeframeInfoF.lowPivots.clear()
timeframeInfoF.highPivots.clear()

timeframeInfoF.lowTimes.clear()
timeframeInfoF.highTimes.clear()

timeframeInfoF.lowTRs.clear()
timeframeInfoF.highTRs.clear()

timeframeInfoF.lowPivots := lowPivots
timeframeInfoF.highPivots := highPivots

timeframeInfoF.lowTimes := lowTimes
timeframeInfoF.highTimes := highTimes

timeframeInfoF.lowTRs := lowTRs
timeframeInfoF.highTRs := highTRs

getHigherTFData (timeframeStr) =>


request.security(syminfo.tickerid, getMaxTimeframe(timeframe.period,
timeframeStr), [allLowPivots, allHighPivots, allLowTimes, allHighTimes, allLowTR,
allHighTR])

pushHighPivots (timeframeInfoF, highPivotF, timeF, trF) =>


if not na(highPivotF)
timeframeInfoF.highPivots.push(highPivotF)
timeframeInfoF.highTimes.push(timeF)
timeframeInfoF.highTRs.push(trF)

pushLowPivots (timeframeInfoF, lowPivotF, timeF, trF) =>


if not na(lowPivotF)
timeframeInfoF.lowPivots.push(lowPivotF)
timeframeInfoF.lowTimes.push(timeF)
timeframeInfoF.lowTRs.push(trF)
handleTimeframeIfLower (timeframeInfo timeframeInfoF, highs, lows, int[] timesF,
float[] trsF) =>
if timeframeInfoF.isEnabled and isTimeframeLower(timeframeInfoF.timeframeStr,
timeframe.period)
if highs.size() > 0
for i = 0 to highs.size() - 1
timeF = timesF.get(i)
pushHighPivots(timeframeInfoF, highs.get(i), timeF, trsF.get(i))
if lows.size() > 0
for i = 0 to lows.size() - 1
timeF = timesF.get(i)
pushLowPivots(timeframeInfoF, lows.get(i), timeF, trsF.get(i))

getLowerTFData (timeframeStr) =>


lowPivots = isTimeframeLower(timeframeStr, timeframe.period) ?
request.security_lower_tf(syminfo.tickerid, getMinTimeframe(timeframeStr,
timeframe.period), ta.pivotlow(low, pivotRange, pivotRange)) : na
highPivots = isTimeframeLower(timeframeStr, timeframe.period) ?
request.security_lower_tf(syminfo.tickerid, getMinTimeframe(timeframeStr,
timeframe.period), ta.pivothigh(high, pivotRange, pivotRange)) : na
times = isTimeframeLower(timeframeStr, timeframe.period) ?
request.security_lower_tf(syminfo.tickerid, getMinTimeframe(timeframeStr,
timeframe.period), pivotTime) : na
trs = isTimeframeLower(timeframeStr, timeframe.period) ?
request.security_lower_tf(syminfo.tickerid, getMinTimeframe(timeframeStr,
timeframe.period), curTR[pivotRange]) : na
[lowPivots, highPivots, times, times, trs, trs]

getTFData (timeframeStr) =>


if isTimeframeLower(timeframeStr, timeframe.period)
getLowerTFData(timeframeStr)
else
getHigherTFData(timeframeStr)

checkIfRSAreSame (RSInfo rsInfo1, RSInfo rsInfo2) =>


if na(rsInfo1) or na(rsInfo2)
false
else if rsInfo1.RSType != rsInfo2.RSType
false
else if rsInfo1.price != rsInfo2.price
false
else
true

checkIfArrHasRS (RSInfo[] arr, RSInfo rsInfoF) =>


if na(arr) or na(rsInfoF)
true
else if arr.size() == 0
false
else
foundRS = false
for i = 0 to arr.size() - 1
arrRS = arr.get(i)
if checkIfRSAreSame(arrRS, rsInfoF)
foundRS := true
break
if foundRS
true
else
false

clearTimeframeRS (timeframeInfoF) =>


oldRetestsCount = 0
oldBreaksCount = 0

if timeframeInfoF.resistances.size() > 0
for j = 0 to timeframeInfoF.resistances.size() - 1
RSInfo RSInfoF = timeframeInfoF.resistances.get(j)
if not na(RSInfoF)
if debug_enabledHistory
if checkIfArrHasRS(oldRSList, RSInfoF) == false
oldRSList.push(RSInfoF)

oldRetestsCount += RSInfoF.retestLabels.size()
oldBreaksCount += RSInfoF.isBroken ? 1 : 0
derenderRSInfo(RSInfoF)

if timeframeInfoF.supports.size() > 0
for j = 0 to timeframeInfoF.supports.size() - 1
RSInfo RSInfoF = timeframeInfoF.supports.get(j)
if not na(RSInfoF)
if debug_enabledHistory
if checkIfArrHasRS(history, RSInfoF) == false
oldRSList.push(RSInfoF)

oldRetestsCount += RSInfoF.retestLabels.size()
oldBreaksCount += RSInfoF.isBroken ? 1 : 0
derenderRSInfo(RSInfoF)

timeframeInfoF.resistances.clear()
timeframeInfoF.supports.clear()
[oldRetestsCount, oldBreaksCount]

findTimeframeRS (timeframeInfoF, RSType, arr, count, pivots, times, trs) =>


curRetestsCount = 0
curBreaksCount = 0

if count > 0
for j = 0 to count - 1
foundRS = findLatestNthRS(timeframeInfoF, RSType, pivots, times, trs, j
+ 1)
if not na(foundRS)
notDuplicate = true
for a = 0 to timeframeInfos.size() - 1
aInfo = timeframeInfos.get(a)
if na(aInfo) or aInfo.isEnabled == false
continue
otherTimeframeArray = (RSType == "Resistance" ?
aInfo.resistances : aInfo.supports)
if otherTimeframeArray.size() > 0
for b = 0 to otherTimeframeArray.size() - 1
if checkIfRSAreSame(foundRS,
otherTimeframeArray.get(b))
notDuplicate := false
break
if notDuplicate == false
break
if notDuplicate or not debug_removeDuplicateRS
arr.push(foundRS)

if arr.size() > 0
for j = 0 to arr.size() - 1
curRS = arr.get(j)
if not na(curRS)
handleRSInfo(timeframeInfoF, curRS, j, RSType)
curRetestsCount += curRS.retestLabels.size()
curBreaksCount += curRS.isBroken ? 1 : 0
[curRetestsCount, curBreaksCount]

if not na(lowPivot)
allLowPivots.push(lowPivot)
allLowTimes.push(pivotTime)
allLowTR.push(curTR[pivotRange])
if allLowPivots.size() > maxPivotsAllowed
allLowPivots.remove(0)
allLowTimes.remove(0)
allLowTR.remove(0)

if not na(highPivot)
allHighPivots.push(highPivot)
allHighTimes.push(pivotTime)
allHighTR.push(curTR[pivotRange])
if allHighPivots.size() > maxPivotsAllowed
allHighPivots.remove(0)
allHighTimes.remove(0)
allHighTR.remove(0)

[lowPivotsTF1, highPivotsTF1, lowTimesTF1, highTimesTF1, lowTRsTF1, highTRsTF1] =


getTFData(timeframe1)
handleTimeframeIfLower(timeframeInfos.get(0), highPivotsTF1, lowPivotsTF1,
highTimesTF1, highTRsTF1)

[lowPivotsTF2, highPivotsTF2, lowTimesTF2, highTimesTF2, lowTRsTF2, highTRsTF2] =


getTFData(timeframe2)
handleTimeframeIfLower(timeframeInfos.get(1), highPivotsTF2, lowPivotsTF2,
highTimesTF2, highTRsTF2)

[lowPivotsTF3, highPivotsTF3, lowTimesTF3, highTimesTF3, lowTRsTF3, highTRsTF3] =


getTFData(timeframe3)
handleTimeframeIfLower(timeframeInfos.get(2), highPivotsTF3, lowPivotsTF3,
highTimesTF3, highTRsTF3)

//plot(nz(na,timeframeInfos.get(0).highPivots.size() > 0 ?
timeframeInfos.get(0).highPivots.get(timeframeInfos.get(0).highPivots.size() - 1) :
0), color = color.blue, title = "High Pivots")
//plot(nz(na,timeframeInfos.get(0).lowPivots.size() > 0 ?
timeframeInfos.get(0).lowPivots.get(timeframeInfos.get(0).lowPivots.size() - 1) :
0), color = color.fuchsia, title = "Low Pivots")

if barstate.islastconfirmedhistory or (barstate.islast and barstate.isnew)


if timeframe1Enabled and not isTimeframeLower(timeframe1, timeframe.period)
handleTimeframe(1, lowPivotsTF1, highPivotsTF1, lowTimesTF1, highTimesTF1,
lowTRsTF1, highTRsTF1)

if timeframe2Enabled and not isTimeframeLower(timeframe2, timeframe.period)


handleTimeframe(2, lowPivotsTF2, highPivotsTF2, lowTimesTF2, highTimesTF2,
lowTRsTF2, highTRsTF2)

if timeframe3Enabled and not isTimeframeLower(timeframe3, timeframe.period)


handleTimeframe(3, lowPivotsTF3, highPivotsTF3, lowTimesTF3, highTimesTF3,
lowTRsTF3, highTRsTF3)

int enabledTimeframeCount = 0
for i = 0 to timeframeCount - 1
timeframeInfo curInfo = timeframeInfos.get(i)
if curInfo.isEnabled
enabledTimeframeCount += 1

int oldRetestsCount = 0
int curRetestsCount = 0

int oldBreaksCount = 0
int curBreaksCount = 0

for i = 0 to timeframeCount - 1
timeframeInfo curInfo = timeframeInfos.get(i)
if not curInfo.isEnabled
continue

[oldRetests, oldBreaks] = clearTimeframeRS(curInfo)


oldRetestsCount += oldRetests
oldBreaksCount += oldBreaks

resistanceCount = math.min(DEBUG ? debug_lastXResistances :


resistanceSupportCount, maxResistances - (enabledTimeframeCount > 1 ? 1 : 0))
resistanceCount := math.max(resistanceCount, 0)

supportCount = math.min(DEBUG ? debug_lastXSupports :


resistanceSupportCount, maxSupports - (enabledTimeframeCount > 1 ? 1 : 0))
supportCount := math.max(supportCount, 0)

[curRetests1, curBreaks1] = findTimeframeRS(curInfo, "Resistance",


curInfo.resistances, resistanceCount, curInfo.highPivots, curInfo.highTimes,
curInfo.highTRs)
[curRetests2, curBreaks2] = findTimeframeRS(curInfo, "Support",
curInfo.supports, supportCount, curInfo.lowPivots, curInfo.lowTimes,
curInfo.lowTRs)
curRetestsCount += curRetests1 + curRetests2
curBreaksCount += curBreaks1 + curBreaks2

if debug_enabledHistory
historyIndexesToDelete = array.new<int>(0)
if history.size() > 0
for i = 0 to history.size() - 1
if checkIfArrHasRS(curRSList, history.get(i))
historyIndexesToDelete.push(i)

if historyIndexesToDelete.size() > 0
for i = 0 to historyIndexesToDelete.size() - 1
deleteIndex =
historyIndexesToDelete.get(historyIndexesToDelete.size() - i - 1)
safeDeleteRSInfo(history.get(deleteIndex))
history.remove(deleteIndex)

if oldRSList.size() > 0
for i = 0 to oldRSList.size() - 1
curRS = oldRSList.get(i)
if checkIfArrHasRS(curRSList, curRS) == false
history.push(histRSInfo(curRS))
if history.size() > debug_maxHistoryRecords
safeDeleteRSInfo(history.get(0))
history.remove(0)

if oldRSList.size() > 0
for i = 0 to oldRSList.size() - 1
safeDeleteRSInfo(oldRSList.get(i))

curRSList.clear()
oldRSList.clear()

if DEBUG
log.info("History Size : " + str.tostring(history.size()))
log.info("Label Count : " + str.tostring(label.all.size()))
log.info("Line Count : " + str.tostring(line.all.size()))
log.info("Box Count : " + str.tostring(box.all.size()))

if enableRetestAlerts and curRetestsCount > oldRetestsCount and initRun ==


false
alert("New Retests Occured.")

if enableBreakAlerts and curBreaksCount > oldBreaksCount and initRun == false


alert("New Breaks Occured.")

initRun := false

You might also like