OPEN-SOURCE SCRIPT
Double Top/Bottom Screener - Clean Today Only v5

//version=6
indicator("Double Top/Bottom Screener - Clean Today Only", overlay=true, max_lines_count=100)
// Inputs
leftBars = input.int(5, "Left Bars", minval=3, maxval=10)
rightBars = input.int(5, "Right Bars", minval=3, maxval=10)
tolerance = input.float(0.02, "Max Difference (e.g., 0.02 for 2 cents)", step=0.01)
atrLength = input.int(14, "ATR Length for Normalized Distance", minval=1)
requiredPeaks = input.int(3, "Required Identical Peaks", minval=2, maxval=5)
// Arrays to store today's swing levels only
var array<float> todaySwingLevels = array.new<float>(0)
var array<int> swingCounts = array.new<int>(0)
var array<line> swingLines = array.new<line>(0)
var array<bool> isResistance = array.new<bool>(0)
var array<int> swingBars = array.new<int>(0)
var bool hasDoubleTop = false
var bool hasDoubleBottom = false
var float doubleTopLevel = na
var float doubleBottomLevel = na
var float nearestDoubleLevel = na
var int currentDay = na
// Detect significant swings only
swingHigh = ta.pivothigh(high, leftBars, rightBars)
swingLow = ta.pivotlow(low, leftBars, rightBars)
// Track current day
currentDay := dayofmonth
isNewDay = currentDay != currentDay[1]
// Clear everything on new day
if barstate.isfirst or isNewDay
// Delete all existing lines
if array.size(swingLines) > 0
for i = array.size(swingLines) - 1 to 0
line.delete(array.get(swingLines, i))
// Clear all arrays
array.clear(todaySwingLevels)
array.clear(swingCounts)
array.clear(swingLines)
array.clear(isResistance)
array.clear(swingBars)
// Reset flags
hasDoubleTop := false
hasDoubleBottom := false
doubleTopLevel := na
doubleBottomLevel := na
nearestDoubleLevel := na
// Function to find matching level within today's swings only
findMatchingLevel(newLevel, isHigh) =>
matchIndex = -1
if array.size(todaySwingLevels) > 0
for i = 0 to array.size(todaySwingLevels) - 1
existingLevel = array.get(todaySwingLevels, i)
existingIsResistance = array.get(isResistance, i)
if math.abs(newLevel - existingLevel) <= tolerance and existingIsResistance == isHigh
matchIndex := i
break
matchIndex
// Process swing highs (resistance levels) - today only
if not na(swingHigh)
matchIndex = findMatchingLevel(swingHigh, true)
if matchIndex >= 0
// Found matching resistance level
newCount = array.get(swingCounts, matchIndex) + 1
array.set(swingCounts, matchIndex, newCount)
// Delete old line and create new one with appropriate color
line.delete(array.get(swingLines, matchIndex))
lineColor = newCount >= requiredPeaks ? color.yellow : color.red
// Start line from the original swing bar, not current bar
originalBar = array.get(swingBars, matchIndex)
newLine = line.new(originalBar, swingHigh, bar_index + 20, swingHigh,
color=lineColor, width=2, extend=extend.right)
array.set(swingLines, matchIndex, newLine)
// Update pattern detection
if newCount >= requiredPeaks
hasDoubleTop := true
doubleTopLevel := swingHigh
else
// New resistance level - add to today's levels
array.push(todaySwingLevels, swingHigh)
array.push(swingCounts, 1)
array.push(isResistance, true)
array.push(swingBars, bar_index)
// Create red horizontal line starting from swing bar
newLine = line.new(bar_index, swingHigh, bar_index + 20, swingHigh,
color=color.red, width=2, extend=extend.right)
array.push(swingLines, newLine)
// Process swing lows (support levels) - today only
if not na(swingLow)
matchIndex = findMatchingLevel(swingLow, false)
if matchIndex >= 0
// Found matching support level
newCount = array.get(swingCounts, matchIndex) + 1
array.set(swingCounts, matchIndex, newCount)
// Delete old line and create new one with appropriate color
line.delete(array.get(swingLines, matchIndex))
lineColor = newCount >= requiredPeaks ? color.yellow : color.green
// Start line from the original swing bar, not current bar
originalBar = array.get(swingBars, matchIndex)
newLine = line.new(originalBar, swingLow, bar_index + 20, swingLow,
color=lineColor, width=2, extend=extend.right)
array.set(swingLines, matchIndex, newLine)
// Update pattern detection
if newCount >= requiredPeaks
hasDoubleBottom := true
doubleBottomLevel := swingLow
else
// New support level - add to today's levels
array.push(todaySwingLevels, swingLow)
array.push(swingCounts, 1)
array.push(isResistance, false)
array.push(swingBars, bar_index)
// Create green horizontal line starting from swing bar
newLine = line.new(bar_index, swingLow, bar_index + 20, swingLow,
color=color.green, width=2, extend=extend.right)
array.push(swingLines, newLine)
// Remove broken levels immediately (strict enforcement)
if array.size(todaySwingLevels) > 0
for i = array.size(todaySwingLevels) - 1 to 0
level = array.get(todaySwingLevels, i)
isRes = array.get(isResistance, i)
// Check if level is broken (even slightly)
levelBroken = isRes ? close > level : close < level
if levelBroken
// Delete line and remove from arrays
line.delete(array.get(swingLines, i))
array.remove(swingLines, i)
array.remove(todaySwingLevels, i)
array.remove(swingCounts, i)
array.remove(isResistance, i)
array.remove(swingBars, i)
// Reset pattern flags if broken level was part of pattern
if level == doubleTopLevel
hasDoubleTop := false
doubleTopLevel := na
if level == doubleBottomLevel
hasDoubleBottom := false
doubleBottomLevel := na
// Calculate pattern signal
patternSignal = (hasDoubleTop or hasDoubleBottom) ? 1 : 0
// Find nearest double level (only from unbroken levels)
if patternSignal == 1
if hasDoubleTop and not na(doubleTopLevel)
nearestDoubleLevel := doubleTopLevel
if hasDoubleBottom and not na(doubleBottomLevel)
if na(nearestDoubleLevel)
nearestDoubleLevel := doubleBottomLevel
else
nearestDoubleLevel := math.abs(close - doubleBottomLevel) < math.abs(close - nearestDoubleLevel) ? doubleBottomLevel : nearestDoubleLevel
else
nearestDoubleLevel := na
// Distance calculation
atr = ta.atr(atrLength)
distanceNormalizedATR = not na(nearestDoubleLevel) and not na(atr) and atr > 0 ? math.abs(close - nearestDoubleLevel) / atr : na
// Outputs (minimal plotting)
plot(patternSignal, title="Pattern Signal", color=patternSignal == 1 ? color.purple : na, style=plot.style_circles)
plot(nearestDoubleLevel, title="Nearest Double Level Price", color=color.orange)
plot(distanceNormalizedATR, title="Normalized Distance (ATR)", color=color.blue)
// Background highlight for pattern
bgcolor(patternSignal == 1 ? color.new(color.purple, 80) : na)
// Alert for pattern detection
if patternSignal == 1 and barstate.isconfirmed
alert("Double Pattern detected on " + syminfo.ticker + " at " + str.tostring(close), alert.freq_once_per_bar_close)
// Clean information table
if barstate.islast
var table infoTable = table.new(position.top_right, 2, 4, bgcolor=color.new(color.black, 70))
table.cell(infoTable, 0, 0, "Pattern:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 0, str.tostring(patternSignal), bgcolor=patternSignal == 1 ? color.new(color.purple, 50) : color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 0, 1, "Level:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 1, str.tostring(nearestDoubleLevel, "#.####"), bgcolor=color.new(color.orange, 50), text_color=color.white)
table.cell(infoTable, 0, 2, "Unbroken Swings:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 2, str.tostring(array.size(todaySwingLevels)), bgcolor=color.new(color.gray, 50), text_color=color.white)
// Count double levels
doubleCount = 0
if array.size(swingCounts) > 0
for i = 0 to array.size(swingCounts) - 1
if array.get(swingCounts, i) >= requiredPeaks
doubleCount += 1
table.cell(infoTable, 0, 3, "Double Levels:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 3, str.tostring(doubleCount), bgcolor=color.new(color.yellow, 50), text_color=color.black)
indicator("Double Top/Bottom Screener - Clean Today Only", overlay=true, max_lines_count=100)
// Inputs
leftBars = input.int(5, "Left Bars", minval=3, maxval=10)
rightBars = input.int(5, "Right Bars", minval=3, maxval=10)
tolerance = input.float(0.02, "Max Difference (e.g., 0.02 for 2 cents)", step=0.01)
atrLength = input.int(14, "ATR Length for Normalized Distance", minval=1)
requiredPeaks = input.int(3, "Required Identical Peaks", minval=2, maxval=5)
// Arrays to store today's swing levels only
var array<float> todaySwingLevels = array.new<float>(0)
var array<int> swingCounts = array.new<int>(0)
var array<line> swingLines = array.new<line>(0)
var array<bool> isResistance = array.new<bool>(0)
var array<int> swingBars = array.new<int>(0)
var bool hasDoubleTop = false
var bool hasDoubleBottom = false
var float doubleTopLevel = na
var float doubleBottomLevel = na
var float nearestDoubleLevel = na
var int currentDay = na
// Detect significant swings only
swingHigh = ta.pivothigh(high, leftBars, rightBars)
swingLow = ta.pivotlow(low, leftBars, rightBars)
// Track current day
currentDay := dayofmonth
isNewDay = currentDay != currentDay[1]
// Clear everything on new day
if barstate.isfirst or isNewDay
// Delete all existing lines
if array.size(swingLines) > 0
for i = array.size(swingLines) - 1 to 0
line.delete(array.get(swingLines, i))
// Clear all arrays
array.clear(todaySwingLevels)
array.clear(swingCounts)
array.clear(swingLines)
array.clear(isResistance)
array.clear(swingBars)
// Reset flags
hasDoubleTop := false
hasDoubleBottom := false
doubleTopLevel := na
doubleBottomLevel := na
nearestDoubleLevel := na
// Function to find matching level within today's swings only
findMatchingLevel(newLevel, isHigh) =>
matchIndex = -1
if array.size(todaySwingLevels) > 0
for i = 0 to array.size(todaySwingLevels) - 1
existingLevel = array.get(todaySwingLevels, i)
existingIsResistance = array.get(isResistance, i)
if math.abs(newLevel - existingLevel) <= tolerance and existingIsResistance == isHigh
matchIndex := i
break
matchIndex
// Process swing highs (resistance levels) - today only
if not na(swingHigh)
matchIndex = findMatchingLevel(swingHigh, true)
if matchIndex >= 0
// Found matching resistance level
newCount = array.get(swingCounts, matchIndex) + 1
array.set(swingCounts, matchIndex, newCount)
// Delete old line and create new one with appropriate color
line.delete(array.get(swingLines, matchIndex))
lineColor = newCount >= requiredPeaks ? color.yellow : color.red
// Start line from the original swing bar, not current bar
originalBar = array.get(swingBars, matchIndex)
newLine = line.new(originalBar, swingHigh, bar_index + 20, swingHigh,
color=lineColor, width=2, extend=extend.right)
array.set(swingLines, matchIndex, newLine)
// Update pattern detection
if newCount >= requiredPeaks
hasDoubleTop := true
doubleTopLevel := swingHigh
else
// New resistance level - add to today's levels
array.push(todaySwingLevels, swingHigh)
array.push(swingCounts, 1)
array.push(isResistance, true)
array.push(swingBars, bar_index)
// Create red horizontal line starting from swing bar
newLine = line.new(bar_index, swingHigh, bar_index + 20, swingHigh,
color=color.red, width=2, extend=extend.right)
array.push(swingLines, newLine)
// Process swing lows (support levels) - today only
if not na(swingLow)
matchIndex = findMatchingLevel(swingLow, false)
if matchIndex >= 0
// Found matching support level
newCount = array.get(swingCounts, matchIndex) + 1
array.set(swingCounts, matchIndex, newCount)
// Delete old line and create new one with appropriate color
line.delete(array.get(swingLines, matchIndex))
lineColor = newCount >= requiredPeaks ? color.yellow : color.green
// Start line from the original swing bar, not current bar
originalBar = array.get(swingBars, matchIndex)
newLine = line.new(originalBar, swingLow, bar_index + 20, swingLow,
color=lineColor, width=2, extend=extend.right)
array.set(swingLines, matchIndex, newLine)
// Update pattern detection
if newCount >= requiredPeaks
hasDoubleBottom := true
doubleBottomLevel := swingLow
else
// New support level - add to today's levels
array.push(todaySwingLevels, swingLow)
array.push(swingCounts, 1)
array.push(isResistance, false)
array.push(swingBars, bar_index)
// Create green horizontal line starting from swing bar
newLine = line.new(bar_index, swingLow, bar_index + 20, swingLow,
color=color.green, width=2, extend=extend.right)
array.push(swingLines, newLine)
// Remove broken levels immediately (strict enforcement)
if array.size(todaySwingLevels) > 0
for i = array.size(todaySwingLevels) - 1 to 0
level = array.get(todaySwingLevels, i)
isRes = array.get(isResistance, i)
// Check if level is broken (even slightly)
levelBroken = isRes ? close > level : close < level
if levelBroken
// Delete line and remove from arrays
line.delete(array.get(swingLines, i))
array.remove(swingLines, i)
array.remove(todaySwingLevels, i)
array.remove(swingCounts, i)
array.remove(isResistance, i)
array.remove(swingBars, i)
// Reset pattern flags if broken level was part of pattern
if level == doubleTopLevel
hasDoubleTop := false
doubleTopLevel := na
if level == doubleBottomLevel
hasDoubleBottom := false
doubleBottomLevel := na
// Calculate pattern signal
patternSignal = (hasDoubleTop or hasDoubleBottom) ? 1 : 0
// Find nearest double level (only from unbroken levels)
if patternSignal == 1
if hasDoubleTop and not na(doubleTopLevel)
nearestDoubleLevel := doubleTopLevel
if hasDoubleBottom and not na(doubleBottomLevel)
if na(nearestDoubleLevel)
nearestDoubleLevel := doubleBottomLevel
else
nearestDoubleLevel := math.abs(close - doubleBottomLevel) < math.abs(close - nearestDoubleLevel) ? doubleBottomLevel : nearestDoubleLevel
else
nearestDoubleLevel := na
// Distance calculation
atr = ta.atr(atrLength)
distanceNormalizedATR = not na(nearestDoubleLevel) and not na(atr) and atr > 0 ? math.abs(close - nearestDoubleLevel) / atr : na
// Outputs (minimal plotting)
plot(patternSignal, title="Pattern Signal", color=patternSignal == 1 ? color.purple : na, style=plot.style_circles)
plot(nearestDoubleLevel, title="Nearest Double Level Price", color=color.orange)
plot(distanceNormalizedATR, title="Normalized Distance (ATR)", color=color.blue)
// Background highlight for pattern
bgcolor(patternSignal == 1 ? color.new(color.purple, 80) : na)
// Alert for pattern detection
if patternSignal == 1 and barstate.isconfirmed
alert("Double Pattern detected on " + syminfo.ticker + " at " + str.tostring(close), alert.freq_once_per_bar_close)
// Clean information table
if barstate.islast
var table infoTable = table.new(position.top_right, 2, 4, bgcolor=color.new(color.black, 70))
table.cell(infoTable, 0, 0, "Pattern:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 0, str.tostring(patternSignal), bgcolor=patternSignal == 1 ? color.new(color.purple, 50) : color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 0, 1, "Level:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 1, str.tostring(nearestDoubleLevel, "#.####"), bgcolor=color.new(color.orange, 50), text_color=color.white)
table.cell(infoTable, 0, 2, "Unbroken Swings:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 2, str.tostring(array.size(todaySwingLevels)), bgcolor=color.new(color.gray, 50), text_color=color.white)
// Count double levels
doubleCount = 0
if array.size(swingCounts) > 0
for i = 0 to array.size(swingCounts) - 1
if array.get(swingCounts, i) >= requiredPeaks
doubleCount += 1
table.cell(infoTable, 0, 3, "Double Levels:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 3, str.tostring(doubleCount), bgcolor=color.new(color.yellow, 50), text_color=color.black)
Open-source Skript
Ganz im Sinne von TradingView hat dieser Autor sein/ihr Script als Open-Source veröffentlicht. Auf diese Weise können nun auch andere Trader das Script rezensieren und die Funktionalität überprüfen. Vielen Dank an den Autor! Sie können das Script kostenlos verwenden, aber eine Wiederveröffentlichung des Codes unterliegt unseren Hausregeln.
Haftungsausschluss
Die Informationen und Veröffentlichungen sind nicht als Finanz-, Anlage-, Handels- oder andere Arten von Ratschlägen oder Empfehlungen gedacht, die von TradingView bereitgestellt oder gebilligt werden, und stellen diese nicht dar. Lesen Sie mehr in den Nutzungsbedingungen.
Open-source Skript
Ganz im Sinne von TradingView hat dieser Autor sein/ihr Script als Open-Source veröffentlicht. Auf diese Weise können nun auch andere Trader das Script rezensieren und die Funktionalität überprüfen. Vielen Dank an den Autor! Sie können das Script kostenlos verwenden, aber eine Wiederveröffentlichung des Codes unterliegt unseren Hausregeln.
Haftungsausschluss
Die Informationen und Veröffentlichungen sind nicht als Finanz-, Anlage-, Handels- oder andere Arten von Ratschlägen oder Empfehlungen gedacht, die von TradingView bereitgestellt oder gebilligt werden, und stellen diese nicht dar. Lesen Sie mehr in den Nutzungsbedingungen.