Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //@version=6
- indicator("TradeAxis Reversals", shorttitle = "TradeAxis Reversals", overlay = true, max_boxes_count = 500, max_lines_count = 500, max_labels_count = 500)
- string GRP_TF = "Timeframe"
- string GRP_MS = "Market Structure"
- string GRP_LEG = "Leg Qualification"
- string GRP_PROJ = "Range Projection"
- string GRP_CONF = "Confluence Filter"
- string GRP_MGMT = "Zone Management"
- string GRP_ALRT = "Alerts"
- string GRP_STY = "Style"
- string tfInput = input.string("Current Timeframe", "Timeframe", options = ["Current Timeframe", "1m", "5m", "15m", "30m", "1h", "4h", "D"], group = GRP_TF, tooltip = "Runs the full detection engine (pivot tracking, leg qualification, zone projection, confluence filtering and touch management) on the selected timeframe. Higher-timeframe data is sourced only from fully confirmed candles, so zones and signals do not repaint. If a timeframe lower than the chart is selected, the script falls back to the chart's native timeframe.")
- int pivotLen = input.int(3, "Pivot Length", minval = 1, maxval = 25, group = GRP_MS, tooltip = "Number of bars required on each side of a candle to confirm a multi-bar pivot high / pivot low. A Break of Structure occurs when a candle closes beyond the most recent confirmed pivot.")
- int atrLen = input.int(14, "ATR Length", minval = 1, maxval = 500, group = GRP_LEG, tooltip = "Average True Range length used as the volatility reference.")
- int minLegBars = input.int(3, "Min Leg Duration (Bars)", minval = 1, maxval = 300, group = GRP_LEG, tooltip = "Minimum number of bars the originating leg must span.")
- float minLegATR = input.float(1.5, "Min Leg Range (x ATR)", minval = 0.0, step = 0.1, group = GRP_LEG, tooltip = "Minimum high-to-low range of the originating leg, expressed as a multiple of the average volatility (ATR).")
- float minEff = input.float(0.35, "Min Directional Efficiency", minval = 0.0, maxval = 1.0, step = 0.05, group = GRP_LEG, tooltip = "Net move of the leg (first open to last close) divided by the sum of the true ranges of every candle inside the leg. Higher values demand a cleaner, more one-directional impulse.")
- float minAgree = input.float(50.0, "Min Candle Agreement (%)", minval = 0.0, maxval = 100.0, step = 5.0, group = GRP_LEG, tooltip = "Required percentage of candles inside the leg that close in the direction of the leg.")
- float innerDev = input.float(1.95, "Deviation Zone", minval = 0.1, step = 0.05, group = GRP_PROJ, inline = "dev")
- float outerDev = input.float(2.5, "-", minval = 0.1, step = 0.05, group = GRP_PROJ, inline = "dev", tooltip = "Multiples of the originating leg's total range, projected from the leg origin in the direction of the break. The reversal zone spans from the inner to the outer deviation.")
- bool useFVG = input.bool(true, "FVG (Fair Value Gaps)", group = GRP_CONF, tooltip = "Standard three-bar price imbalances that remain unfilled.")
- bool useOB = input.bool(true, "OB (Order Blocks)", group = GRP_CONF, tooltip = "The final opposing directional candle prior to a pivot structural shift.")
- bool useLIQ = input.bool(true, "LIQ (Liquidity Nodes)", group = GRP_CONF, tooltip = "Historical structural pivots that have not been swept.")
- float fvgMinATR = input.float(0.1, "FVG Min Size (x ATR)", minval = 0.0, step = 0.05, group = GRP_CONF, tooltip = "Minimum gap size for an imbalance to be registered as an FVG.")
- int fvgMaxHits = input.int(3, "FVG Max Interactions", minval = 1, maxval = 20, group = GRP_CONF, tooltip = "An FVG is invalidated once price has entered it more than this number of separate times.")
- float liqWidthATR = input.float(0.1, "LIQ Node Width (x ATR)", minval = 0.01, step = 0.01, group = GRP_CONF, tooltip = "Vertical thickness of a liquidity node around its pivot price.")
- int maxElements = input.int(100, "Max Stored Elements (per type)", minval = 10, maxval = 300, group = GRP_CONF, tooltip = "Maximum number of unmitigated FVG / OB / LIQ elements kept in memory per type.")
- int maxTouches = input.int(3, "Max Touches", minval = 1, maxval = 20, group = GRP_MGMT, tooltip = "Exhaustion purge: a zone is deleted once it has absorbed this number of separate touches.")
- int touchCooldown = input.int(5, "Touch Cooldown (Bars)", minval = 0, maxval = 200, group = GRP_MGMT, tooltip = "Bars price must stay outside the zone before a new entry is counted as a separate retest (filters sideways chop).")
- int maxZones = input.int(10, "Max Active Zones (per side)", minval = 1, maxval = 50, group = GRP_MGMT, tooltip = "Oldest zones are removed when this limit is exceeded.")
- int extendBars = input.int(8, "Zone Right Extension (Bars)", minval = 0, maxval = 200, group = GRP_MGMT, tooltip = "How far active zones extend beyond the current bar.")
- float approachATR = input.float(0.5, "Approach Distance (x ATR)", minval = 0.0, step = 0.1, group = GRP_ALRT, tooltip = "Distance from a zone's near edge, in ATR, that triggers the approach alert.")
- color bullBorderCol = input.color(color.new(#089981, 40), "Bullish Zone", group = GRP_STY, inline = "bull")
- color bullFillCol = input.color(color.new(#089981, 94), "", group = GRP_STY, inline = "bull")
- color bullArrowCol = input.color(#5fe3a1, "Arrow", group = GRP_STY, inline = "bull")
- color bearBorderCol = input.color(color.new(#f23645, 45), "Bearish Zone", group = GRP_STY, inline = "bear")
- color bearFillCol = input.color(color.new(#f23645, 94), "", group = GRP_STY, inline = "bear")
- color bearArrowCol = input.color(#f7525f, "Arrow", group = GRP_STY, inline = "bear")
- color fvgBorderCol = input.color(color.new(#26a69a, 15), "FVG", group = GRP_STY, inline = "fvg")
- color fvgFillCol = input.color(color.new(#26a69a, 72), "", group = GRP_STY, inline = "fvg")
- color fvgTextCol = input.color(#80cbc4, "Text", group = GRP_STY, inline = "fvg")
- color obBorderCol = input.color(color.new(#ba68c8, 20), "OB", group = GRP_STY, inline = "ob")
- color obFillCol = input.color(color.new(#ba68c8, 78), "", group = GRP_STY, inline = "ob")
- color obTextCol = input.color(#ce93d8, "Text", group = GRP_STY, inline = "ob")
- color liqBorderCol = input.color(color.new(#ff9800, 0), "LIQ", group = GRP_STY, inline = "liq")
- color liqFillCol = input.color(color.new(#ff9800, 85), "", group = GRP_STY, inline = "liq")
- color liqTextCol = input.color(#ffb74d, "Text", group = GRP_STY, inline = "liq")
- bool showLeg = input.bool(true, "Origin Leg", group = GRP_STY, inline = "leg")
- color legBorderCol = input.color(color.new(#b2b5be, 45), "", group = GRP_STY, inline = "leg")
- color legFillCol = input.color(color.new(#b2b5be, 80), "", group = GRP_STY, inline = "leg")
- bool showMid = input.bool(true, "Zone Midline", group = GRP_STY)
- bool showConfBox = input.bool(true, "Confluence Element", group = GRP_STY)
- string lblSizeIn = input.string("Tiny", "Label Size", options = ["Tiny", "Small", "Normal"], group = GRP_STY)
- string arrowSizeIn = input.string("Small", "Arrow Size", options = ["Tiny", "Small", "Normal"], group = GRP_STY)
- int BULL = 1
- int BEAR = -1
- int MAX_HIST = 1500
- int LEG_SEARCH = 300
- int OB_SCAN = 15
- string K_FVG = "FVG"
- string K_OB = "OB"
- string K_LIQ = "LIQ"
- color NO_COLOR = #00000000
- int chartMs = timeframe.in_seconds(timeframe.period) * 1000
- int halfBarMs = int(chartMs / 2)
- type Pivot
- float price
- int idx
- int prevIdx
- bool broken = false
- type Element
- string kind
- int dir
- float top
- float bot
- float level
- int originTime
- int hits = 0
- bool inside = false
- type Zone
- int dir
- float top
- float bot
- int leftTime
- int touches = 0
- int lastInIdx
- bool wasInside = false
- bool approached = false
- box zoneBox
- line midLine
- label arrowLbl
- label confLbl
- box confBox
- box legBox
- var array<float> bO = array.new<float>()
- var array<float> bH = array.new<float>()
- var array<float> bL = array.new<float>()
- var array<float> bC = array.new<float>()
- var array<float> bTR = array.new<float>()
- var array<int> bT = array.new<int>()
- var array<int> bTC = array.new<int>()
- var int eCount = 0
- var float eATR = na
- var float trSeed = 0.0
- var array<Element> fvgs = array.new<Element>()
- var array<Element> obs = array.new<Element>()
- var array<Element> liqs = array.new<Element>()
- var array<Zone> zones = array.new<Zone>()
- var Pivot lastPH = na
- var Pivot lastPL = na
- f_base() =>
- eCount - bH.size()
- getO(int i) =>
- bO.get(i - f_base())
- getH(int i) =>
- bH.get(i - f_base())
- getL(int i) =>
- bL.get(i - f_base())
- getC(int i) =>
- bC.get(i - f_base())
- getTR(int i) =>
- bTR.get(i - f_base())
- getT(int i) =>
- bT.get(i - f_base())
- getTC(int i) =>
- bTC.get(i - f_base())
- f_size(string s) =>
- switch s
- "Tiny" => size.tiny
- "Small" => size.small
- "Normal" => size.normal
- => size.tiny
- f_edge(Element e, int zdir) =>
- zdir == BEAR ? e.bot : e.top
- f_better(int zdir, float edge, float ref) =>
- zdir == BEAR ? edge < ref : edge > ref
- f_lowestIdx(int fromIdx, int toIdx) =>
- int bestIdx = toIdx
- float bestVal = getL(toIdx)
- if toIdx > fromIdx
- for i = toIdx - 1 to fromIdx
- float v = getL(i)
- if v < bestVal
- bestVal := v
- bestIdx := i
- [bestIdx, bestVal]
- f_highestIdx(int fromIdx, int toIdx) =>
- int bestIdx = toIdx
- float bestVal = getH(toIdx)
- if toIdx > fromIdx
- for i = toIdx - 1 to fromIdx
- float v = getH(i)
- if v > bestVal
- bestVal := v
- bestIdx := i
- [bestIdx, bestVal]
- f_findOpposite(int startIdx, bool bullishShift) =>
- int found = na
- int stopIdx = math.max(f_base(), startIdx - OB_SCAN)
- for i = startIdx to stopIdx
- bool opp = bullishShift ? getC(i) < getO(i) : getC(i) > getO(i)
- if opp
- found := i
- break
- found
- f_legStats(int fromIdx, int toIdx, bool bullishLeg) =>
- float trSum = 0.0
- int agree = 0
- for i = fromIdx to toIdx
- trSum += getTR(i)
- bool agrees = bullishLeg ? getC(i) > getO(i) : getC(i) < getO(i)
- if agrees
- agree += 1
- float netMove = bullishLeg ? getC(toIdx) - getO(fromIdx) : getO(fromIdx) - getC(toIdx)
- float eff = trSum > 0 ? math.max(netMove, 0.0) / trSum : 0.0
- float pct = 100.0 * agree / math.max(toIdx - fromIdx + 1, 1)
- [eff, pct]
- f_pushCapped(array<Element> arr, Element e) =>
- bool enabled = e.kind == K_FVG ? useFVG : e.kind == K_OB ? useOB : useLIQ
- if enabled
- arr.push(e)
- if arr.size() > maxElements
- arr.shift()
- arr.size()
- f_updateElements(array<Element> arr, float h, float l, float c) =>
- int n = arr.size()
- if n > 0
- for i = n - 1 to 0
- Element e = arr.get(i)
- bool remove = false
- if e.kind == K_FVG
- bool touching = false
- if e.dir == BULL
- remove := l <= e.bot
- touching := l <= e.top
- else
- remove := h >= e.top
- touching := h >= e.bot
- if not remove
- if touching and not e.inside
- e.hits := e.hits + 1
- e.inside := touching
- remove := e.hits > fvgMaxHits
- else if e.kind == K_OB
- remove := e.dir == BULL ? c < e.bot : c > e.top
- else
- remove := e.dir == BULL ? l < e.level : h > e.level
- if remove
- arr.remove(i)
- n
- f_scanArr(array<Element> arr, int zdir, float zTop, float zBot) =>
- Element best = na
- for e in arr
- if e.dir == zdir and e.top >= zBot and e.bot <= zTop
- bool take = na(best)
- if not take
- take := f_better(zdir, f_edge(e, zdir), f_edge(best, zdir))
- if take
- best := e
- best
- f_pickConfluence(int zdir, float zTop, float zBot) =>
- Element pick = na
- if useFVG
- pick := f_scanArr(fvgs, zdir, zTop, zBot)
- if useOB
- Element ob = f_scanArr(obs, zdir, zTop, zBot)
- if not na(ob)
- if na(pick)
- pick := ob
- else if f_better(zdir, f_edge(ob, zdir), f_edge(pick, zdir))
- pick := ob
- if useLIQ
- Element lq = f_scanArr(liqs, zdir, zTop, zBot)
- if not na(lq)
- if na(pick)
- pick := lq
- else if f_better(zdir, f_edge(lq, zdir), f_edge(pick, zdir))
- pick := lq
- pick
- method purge(Zone z) =>
- box.delete(z.zoneBox)
- line.delete(z.midLine)
- label.delete(z.arrowLbl)
- label.delete(z.confLbl)
- box.delete(z.confBox)
- box.delete(z.legBox)
- true
- f_enforceMax(int zdir) =>
- int cnt = 0
- for z in zones
- if z.dir == zdir
- cnt += 1
- if cnt > maxZones
- int n = zones.size()
- for i = 0 to n - 1
- Zone z = zones.get(i)
- if z.dir == zdir
- z.purge()
- zones.remove(i)
- break
- cnt
- f_createZone(int zdir, float zTop, float zBot, int leftT, Element conf, int legLT, int legRT, float legTop, float legBot, int cur, float barH, float barL) =>
- int rightT = time + extendBars * chartMs
- float mid = (zTop + zBot) / 2.0
- color bCol = zdir == BULL ? bullBorderCol : bearBorderCol
- color fCol = zdir == BULL ? bullFillCol : bearFillCol
- color aCol = zdir == BULL ? bullArrowCol : bearArrowCol
- color cbCol = conf.kind == K_FVG ? fvgBorderCol : conf.kind == K_OB ? obBorderCol : liqBorderCol
- color cfCol = conf.kind == K_FVG ? fvgFillCol : conf.kind == K_OB ? obFillCol : liqFillCol
- color ctCol = conf.kind == K_FVG ? fvgTextCol : conf.kind == K_OB ? obTextCol : liqTextCol
- box lb = showLeg ? box.new(legLT, legTop, legRT, legBot, border_color = legBorderCol, border_width = 1, xloc = xloc.bar_time, bgcolor = legFillCol) : na
- box zb = box.new(leftT, zTop, rightT, zBot, border_color = bCol, border_width = 1, xloc = xloc.bar_time, bgcolor = fCol)
- box cb = showConfBox ? box.new(conf.originTime, conf.top, rightT, conf.bot, border_color = cbCol, border_width = 1, xloc = xloc.bar_time, bgcolor = cfCol) : na
- line ml = showMid ? line.new(leftT, mid, rightT, mid, xloc = xloc.bar_time, color = bCol, style = line.style_dashed, width = 1) : na
- label al = label.new(int(math.round((leftT + rightT) / 2.0)), mid, "", xloc = xloc.bar_time, color = aCol, style = zdir == BULL ? label.style_triangleup : label.style_triangledown, size = f_size(arrowSizeIn))
- float lblY = math.max(math.min(conf.level, zTop), zBot)
- label cl = label.new(rightT, lblY, conf.kind, xloc = xloc.bar_time, color = NO_COLOR, style = label.style_label_right, textcolor = ctCol, size = f_size(lblSizeIn), textalign = text.align_right)
- bool inside = barH >= zBot and barL <= zTop
- Zone.new(dir = zdir, top = zTop, bot = zBot, leftTime = leftT, touches = 0, lastInIdx = inside ? cur : na, wasInside = inside, approached = inside, zoneBox = zb, midLine = ml, arrowLbl = al, confLbl = cl, confBox = cb, legBox = lb)
- string tfStr = switch tfInput
- "1m" => "1"
- "5m" => "5"
- "15m" => "15"
- "30m" => "30"
- "1h" => "60"
- "4h" => "240"
- "D" => "1D"
- => ""
- bool useHTF = tfStr != "" and timeframe.in_seconds(tfStr) > timeframe.in_seconds(timeframe.period)
- string engineTF = useHTF ? tfStr : timeframe.period
- [htfO, htfH, htfL, htfC, htfT, htfTC] = request.security(syminfo.tickerid, engineTF, [open[1], high[1], low[1], close[1], time[1], time_close[1]], lookahead = barmerge.lookahead_on)
- bool htfNewBar = not na(htfT) and (na(htfT[1]) or htfT != htfT[1])
- bool newEngineBar = useHTF ? htfNewBar : barstate.isconfirmed
- float eO = useHTF ? htfO : open
- float eH = useHTF ? htfH : high
- float eL = useHTF ? htfL : low
- float eC = useHTF ? htfC : close
- int eT = useHTF ? htfT : time
- int eTC = useHTF ? nz(htfTC, htfT + timeframe.in_seconds(engineTF) * 1000) : nz(time_close, time + chartMs)
- bool evNewBull = false
- bool evNewBear = false
- bool evApprBull = false
- bool evApprBear = false
- bool evTouchBull = false
- bool evTouchBear = false
- if newEngineBar and not na(eC) and not na(eT)
- float prevClose = bC.size() > 0 ? bC.last() : na
- float trueRange = na(prevClose) ? eH - eL : math.max(eH - eL, math.abs(eH - prevClose), math.abs(eL - prevClose))
- bO.push(eO)
- bH.push(eH)
- bL.push(eL)
- bC.push(eC)
- bTR.push(trueRange)
- bT.push(eT)
- bTC.push(eTC)
- eCount += 1
- if bH.size() > MAX_HIST
- bO.shift()
- bH.shift()
- bL.shift()
- bC.shift()
- bTR.shift()
- bT.shift()
- bTC.shift()
- int cur = eCount - 1
- if eCount <= atrLen
- trSeed += trueRange
- eATR := trSeed / eCount
- else
- eATR := (eATR * (atrLen - 1) + trueRange) / atrLen
- float atrV = math.max(nz(eATR, trueRange), syminfo.mintick)
- f_updateElements(fvgs, eH, eL, eC)
- f_updateElements(obs, eH, eL, eC)
- f_updateElements(liqs, eH, eL, eC)
- if zones.size() > 0
- for i = zones.size() - 1 to 0
- Zone z = zones.get(i)
- bool inZone = eH >= z.bot and eL <= z.top
- bool invalid = z.dir == BEAR ? eC > z.top : eC < z.bot
- if invalid
- z.purge()
- zones.remove(i)
- else
- bool newTouch = inZone and not z.wasInside and (na(z.lastInIdx) or cur - z.lastInIdx > touchCooldown)
- if newTouch
- z.touches := z.touches + 1
- if z.dir == BULL
- evTouchBull := true
- else
- evTouchBear := true
- if inZone
- z.lastInIdx := cur
- z.wasInside := inZone
- float dist = z.dir == BULL ? eL - z.top : z.bot - eH
- bool near = not inZone and dist <= approachATR * atrV
- if inZone
- z.approached := true
- else if near
- if not z.approached
- z.approached := true
- if z.dir == BULL
- evApprBull := true
- else
- evApprBear := true
- else
- z.approached := false
- if z.touches >= maxTouches and not inZone
- z.purge()
- zones.remove(i)
- if not na(lastPH) and not lastPH.broken and eC > lastPH.price
- lastPH.broken := true
- int baseU = f_base()
- int obFromU = math.max(lastPH.idx + 1, baseU)
- if useOB and obFromU <= cur
- [retIdxU, _] = f_lowestIdx(obFromU, cur)
- int obIdxU = f_findOpposite(retIdxU, true)
- if not na(obIdxU)
- f_pushCapped(obs, Element.new(kind = K_OB, dir = BULL, top = getH(obIdxU), bot = getL(obIdxU), level = (getH(obIdxU) + getL(obIdxU)) / 2.0, originTime = getT(obIdxU)))
- int legEndU = lastPH.idx
- int legFromU = na(lastPH.prevIdx) ? legEndU - LEG_SEARCH : math.max(lastPH.prevIdx + 1, legEndU - LEG_SEARCH)
- legFromU := math.max(legFromU, baseU)
- if legEndU >= baseU and legFromU <= legEndU - 1
- [legStartU, legLowU] = f_lowestIdx(legFromU, legEndU - 1)
- float legHighU = lastPH.price
- float legRangeU = legHighU - legLowU
- [effU, agreeU] = f_legStats(legStartU, legEndU, true)
- bool qualU = legRangeU > 0 and legEndU - legStartU >= minLegBars and legRangeU >= minLegATR * atrV and effU >= minEff and agreeU >= minAgree
- if qualU
- float zBotU = legLowU + math.min(innerDev, outerDev) * legRangeU
- float zTopU = legLowU + math.max(innerDev, outerDev) * legRangeU
- if eC <= zTopU
- Element confU = f_pickConfluence(BEAR, zTopU, zBotU)
- if not na(confU)
- zones.push(f_createZone(BEAR, zTopU, zBotU, eT, confU, getT(legStartU) - halfBarMs, getTC(legEndU) - halfBarMs, legHighU, legLowU, cur, eH, eL))
- f_enforceMax(BEAR)
- evNewBear := true
- if not na(lastPL) and not lastPL.broken and eC < lastPL.price
- lastPL.broken := true
- int baseD = f_base()
- int obFromD = math.max(lastPL.idx + 1, baseD)
- if useOB and obFromD <= cur
- [retIdxD, _] = f_highestIdx(obFromD, cur)
- int obIdxD = f_findOpposite(retIdxD, false)
- if not na(obIdxD)
- f_pushCapped(obs, Element.new(kind = K_OB, dir = BEAR, top = getH(obIdxD), bot = getL(obIdxD), level = (getH(obIdxD) + getL(obIdxD)) / 2.0, originTime = getT(obIdxD)))
- int legEndD = lastPL.idx
- int legFromD = na(lastPL.prevIdx) ? legEndD - LEG_SEARCH : math.max(lastPL.prevIdx + 1, legEndD - LEG_SEARCH)
- legFromD := math.max(legFromD, baseD)
- if legEndD >= baseD and legFromD <= legEndD - 1
- [legStartD, legHighD] = f_highestIdx(legFromD, legEndD - 1)
- float legLowD = lastPL.price
- float legRangeD = legHighD - legLowD
- [effD, agreeD] = f_legStats(legStartD, legEndD, false)
- bool qualD = legRangeD > 0 and legEndD - legStartD >= minLegBars and legRangeD >= minLegATR * atrV and effD >= minEff and agreeD >= minAgree
- if qualD
- float zTopD = legHighD - math.min(innerDev, outerDev) * legRangeD
- float zBotD = legHighD - math.max(innerDev, outerDev) * legRangeD
- if eC >= zBotD
- Element confD = f_pickConfluence(BULL, zTopD, zBotD)
- if not na(confD)
- zones.push(f_createZone(BULL, zTopD, zBotD, eT, confD, getT(legStartD) - halfBarMs, getTC(legEndD) - halfBarMs, legHighD, legLowD, cur, eH, eL))
- f_enforceMax(BULL)
- evNewBull := true
- if eCount >= 3
- float h2 = getH(cur - 2)
- float l2 = getL(cur - 2)
- int midT = getT(cur - 1)
- if eL > h2 and eL - h2 >= fvgMinATR * atrV
- f_pushCapped(fvgs, Element.new(kind = K_FVG, dir = BULL, top = eL, bot = h2, level = (eL + h2) / 2.0, originTime = midT))
- if eH < l2 and l2 - eH >= fvgMinATR * atrV
- f_pushCapped(fvgs, Element.new(kind = K_FVG, dir = BEAR, top = l2, bot = eH, level = (l2 + eH) / 2.0, originTime = midT))
- if eCount >= 2 * pivotLen + 1
- int c = cur - pivotLen
- float cHi = getH(c)
- float cLo = getL(c)
- bool isPH = true
- bool isPL = true
- for k = 1 to pivotLen
- if getH(c - k) > cHi or getH(c + k) >= cHi
- isPH := false
- if getL(c - k) < cLo or getL(c + k) <= cLo
- isPL := false
- if not isPH and not isPL
- break
- float liqW = liqWidthATR * atrV
- if isPH
- int prevPH = na(lastPH) ? na : lastPH.idx
- lastPH := Pivot.new(price = cHi, idx = c, prevIdx = prevPH)
- f_pushCapped(liqs, Element.new(kind = K_LIQ, dir = BEAR, top = cHi + liqW / 2.0, bot = cHi - liqW / 2.0, level = cHi, originTime = getT(c)))
- if isPL
- int prevPL = na(lastPL) ? na : lastPL.idx
- lastPL := Pivot.new(price = cLo, idx = c, prevIdx = prevPL)
- f_pushCapped(liqs, Element.new(kind = K_LIQ, dir = BULL, top = cLo + liqW / 2.0, bot = cLo - liqW / 2.0, level = cLo, originTime = getT(c)))
- if barstate.islast and zones.size() > 0
- int rT = time + extendBars * chartMs
- for z in zones
- if not na(z.zoneBox)
- box.set_right(z.zoneBox, rT)
- if not na(z.midLine)
- line.set_x2(z.midLine, rT)
- if not na(z.arrowLbl)
- label.set_x(z.arrowLbl, int(math.round((z.leftTime + rT) / 2.0)))
- if not na(z.confBox)
- box.set_right(z.confBox, rT)
- if not na(z.confLbl)
- label.set_x(z.confLbl, rT)
- alertcondition(evNewBull, "TradeAxis Reversals - New Bullish Zone", "TradeAxis Reversals: New bullish reversal zone created on {{ticker}} ({{interval}}).")
- alertcondition(evNewBear, "TradeAxis Reversals - New Bearish Zone", "TradeAxis Reversals: New bearish reversal zone created on {{ticker}} ({{interval}}).")
- alertcondition(evNewBull or evNewBear, "TradeAxis Reversals - Any New Zone", "TradeAxis Reversals: New reversal zone created on {{ticker}} ({{interval}}).")
- alertcondition(evApprBull, "TradeAxis Reversals - Approaching Bullish Zone", "TradeAxis Reversals: Price is approaching a bullish reversal zone on {{ticker}} ({{interval}}).")
- alertcondition(evApprBear, "TradeAxis Reversals - Approaching Bearish Zone", "TradeAxis Reversals: Price is approaching a bearish reversal zone on {{ticker}} ({{interval}}).")
- alertcondition(evApprBull or evApprBear, "TradeAxis Reversals - Any Zone Approach", "TradeAxis Reversals: Price is approaching a reversal zone on {{ticker}} ({{interval}}).")
- alertcondition(evTouchBull, "TradeAxis Reversals - Bullish Zone Touch", "TradeAxis Reversals: Price touched a bullish reversal zone on {{ticker}} ({{interval}}).")
- alertcondition(evTouchBear, "TradeAxis Reversals - Bearish Zone Touch", "TradeAxis Reversals: Price touched a bearish reversal zone on {{ticker}} ({{interval}}).")
- alertcondition(evTouchBull or evTouchBear, "TradeAxis Reversals - Any Zone Touch", "TradeAxis Reversals: Price touched a reversal zone on {{ticker}} ({{interval}}).")
Advertisement
Add Comment
Please, Sign In to add comment