//@version=5 indicator("Fresh HH/LL — solid extremes, dashed prunes @3 touches (final)", overlay=true, max_lines_count=500, max_labels_count=500) // -------- Inputs -------- scanBars = input.int(150, minval=1, title="تعداد کندل‌هایی که بررسی/نگه‌داری می‌شود") lookback = input.int(78, minval=1, title="عدم تاچ در چند کندل قبلی؟") showLabels = input.bool(true, title="نمایش برچسب کنار سطح‌ها؟") touchLimit = input.int(3, minval=1, title="حذف خط‌چین بعد از چند برخورد؟") // -------- Conditions: new untouched highs/lows -------- enoughHist = bar_index >= lookback newFreshHigh = enoughHist and high > ta.highest(high[1], lookback) newFreshLow = enoughHist and low < ta.lowest(low[1], lookback) // -------- Storage -------- var line[] highLines = array.new_line() var line[] lowLines = array.new_line() var int[] highBars = array.new_int() var int[] lowBars = array.new_int() var label[] highLabels = array.new_label() var label[] lowLabels = array.new_label() var int[] highTouches = array.new_int() var int[] lowTouches = array.new_int() // -------- Create lines when signal occurs -------- if newFreshHigh lH = line.new(bar_index, high, bar_index + 1, high, extend=extend.right, width=2, color=color.red) array.push(highLines, lH) array.push(highBars, bar_index) array.push(highTouches, 0) label lbH = na if showLabels lbH := label.new(bar_index, high, text="HH (fresh)", style=label.style_label_right, textcolor=color.white, color=color.red) array.push(highLabels, lbH) if newFreshLow lL = line.new(bar_index, low, bar_index + 1, low, extend=extend.right, width=2, color=color.lime) array.push(lowLines, lL) array.push(lowBars, bar_index) array.push(lowTouches, 0) label lbL = na if showLabels lbL := label.new(bar_index, low, text="LL (fresh)", style=label.style_label_right, textcolor=color.white, color=color.lime) array.push(lowLabels, lbL) // -------- Helpers -------- touchUpdate(_linesArr, _barsArr, _touchesArr) => sz = array.size(_linesArr) if sz > 0 for i = 0 to sz - 1 ln = array.get(_linesArr, i) born = array.get(_barsArr, i) y = line.get_y1(ln) touched = (low <= y and high >= y) and (bar_index > born) if touched cnt = array.get(_touchesArr, i) array.set(_touchesArr, i, cnt + 1) cleanup(_linesArr, _labelsArr, _barsArr, _touchesArr) => szLines = array.size(_linesArr) szLabels = array.size(_labelsArr) szBars = array.size(_barsArr) szTouch = array.size(_touchesArr) sz = math.min(math.min(szLines, szLabels), math.min(szBars, szTouch)) if sz > 0 for k = 0 to sz - 1 i = (sz - 1) - k born = array.get(_barsArr, i) if bar_index - born > scanBars ln = array.get(_linesArr, i) lb = array.get(_labelsArr, i) line.delete(ln) if not na(lb) label.delete(lb) array.remove(_linesArr, i) array.remove(_labelsArr, i) array.remove(_barsArr, i) array.remove(_touchesArr, i) // اندیس خط توپر برای سقف‌ها (بالاترین y) getSolidIdxHigh(_linesArr) => sz = array.size(_linesArr) int idx = na if sz > 0 idx := 0 best = line.get_y1(array.get(_linesArr, 0)) if sz >= 2 for i = 1 to sz - 1 yi = line.get_y1(array.get(_linesArr, i)) if yi > best best := yi idx := i idx // اندیس خط توپر برای کف‌ها (پایین‌ترین y) getSolidIdxLow(_linesArr) => sz = array.size(_linesArr) int idx = na if sz > 0 idx := 0 best = line.get_y1(array.get(_linesArr, 0)) if sz >= 2 for i = 1 to sz - 1 yi = line.get_y1(array.get(_linesArr, i)) if yi < best best := yi idx := i idx applyStyles(_linesArr, _solidIdx) => sz = array.size(_linesArr) if sz > 0 for i = 0 to sz - 1 ln = array.get(_linesArr, i) isSolid = (not na(_solidIdx)) and (i == _solidIdx) line.set_style(ln, isSolid ? line.style_solid : line.style_dashed) line.set_width(ln, isSolid ? 2 : 1) pruneDashedByTouches(_linesArr, _labelsArr, _barsArr, _touchesArr, _solidIdx) => szLines = array.size(_linesArr) szLabels = array.size(_labelsArr) szBars = array.size(_barsArr) szTouch = array.size(_touchesArr) sz = math.min(math.min(szLines, szLabels), math.min(szBars, szTouch)) if sz > 0 for k = 0 to sz - 1 i = (sz - 1) - k isSolid = (not na(_solidIdx)) and (i == _solidIdx) if not isSolid cnt = array.get(_touchesArr, i) if cnt >= touchLimit ln = array.get(_linesArr, i) lb = array.get(_labelsArr, i) line.delete(ln) if not na(lb) label.delete(lb) array.remove(_linesArr, i) array.remove(_labelsArr, i) array.remove(_barsArr, i) array.remove(_touchesArr, i) // -------- Per-bar maintenance -------- touchUpdate(highLines, highBars, highTouches) touchUpdate(lowLines, lowBars, lowTouches) cleanup(highLines, highLabels, highBars, highTouches) cleanup(lowLines, lowLabels, lowBars, lowTouches) int solidHighIdx = na int solidLowIdx = na solidHighIdx := getSolidIdxHigh(highLines) solidLowIdx := getSolidIdxLow(lowLines) applyStyles(highLines, solidHighIdx) applyStyles(lowLines, solidLowIdx) pruneDashedByTouches(highLines, highLabels, highBars, highTouches, solidHighIdx) pruneDashedByTouches(lowLines, lowLabels, lowBars, lowTouches, solidLowIdx)