ajiim

🎁

Oct 20th, 2026
676
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 36.31 KB | None | 0 0
  1. //@version=6
  2. indicator("TradeAxis DOL", shorttitle = "TradeAxis DOL", overlay = true, max_lines_count = 500, max_boxes_count = 500, max_labels_count = 500, max_bars_back = 1000)
  3.  
  4. const string GRP_MODE = "Trading Mode"
  5. const string GRP_SCORE = "DOL Scoring Engine"
  6. const string GRP_SRC = "Liquidity Sources"
  7. const string GRP_CONF = "Confluence"
  8. const string GRP_DENS = "Density"
  9. const string GRP_DOL = "DOL Target Zone"
  10. const string GRP_GHOST = "Ghost Trail"
  11. const string GRP_IFVG = "Inversion Fair Value Gaps (iFVG)"
  12. const string GRP_LVN = "Volume Profile LVN"
  13. const string GRP_TBL = "Multi-TF Bias Table"
  14.  
  15. string i_mode = input.string("Day Trading", "Trading Mode", options = ["Swing", "Day Trading", "Scalping"], group = GRP_MODE, tooltip = "Adaptive multi-timeframe engine.\nSwing: HTF W | STF D | Execution 4H\nDay Trading: HTF D | STF 4H | Execution 1H\nScalping: HTF 4H | STF 1H | Execution 15m\n\nKeep the chart timeframe equal to or lower than the Execution timeframe.")
  16.  
  17. int i_maxPool = input.int(30, "Max Pool Size", minval = 5, maxval = 100, group = GRP_SCORE, tooltip = "Maximum number of candidate levels kept inside the constrained scoring queue.")
  18. int i_atrLen = input.int(14, "ATR Length", minval = 1, maxval = 200, group = GRP_SCORE)
  19. float i_maxAtrDist = input.float(8.0, "Max ATR Distance", minval = 0.5, maxval = 100.0, step = 0.5, group = GRP_SCORE, tooltip = "Levels farther than this ATR-adjusted distance from price are penalized or ejected from the active pool.")
  20. string i_rangeAct = input.string("Eject", "Out-of-Range Action", options = ["Eject", "Penalize"], group = GRP_SCORE, tooltip = "Eject: remove levels beyond Max ATR Distance.\nPenalize: keep them with zero proximity and a 50% score penalty.")
  21. int i_halfLife = input.int(150, "Freshness Half-Life (bars)", minval = 1, maxval = 5000, group = GRP_SCORE, tooltip = "Exponential time decay. A level loses half of its freshness weight every N bars.")
  22. int i_maxAge = input.int(2000, "Max Level Age (bars)", minval = 50, maxval = 4500, group = GRP_SCORE)
  23. float i_wProx = input.float(35.0, "Proximity Weight", minval = 0.0, maxval = 100.0, step = 1.0, group = GRP_SCORE)
  24. float i_wFresh = input.float(25.0, "Freshness Weight", minval = 0.0, maxval = 100.0, step = 1.0, group = GRP_SCORE)
  25. float i_wConf = input.float(25.0, "Confluence Weight", minval = 0.0, maxval = 100.0, step = 1.0, group = GRP_SCORE)
  26. float i_wDens = input.float(15.0, "Density Weight", minval = 0.0, maxval = 100.0, step = 1.0, group = GRP_SCORE)
  27.  
  28. int i_swingLen = input.int(10, "Swing Length", minval = 2, maxval = 50, group = GRP_SRC, tooltip = "Pivot strength used to confirm swing highs (BSL) and swing lows (SSL).")
  29. bool i_useBSL = input.bool(true, "Buy-Side / Sell-Side Liquidity (BSL / SSL)", group = GRP_SRC)
  30. bool i_useFVG = input.bool(true, "Fair Value Gaps (FVG)", group = GRP_SRC)
  31. float i_fvgMin = input.float(0.15, "FVG Min Size (ATR)", minval = 0.0, maxval = 5.0, step = 0.05, group = GRP_SRC)
  32. bool i_useOB = input.bool(true, "Order Blocks (OB)", group = GRP_SRC)
  33. bool i_useBRK = input.bool(true, "Breakers (BRK)", group = GRP_SRC)
  34.  
  35. float i_confTol = input.float(0.5, "Confluence Tolerance (ATR)", minval = 0.05, maxval = 5.0, step = 0.05, group = GRP_CONF)
  36. bool i_cPD = input.bool(true, "Previous Day High / Low (PDH / PDL)", group = GRP_CONF)
  37. bool i_cSess = input.bool(true, "Session Opens (Daily / London / New York)", group = GRP_CONF)
  38. bool i_cEQ = input.bool(true, "Equilibrium (HTF / Dealing Range)", group = GRP_CONF)
  39. bool i_cHTF = input.bool(true, "HTF Directional Bias", group = GRP_CONF)
  40.  
  41. int i_densLen = input.int(20, "Density Lookback (bars)", minval = 5, maxval = 150, group = GRP_DENS)
  42. float i_eqTol = input.float(0.15, "Equal Highs / Lows Tolerance (ATR)", minval = 0.01, maxval = 2.0, step = 0.01, group = GRP_DENS)
  43.  
  44. bool i_showDOL = input.bool(true, "Show DOL Target Zone", group = GRP_DOL)
  45. float i_zoneW = input.float(0.5, "DOL Zone Width (ATR)", minval = 0.05, maxval = 5.0, step = 0.05, group = GRP_DOL)
  46. int i_rightOff = input.int(25, "Projection Offset (bars)", minval = 5, maxval = 250, group = GRP_DOL)
  47. float i_minPoT = input.float(25.0, "Minimum PoT to Show DOL (%)", minval = 0.0, maxval = 95.0, step = 0.5, group = GRP_DOL)
  48. int i_potHorizon = input.int(6, "PoT Horizon (Execution TF bars)", minval = 1, maxval = 100, group = GRP_DOL)
  49. bool i_showConn = input.bool(true, "Show Price Connector", group = GRP_DOL)
  50. color i_bullDol = input.color(#39FF14, "Bullish DOL", group = GRP_DOL, inline = "dolc")
  51. color i_bearDol = input.color(#FF2E4D, "Bearish DOL", group = GRP_DOL, inline = "dolc")
  52. color i_lblBg = input.color(#2B2B30, "Label Background", group = GRP_DOL, inline = "lbl")
  53. string i_lblSize = input.string("Small", "Size", options = ["Tiny", "Small", "Normal"], group = GRP_DOL, inline = "lbl")
  54.  
  55. bool i_showGhost = input.bool(true, "Show Ghost Trail", group = GRP_GHOST)
  56. int i_maxGhost = input.int(5, "Max Ghost Trails", minval = 1, maxval = 50, group = GRP_GHOST)
  57. color i_ghostCol = input.color(#787B86, "Ghost Color", group = GRP_GHOST)
  58.  
  59. bool i_showIFVG = input.bool(true, "Show iFVG Zones", group = GRP_IFVG)
  60. bool i_showFVG = input.bool(false, "Show Unmitigated FVGs", group = GRP_IFVG)
  61. int i_maxInside = input.int(2, "Max Body Closes Inside iFVG", minval = 0, maxval = 20, group = GRP_IFVG, tooltip = "When the number of candle body closures inside an iFVG exceeds this threshold, the zone is considered invalidated and is removed from the chart.")
  62. int i_maxFVG = input.int(20, "Max Tracked FVGs", minval = 2, maxval = 100, group = GRP_IFVG)
  63. int i_fvgAge = input.int(1500, "Max FVG Age (bars)", minval = 20, maxval = 4500, group = GRP_IFVG)
  64. color i_bullIFVG = input.color(#089981, "Bullish iFVG", group = GRP_IFVG, inline = "ifc")
  65. color i_bearIFVG = input.color(#F23645, "Bearish iFVG", group = GRP_IFVG, inline = "ifc")
  66. color i_fvgCol = input.color(#787B86, "FVG", group = GRP_IFVG, inline = "ifc")
  67.  
  68. bool i_showLVN = input.bool(false, "Show LVN Zones", group = GRP_LVN)
  69. int i_lvnLook = input.int(240, "Profile Lookback (1H bars)", minval = 24, maxval = 2000, group = GRP_LVN)
  70. int i_lvnRows = input.int(40, "Profile Rows", minval = 10, maxval = 100, group = GRP_LVN)
  71. float i_lvnThr = input.float(30.0, "LVN Threshold (% of POC)", minval = 1.0, maxval = 90.0, step = 1.0, group = GRP_LVN)
  72. int i_lvnSide = input.int(2, "LVNs per Side", minval = 1, maxval = 5, group = GRP_LVN)
  73. color i_lvnCol = input.color(#FFB300, "LVN Color", group = GRP_LVN)
  74.  
  75. bool i_showTbl = input.bool(true, "Show Bias Table", group = GRP_TBL)
  76. int i_biasLen = input.int(3, "Structure Pivot Length", minval = 1, maxval = 20, group = GRP_TBL)
  77. string i_tblPos = input.string("Top Right", "Position", options = ["Top Right", "Top Left", "Middle Right", "Bottom Right", "Bottom Left"], group = GRP_TBL, inline = "tp")
  78. string i_tblSize = input.string("Tiny", "Size", options = ["Tiny", "Small", "Normal"], group = GRP_TBL, inline = "tp")
  79. color i_tBull = input.color(#00E676, "Bullish", group = GRP_TBL, inline = "tc")
  80. color i_tBear = input.color(#FF5252, "Bearish", group = GRP_TBL, inline = "tc")
  81. color i_tNeut = input.color(#9598A1, "Neutral", group = GRP_TBL, inline = "tc")
  82.  
  83. const float LN2 = 0.6931471805599453
  84. const float POT_CAP = 95.0
  85. const int ANCHOR_SCAN = 500
  86. const int MAX_RECENT_PIV = 10
  87. const int MAX_OB_TRACK = 30
  88. const float RETARGET_HYST = 2.0
  89. const float DUP_TOL_ATR = 0.05
  90. const color TBL_BG = #0B0D12
  91. const color TBL_HEAD_BG = #1A1D26
  92. const color TBL_FRAME = #363A45
  93. const color TBL_TEXT = #D1D4DC
  94.  
  95. string HTF_TF = i_mode == "Swing" ? "W" : i_mode == "Scalping" ? "240" : "D"
  96. string STF_TF = i_mode == "Swing" ? "D" : i_mode == "Scalping" ? "60" : "240"
  97. string EXEC_TF = i_mode == "Swing" ? "240" : i_mode == "Scalping" ? "15" : "60"
  98.  
  99. type Level
  100. int uid
  101. string kind
  102. float px
  103. float top
  104. float bot
  105. int born
  106. int origin
  107. int added
  108. float density
  109. float prox = 0.0
  110. float fresh = 0.0
  111. float conf = 0.0
  112. float score = 0.0
  113.  
  114. type FVGZone
  115. float top
  116. float bot
  117. int dir
  118. int born
  119. bool inverted = false
  120. int insideCloses = 0
  121. box bx
  122.  
  123. type OBZone
  124. float top
  125. float bot
  126. int dir
  127. int born
  128.  
  129. f_clamp(float v, float lo, float hi) =>
  130. math.max(lo, math.min(hi, v))
  131.  
  132. f_normCdf(float x) =>
  133. float t = 1.0 / (1.0 + 0.2316419 * math.abs(x))
  134. float d = 0.3989422804014327 * math.exp(-x * x / 2.0)
  135. float p = d * t * (0.319381530 + t * (-0.356563782 + t * (1.781477937 + t * (-1.821255978 + t * 1.330274429))))
  136. x >= 0 ? 1.0 - p : p
  137.  
  138. f_size(string s) =>
  139. switch s
  140. "Tiny" => size.tiny
  141. "Small" => size.small
  142. "Normal" => size.normal
  143. => size.small
  144.  
  145. f_tablePos(string s) =>
  146. switch s
  147. "Top Left" => position.top_left
  148. "Middle Right" => position.middle_right
  149. "Bottom Right" => position.bottom_right
  150. "Bottom Left" => position.bottom_left
  151. => position.top_right
  152.  
  153. f_tfLabel(string tf) =>
  154. switch tf
  155. "W" => "W"
  156. "D" => "D"
  157. "240" => "4H"
  158. "60" => "1H"
  159. "15" => "15m"
  160. => tf
  161.  
  162. f_biasText(int b) =>
  163. b == 1 ? "BULLISH" : b == -1 ? "BEARISH" : "NEUTRAL"
  164.  
  165. f_biasColor(int b) =>
  166. b == 1 ? i_tBull : b == -1 ? i_tBear : i_tNeut
  167.  
  168. f_structureBias(int len) =>
  169. var int bias = 0
  170. var float nodeHi = na
  171. var float nodeLo = na
  172. float pivH = ta.pivothigh(high, len, len)
  173. float pivL = ta.pivotlow(low, len, len)
  174. if not na(pivH)
  175. nodeHi := pivH
  176. if not na(pivL)
  177. nodeLo := pivL
  178. if not na(nodeHi) and close > nodeHi
  179. bias := 1
  180. nodeHi := na
  181. else if not na(nodeLo) and close < nodeLo
  182. bias := -1
  183. nodeLo := na
  184. nz(bias[1])
  185.  
  186. f_density(float lvl, int side, int startOff, float atrVal, array<float> pivArr) =>
  187. float tol = atrVal * i_eqTol
  188. int eqCount = 0
  189. for p in pivArr
  190. if math.abs(p - lvl) <= tol
  191. eqCount += 1
  192. int touches = 0
  193. int sweeps = 0
  194. int counted = 0
  195. float rangeSum = 0.0
  196. int endOff = math.min(startOff + i_densLen - 1, bar_index)
  197. if endOff >= startOff
  198. for i = startOff to endOff
  199. float hi = high[i]
  200. float lo = low[i]
  201. float bodyHi = math.max(open[i], close[i])
  202. float bodyLo = math.min(open[i], close[i])
  203. if not na(hi) and not na(lo)
  204. rangeSum += hi - lo
  205. counted += 1
  206. if hi >= lvl - tol and lo <= lvl + tol
  207. touches += 1
  208. if side == 1 and hi >= lvl - tol and bodyHi < lvl - tol
  209. sweeps += 1
  210. if side == -1 and lo <= lvl + tol and bodyLo > lvl + tol
  211. sweeps += 1
  212. float touchRatio = counted > 0 ? float(touches) / counted : 0.0
  213. float avgRange = counted > 0 ? rangeSum / counted : atrVal
  214. float coil = f_clamp(1.0 - avgRange / (atrVal * 1.25), 0.0, 1.0)
  215. float eqNorm = math.min(eqCount, 3) / 3.0
  216. float swNorm = math.min(sweeps, 3) / 3.0
  217. f_clamp(0.35 * eqNorm + 0.25 * math.min(1.0, touchRatio * 2.0) + 0.20 * swNorm + 0.20 * coil, 0.0, 1.0)
  218.  
  219. f_findOB(int span, bool bullish) =>
  220. int extIdx = 1
  221. float extVal = bullish ? low[1] : high[1]
  222. for i = 1 to span
  223. if bullish and low[i] < extVal
  224. extVal := low[i]
  225. extIdx := i
  226. else if not bullish and high[i] > extVal
  227. extVal := high[i]
  228. extIdx := i
  229. int obIdx = extIdx
  230. int lim = math.min(extIdx + 10, bar_index)
  231. for i = extIdx to lim
  232. bool opposite = bullish ? close[i] < open[i] : close[i] > open[i]
  233. if opposite
  234. obIdx := i
  235. break
  236. obIdx
  237.  
  238. f_anchor(float zTop, float zBot, int origin) =>
  239. int span = math.min(ANCHOR_SCAN, bar_index - origin)
  240. int anchor = math.max(origin, bar_index - ANCHOR_SCAN)
  241. if span >= 1
  242. for i = 1 to span
  243. if high[i] >= zBot and low[i] <= zTop
  244. anchor := bar_index - i
  245. break
  246. anchor
  247.  
  248. f_pushValid(array<float> arr, float v) =>
  249. if not na(v)
  250. array.push(arr, v)
  251.  
  252. f_confluence(float px, bool above, float atrVal, array<float> anchorArr, int htfB, int stfB) =>
  253. float tol = atrVal * i_confTol
  254. int hits = 0
  255. for a in anchorArr
  256. if math.abs(px - a) <= tol
  257. hits += 1
  258. float biasPts = 0.0
  259. if i_cHTF
  260. int want = above ? 1 : -1
  261. if htfB == want
  262. biasPts += 0.35
  263. if stfB == want
  264. biasPts += 0.15
  265. f_clamp(math.min(hits, 3) * 0.2 + biasPts, 0.0, 1.0)
  266.  
  267. f_addLevel(array<Level> lvls, Level act, int newId, string kind, float px, int born, int origin, float atrVal, float dens) =>
  268. bool dup = false
  269. for cand in lvls
  270. if cand.kind == kind and math.abs(cand.px - px) <= atrVal * DUP_TOL_ATR
  271. dup := true
  272. break
  273. if not dup
  274. if array.size(lvls) >= i_maxPool
  275. int worstIdx = -1
  276. float worstScore = 1e12
  277. for j = 0 to array.size(lvls) - 1
  278. Level c = array.get(lvls, j)
  279. bool isAct = not na(act) and c.uid == act.uid
  280. if not isAct and c.score < worstScore
  281. worstScore := c.score
  282. worstIdx := j
  283. if worstIdx >= 0
  284. array.remove(lvls, worstIdx)
  285. float hw = atrVal * i_zoneW * 0.5
  286. array.push(lvls, Level.new(uid = newId, kind = kind, px = px, top = px + hw, bot = px - hw, born = born, origin = origin, added = bar_index, density = dens))
  287.  
  288. f_addGhost(array<line> gl, array<label> gb, Level lv, int endBar, string reason) =>
  289. if i_showGhost
  290. int x1 = f_anchor(lv.top, lv.bot, lv.origin)
  291. array.push(gl, line.new(x1, lv.px, endBar, lv.px, xloc = xloc.bar_index, color = color.new(i_ghostCol, 35), style = line.style_dotted, width = 1))
  292. array.push(gb, label.new(endBar, lv.px, text = reason + " " + lv.kind, xloc = xloc.bar_index, style = label.style_label_left, color = color.new(color.black, 100), textcolor = color.new(i_ghostCol, 20), size = size.tiny))
  293. while array.size(gl) > i_maxGhost
  294. line.delete(array.shift(gl))
  295. while array.size(gb) > i_maxGhost
  296. label.delete(array.shift(gb))
  297.  
  298. f_styleIfvg(box b, float top, float bot, int left, bool bullish) =>
  299. box res = b
  300. color col = bullish ? i_bullIFVG : i_bearIFVG
  301. if i_showIFVG
  302. if na(res)
  303. res := box.new(left, top, bar_index + i_rightOff, bot, border_color = color.new(col, 30), border_width = 1, bgcolor = color.new(col, 80))
  304. else
  305. box.set_border_color(res, color.new(col, 30))
  306. box.set_bgcolor(res, color.new(col, 80))
  307. else
  308. if not na(res)
  309. box.delete(res)
  310. res := na
  311. res
  312.  
  313. f_fvgBox(float top, float bot) =>
  314. i_showFVG ? box.new(bar_index - 1, top, bar_index + i_rightOff, bot, border_color = color.new(i_fvgCol, 50), border_width = 1, bgcolor = color.new(i_fvgCol, 88)) : na
  315.  
  316. f_pot(Level lv, float price, float sigma, int htfB, int execB) =>
  317. float gap = price > lv.top ? price - lv.top : price < lv.bot ? lv.bot - price : 0.0
  318. float pot = POT_CAP
  319. if gap > 0
  320. float s = math.max(sigma, syminfo.mintick) * math.sqrt(i_potHorizon)
  321. float base = 2.0 * (1.0 - f_normCdf(gap / s))
  322. int want = lv.px > price ? 1 : -1
  323. float mult = 1.0
  324. mult += htfB == want ? 0.15 : htfB == -want ? -0.15 : 0.0
  325. mult += execB == want ? 0.10 : execB == -want ? -0.10 : 0.0
  326. float scoreAdj = 0.60 + 0.40 * f_clamp(lv.score, 0.0, 100.0) / 100.0
  327. pot := f_clamp(100.0 * base * scoreAdj * mult, 0.0, POT_CAP)
  328. pot
  329.  
  330. f_isLvn(array<float> rv, int r, float poc) =>
  331. float v = array.get(rv, r)
  332. v <= poc * i_lvnThr / 100.0 and v <= array.get(rv, r - 1) and v <= array.get(rv, r + 1)
  333.  
  334. f_lvnBox(int leftT, float rt, int rightT, float rb) =>
  335. box.new(leftT, rt, rightT, rb, xloc = xloc.bar_time, border_color = color.new(i_lvnCol, 55), border_width = 1, border_style = line.style_dotted, bgcolor = color.new(i_lvnCol, 85), text = "LVN", text_size = size.tiny, text_color = color.new(i_lvnCol, 15), text_halign = text.align_right, text_valign = text.align_center)
  336.  
  337. f_biasRow(table t, int row, string tf, int b, string tsz) =>
  338. table.cell(t, 0, row, f_tfLabel(tf), text_color = TBL_TEXT, text_size = tsz, bgcolor = TBL_BG, text_halign = text.align_center, text_formatting = text.format_bold)
  339. table.cell(t, 1, row, f_biasText(b), text_color = f_biasColor(b), text_size = tsz, bgcolor = TBL_BG, text_halign = text.align_center)
  340.  
  341. float atr = ta.atr(i_atrLen)
  342. float ph = ta.pivothigh(high, i_swingLen, i_swingLen)
  343. float pl = ta.pivotlow(low, i_swingLen, i_swingLen)
  344. bool bullFVG = not na(atr) and low > high[2] and (low - high[2]) >= atr * i_fvgMin
  345. bool bearFVG = not na(atr) and high < low[2] and (low[2] - high) >= atr * i_fvgMin
  346. bool ready = not na(atr) and atr > 0 and bar_index > i_swingLen * 2 + 3
  347.  
  348. int htfBias = nz(request.security(syminfo.tickerid, HTF_TF, f_structureBias(i_biasLen), lookahead = barmerge.lookahead_on))
  349. int stfBias = nz(request.security(syminfo.tickerid, STF_TF, f_structureBias(i_biasLen), lookahead = barmerge.lookahead_on))
  350. int execBias = nz(request.security(syminfo.tickerid, EXEC_TF, f_structureBias(i_biasLen), lookahead = barmerge.lookahead_on))
  351.  
  352. bool needD = i_cPD or (i_cEQ and HTF_TF == "D")
  353. string D_TF = needD ? "D" : timeframe.period
  354. [pdh, pdl] = request.security(syminfo.tickerid, D_TF, [high[1], low[1]], lookahead = barmerge.lookahead_on)
  355. float htfEQ = na
  356. if HTF_TF == "D"
  357. htfEQ := (pdh + pdl) / 2.0
  358. else if i_cEQ
  359. htfEQ := request.security(syminfo.tickerid, HTF_TF, (high[1] + low[1]) / 2.0, lookahead = barmerge.lookahead_on)
  360.  
  361. string VP_TF = i_showLVN ? "60" : timeframe.period
  362. [h1o, h1h, h1l, h1c, h1v, h1t] = request.security(syminfo.tickerid, VP_TF, [open[1], high[1], low[1], close[1], volume[1], time[1]], lookahead = barmerge.lookahead_on)
  363.  
  364. float execAtrLive = request.security(syminfo.tickerid, EXEC_TF, ta.atr(i_atrLen), lookahead = barmerge.lookahead_off)
  365.  
  366. bool newDay = timeframe.change("D")
  367. bool inLdn = not na(time(timeframe.period, "0300-1130", "America/New_York"))
  368. bool inNY = not na(time(timeframe.period, "0930-1600", "America/New_York"))
  369. bool ldnStart = inLdn and not inLdn[1]
  370. bool nyStart = inNY and not inNY[1]
  371.  
  372. var float dailyOpen = na
  373. var float ldnOpen = na
  374. var float nyOpen = na
  375.  
  376. var float lastSH = na
  377. var int lastSHBar = na
  378. var bool shBroken = true
  379. var float lastSL = na
  380. var int lastSLBar = na
  381. var bool slBroken = true
  382.  
  383. var array<Level> pool = array.new<Level>()
  384. var array<FVGZone> fvgs = array.new<FVGZone>()
  385. var array<OBZone> obs = array.new<OBZone>()
  386. var array<line> ghostLines = array.new<line>()
  387. var array<label> ghostLabels = array.new<label>()
  388. var array<float> recentPH = array.new<float>()
  389. var array<float> recentPL = array.new<float>()
  390.  
  391. var array<float> vpOpen = array.new<float>()
  392. var array<float> vpHigh = array.new<float>()
  393. var array<float> vpLow = array.new<float>()
  394. var array<float> vpClose = array.new<float>()
  395. var array<float> vpVol = array.new<float>()
  396. var array<int> vpTime = array.new<int>()
  397.  
  398. var Level activeLv = na
  399. var int levelSeq = 0
  400.  
  401. if newDay
  402. dailyOpen := open
  403. if ldnStart
  404. ldnOpen := open
  405. if nyStart
  406. nyOpen := open
  407.  
  408. float drEQ = not na(lastSH) and not na(lastSL) ? (lastSH + lastSL) / 2.0 : na
  409.  
  410. bool newH1 = not na(h1t) and (na(h1t[1]) or h1t != h1t[1])
  411. if i_showLVN and newH1 and not na(h1h) and not na(h1l)
  412. array.push(vpOpen, nz(h1o, h1c))
  413. array.push(vpHigh, h1h)
  414. array.push(vpLow, h1l)
  415. array.push(vpClose, nz(h1c, h1o))
  416. array.push(vpVol, nz(h1v))
  417. array.push(vpTime, h1t)
  418. while array.size(vpHigh) > i_lvnLook
  419. array.shift(vpOpen)
  420. array.shift(vpHigh)
  421. array.shift(vpLow)
  422. array.shift(vpClose)
  423. array.shift(vpVol)
  424. array.shift(vpTime)
  425.  
  426. bool liveSweep = false
  427. string sweepKind = ""
  428. float sweepPrice = na
  429. if not na(activeLv)
  430. float pc = nz(close[1], close)
  431. if math.max(high, pc) >= activeLv.bot and math.min(low, pc) <= activeLv.top
  432. liveSweep := true
  433. sweepKind := activeLv.kind
  434. sweepPrice := activeLv.px
  435.  
  436. bool newDolEvent = false
  437. bool newIfvgEvent = false
  438. string ifvgMsg = ""
  439.  
  440. if barstate.isconfirmed and ready
  441. array<float> anchors = array.new<float>()
  442. if i_cPD
  443. f_pushValid(anchors, pdh)
  444. f_pushValid(anchors, pdl)
  445. if i_cSess
  446. f_pushValid(anchors, dailyOpen)
  447. f_pushValid(anchors, ldnOpen)
  448. f_pushValid(anchors, nyOpen)
  449. if i_cEQ
  450. f_pushValid(anchors, htfEQ)
  451. f_pushValid(anchors, drEQ)
  452.  
  453. if array.size(fvgs) > 0
  454. for j = array.size(fvgs) - 1 to 0
  455. FVGZone fz = array.get(fvgs, j)
  456. bool killFvg = false
  457. if not fz.inverted
  458. if fz.dir == 1 and close < fz.bot
  459. fz.inverted := true
  460. fz.insideCloses := 0
  461. fz.bx := f_styleIfvg(fz.bx, fz.top, fz.bot, fz.born, false)
  462. newIfvgEvent := true
  463. ifvgMsg := "Bearish iFVG " + str.tostring(fz.bot, format.mintick) + " - " + str.tostring(fz.top, format.mintick)
  464. else if fz.dir == -1 and close > fz.top
  465. fz.inverted := true
  466. fz.insideCloses := 0
  467. fz.bx := f_styleIfvg(fz.bx, fz.top, fz.bot, fz.born, true)
  468. newIfvgEvent := true
  469. ifvgMsg := "Bullish iFVG " + str.tostring(fz.bot, format.mintick) + " - " + str.tostring(fz.top, format.mintick)
  470. else if bar_index - fz.born > i_fvgAge
  471. killFvg := true
  472. else
  473. if close >= fz.bot and close <= fz.top
  474. fz.insideCloses := fz.insideCloses + 1
  475. if fz.insideCloses > i_maxInside
  476. killFvg := true
  477. else if fz.dir == 1 and close > fz.top
  478. killFvg := true
  479. else if fz.dir == -1 and close < fz.bot
  480. killFvg := true
  481. else if bar_index - fz.born > i_fvgAge
  482. killFvg := true
  483. if killFvg
  484. if not na(fz.bx)
  485. box.delete(fz.bx)
  486. array.remove(fvgs, j)
  487.  
  488. if array.size(obs) > 0
  489. for j = array.size(obs) - 1 to 0
  490. OBZone z = array.get(obs, j)
  491. bool killOb = false
  492. float zMid = (z.top + z.bot) / 2.0
  493. if z.dir == 1 and close < z.bot
  494. levelSeq += 1
  495. f_addLevel(pool, activeLv, levelSeq, "BEBRK", zMid, bar_index, z.born, atr, f_density(zMid, 1, 1, atr, recentPH))
  496. killOb := true
  497. else if z.dir == -1 and close > z.top
  498. levelSeq += 1
  499. f_addLevel(pool, activeLv, levelSeq, "BUBRK", zMid, bar_index, z.born, atr, f_density(zMid, -1, 1, atr, recentPL))
  500. killOb := true
  501. else if bar_index - z.born > i_maxAge
  502. killOb := true
  503. if killOb
  504. array.remove(obs, j)
  505.  
  506. if not na(ph)
  507. int phBar = bar_index - i_swingLen
  508. if i_useBSL
  509. levelSeq += 1
  510. f_addLevel(pool, activeLv, levelSeq, "BSL", ph, phBar, phBar, atr, f_density(ph, 1, i_swingLen + 1, atr, recentPH))
  511. array.push(recentPH, ph)
  512. if array.size(recentPH) > MAX_RECENT_PIV
  513. array.shift(recentPH)
  514. lastSH := ph
  515. lastSHBar := phBar
  516. shBroken := false
  517. if not na(pl)
  518. int plBar = bar_index - i_swingLen
  519. if i_useBSL
  520. levelSeq += 1
  521. f_addLevel(pool, activeLv, levelSeq, "SSL", pl, plBar, plBar, atr, f_density(pl, -1, i_swingLen + 1, atr, recentPL))
  522. array.push(recentPL, pl)
  523. if array.size(recentPL) > MAX_RECENT_PIV
  524. array.shift(recentPL)
  525. lastSL := pl
  526. lastSLBar := plBar
  527. slBroken := false
  528.  
  529. if not shBroken and not na(lastSH) and close > lastSH
  530. shBroken := true
  531. int spanB = math.min(bar_index - lastSHBar, 100)
  532. if spanB >= 1 and (i_useOB or i_useBRK)
  533. int bIdx = f_findOB(spanB, true)
  534. float bTop = high[bIdx]
  535. float bBot = low[bIdx]
  536. float bMid = (bTop + bBot) / 2.0
  537. int bBar = bar_index - bIdx
  538. if i_useOB
  539. levelSeq += 1
  540. f_addLevel(pool, activeLv, levelSeq, "BUOB", bMid, bBar, bBar, atr, f_density(bMid, -1, bIdx + 1, atr, recentPL))
  541. if i_useBRK
  542. array.push(obs, OBZone.new(bTop, bBot, 1, bBar))
  543. if array.size(obs) > MAX_OB_TRACK
  544. array.shift(obs)
  545. if not slBroken and not na(lastSL) and close < lastSL
  546. slBroken := true
  547. int spanS = math.min(bar_index - lastSLBar, 100)
  548. if spanS >= 1 and (i_useOB or i_useBRK)
  549. int sIdx = f_findOB(spanS, false)
  550. float sTop = high[sIdx]
  551. float sBot = low[sIdx]
  552. float sMid = (sTop + sBot) / 2.0
  553. int sBar = bar_index - sIdx
  554. if i_useOB
  555. levelSeq += 1
  556. f_addLevel(pool, activeLv, levelSeq, "BEOB", sMid, sBar, sBar, atr, f_density(sMid, 1, sIdx + 1, atr, recentPH))
  557. if i_useBRK
  558. array.push(obs, OBZone.new(sTop, sBot, -1, sBar))
  559. if array.size(obs) > MAX_OB_TRACK
  560. array.shift(obs)
  561.  
  562. if bullFVG
  563. float uTop = low
  564. float uBot = high[2]
  565. float uCE = (uTop + uBot) / 2.0
  566. if i_useFVG
  567. levelSeq += 1
  568. f_addLevel(pool, activeLv, levelSeq, "BUFVG", uCE, bar_index - 1, bar_index - 1, atr, f_density(uCE, -1, 3, atr, recentPL))
  569. box uBox = f_fvgBox(uTop, uBot)
  570. array.push(fvgs, FVGZone.new(uTop, uBot, 1, bar_index - 1, false, 0, uBox))
  571. if bearFVG
  572. float eTop = low[2]
  573. float eBot = high
  574. float eCE = (eTop + eBot) / 2.0
  575. if i_useFVG
  576. levelSeq += 1
  577. f_addLevel(pool, activeLv, levelSeq, "BEFVG", eCE, bar_index - 1, bar_index - 1, atr, f_density(eCE, 1, 3, atr, recentPH))
  578. box eBox = f_fvgBox(eTop, eBot)
  579. array.push(fvgs, FVGZone.new(eTop, eBot, -1, bar_index - 1, false, 0, eBox))
  580. while array.size(fvgs) > i_maxFVG
  581. FVGZone oldF = array.shift(fvgs)
  582. if not na(oldF.bx)
  583. box.delete(oldF.bx)
  584.  
  585. if array.size(pool) > 0
  586. for j = array.size(pool) - 1 to 0
  587. Level lv = array.get(pool, j)
  588. bool isActive = not na(activeLv) and lv.uid == activeLv.uid
  589. string reason = ""
  590. if lv.added < bar_index
  591. float prevC = nz(close[1], close)
  592. bool zoneHit = math.max(high, prevC) >= lv.bot and math.min(low, prevC) <= lv.top
  593. bool priceHit = math.max(high, prevC) >= lv.px and math.min(low, prevC) <= lv.px
  594. if (isActive and zoneHit) or priceHit
  595. reason := "Swept"
  596. if reason == "" and i_rangeAct == "Eject" and math.abs(close - lv.px) / atr > i_maxAtrDist
  597. reason := "Ejected"
  598. if reason == "" and bar_index - lv.born > i_maxAge
  599. reason := "Expired"
  600. if reason != ""
  601. if isActive
  602. if reason != "Expired"
  603. f_addGhost(ghostLines, ghostLabels, lv, bar_index, reason)
  604. activeLv := na
  605. array.remove(pool, j)
  606.  
  607. float wSum = i_wProx + i_wFresh + i_wConf + i_wDens
  608. Level best = na
  609. float bestScore = -1.0
  610. if array.size(pool) > 0 and wSum > 0
  611. for lv in pool
  612. float distAtr = math.abs(close - lv.px) / atr
  613. float prox = f_clamp(1.0 - distAtr / i_maxAtrDist, 0.0, 1.0)
  614. float fresh = math.exp(-LN2 * float(bar_index - lv.born) / i_halfLife)
  615. bool above = lv.px > close
  616. float conf = f_confluence(lv.px, above, atr, anchors, htfBias, stfBias)
  617. float sc = 100.0 * (i_wProx * prox + i_wFresh * fresh + i_wConf * conf + i_wDens * lv.density) / wSum
  618. if distAtr > i_maxAtrDist
  619. sc := sc * 0.5
  620. lv.prox := prox
  621. lv.fresh := fresh
  622. lv.conf := conf
  623. lv.score := sc
  624. bool inZone = close >= lv.bot and close <= lv.top
  625. if not inZone and sc > bestScore
  626. bestScore := sc
  627. best := lv
  628.  
  629. if not na(activeLv) and not na(best)
  630. if best.uid != activeLv.uid
  631. bool actInZone = close >= activeLv.bot and close <= activeLv.top
  632. if not actInZone and activeLv.score + RETARGET_HYST >= best.score
  633. best := activeLv
  634.  
  635. int prevUid = -1
  636. if not na(activeLv)
  637. prevUid := activeLv.uid
  638. activeLv := best
  639. if not na(best)
  640. if best.uid != prevUid
  641. newDolEvent := true
  642.  
  643. float potLive = na
  644. if barstate.islast and not na(activeLv)
  645. float sigma = na(execAtrLive) or execAtrLive <= 0 ? nz(atr, syminfo.mintick) : execAtrLive
  646. potLive := f_pot(activeLv, close, sigma, htfBias, execBias)
  647.  
  648. var array<line> dolLines = array.new<line>()
  649. var box dolBox = na
  650. var label dolLabel = na
  651. var array<box> lvnBoxes = array.new<box>()
  652.  
  653. if barstate.islast
  654. if array.size(dolLines) > 0
  655. for ln in dolLines
  656. line.delete(ln)
  657. array.clear(dolLines)
  658. if not na(dolBox)
  659. box.delete(dolBox)
  660. dolBox := na
  661. if not na(dolLabel)
  662. label.delete(dolLabel)
  663. dolLabel := na
  664.  
  665. if i_showDOL and not na(activeLv) and not na(potLive)
  666. if potLive >= i_minPoT
  667. bool tgtAbove = activeLv.px > close
  668. color dolCol = tgtAbove ? i_bullDol : i_bearDol
  669. int xLeft = f_anchor(activeLv.top, activeLv.bot, activeLv.origin)
  670. int xRight = bar_index + i_rightOff
  671. dolBox := box.new(xLeft, activeLv.top, xRight, activeLv.bot, border_color = color.new(dolCol, 35), border_width = 1, border_style = line.style_dashed, bgcolor = color.new(dolCol, 88))
  672. array.push(dolLines, line.new(xLeft, activeLv.px, xRight, activeLv.px, color = color.new(dolCol, 82), width = 8))
  673. array.push(dolLines, line.new(xLeft, activeLv.px, xRight, activeLv.px, color = color.new(dolCol, 55), width = 4))
  674. array.push(dolLines, line.new(xLeft, activeLv.px, xRight, activeLv.px, color = dolCol, width = 2))
  675. if i_showConn
  676. array.push(dolLines, line.new(bar_index, close, xRight, activeLv.px, color = color.new(dolCol, 20), style = line.style_dashed, width = 1))
  677. string tip = "Score: " + str.tostring(activeLv.score, "0.0") + " / 100" + "\nProximity: " + str.tostring(activeLv.prox * 100.0, "0") + "%" + "\nFreshness: " + str.tostring(activeLv.fresh * 100.0, "0") + "%" + "\nConfluence: " + str.tostring(activeLv.conf * 100.0, "0") + "%" + "\nDensity: " + str.tostring(activeLv.density * 100.0, "0") + "%" + "\nLevel: " + str.tostring(activeLv.px, format.mintick)
  678. dolLabel := label.new(xRight, activeLv.px, text = "Target: " + activeLv.kind + "\nPoT: " + str.tostring(potLive, "0.0") + "%", xloc = xloc.bar_index, style = label.style_label_left, color = i_lblBg, textcolor = dolCol, size = f_size(i_lblSize), textalign = text.align_center, tooltip = tip)
  679.  
  680. if array.size(fvgs) > 0
  681. for fz in fvgs
  682. if not na(fz.bx)
  683. box.set_right(fz.bx, bar_index + i_rightOff)
  684.  
  685. if array.size(lvnBoxes) > 0
  686. for bx in lvnBoxes
  687. box.delete(bx)
  688. array.clear(lvnBoxes)
  689. int vpN = array.size(vpHigh)
  690. if i_showLVN and vpN >= 10
  691. float vpMax = array.max(vpHigh)
  692. float vpMin = array.min(vpLow)
  693. float vpStep = (vpMax - vpMin) / i_lvnRows
  694. if vpStep > 0
  695. array<float> rowVol = array.new<float>(i_lvnRows, 0.0)
  696. for k = 0 to vpN - 1
  697. float hH = array.get(vpHigh, k)
  698. float hL = array.get(vpLow, k)
  699. float hO = array.get(vpOpen, k)
  700. float hC = array.get(vpClose, k)
  701. float hV = array.get(vpVol, k)
  702. float bTp = math.max(hO, hC)
  703. float bBt = math.min(hO, hC)
  704. int rLo = math.max(0, math.min(i_lvnRows - 1, math.floor((hL - vpMin) / vpStep)))
  705. int rHi = math.max(0, math.min(i_lvnRows - 1, math.floor((hH - vpMin) / vpStep)))
  706. for r = rLo to rHi
  707. float rowBot = vpMin + r * vpStep
  708. float rowTop = rowBot + vpStep
  709. float rngShare = hH > hL ? math.max(0.0, math.min(hH, rowTop) - math.max(hL, rowBot)) / (hH - hL) : 1.0 / (rHi - rLo + 1)
  710. float bodyShare = bTp > bBt ? math.max(0.0, math.min(bTp, rowTop) - math.max(bBt, rowBot)) / (bTp - bBt) : (bBt >= rowBot and bBt <= rowTop ? 1.0 : 0.0)
  711. array.set(rowVol, r, array.get(rowVol, r) + hV * (0.4 * rngShare + 0.6 * bodyShare))
  712. float poc = array.max(rowVol)
  713. if poc > 0
  714. int tfMs = timeframe.in_seconds() * 1000
  715. int leftT = array.get(vpTime, 0)
  716. int rightT = time + i_rightOff * tfMs
  717. int upCnt = 0
  718. int dnCnt = 0
  719. for r = 1 to i_lvnRows - 2
  720. bool isLvn = f_isLvn(rowVol, r, poc)
  721. float rb = vpMin + r * vpStep
  722. float rt = rb + vpStep
  723. if isLvn and rb > close and upCnt < i_lvnSide
  724. array.push(lvnBoxes, f_lvnBox(leftT, rt, rightT, rb))
  725. upCnt += 1
  726. for r = i_lvnRows - 2 to 1
  727. bool isLvn = f_isLvn(rowVol, r, poc)
  728. float rb = vpMin + r * vpStep
  729. float rt = rb + vpStep
  730. if isLvn and rt < close and dnCnt < i_lvnSide
  731. array.push(lvnBoxes, f_lvnBox(leftT, rt, rightT, rb))
  732. dnCnt += 1
  733.  
  734. var table biasTable = i_showTbl ? table.new(f_tablePos(i_tblPos), 2, 4, bgcolor = TBL_BG, frame_color = TBL_FRAME, frame_width = 1, border_color = TBL_FRAME, border_width = 1) : na
  735.  
  736. if barstate.islast and i_showTbl and not na(biasTable)
  737. string tsz = f_size(i_tblSize)
  738. table.cell(biasTable, 0, 0, "Timeframe", text_color = TBL_TEXT, text_size = tsz, bgcolor = TBL_HEAD_BG, text_halign = text.align_center, text_formatting = text.format_bold)
  739. table.cell(biasTable, 1, 0, "Bias", text_color = TBL_TEXT, text_size = tsz, bgcolor = TBL_HEAD_BG, text_halign = text.align_center, text_formatting = text.format_bold)
  740. f_biasRow(biasTable, 1, HTF_TF, htfBias, tsz)
  741. f_biasRow(biasTable, 2, STF_TF, stfBias, tsz)
  742. f_biasRow(biasTable, 3, EXEC_TF, execBias, tsz)
  743.  
  744. alertcondition(newDolEvent, "New DOL Target Active", "TradeAxis DOL: A new highest-scoring Draw on Liquidity target is now active.")
  745. alertcondition(newIfvgEvent, "New iFVG Formed", "TradeAxis DOL: A Fair Value Gap was invalidated and flipped into an active Inversion Gap.")
  746. alertcondition(liveSweep, "DOL Target Swept", "TradeAxis DOL: Price touched the currently active Draw on Liquidity target zone.")
  747.  
  748. if newDolEvent and not na(activeLv)
  749. alert("TradeAxis DOL | New DOL Target Active: " + activeLv.kind + " @ " + str.tostring(activeLv.px, format.mintick), alert.freq_once_per_bar_close)
  750. if newIfvgEvent
  751. alert("TradeAxis DOL | New iFVG Formed: " + ifvgMsg, alert.freq_once_per_bar_close)
  752. if liveSweep
  753. alert("TradeAxis DOL | DOL Target Swept: " + sweepKind + " @ " + str.tostring(sweepPrice, format.mintick), alert.freq_once_per_bar)
Advertisement
Add Comment
Please, Sign In to add comment