ajiim

🎁

Oct 30th, 2026
422
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 25.78 KB | None | 0 0
  1. //@version=6
  2. indicator("TradeAxis Reversals", shorttitle = "TradeAxis Reversals", overlay = true, max_boxes_count = 500, max_lines_count = 500, max_labels_count = 500)
  3.  
  4. string GRP_TF = "Timeframe"
  5. string GRP_MS = "Market Structure"
  6. string GRP_LEG = "Leg Qualification"
  7. string GRP_PROJ = "Range Projection"
  8. string GRP_CONF = "Confluence Filter"
  9. string GRP_MGMT = "Zone Management"
  10. string GRP_ALRT = "Alerts"
  11. string GRP_STY = "Style"
  12.  
  13. 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.")
  14.  
  15. 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.")
  16.  
  17. int atrLen = input.int(14, "ATR Length", minval = 1, maxval = 500, group = GRP_LEG, tooltip = "Average True Range length used as the volatility reference.")
  18. 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.")
  19. 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).")
  20. 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.")
  21. 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.")
  22.  
  23. float innerDev = input.float(1.95, "Deviation Zone", minval = 0.1, step = 0.05, group = GRP_PROJ, inline = "dev")
  24. 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.")
  25.  
  26. bool useFVG = input.bool(true, "FVG (Fair Value Gaps)", group = GRP_CONF, tooltip = "Standard three-bar price imbalances that remain unfilled.")
  27. bool useOB = input.bool(true, "OB (Order Blocks)", group = GRP_CONF, tooltip = "The final opposing directional candle prior to a pivot structural shift.")
  28. bool useLIQ = input.bool(true, "LIQ (Liquidity Nodes)", group = GRP_CONF, tooltip = "Historical structural pivots that have not been swept.")
  29. 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.")
  30. 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.")
  31. 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.")
  32. 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.")
  33.  
  34. 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.")
  35. 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).")
  36. 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.")
  37. 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.")
  38.  
  39. 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.")
  40.  
  41. color bullBorderCol = input.color(color.new(#089981, 40), "Bullish Zone", group = GRP_STY, inline = "bull")
  42. color bullFillCol = input.color(color.new(#089981, 94), "", group = GRP_STY, inline = "bull")
  43. color bullArrowCol = input.color(#5fe3a1, "Arrow", group = GRP_STY, inline = "bull")
  44. color bearBorderCol = input.color(color.new(#f23645, 45), "Bearish Zone", group = GRP_STY, inline = "bear")
  45. color bearFillCol = input.color(color.new(#f23645, 94), "", group = GRP_STY, inline = "bear")
  46. color bearArrowCol = input.color(#f7525f, "Arrow", group = GRP_STY, inline = "bear")
  47. color fvgBorderCol = input.color(color.new(#26a69a, 15), "FVG", group = GRP_STY, inline = "fvg")
  48. color fvgFillCol = input.color(color.new(#26a69a, 72), "", group = GRP_STY, inline = "fvg")
  49. color fvgTextCol = input.color(#80cbc4, "Text", group = GRP_STY, inline = "fvg")
  50. color obBorderCol = input.color(color.new(#ba68c8, 20), "OB", group = GRP_STY, inline = "ob")
  51. color obFillCol = input.color(color.new(#ba68c8, 78), "", group = GRP_STY, inline = "ob")
  52. color obTextCol = input.color(#ce93d8, "Text", group = GRP_STY, inline = "ob")
  53. color liqBorderCol = input.color(color.new(#ff9800, 0), "LIQ", group = GRP_STY, inline = "liq")
  54. color liqFillCol = input.color(color.new(#ff9800, 85), "", group = GRP_STY, inline = "liq")
  55. color liqTextCol = input.color(#ffb74d, "Text", group = GRP_STY, inline = "liq")
  56. bool showLeg = input.bool(true, "Origin Leg", group = GRP_STY, inline = "leg")
  57. color legBorderCol = input.color(color.new(#b2b5be, 45), "", group = GRP_STY, inline = "leg")
  58. color legFillCol = input.color(color.new(#b2b5be, 80), "", group = GRP_STY, inline = "leg")
  59. bool showMid = input.bool(true, "Zone Midline", group = GRP_STY)
  60. bool showConfBox = input.bool(true, "Confluence Element", group = GRP_STY)
  61. string lblSizeIn = input.string("Tiny", "Label Size", options = ["Tiny", "Small", "Normal"], group = GRP_STY)
  62. string arrowSizeIn = input.string("Small", "Arrow Size", options = ["Tiny", "Small", "Normal"], group = GRP_STY)
  63.  
  64. int BULL = 1
  65. int BEAR = -1
  66. int MAX_HIST = 1500
  67. int LEG_SEARCH = 300
  68. int OB_SCAN = 15
  69. string K_FVG = "FVG"
  70. string K_OB = "OB"
  71. string K_LIQ = "LIQ"
  72. color NO_COLOR = #00000000
  73. int chartMs = timeframe.in_seconds(timeframe.period) * 1000
  74. int halfBarMs = int(chartMs / 2)
  75.  
  76. type Pivot
  77. float price
  78. int idx
  79. int prevIdx
  80. bool broken = false
  81.  
  82. type Element
  83. string kind
  84. int dir
  85. float top
  86. float bot
  87. float level
  88. int originTime
  89. int hits = 0
  90. bool inside = false
  91.  
  92. type Zone
  93. int dir
  94. float top
  95. float bot
  96. int leftTime
  97. int touches = 0
  98. int lastInIdx
  99. bool wasInside = false
  100. bool approached = false
  101. box zoneBox
  102. line midLine
  103. label arrowLbl
  104. label confLbl
  105. box confBox
  106. box legBox
  107.  
  108. var array<float> bO = array.new<float>()
  109. var array<float> bH = array.new<float>()
  110. var array<float> bL = array.new<float>()
  111. var array<float> bC = array.new<float>()
  112. var array<float> bTR = array.new<float>()
  113. var array<int> bT = array.new<int>()
  114. var array<int> bTC = array.new<int>()
  115. var int eCount = 0
  116. var float eATR = na
  117. var float trSeed = 0.0
  118. var array<Element> fvgs = array.new<Element>()
  119. var array<Element> obs = array.new<Element>()
  120. var array<Element> liqs = array.new<Element>()
  121. var array<Zone> zones = array.new<Zone>()
  122. var Pivot lastPH = na
  123. var Pivot lastPL = na
  124.  
  125. f_base() =>
  126. eCount - bH.size()
  127.  
  128. getO(int i) =>
  129. bO.get(i - f_base())
  130.  
  131. getH(int i) =>
  132. bH.get(i - f_base())
  133.  
  134. getL(int i) =>
  135. bL.get(i - f_base())
  136.  
  137. getC(int i) =>
  138. bC.get(i - f_base())
  139.  
  140. getTR(int i) =>
  141. bTR.get(i - f_base())
  142.  
  143. getT(int i) =>
  144. bT.get(i - f_base())
  145.  
  146. getTC(int i) =>
  147. bTC.get(i - f_base())
  148.  
  149. f_size(string s) =>
  150. switch s
  151. "Tiny" => size.tiny
  152. "Small" => size.small
  153. "Normal" => size.normal
  154. => size.tiny
  155.  
  156. f_edge(Element e, int zdir) =>
  157. zdir == BEAR ? e.bot : e.top
  158.  
  159. f_better(int zdir, float edge, float ref) =>
  160. zdir == BEAR ? edge < ref : edge > ref
  161.  
  162. f_lowestIdx(int fromIdx, int toIdx) =>
  163. int bestIdx = toIdx
  164. float bestVal = getL(toIdx)
  165. if toIdx > fromIdx
  166. for i = toIdx - 1 to fromIdx
  167. float v = getL(i)
  168. if v < bestVal
  169. bestVal := v
  170. bestIdx := i
  171. [bestIdx, bestVal]
  172.  
  173. f_highestIdx(int fromIdx, int toIdx) =>
  174. int bestIdx = toIdx
  175. float bestVal = getH(toIdx)
  176. if toIdx > fromIdx
  177. for i = toIdx - 1 to fromIdx
  178. float v = getH(i)
  179. if v > bestVal
  180. bestVal := v
  181. bestIdx := i
  182. [bestIdx, bestVal]
  183.  
  184. f_findOpposite(int startIdx, bool bullishShift) =>
  185. int found = na
  186. int stopIdx = math.max(f_base(), startIdx - OB_SCAN)
  187. for i = startIdx to stopIdx
  188. bool opp = bullishShift ? getC(i) < getO(i) : getC(i) > getO(i)
  189. if opp
  190. found := i
  191. break
  192. found
  193.  
  194. f_legStats(int fromIdx, int toIdx, bool bullishLeg) =>
  195. float trSum = 0.0
  196. int agree = 0
  197. for i = fromIdx to toIdx
  198. trSum += getTR(i)
  199. bool agrees = bullishLeg ? getC(i) > getO(i) : getC(i) < getO(i)
  200. if agrees
  201. agree += 1
  202. float netMove = bullishLeg ? getC(toIdx) - getO(fromIdx) : getO(fromIdx) - getC(toIdx)
  203. float eff = trSum > 0 ? math.max(netMove, 0.0) / trSum : 0.0
  204. float pct = 100.0 * agree / math.max(toIdx - fromIdx + 1, 1)
  205. [eff, pct]
  206.  
  207. f_pushCapped(array<Element> arr, Element e) =>
  208. bool enabled = e.kind == K_FVG ? useFVG : e.kind == K_OB ? useOB : useLIQ
  209. if enabled
  210. arr.push(e)
  211. if arr.size() > maxElements
  212. arr.shift()
  213. arr.size()
  214.  
  215. f_updateElements(array<Element> arr, float h, float l, float c) =>
  216. int n = arr.size()
  217. if n > 0
  218. for i = n - 1 to 0
  219. Element e = arr.get(i)
  220. bool remove = false
  221. if e.kind == K_FVG
  222. bool touching = false
  223. if e.dir == BULL
  224. remove := l <= e.bot
  225. touching := l <= e.top
  226. else
  227. remove := h >= e.top
  228. touching := h >= e.bot
  229. if not remove
  230. if touching and not e.inside
  231. e.hits := e.hits + 1
  232. e.inside := touching
  233. remove := e.hits > fvgMaxHits
  234. else if e.kind == K_OB
  235. remove := e.dir == BULL ? c < e.bot : c > e.top
  236. else
  237. remove := e.dir == BULL ? l < e.level : h > e.level
  238. if remove
  239. arr.remove(i)
  240. n
  241.  
  242. f_scanArr(array<Element> arr, int zdir, float zTop, float zBot) =>
  243. Element best = na
  244. for e in arr
  245. if e.dir == zdir and e.top >= zBot and e.bot <= zTop
  246. bool take = na(best)
  247. if not take
  248. take := f_better(zdir, f_edge(e, zdir), f_edge(best, zdir))
  249. if take
  250. best := e
  251. best
  252.  
  253. f_pickConfluence(int zdir, float zTop, float zBot) =>
  254. Element pick = na
  255. if useFVG
  256. pick := f_scanArr(fvgs, zdir, zTop, zBot)
  257. if useOB
  258. Element ob = f_scanArr(obs, zdir, zTop, zBot)
  259. if not na(ob)
  260. if na(pick)
  261. pick := ob
  262. else if f_better(zdir, f_edge(ob, zdir), f_edge(pick, zdir))
  263. pick := ob
  264. if useLIQ
  265. Element lq = f_scanArr(liqs, zdir, zTop, zBot)
  266. if not na(lq)
  267. if na(pick)
  268. pick := lq
  269. else if f_better(zdir, f_edge(lq, zdir), f_edge(pick, zdir))
  270. pick := lq
  271. pick
  272.  
  273. method purge(Zone z) =>
  274. box.delete(z.zoneBox)
  275. line.delete(z.midLine)
  276. label.delete(z.arrowLbl)
  277. label.delete(z.confLbl)
  278. box.delete(z.confBox)
  279. box.delete(z.legBox)
  280. true
  281.  
  282. f_enforceMax(int zdir) =>
  283. int cnt = 0
  284. for z in zones
  285. if z.dir == zdir
  286. cnt += 1
  287. if cnt > maxZones
  288. int n = zones.size()
  289. for i = 0 to n - 1
  290. Zone z = zones.get(i)
  291. if z.dir == zdir
  292. z.purge()
  293. zones.remove(i)
  294. break
  295. cnt
  296.  
  297. 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) =>
  298. int rightT = time + extendBars * chartMs
  299. float mid = (zTop + zBot) / 2.0
  300. color bCol = zdir == BULL ? bullBorderCol : bearBorderCol
  301. color fCol = zdir == BULL ? bullFillCol : bearFillCol
  302. color aCol = zdir == BULL ? bullArrowCol : bearArrowCol
  303. color cbCol = conf.kind == K_FVG ? fvgBorderCol : conf.kind == K_OB ? obBorderCol : liqBorderCol
  304. color cfCol = conf.kind == K_FVG ? fvgFillCol : conf.kind == K_OB ? obFillCol : liqFillCol
  305. color ctCol = conf.kind == K_FVG ? fvgTextCol : conf.kind == K_OB ? obTextCol : liqTextCol
  306. box lb = showLeg ? box.new(legLT, legTop, legRT, legBot, border_color = legBorderCol, border_width = 1, xloc = xloc.bar_time, bgcolor = legFillCol) : na
  307. box zb = box.new(leftT, zTop, rightT, zBot, border_color = bCol, border_width = 1, xloc = xloc.bar_time, bgcolor = fCol)
  308. 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
  309. line ml = showMid ? line.new(leftT, mid, rightT, mid, xloc = xloc.bar_time, color = bCol, style = line.style_dashed, width = 1) : na
  310. 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))
  311. float lblY = math.max(math.min(conf.level, zTop), zBot)
  312. 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)
  313. bool inside = barH >= zBot and barL <= zTop
  314. 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)
  315.  
  316. string tfStr = switch tfInput
  317. "1m" => "1"
  318. "5m" => "5"
  319. "15m" => "15"
  320. "30m" => "30"
  321. "1h" => "60"
  322. "4h" => "240"
  323. "D" => "1D"
  324. => ""
  325.  
  326. bool useHTF = tfStr != "" and timeframe.in_seconds(tfStr) > timeframe.in_seconds(timeframe.period)
  327. string engineTF = useHTF ? tfStr : timeframe.period
  328.  
  329. [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)
  330.  
  331. bool htfNewBar = not na(htfT) and (na(htfT[1]) or htfT != htfT[1])
  332. bool newEngineBar = useHTF ? htfNewBar : barstate.isconfirmed
  333.  
  334. float eO = useHTF ? htfO : open
  335. float eH = useHTF ? htfH : high
  336. float eL = useHTF ? htfL : low
  337. float eC = useHTF ? htfC : close
  338. int eT = useHTF ? htfT : time
  339. int eTC = useHTF ? nz(htfTC, htfT + timeframe.in_seconds(engineTF) * 1000) : nz(time_close, time + chartMs)
  340.  
  341. bool evNewBull = false
  342. bool evNewBear = false
  343. bool evApprBull = false
  344. bool evApprBear = false
  345. bool evTouchBull = false
  346. bool evTouchBear = false
  347.  
  348. if newEngineBar and not na(eC) and not na(eT)
  349. float prevClose = bC.size() > 0 ? bC.last() : na
  350. float trueRange = na(prevClose) ? eH - eL : math.max(eH - eL, math.abs(eH - prevClose), math.abs(eL - prevClose))
  351. bO.push(eO)
  352. bH.push(eH)
  353. bL.push(eL)
  354. bC.push(eC)
  355. bTR.push(trueRange)
  356. bT.push(eT)
  357. bTC.push(eTC)
  358. eCount += 1
  359. if bH.size() > MAX_HIST
  360. bO.shift()
  361. bH.shift()
  362. bL.shift()
  363. bC.shift()
  364. bTR.shift()
  365. bT.shift()
  366. bTC.shift()
  367. int cur = eCount - 1
  368.  
  369. if eCount <= atrLen
  370. trSeed += trueRange
  371. eATR := trSeed / eCount
  372. else
  373. eATR := (eATR * (atrLen - 1) + trueRange) / atrLen
  374. float atrV = math.max(nz(eATR, trueRange), syminfo.mintick)
  375.  
  376. f_updateElements(fvgs, eH, eL, eC)
  377. f_updateElements(obs, eH, eL, eC)
  378. f_updateElements(liqs, eH, eL, eC)
  379.  
  380. if zones.size() > 0
  381. for i = zones.size() - 1 to 0
  382. Zone z = zones.get(i)
  383. bool inZone = eH >= z.bot and eL <= z.top
  384. bool invalid = z.dir == BEAR ? eC > z.top : eC < z.bot
  385. if invalid
  386. z.purge()
  387. zones.remove(i)
  388. else
  389. bool newTouch = inZone and not z.wasInside and (na(z.lastInIdx) or cur - z.lastInIdx > touchCooldown)
  390. if newTouch
  391. z.touches := z.touches + 1
  392. if z.dir == BULL
  393. evTouchBull := true
  394. else
  395. evTouchBear := true
  396. if inZone
  397. z.lastInIdx := cur
  398. z.wasInside := inZone
  399.  
  400. float dist = z.dir == BULL ? eL - z.top : z.bot - eH
  401. bool near = not inZone and dist <= approachATR * atrV
  402. if inZone
  403. z.approached := true
  404. else if near
  405. if not z.approached
  406. z.approached := true
  407. if z.dir == BULL
  408. evApprBull := true
  409. else
  410. evApprBear := true
  411. else
  412. z.approached := false
  413.  
  414. if z.touches >= maxTouches and not inZone
  415. z.purge()
  416. zones.remove(i)
  417.  
  418. if not na(lastPH) and not lastPH.broken and eC > lastPH.price
  419. lastPH.broken := true
  420. int baseU = f_base()
  421. int obFromU = math.max(lastPH.idx + 1, baseU)
  422. if useOB and obFromU <= cur
  423. [retIdxU, _] = f_lowestIdx(obFromU, cur)
  424. int obIdxU = f_findOpposite(retIdxU, true)
  425. if not na(obIdxU)
  426. 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)))
  427. int legEndU = lastPH.idx
  428. int legFromU = na(lastPH.prevIdx) ? legEndU - LEG_SEARCH : math.max(lastPH.prevIdx + 1, legEndU - LEG_SEARCH)
  429. legFromU := math.max(legFromU, baseU)
  430. if legEndU >= baseU and legFromU <= legEndU - 1
  431. [legStartU, legLowU] = f_lowestIdx(legFromU, legEndU - 1)
  432. float legHighU = lastPH.price
  433. float legRangeU = legHighU - legLowU
  434. [effU, agreeU] = f_legStats(legStartU, legEndU, true)
  435. bool qualU = legRangeU > 0 and legEndU - legStartU >= minLegBars and legRangeU >= minLegATR * atrV and effU >= minEff and agreeU >= minAgree
  436. if qualU
  437. float zBotU = legLowU + math.min(innerDev, outerDev) * legRangeU
  438. float zTopU = legLowU + math.max(innerDev, outerDev) * legRangeU
  439. if eC <= zTopU
  440. Element confU = f_pickConfluence(BEAR, zTopU, zBotU)
  441. if not na(confU)
  442. zones.push(f_createZone(BEAR, zTopU, zBotU, eT, confU, getT(legStartU) - halfBarMs, getTC(legEndU) - halfBarMs, legHighU, legLowU, cur, eH, eL))
  443. f_enforceMax(BEAR)
  444. evNewBear := true
  445.  
  446. if not na(lastPL) and not lastPL.broken and eC < lastPL.price
  447. lastPL.broken := true
  448. int baseD = f_base()
  449. int obFromD = math.max(lastPL.idx + 1, baseD)
  450. if useOB and obFromD <= cur
  451. [retIdxD, _] = f_highestIdx(obFromD, cur)
  452. int obIdxD = f_findOpposite(retIdxD, false)
  453. if not na(obIdxD)
  454. 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)))
  455. int legEndD = lastPL.idx
  456. int legFromD = na(lastPL.prevIdx) ? legEndD - LEG_SEARCH : math.max(lastPL.prevIdx + 1, legEndD - LEG_SEARCH)
  457. legFromD := math.max(legFromD, baseD)
  458. if legEndD >= baseD and legFromD <= legEndD - 1
  459. [legStartD, legHighD] = f_highestIdx(legFromD, legEndD - 1)
  460. float legLowD = lastPL.price
  461. float legRangeD = legHighD - legLowD
  462. [effD, agreeD] = f_legStats(legStartD, legEndD, false)
  463. bool qualD = legRangeD > 0 and legEndD - legStartD >= minLegBars and legRangeD >= minLegATR * atrV and effD >= minEff and agreeD >= minAgree
  464. if qualD
  465. float zTopD = legHighD - math.min(innerDev, outerDev) * legRangeD
  466. float zBotD = legHighD - math.max(innerDev, outerDev) * legRangeD
  467. if eC >= zBotD
  468. Element confD = f_pickConfluence(BULL, zTopD, zBotD)
  469. if not na(confD)
  470. zones.push(f_createZone(BULL, zTopD, zBotD, eT, confD, getT(legStartD) - halfBarMs, getTC(legEndD) - halfBarMs, legHighD, legLowD, cur, eH, eL))
  471. f_enforceMax(BULL)
  472. evNewBull := true
  473.  
  474. if eCount >= 3
  475. float h2 = getH(cur - 2)
  476. float l2 = getL(cur - 2)
  477. int midT = getT(cur - 1)
  478. if eL > h2 and eL - h2 >= fvgMinATR * atrV
  479. f_pushCapped(fvgs, Element.new(kind = K_FVG, dir = BULL, top = eL, bot = h2, level = (eL + h2) / 2.0, originTime = midT))
  480. if eH < l2 and l2 - eH >= fvgMinATR * atrV
  481. f_pushCapped(fvgs, Element.new(kind = K_FVG, dir = BEAR, top = l2, bot = eH, level = (l2 + eH) / 2.0, originTime = midT))
  482.  
  483. if eCount >= 2 * pivotLen + 1
  484. int c = cur - pivotLen
  485. float cHi = getH(c)
  486. float cLo = getL(c)
  487. bool isPH = true
  488. bool isPL = true
  489. for k = 1 to pivotLen
  490. if getH(c - k) > cHi or getH(c + k) >= cHi
  491. isPH := false
  492. if getL(c - k) < cLo or getL(c + k) <= cLo
  493. isPL := false
  494. if not isPH and not isPL
  495. break
  496. float liqW = liqWidthATR * atrV
  497. if isPH
  498. int prevPH = na(lastPH) ? na : lastPH.idx
  499. lastPH := Pivot.new(price = cHi, idx = c, prevIdx = prevPH)
  500. 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)))
  501. if isPL
  502. int prevPL = na(lastPL) ? na : lastPL.idx
  503. lastPL := Pivot.new(price = cLo, idx = c, prevIdx = prevPL)
  504. 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)))
  505.  
  506. if barstate.islast and zones.size() > 0
  507. int rT = time + extendBars * chartMs
  508. for z in zones
  509. if not na(z.zoneBox)
  510. box.set_right(z.zoneBox, rT)
  511. if not na(z.midLine)
  512. line.set_x2(z.midLine, rT)
  513. if not na(z.arrowLbl)
  514. label.set_x(z.arrowLbl, int(math.round((z.leftTime + rT) / 2.0)))
  515. if not na(z.confBox)
  516. box.set_right(z.confBox, rT)
  517. if not na(z.confLbl)
  518. label.set_x(z.confLbl, rT)
  519.  
  520. alertcondition(evNewBull, "TradeAxis Reversals - New Bullish Zone", "TradeAxis Reversals: New bullish reversal zone created on {{ticker}} ({{interval}}).")
  521. alertcondition(evNewBear, "TradeAxis Reversals - New Bearish Zone", "TradeAxis Reversals: New bearish reversal zone created on {{ticker}} ({{interval}}).")
  522. alertcondition(evNewBull or evNewBear, "TradeAxis Reversals - Any New Zone", "TradeAxis Reversals: New reversal zone created on {{ticker}} ({{interval}}).")
  523. alertcondition(evApprBull, "TradeAxis Reversals - Approaching Bullish Zone", "TradeAxis Reversals: Price is approaching a bullish reversal zone on {{ticker}} ({{interval}}).")
  524. alertcondition(evApprBear, "TradeAxis Reversals - Approaching Bearish Zone", "TradeAxis Reversals: Price is approaching a bearish reversal zone on {{ticker}} ({{interval}}).")
  525. alertcondition(evApprBull or evApprBear, "TradeAxis Reversals - Any Zone Approach", "TradeAxis Reversals: Price is approaching a reversal zone on {{ticker}} ({{interval}}).")
  526. alertcondition(evTouchBull, "TradeAxis Reversals - Bullish Zone Touch", "TradeAxis Reversals: Price touched a bullish reversal zone on {{ticker}} ({{interval}}).")
  527. alertcondition(evTouchBear, "TradeAxis Reversals - Bearish Zone Touch", "TradeAxis Reversals: Price touched a bearish reversal zone on {{ticker}} ({{interval}}).")
  528. 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