OPEN-SOURCE SCRIPT
Double Pattern Screener v7

//version=6
indicator("Double Pattern Screener", shorttitle="DPS", overlay=false)
// Screener 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", step=0.01)
atrLength = input.int(14, "ATR Length", minval=1)
// NEW: Filter for number of equal peaks
filterPeaks = input.int(3, "Filter: Show Only X Equal Peaks", minval=2, maxval=5)
enableFilter = input.bool(true, "Enable Peak Count Filter")
// Arrays for tracking swings
var array<float> todaySwingLevels = array.new<float>(0)
var array<int> swingCounts = array.new<int>(0)
var array<bool> isResistance = array.new<bool>(0)
var array<int> swingBars = array.new<int>(0)
var int maxEqualPeaks = 0
var float nearestEqualLevel = na
var float distanceToNearest = na
var bool hasPattern = false
// Detect swings
swingHigh = ta.pivothigh(high, leftBars, rightBars)
swingLow = ta.pivotlow(low, leftBars, rightBars)
// Track current day
currentDay = dayofmonth
isNewDay = currentDay != currentDay[1]
// Clear on new day
if barstate.isfirst or isNewDay
array.clear(todaySwingLevels)
array.clear(swingCounts)
array.clear(isResistance)
array.clear(swingBars)
maxEqualPeaks := 0
nearestEqualLevel := na
distanceToNearest := na
hasPattern := false
// Function to find matching level
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
if not na(swingHigh)
matchIndex = findMatchingLevel(swingHigh, true)
if matchIndex >= 0
newCount = array.get(swingCounts, matchIndex) + 1
array.set(swingCounts, matchIndex, newCount)
// Update max equal peaks
if newCount > maxEqualPeaks
maxEqualPeaks := newCount
else
array.push(todaySwingLevels, swingHigh)
array.push(swingCounts, 1)
array.push(isResistance, true)
array.push(swingBars, bar_index)
// Process swing lows
if not na(swingLow)
matchIndex = findMatchingLevel(swingLow, false)
if matchIndex >= 0
newCount = array.get(swingCounts, matchIndex) + 1
array.set(swingCounts, matchIndex, newCount)
// Update max equal peaks
if newCount > maxEqualPeaks
maxEqualPeaks := newCount
else
array.push(todaySwingLevels, swingLow)
array.push(swingCounts, 1)
array.push(isResistance, false)
array.push(swingBars, bar_index)
// Remove broken levels
if array.size(todaySwingLevels) > 0
for i = array.size(todaySwingLevels) - 1 to 0
level = array.get(todaySwingLevels, i)
isRes = array.get(isResistance, i)
levelBroken = isRes ? close > level : close < level
if levelBroken
removedCount = array.get(swingCounts, i)
array.remove(todaySwingLevels, i)
array.remove(swingCounts, i)
array.remove(isResistance, i)
array.remove(swingBars, i)
// Recalculate max if we removed the highest count
if removedCount == maxEqualPeaks
maxEqualPeaks := 0
if array.size(swingCounts) > 0
for j = 0 to array.size(swingCounts) - 1
count = array.get(swingCounts, j)
if count > maxEqualPeaks
maxEqualPeaks := count
// Calculate nearest equal level and distance
nearestEqualLevel := na
distanceToNearest := na
smallestDistance = 999999.0
if array.size(todaySwingLevels) > 0
for i = 0 to array.size(todaySwingLevels) - 1
count = array.get(swingCounts, i)
level = array.get(todaySwingLevels, i)
// Only consider levels with 2+ touches
if count >= 2
distance = math.abs(close - level)
if distance < smallestDistance
smallestDistance := distance
nearestEqualLevel := level
distanceToNearest := distance
// Pattern detection with filter
hasPattern := false
if maxEqualPeaks >= 2
if enableFilter
hasPattern := maxEqualPeaks == filterPeaks
else
hasPattern := true
// Screener outputs
patternSignal = hasPattern ? 1 : 0
numberEqualPeaks = maxEqualPeaks
nearestLevelPrice = nearestEqualLevel
distanceCents = distanceToNearest
// Calculate ATR normalized distance
atr = ta.atr(atrLength)
atrDistance = not na(distanceToNearest) and not na(atr) and atr > 0 ? distanceToNearest / atr : na
// Plot screener values
plot(patternSignal, title="Pattern Signal", display=display.data_window)
plot(numberEqualPeaks, title="Number Equal Peaks", display=display.data_window)
plot(nearestLevelPrice, title="Nearest Equal Level Price", display=display.data_window)
plot(distanceCents, title="Distance to Nearest (Price Units)", display=display.data_window)
plot(atrDistance, title="ATR Normalized Distance", display=display.data_window)
// Table for current symbol info
if barstate.islast
var table infoTable = table.new(position.top_right, 2, 6, bgcolor=color.new(color.black, 70))
table.cell(infoTable, 0, 0, "Symbol:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 0, syminfo.ticker, bgcolor=color.new(color.blue, 50), text_color=color.white)
table.cell(infoTable, 0, 1, "Pattern:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 1, str.tostring(patternSignal), bgcolor=patternSignal == 1 ? color.new(color.purple, 50) : color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 0, 2, "Equal Peaks:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 2, str.tostring(numberEqualPeaks), bgcolor=color.new(color.yellow, 50), text_color=color.black)
table.cell(infoTable, 0, 3, "Nearest Level:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 3, str.tostring(nearestLevelPrice, "#.####"), bgcolor=color.new(color.orange, 50), text_color=color.white)
table.cell(infoTable, 0, 4, "Distance:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 4, str.tostring(distanceCents, "#.####"), bgcolor=color.new(color.green, 50), text_color=color.white)
table.cell(infoTable, 0, 5, "Filter Active:", bgcolor=color.new(color.gray, 50), text_color=color.white)
filterText = enableFilter ? str.tostring(filterPeaks) + " peaks" : "OFF"
table.cell(infoTable, 1, 5, filterText, bgcolor=enableFilter ? color.new(color.red, 50) : color.new(color.gray, 50), text_color=color.white)
indicator("Double Pattern Screener", shorttitle="DPS", overlay=false)
// Screener 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", step=0.01)
atrLength = input.int(14, "ATR Length", minval=1)
// NEW: Filter for number of equal peaks
filterPeaks = input.int(3, "Filter: Show Only X Equal Peaks", minval=2, maxval=5)
enableFilter = input.bool(true, "Enable Peak Count Filter")
// Arrays for tracking swings
var array<float> todaySwingLevels = array.new<float>(0)
var array<int> swingCounts = array.new<int>(0)
var array<bool> isResistance = array.new<bool>(0)
var array<int> swingBars = array.new<int>(0)
var int maxEqualPeaks = 0
var float nearestEqualLevel = na
var float distanceToNearest = na
var bool hasPattern = false
// Detect swings
swingHigh = ta.pivothigh(high, leftBars, rightBars)
swingLow = ta.pivotlow(low, leftBars, rightBars)
// Track current day
currentDay = dayofmonth
isNewDay = currentDay != currentDay[1]
// Clear on new day
if barstate.isfirst or isNewDay
array.clear(todaySwingLevels)
array.clear(swingCounts)
array.clear(isResistance)
array.clear(swingBars)
maxEqualPeaks := 0
nearestEqualLevel := na
distanceToNearest := na
hasPattern := false
// Function to find matching level
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
if not na(swingHigh)
matchIndex = findMatchingLevel(swingHigh, true)
if matchIndex >= 0
newCount = array.get(swingCounts, matchIndex) + 1
array.set(swingCounts, matchIndex, newCount)
// Update max equal peaks
if newCount > maxEqualPeaks
maxEqualPeaks := newCount
else
array.push(todaySwingLevels, swingHigh)
array.push(swingCounts, 1)
array.push(isResistance, true)
array.push(swingBars, bar_index)
// Process swing lows
if not na(swingLow)
matchIndex = findMatchingLevel(swingLow, false)
if matchIndex >= 0
newCount = array.get(swingCounts, matchIndex) + 1
array.set(swingCounts, matchIndex, newCount)
// Update max equal peaks
if newCount > maxEqualPeaks
maxEqualPeaks := newCount
else
array.push(todaySwingLevels, swingLow)
array.push(swingCounts, 1)
array.push(isResistance, false)
array.push(swingBars, bar_index)
// Remove broken levels
if array.size(todaySwingLevels) > 0
for i = array.size(todaySwingLevels) - 1 to 0
level = array.get(todaySwingLevels, i)
isRes = array.get(isResistance, i)
levelBroken = isRes ? close > level : close < level
if levelBroken
removedCount = array.get(swingCounts, i)
array.remove(todaySwingLevels, i)
array.remove(swingCounts, i)
array.remove(isResistance, i)
array.remove(swingBars, i)
// Recalculate max if we removed the highest count
if removedCount == maxEqualPeaks
maxEqualPeaks := 0
if array.size(swingCounts) > 0
for j = 0 to array.size(swingCounts) - 1
count = array.get(swingCounts, j)
if count > maxEqualPeaks
maxEqualPeaks := count
// Calculate nearest equal level and distance
nearestEqualLevel := na
distanceToNearest := na
smallestDistance = 999999.0
if array.size(todaySwingLevels) > 0
for i = 0 to array.size(todaySwingLevels) - 1
count = array.get(swingCounts, i)
level = array.get(todaySwingLevels, i)
// Only consider levels with 2+ touches
if count >= 2
distance = math.abs(close - level)
if distance < smallestDistance
smallestDistance := distance
nearestEqualLevel := level
distanceToNearest := distance
// Pattern detection with filter
hasPattern := false
if maxEqualPeaks >= 2
if enableFilter
hasPattern := maxEqualPeaks == filterPeaks
else
hasPattern := true
// Screener outputs
patternSignal = hasPattern ? 1 : 0
numberEqualPeaks = maxEqualPeaks
nearestLevelPrice = nearestEqualLevel
distanceCents = distanceToNearest
// Calculate ATR normalized distance
atr = ta.atr(atrLength)
atrDistance = not na(distanceToNearest) and not na(atr) and atr > 0 ? distanceToNearest / atr : na
// Plot screener values
plot(patternSignal, title="Pattern Signal", display=display.data_window)
plot(numberEqualPeaks, title="Number Equal Peaks", display=display.data_window)
plot(nearestLevelPrice, title="Nearest Equal Level Price", display=display.data_window)
plot(distanceCents, title="Distance to Nearest (Price Units)", display=display.data_window)
plot(atrDistance, title="ATR Normalized Distance", display=display.data_window)
// Table for current symbol info
if barstate.islast
var table infoTable = table.new(position.top_right, 2, 6, bgcolor=color.new(color.black, 70))
table.cell(infoTable, 0, 0, "Symbol:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 0, syminfo.ticker, bgcolor=color.new(color.blue, 50), text_color=color.white)
table.cell(infoTable, 0, 1, "Pattern:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 1, str.tostring(patternSignal), bgcolor=patternSignal == 1 ? color.new(color.purple, 50) : color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 0, 2, "Equal Peaks:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 2, str.tostring(numberEqualPeaks), bgcolor=color.new(color.yellow, 50), text_color=color.black)
table.cell(infoTable, 0, 3, "Nearest Level:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 3, str.tostring(nearestLevelPrice, "#.####"), bgcolor=color.new(color.orange, 50), text_color=color.white)
table.cell(infoTable, 0, 4, "Distance:", bgcolor=color.new(color.gray, 50), text_color=color.white)
table.cell(infoTable, 1, 4, str.tostring(distanceCents, "#.####"), bgcolor=color.new(color.green, 50), text_color=color.white)
table.cell(infoTable, 0, 5, "Filter Active:", bgcolor=color.new(color.gray, 50), text_color=color.white)
filterText = enableFilter ? str.tostring(filterPeaks) + " peaks" : "OFF"
table.cell(infoTable, 1, 5, filterText, bgcolor=enableFilter ? color.new(color.red, 50) : color.new(color.gray, 50), text_color=color.white)
สคริปต์โอเพนซอร์ซ
ด้วยเจตนารมณ์หลักของ TradingView ผู้สร้างสคริปต์นี้ได้ทำให้มันเป็นโอเพ่นซอร์ส เพื่อให้เทรดเดอร์สามารถตรวจสอบและยืนยันการทำงานของสคริปต์ได้ ขอแสดงความชื่นชมผู้เขียน! แม้ว่าคุณจะสามารถใช้งานได้ฟรี แต่อย่าลืมว่าการเผยแพร่โค้ดซ้ำนั้นจะต้องเป็นไปตามกฎระเบียบการใช้งานของเรา
คำจำกัดสิทธิ์ความรับผิดชอบ
ข้อมูลและบทความไม่ได้มีวัตถุประสงค์เพื่อก่อให้เกิดกิจกรรมทางการเงิน, การลงทุน, การซื้อขาย, ข้อเสนอแนะ หรือคำแนะนำประเภทอื่น ๆ ที่ให้หรือรับรองโดย TradingView อ่านเพิ่มเติมที่ ข้อกำหนดการใช้งาน
สคริปต์โอเพนซอร์ซ
ด้วยเจตนารมณ์หลักของ TradingView ผู้สร้างสคริปต์นี้ได้ทำให้มันเป็นโอเพ่นซอร์ส เพื่อให้เทรดเดอร์สามารถตรวจสอบและยืนยันการทำงานของสคริปต์ได้ ขอแสดงความชื่นชมผู้เขียน! แม้ว่าคุณจะสามารถใช้งานได้ฟรี แต่อย่าลืมว่าการเผยแพร่โค้ดซ้ำนั้นจะต้องเป็นไปตามกฎระเบียบการใช้งานของเรา
คำจำกัดสิทธิ์ความรับผิดชอบ
ข้อมูลและบทความไม่ได้มีวัตถุประสงค์เพื่อก่อให้เกิดกิจกรรมทางการเงิน, การลงทุน, การซื้อขาย, ข้อเสนอแนะ หรือคำแนะนำประเภทอื่น ๆ ที่ให้หรือรับรองโดย TradingView อ่านเพิ่มเติมที่ ข้อกำหนดการใช้งาน