OPEN-SOURCE SCRIPT

Key Box Zone Finder — ATR + EMA200 Filter

475
//version=5
indicator("Key Box Zone Finder — ATR + EMA200 Filter", overlay=true, max_lines_count=500, max_boxes_count=100, max_labels_count=500)

// ---------- Inputs ----------
len = input.int(60, "Box Length (bars)", minval=10)
maxWidthPct = input.float(0.6, "Max Box Width %", step=0.05)
edgeTolPct = input.float(0.08, "Edge tolerance %", step=0.01)
bins = input.int(8, "Bins inside box", minval=3, maxval=20)
extendBars = input.int(120, "Extend right (bars)", minval=0)
showTouches = input.bool(true, "Show edge touches")
showSubZone = input.bool(true, "Show densest sub-zone")
boxColor = input.color(color.new(color.teal, 85), "Box fill")
subBoxColor = input.color(color.new(color.orange, 75), "Sub-zone fill")
edgeLineColor = input.color(color.new(color.teal, 0), "Edge line color")
midLineColor = input.color(color.new(color.gray, 0), "Mid line color")

// فیلترها
atrLen = input.int(14, "ATR Length", minval=1)
atrMaxMult = input.float(0.5, "ATR Max % of Close", step=0.01)
emaLen = input.int(200, "EMA Length", minval=1)
emaDistancePct = input.float(0.5, "Max Distance % from EMA", step=0.1)

// ---------- Core calc ----------
hi = ta.highest(high, len)
lo = ta.lowest(low, len)
boxRange = hi - lo
boxRangePct = boxRange / math.max(close, 1e-6) * 100.0
isBoxWidth = boxRangePct <= maxWidthPct

// شمارش برخوردها
edgeTolHi = hi * (1 - edgeTolPct/100.0)
edgeTolLo = lo * (1 + edgeTolPct/100.0)
touchUpper = 0
touchLower = 0
for j = 0 to len - 1
touchUpper += (high[j] >= edgeTolHi) ? 1 : 0
touchLower += (low[j] <= edgeTolLo) ? 1 : 0

// ---------- ATR filter ----------
atrValue = ta.atr(atrLen)
atrCondition = (atrValue / close) * 100 <= atrMaxMult

// ---------- EMA200 filter ----------
emaValue = ta.ema(close, emaLen)
emaCondition = math.abs(close - emaValue) / close * 100 <= emaDistancePct

// ---------- Final filter ----------
isValidBox = isBoxWidth and atrCondition and emaCondition

// ---------- Draw main box ----------
var box bMain = na
var line lTop = na
var line lBot = na
var line lMid = na
var label labU = na
var label labL = na

if barstate.islast and isValidBox
if not na(bMain)
box.delete(bMain)
if not na(lTop)
line.delete(lTop)
if not na(lBot)
line.delete(lBot)
if not na(lMid)
line.delete(lMid)
if not na(labU)
label.delete(labU)
if not na(labL)
label.delete(labL)

left = bar_index - len + 1
right = bar_index + extendBars

bMain := box.new(left, hi, bar_index, lo, bgcolor=boxColor, border_color=edgeLineColor)
box.set_extend(bMain, extend.right)

lTop := line.new(left, hi, right, hi, extend=extend.right, color=edgeLineColor, width=1)
lBot := line.new(left, lo, right, lo, extend=extend.right, color=edgeLineColor, width=1)
mid = (hi + lo) / 2.0
lMid := line.new(left, mid, right, mid, extend=extend.right, color=midLineColor, style=line.style_dotted)

if showTouches
labU := label.new(bar_index, hi, "▲ touches: " + str.tostring(touchUpper), textcolor=color.white, color=color.new(color.teal, 0), style=label.style_label_down, size=size.tiny)
labL := label.new(bar_index, lo, "▼ touches: " + str.tostring(touchLower), textcolor=color.white, color=color.new(color.teal, 0), style=label.style_label_up, size=size.tiny)

// ---------- Densest sub-zone ----------
var box bSub = na
if barstate.islast and isValidBox and showSubZone and boxRange > 0
step = boxRange / bins
maxCount = -1
bestIdx = 0
for i = 0 to bins - 1
binLo = lo + step * i
binHi = binLo + step
cIn = 0
for j = 0 to len - 1
c = close[j]
cIn += (c >= binLo and c <= binHi) ? 1 : 0
if cIn > maxCount
maxCount := cIn
bestIdx := i

subLo = lo + step * bestIdx
subHi = subLo + step

if not na(bSub)
box.delete(bSub)
bSub := box.new(bar_index - len + 1, subHi, bar_index, subLo, bgcolor=subBoxColor, border_color=color.new(color.orange, 0))
box.set_extend(bSub, extend.right)
label.new(bar_index, subHi, "Dense zone", style=label.style_label_down, textcolor=color.white, color=color.new(color.orange, 0), size=size.tiny)

// ---------- Alerts ----------
alertcondition(isValidBox, title="Valid Box Detected", message="Consolidation box detected with ATR & EMA filter")

Penafian

Maklumat dan penerbitan adalah tidak dimaksudkan untuk menjadi, dan tidak membentuk, nasihat untuk kewangan, pelaburan, perdagangan dan jenis-jenis lain atau cadangan yang dibekalkan atau disahkan oleh TradingView. Baca dengan lebih lanjut di Terma Penggunaan.