Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //@version=6
- indicator("TradeAxis DOL", shorttitle = "TradeAxis DOL", overlay = true, max_lines_count = 500, max_boxes_count = 500, max_labels_count = 500, max_bars_back = 1000)
- const string GRP_MODE = "Trading Mode"
- const string GRP_SCORE = "DOL Scoring Engine"
- const string GRP_SRC = "Liquidity Sources"
- const string GRP_CONF = "Confluence"
- const string GRP_DENS = "Density"
- const string GRP_DOL = "DOL Target Zone"
- const string GRP_GHOST = "Ghost Trail"
- const string GRP_IFVG = "Inversion Fair Value Gaps (iFVG)"
- const string GRP_LVN = "Volume Profile LVN"
- const string GRP_TBL = "Multi-TF Bias Table"
- 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.")
- 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.")
- int i_atrLen = input.int(14, "ATR Length", minval = 1, maxval = 200, group = GRP_SCORE)
- 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.")
- 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.")
- 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.")
- int i_maxAge = input.int(2000, "Max Level Age (bars)", minval = 50, maxval = 4500, group = GRP_SCORE)
- float i_wProx = input.float(35.0, "Proximity Weight", minval = 0.0, maxval = 100.0, step = 1.0, group = GRP_SCORE)
- float i_wFresh = input.float(25.0, "Freshness Weight", minval = 0.0, maxval = 100.0, step = 1.0, group = GRP_SCORE)
- float i_wConf = input.float(25.0, "Confluence Weight", minval = 0.0, maxval = 100.0, step = 1.0, group = GRP_SCORE)
- float i_wDens = input.float(15.0, "Density Weight", minval = 0.0, maxval = 100.0, step = 1.0, group = GRP_SCORE)
- 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).")
- bool i_useBSL = input.bool(true, "Buy-Side / Sell-Side Liquidity (BSL / SSL)", group = GRP_SRC)
- bool i_useFVG = input.bool(true, "Fair Value Gaps (FVG)", group = GRP_SRC)
- float i_fvgMin = input.float(0.15, "FVG Min Size (ATR)", minval = 0.0, maxval = 5.0, step = 0.05, group = GRP_SRC)
- bool i_useOB = input.bool(true, "Order Blocks (OB)", group = GRP_SRC)
- bool i_useBRK = input.bool(true, "Breakers (BRK)", group = GRP_SRC)
- float i_confTol = input.float(0.5, "Confluence Tolerance (ATR)", minval = 0.05, maxval = 5.0, step = 0.05, group = GRP_CONF)
- bool i_cPD = input.bool(true, "Previous Day High / Low (PDH / PDL)", group = GRP_CONF)
- bool i_cSess = input.bool(true, "Session Opens (Daily / London / New York)", group = GRP_CONF)
- bool i_cEQ = input.bool(true, "Equilibrium (HTF / Dealing Range)", group = GRP_CONF)
- bool i_cHTF = input.bool(true, "HTF Directional Bias", group = GRP_CONF)
- int i_densLen = input.int(20, "Density Lookback (bars)", minval = 5, maxval = 150, group = GRP_DENS)
- float i_eqTol = input.float(0.15, "Equal Highs / Lows Tolerance (ATR)", minval = 0.01, maxval = 2.0, step = 0.01, group = GRP_DENS)
- bool i_showDOL = input.bool(true, "Show DOL Target Zone", group = GRP_DOL)
- float i_zoneW = input.float(0.5, "DOL Zone Width (ATR)", minval = 0.05, maxval = 5.0, step = 0.05, group = GRP_DOL)
- int i_rightOff = input.int(25, "Projection Offset (bars)", minval = 5, maxval = 250, group = GRP_DOL)
- float i_minPoT = input.float(25.0, "Minimum PoT to Show DOL (%)", minval = 0.0, maxval = 95.0, step = 0.5, group = GRP_DOL)
- int i_potHorizon = input.int(6, "PoT Horizon (Execution TF bars)", minval = 1, maxval = 100, group = GRP_DOL)
- bool i_showConn = input.bool(true, "Show Price Connector", group = GRP_DOL)
- color i_bullDol = input.color(#39FF14, "Bullish DOL", group = GRP_DOL, inline = "dolc")
- color i_bearDol = input.color(#FF2E4D, "Bearish DOL", group = GRP_DOL, inline = "dolc")
- color i_lblBg = input.color(#2B2B30, "Label Background", group = GRP_DOL, inline = "lbl")
- string i_lblSize = input.string("Small", "Size", options = ["Tiny", "Small", "Normal"], group = GRP_DOL, inline = "lbl")
- bool i_showGhost = input.bool(true, "Show Ghost Trail", group = GRP_GHOST)
- int i_maxGhost = input.int(5, "Max Ghost Trails", minval = 1, maxval = 50, group = GRP_GHOST)
- color i_ghostCol = input.color(#787B86, "Ghost Color", group = GRP_GHOST)
- bool i_showIFVG = input.bool(true, "Show iFVG Zones", group = GRP_IFVG)
- bool i_showFVG = input.bool(false, "Show Unmitigated FVGs", group = GRP_IFVG)
- 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.")
- int i_maxFVG = input.int(20, "Max Tracked FVGs", minval = 2, maxval = 100, group = GRP_IFVG)
- int i_fvgAge = input.int(1500, "Max FVG Age (bars)", minval = 20, maxval = 4500, group = GRP_IFVG)
- color i_bullIFVG = input.color(#089981, "Bullish iFVG", group = GRP_IFVG, inline = "ifc")
- color i_bearIFVG = input.color(#F23645, "Bearish iFVG", group = GRP_IFVG, inline = "ifc")
- color i_fvgCol = input.color(#787B86, "FVG", group = GRP_IFVG, inline = "ifc")
- bool i_showLVN = input.bool(false, "Show LVN Zones", group = GRP_LVN)
- int i_lvnLook = input.int(240, "Profile Lookback (1H bars)", minval = 24, maxval = 2000, group = GRP_LVN)
- int i_lvnRows = input.int(40, "Profile Rows", minval = 10, maxval = 100, group = GRP_LVN)
- float i_lvnThr = input.float(30.0, "LVN Threshold (% of POC)", minval = 1.0, maxval = 90.0, step = 1.0, group = GRP_LVN)
- int i_lvnSide = input.int(2, "LVNs per Side", minval = 1, maxval = 5, group = GRP_LVN)
- color i_lvnCol = input.color(#FFB300, "LVN Color", group = GRP_LVN)
- bool i_showTbl = input.bool(true, "Show Bias Table", group = GRP_TBL)
- int i_biasLen = input.int(3, "Structure Pivot Length", minval = 1, maxval = 20, group = GRP_TBL)
- string i_tblPos = input.string("Top Right", "Position", options = ["Top Right", "Top Left", "Middle Right", "Bottom Right", "Bottom Left"], group = GRP_TBL, inline = "tp")
- string i_tblSize = input.string("Tiny", "Size", options = ["Tiny", "Small", "Normal"], group = GRP_TBL, inline = "tp")
- color i_tBull = input.color(#00E676, "Bullish", group = GRP_TBL, inline = "tc")
- color i_tBear = input.color(#FF5252, "Bearish", group = GRP_TBL, inline = "tc")
- color i_tNeut = input.color(#9598A1, "Neutral", group = GRP_TBL, inline = "tc")
- const float LN2 = 0.6931471805599453
- const float POT_CAP = 95.0
- const int ANCHOR_SCAN = 500
- const int MAX_RECENT_PIV = 10
- const int MAX_OB_TRACK = 30
- const float RETARGET_HYST = 2.0
- const float DUP_TOL_ATR = 0.05
- const color TBL_BG = #0B0D12
- const color TBL_HEAD_BG = #1A1D26
- const color TBL_FRAME = #363A45
- const color TBL_TEXT = #D1D4DC
- string HTF_TF = i_mode == "Swing" ? "W" : i_mode == "Scalping" ? "240" : "D"
- string STF_TF = i_mode == "Swing" ? "D" : i_mode == "Scalping" ? "60" : "240"
- string EXEC_TF = i_mode == "Swing" ? "240" : i_mode == "Scalping" ? "15" : "60"
- type Level
- int uid
- string kind
- float px
- float top
- float bot
- int born
- int origin
- int added
- float density
- float prox = 0.0
- float fresh = 0.0
- float conf = 0.0
- float score = 0.0
- type FVGZone
- float top
- float bot
- int dir
- int born
- bool inverted = false
- int insideCloses = 0
- box bx
- type OBZone
- float top
- float bot
- int dir
- int born
- f_clamp(float v, float lo, float hi) =>
- math.max(lo, math.min(hi, v))
- f_normCdf(float x) =>
- float t = 1.0 / (1.0 + 0.2316419 * math.abs(x))
- float d = 0.3989422804014327 * math.exp(-x * x / 2.0)
- float p = d * t * (0.319381530 + t * (-0.356563782 + t * (1.781477937 + t * (-1.821255978 + t * 1.330274429))))
- x >= 0 ? 1.0 - p : p
- f_size(string s) =>
- switch s
- "Tiny" => size.tiny
- "Small" => size.small
- "Normal" => size.normal
- => size.small
- f_tablePos(string s) =>
- switch s
- "Top Left" => position.top_left
- "Middle Right" => position.middle_right
- "Bottom Right" => position.bottom_right
- "Bottom Left" => position.bottom_left
- => position.top_right
- f_tfLabel(string tf) =>
- switch tf
- "W" => "W"
- "D" => "D"
- "240" => "4H"
- "60" => "1H"
- "15" => "15m"
- => tf
- f_biasText(int b) =>
- b == 1 ? "BULLISH" : b == -1 ? "BEARISH" : "NEUTRAL"
- f_biasColor(int b) =>
- b == 1 ? i_tBull : b == -1 ? i_tBear : i_tNeut
- f_structureBias(int len) =>
- var int bias = 0
- var float nodeHi = na
- var float nodeLo = na
- float pivH = ta.pivothigh(high, len, len)
- float pivL = ta.pivotlow(low, len, len)
- if not na(pivH)
- nodeHi := pivH
- if not na(pivL)
- nodeLo := pivL
- if not na(nodeHi) and close > nodeHi
- bias := 1
- nodeHi := na
- else if not na(nodeLo) and close < nodeLo
- bias := -1
- nodeLo := na
- nz(bias[1])
- f_density(float lvl, int side, int startOff, float atrVal, array<float> pivArr) =>
- float tol = atrVal * i_eqTol
- int eqCount = 0
- for p in pivArr
- if math.abs(p - lvl) <= tol
- eqCount += 1
- int touches = 0
- int sweeps = 0
- int counted = 0
- float rangeSum = 0.0
- int endOff = math.min(startOff + i_densLen - 1, bar_index)
- if endOff >= startOff
- for i = startOff to endOff
- float hi = high[i]
- float lo = low[i]
- float bodyHi = math.max(open[i], close[i])
- float bodyLo = math.min(open[i], close[i])
- if not na(hi) and not na(lo)
- rangeSum += hi - lo
- counted += 1
- if hi >= lvl - tol and lo <= lvl + tol
- touches += 1
- if side == 1 and hi >= lvl - tol and bodyHi < lvl - tol
- sweeps += 1
- if side == -1 and lo <= lvl + tol and bodyLo > lvl + tol
- sweeps += 1
- float touchRatio = counted > 0 ? float(touches) / counted : 0.0
- float avgRange = counted > 0 ? rangeSum / counted : atrVal
- float coil = f_clamp(1.0 - avgRange / (atrVal * 1.25), 0.0, 1.0)
- float eqNorm = math.min(eqCount, 3) / 3.0
- float swNorm = math.min(sweeps, 3) / 3.0
- f_clamp(0.35 * eqNorm + 0.25 * math.min(1.0, touchRatio * 2.0) + 0.20 * swNorm + 0.20 * coil, 0.0, 1.0)
- f_findOB(int span, bool bullish) =>
- int extIdx = 1
- float extVal = bullish ? low[1] : high[1]
- for i = 1 to span
- if bullish and low[i] < extVal
- extVal := low[i]
- extIdx := i
- else if not bullish and high[i] > extVal
- extVal := high[i]
- extIdx := i
- int obIdx = extIdx
- int lim = math.min(extIdx + 10, bar_index)
- for i = extIdx to lim
- bool opposite = bullish ? close[i] < open[i] : close[i] > open[i]
- if opposite
- obIdx := i
- break
- obIdx
- f_anchor(float zTop, float zBot, int origin) =>
- int span = math.min(ANCHOR_SCAN, bar_index - origin)
- int anchor = math.max(origin, bar_index - ANCHOR_SCAN)
- if span >= 1
- for i = 1 to span
- if high[i] >= zBot and low[i] <= zTop
- anchor := bar_index - i
- break
- anchor
- f_pushValid(array<float> arr, float v) =>
- if not na(v)
- array.push(arr, v)
- f_confluence(float px, bool above, float atrVal, array<float> anchorArr, int htfB, int stfB) =>
- float tol = atrVal * i_confTol
- int hits = 0
- for a in anchorArr
- if math.abs(px - a) <= tol
- hits += 1
- float biasPts = 0.0
- if i_cHTF
- int want = above ? 1 : -1
- if htfB == want
- biasPts += 0.35
- if stfB == want
- biasPts += 0.15
- f_clamp(math.min(hits, 3) * 0.2 + biasPts, 0.0, 1.0)
- f_addLevel(array<Level> lvls, Level act, int newId, string kind, float px, int born, int origin, float atrVal, float dens) =>
- bool dup = false
- for cand in lvls
- if cand.kind == kind and math.abs(cand.px - px) <= atrVal * DUP_TOL_ATR
- dup := true
- break
- if not dup
- if array.size(lvls) >= i_maxPool
- int worstIdx = -1
- float worstScore = 1e12
- for j = 0 to array.size(lvls) - 1
- Level c = array.get(lvls, j)
- bool isAct = not na(act) and c.uid == act.uid
- if not isAct and c.score < worstScore
- worstScore := c.score
- worstIdx := j
- if worstIdx >= 0
- array.remove(lvls, worstIdx)
- float hw = atrVal * i_zoneW * 0.5
- 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))
- f_addGhost(array<line> gl, array<label> gb, Level lv, int endBar, string reason) =>
- if i_showGhost
- int x1 = f_anchor(lv.top, lv.bot, lv.origin)
- 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))
- 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))
- while array.size(gl) > i_maxGhost
- line.delete(array.shift(gl))
- while array.size(gb) > i_maxGhost
- label.delete(array.shift(gb))
- f_styleIfvg(box b, float top, float bot, int left, bool bullish) =>
- box res = b
- color col = bullish ? i_bullIFVG : i_bearIFVG
- if i_showIFVG
- if na(res)
- res := box.new(left, top, bar_index + i_rightOff, bot, border_color = color.new(col, 30), border_width = 1, bgcolor = color.new(col, 80))
- else
- box.set_border_color(res, color.new(col, 30))
- box.set_bgcolor(res, color.new(col, 80))
- else
- if not na(res)
- box.delete(res)
- res := na
- res
- f_fvgBox(float top, float bot) =>
- 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
- f_pot(Level lv, float price, float sigma, int htfB, int execB) =>
- float gap = price > lv.top ? price - lv.top : price < lv.bot ? lv.bot - price : 0.0
- float pot = POT_CAP
- if gap > 0
- float s = math.max(sigma, syminfo.mintick) * math.sqrt(i_potHorizon)
- float base = 2.0 * (1.0 - f_normCdf(gap / s))
- int want = lv.px > price ? 1 : -1
- float mult = 1.0
- mult += htfB == want ? 0.15 : htfB == -want ? -0.15 : 0.0
- mult += execB == want ? 0.10 : execB == -want ? -0.10 : 0.0
- float scoreAdj = 0.60 + 0.40 * f_clamp(lv.score, 0.0, 100.0) / 100.0
- pot := f_clamp(100.0 * base * scoreAdj * mult, 0.0, POT_CAP)
- pot
- f_isLvn(array<float> rv, int r, float poc) =>
- float v = array.get(rv, r)
- v <= poc * i_lvnThr / 100.0 and v <= array.get(rv, r - 1) and v <= array.get(rv, r + 1)
- f_lvnBox(int leftT, float rt, int rightT, float rb) =>
- 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)
- f_biasRow(table t, int row, string tf, int b, string tsz) =>
- 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)
- table.cell(t, 1, row, f_biasText(b), text_color = f_biasColor(b), text_size = tsz, bgcolor = TBL_BG, text_halign = text.align_center)
- float atr = ta.atr(i_atrLen)
- float ph = ta.pivothigh(high, i_swingLen, i_swingLen)
- float pl = ta.pivotlow(low, i_swingLen, i_swingLen)
- bool bullFVG = not na(atr) and low > high[2] and (low - high[2]) >= atr * i_fvgMin
- bool bearFVG = not na(atr) and high < low[2] and (low[2] - high) >= atr * i_fvgMin
- bool ready = not na(atr) and atr > 0 and bar_index > i_swingLen * 2 + 3
- int htfBias = nz(request.security(syminfo.tickerid, HTF_TF, f_structureBias(i_biasLen), lookahead = barmerge.lookahead_on))
- int stfBias = nz(request.security(syminfo.tickerid, STF_TF, f_structureBias(i_biasLen), lookahead = barmerge.lookahead_on))
- int execBias = nz(request.security(syminfo.tickerid, EXEC_TF, f_structureBias(i_biasLen), lookahead = barmerge.lookahead_on))
- bool needD = i_cPD or (i_cEQ and HTF_TF == "D")
- string D_TF = needD ? "D" : timeframe.period
- [pdh, pdl] = request.security(syminfo.tickerid, D_TF, [high[1], low[1]], lookahead = barmerge.lookahead_on)
- float htfEQ = na
- if HTF_TF == "D"
- htfEQ := (pdh + pdl) / 2.0
- else if i_cEQ
- htfEQ := request.security(syminfo.tickerid, HTF_TF, (high[1] + low[1]) / 2.0, lookahead = barmerge.lookahead_on)
- string VP_TF = i_showLVN ? "60" : timeframe.period
- [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)
- float execAtrLive = request.security(syminfo.tickerid, EXEC_TF, ta.atr(i_atrLen), lookahead = barmerge.lookahead_off)
- bool newDay = timeframe.change("D")
- bool inLdn = not na(time(timeframe.period, "0300-1130", "America/New_York"))
- bool inNY = not na(time(timeframe.period, "0930-1600", "America/New_York"))
- bool ldnStart = inLdn and not inLdn[1]
- bool nyStart = inNY and not inNY[1]
- var float dailyOpen = na
- var float ldnOpen = na
- var float nyOpen = na
- var float lastSH = na
- var int lastSHBar = na
- var bool shBroken = true
- var float lastSL = na
- var int lastSLBar = na
- var bool slBroken = true
- var array<Level> pool = array.new<Level>()
- var array<FVGZone> fvgs = array.new<FVGZone>()
- var array<OBZone> obs = array.new<OBZone>()
- var array<line> ghostLines = array.new<line>()
- var array<label> ghostLabels = array.new<label>()
- var array<float> recentPH = array.new<float>()
- var array<float> recentPL = array.new<float>()
- var array<float> vpOpen = array.new<float>()
- var array<float> vpHigh = array.new<float>()
- var array<float> vpLow = array.new<float>()
- var array<float> vpClose = array.new<float>()
- var array<float> vpVol = array.new<float>()
- var array<int> vpTime = array.new<int>()
- var Level activeLv = na
- var int levelSeq = 0
- if newDay
- dailyOpen := open
- if ldnStart
- ldnOpen := open
- if nyStart
- nyOpen := open
- float drEQ = not na(lastSH) and not na(lastSL) ? (lastSH + lastSL) / 2.0 : na
- bool newH1 = not na(h1t) and (na(h1t[1]) or h1t != h1t[1])
- if i_showLVN and newH1 and not na(h1h) and not na(h1l)
- array.push(vpOpen, nz(h1o, h1c))
- array.push(vpHigh, h1h)
- array.push(vpLow, h1l)
- array.push(vpClose, nz(h1c, h1o))
- array.push(vpVol, nz(h1v))
- array.push(vpTime, h1t)
- while array.size(vpHigh) > i_lvnLook
- array.shift(vpOpen)
- array.shift(vpHigh)
- array.shift(vpLow)
- array.shift(vpClose)
- array.shift(vpVol)
- array.shift(vpTime)
- bool liveSweep = false
- string sweepKind = ""
- float sweepPrice = na
- if not na(activeLv)
- float pc = nz(close[1], close)
- if math.max(high, pc) >= activeLv.bot and math.min(low, pc) <= activeLv.top
- liveSweep := true
- sweepKind := activeLv.kind
- sweepPrice := activeLv.px
- bool newDolEvent = false
- bool newIfvgEvent = false
- string ifvgMsg = ""
- if barstate.isconfirmed and ready
- array<float> anchors = array.new<float>()
- if i_cPD
- f_pushValid(anchors, pdh)
- f_pushValid(anchors, pdl)
- if i_cSess
- f_pushValid(anchors, dailyOpen)
- f_pushValid(anchors, ldnOpen)
- f_pushValid(anchors, nyOpen)
- if i_cEQ
- f_pushValid(anchors, htfEQ)
- f_pushValid(anchors, drEQ)
- if array.size(fvgs) > 0
- for j = array.size(fvgs) - 1 to 0
- FVGZone fz = array.get(fvgs, j)
- bool killFvg = false
- if not fz.inverted
- if fz.dir == 1 and close < fz.bot
- fz.inverted := true
- fz.insideCloses := 0
- fz.bx := f_styleIfvg(fz.bx, fz.top, fz.bot, fz.born, false)
- newIfvgEvent := true
- ifvgMsg := "Bearish iFVG " + str.tostring(fz.bot, format.mintick) + " - " + str.tostring(fz.top, format.mintick)
- else if fz.dir == -1 and close > fz.top
- fz.inverted := true
- fz.insideCloses := 0
- fz.bx := f_styleIfvg(fz.bx, fz.top, fz.bot, fz.born, true)
- newIfvgEvent := true
- ifvgMsg := "Bullish iFVG " + str.tostring(fz.bot, format.mintick) + " - " + str.tostring(fz.top, format.mintick)
- else if bar_index - fz.born > i_fvgAge
- killFvg := true
- else
- if close >= fz.bot and close <= fz.top
- fz.insideCloses := fz.insideCloses + 1
- if fz.insideCloses > i_maxInside
- killFvg := true
- else if fz.dir == 1 and close > fz.top
- killFvg := true
- else if fz.dir == -1 and close < fz.bot
- killFvg := true
- else if bar_index - fz.born > i_fvgAge
- killFvg := true
- if killFvg
- if not na(fz.bx)
- box.delete(fz.bx)
- array.remove(fvgs, j)
- if array.size(obs) > 0
- for j = array.size(obs) - 1 to 0
- OBZone z = array.get(obs, j)
- bool killOb = false
- float zMid = (z.top + z.bot) / 2.0
- if z.dir == 1 and close < z.bot
- levelSeq += 1
- f_addLevel(pool, activeLv, levelSeq, "BEBRK", zMid, bar_index, z.born, atr, f_density(zMid, 1, 1, atr, recentPH))
- killOb := true
- else if z.dir == -1 and close > z.top
- levelSeq += 1
- f_addLevel(pool, activeLv, levelSeq, "BUBRK", zMid, bar_index, z.born, atr, f_density(zMid, -1, 1, atr, recentPL))
- killOb := true
- else if bar_index - z.born > i_maxAge
- killOb := true
- if killOb
- array.remove(obs, j)
- if not na(ph)
- int phBar = bar_index - i_swingLen
- if i_useBSL
- levelSeq += 1
- f_addLevel(pool, activeLv, levelSeq, "BSL", ph, phBar, phBar, atr, f_density(ph, 1, i_swingLen + 1, atr, recentPH))
- array.push(recentPH, ph)
- if array.size(recentPH) > MAX_RECENT_PIV
- array.shift(recentPH)
- lastSH := ph
- lastSHBar := phBar
- shBroken := false
- if not na(pl)
- int plBar = bar_index - i_swingLen
- if i_useBSL
- levelSeq += 1
- f_addLevel(pool, activeLv, levelSeq, "SSL", pl, plBar, plBar, atr, f_density(pl, -1, i_swingLen + 1, atr, recentPL))
- array.push(recentPL, pl)
- if array.size(recentPL) > MAX_RECENT_PIV
- array.shift(recentPL)
- lastSL := pl
- lastSLBar := plBar
- slBroken := false
- if not shBroken and not na(lastSH) and close > lastSH
- shBroken := true
- int spanB = math.min(bar_index - lastSHBar, 100)
- if spanB >= 1 and (i_useOB or i_useBRK)
- int bIdx = f_findOB(spanB, true)
- float bTop = high[bIdx]
- float bBot = low[bIdx]
- float bMid = (bTop + bBot) / 2.0
- int bBar = bar_index - bIdx
- if i_useOB
- levelSeq += 1
- f_addLevel(pool, activeLv, levelSeq, "BUOB", bMid, bBar, bBar, atr, f_density(bMid, -1, bIdx + 1, atr, recentPL))
- if i_useBRK
- array.push(obs, OBZone.new(bTop, bBot, 1, bBar))
- if array.size(obs) > MAX_OB_TRACK
- array.shift(obs)
- if not slBroken and not na(lastSL) and close < lastSL
- slBroken := true
- int spanS = math.min(bar_index - lastSLBar, 100)
- if spanS >= 1 and (i_useOB or i_useBRK)
- int sIdx = f_findOB(spanS, false)
- float sTop = high[sIdx]
- float sBot = low[sIdx]
- float sMid = (sTop + sBot) / 2.0
- int sBar = bar_index - sIdx
- if i_useOB
- levelSeq += 1
- f_addLevel(pool, activeLv, levelSeq, "BEOB", sMid, sBar, sBar, atr, f_density(sMid, 1, sIdx + 1, atr, recentPH))
- if i_useBRK
- array.push(obs, OBZone.new(sTop, sBot, -1, sBar))
- if array.size(obs) > MAX_OB_TRACK
- array.shift(obs)
- if bullFVG
- float uTop = low
- float uBot = high[2]
- float uCE = (uTop + uBot) / 2.0
- if i_useFVG
- levelSeq += 1
- f_addLevel(pool, activeLv, levelSeq, "BUFVG", uCE, bar_index - 1, bar_index - 1, atr, f_density(uCE, -1, 3, atr, recentPL))
- box uBox = f_fvgBox(uTop, uBot)
- array.push(fvgs, FVGZone.new(uTop, uBot, 1, bar_index - 1, false, 0, uBox))
- if bearFVG
- float eTop = low[2]
- float eBot = high
- float eCE = (eTop + eBot) / 2.0
- if i_useFVG
- levelSeq += 1
- f_addLevel(pool, activeLv, levelSeq, "BEFVG", eCE, bar_index - 1, bar_index - 1, atr, f_density(eCE, 1, 3, atr, recentPH))
- box eBox = f_fvgBox(eTop, eBot)
- array.push(fvgs, FVGZone.new(eTop, eBot, -1, bar_index - 1, false, 0, eBox))
- while array.size(fvgs) > i_maxFVG
- FVGZone oldF = array.shift(fvgs)
- if not na(oldF.bx)
- box.delete(oldF.bx)
- if array.size(pool) > 0
- for j = array.size(pool) - 1 to 0
- Level lv = array.get(pool, j)
- bool isActive = not na(activeLv) and lv.uid == activeLv.uid
- string reason = ""
- if lv.added < bar_index
- float prevC = nz(close[1], close)
- bool zoneHit = math.max(high, prevC) >= lv.bot and math.min(low, prevC) <= lv.top
- bool priceHit = math.max(high, prevC) >= lv.px and math.min(low, prevC) <= lv.px
- if (isActive and zoneHit) or priceHit
- reason := "Swept"
- if reason == "" and i_rangeAct == "Eject" and math.abs(close - lv.px) / atr > i_maxAtrDist
- reason := "Ejected"
- if reason == "" and bar_index - lv.born > i_maxAge
- reason := "Expired"
- if reason != ""
- if isActive
- if reason != "Expired"
- f_addGhost(ghostLines, ghostLabels, lv, bar_index, reason)
- activeLv := na
- array.remove(pool, j)
- float wSum = i_wProx + i_wFresh + i_wConf + i_wDens
- Level best = na
- float bestScore = -1.0
- if array.size(pool) > 0 and wSum > 0
- for lv in pool
- float distAtr = math.abs(close - lv.px) / atr
- float prox = f_clamp(1.0 - distAtr / i_maxAtrDist, 0.0, 1.0)
- float fresh = math.exp(-LN2 * float(bar_index - lv.born) / i_halfLife)
- bool above = lv.px > close
- float conf = f_confluence(lv.px, above, atr, anchors, htfBias, stfBias)
- float sc = 100.0 * (i_wProx * prox + i_wFresh * fresh + i_wConf * conf + i_wDens * lv.density) / wSum
- if distAtr > i_maxAtrDist
- sc := sc * 0.5
- lv.prox := prox
- lv.fresh := fresh
- lv.conf := conf
- lv.score := sc
- bool inZone = close >= lv.bot and close <= lv.top
- if not inZone and sc > bestScore
- bestScore := sc
- best := lv
- if not na(activeLv) and not na(best)
- if best.uid != activeLv.uid
- bool actInZone = close >= activeLv.bot and close <= activeLv.top
- if not actInZone and activeLv.score + RETARGET_HYST >= best.score
- best := activeLv
- int prevUid = -1
- if not na(activeLv)
- prevUid := activeLv.uid
- activeLv := best
- if not na(best)
- if best.uid != prevUid
- newDolEvent := true
- float potLive = na
- if barstate.islast and not na(activeLv)
- float sigma = na(execAtrLive) or execAtrLive <= 0 ? nz(atr, syminfo.mintick) : execAtrLive
- potLive := f_pot(activeLv, close, sigma, htfBias, execBias)
- var array<line> dolLines = array.new<line>()
- var box dolBox = na
- var label dolLabel = na
- var array<box> lvnBoxes = array.new<box>()
- if barstate.islast
- if array.size(dolLines) > 0
- for ln in dolLines
- line.delete(ln)
- array.clear(dolLines)
- if not na(dolBox)
- box.delete(dolBox)
- dolBox := na
- if not na(dolLabel)
- label.delete(dolLabel)
- dolLabel := na
- if i_showDOL and not na(activeLv) and not na(potLive)
- if potLive >= i_minPoT
- bool tgtAbove = activeLv.px > close
- color dolCol = tgtAbove ? i_bullDol : i_bearDol
- int xLeft = f_anchor(activeLv.top, activeLv.bot, activeLv.origin)
- int xRight = bar_index + i_rightOff
- 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))
- array.push(dolLines, line.new(xLeft, activeLv.px, xRight, activeLv.px, color = color.new(dolCol, 82), width = 8))
- array.push(dolLines, line.new(xLeft, activeLv.px, xRight, activeLv.px, color = color.new(dolCol, 55), width = 4))
- array.push(dolLines, line.new(xLeft, activeLv.px, xRight, activeLv.px, color = dolCol, width = 2))
- if i_showConn
- array.push(dolLines, line.new(bar_index, close, xRight, activeLv.px, color = color.new(dolCol, 20), style = line.style_dashed, width = 1))
- 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)
- 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)
- if array.size(fvgs) > 0
- for fz in fvgs
- if not na(fz.bx)
- box.set_right(fz.bx, bar_index + i_rightOff)
- if array.size(lvnBoxes) > 0
- for bx in lvnBoxes
- box.delete(bx)
- array.clear(lvnBoxes)
- int vpN = array.size(vpHigh)
- if i_showLVN and vpN >= 10
- float vpMax = array.max(vpHigh)
- float vpMin = array.min(vpLow)
- float vpStep = (vpMax - vpMin) / i_lvnRows
- if vpStep > 0
- array<float> rowVol = array.new<float>(i_lvnRows, 0.0)
- for k = 0 to vpN - 1
- float hH = array.get(vpHigh, k)
- float hL = array.get(vpLow, k)
- float hO = array.get(vpOpen, k)
- float hC = array.get(vpClose, k)
- float hV = array.get(vpVol, k)
- float bTp = math.max(hO, hC)
- float bBt = math.min(hO, hC)
- int rLo = math.max(0, math.min(i_lvnRows - 1, math.floor((hL - vpMin) / vpStep)))
- int rHi = math.max(0, math.min(i_lvnRows - 1, math.floor((hH - vpMin) / vpStep)))
- for r = rLo to rHi
- float rowBot = vpMin + r * vpStep
- float rowTop = rowBot + vpStep
- float rngShare = hH > hL ? math.max(0.0, math.min(hH, rowTop) - math.max(hL, rowBot)) / (hH - hL) : 1.0 / (rHi - rLo + 1)
- 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)
- array.set(rowVol, r, array.get(rowVol, r) + hV * (0.4 * rngShare + 0.6 * bodyShare))
- float poc = array.max(rowVol)
- if poc > 0
- int tfMs = timeframe.in_seconds() * 1000
- int leftT = array.get(vpTime, 0)
- int rightT = time + i_rightOff * tfMs
- int upCnt = 0
- int dnCnt = 0
- for r = 1 to i_lvnRows - 2
- bool isLvn = f_isLvn(rowVol, r, poc)
- float rb = vpMin + r * vpStep
- float rt = rb + vpStep
- if isLvn and rb > close and upCnt < i_lvnSide
- array.push(lvnBoxes, f_lvnBox(leftT, rt, rightT, rb))
- upCnt += 1
- for r = i_lvnRows - 2 to 1
- bool isLvn = f_isLvn(rowVol, r, poc)
- float rb = vpMin + r * vpStep
- float rt = rb + vpStep
- if isLvn and rt < close and dnCnt < i_lvnSide
- array.push(lvnBoxes, f_lvnBox(leftT, rt, rightT, rb))
- dnCnt += 1
- 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
- if barstate.islast and i_showTbl and not na(biasTable)
- string tsz = f_size(i_tblSize)
- 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)
- 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)
- f_biasRow(biasTable, 1, HTF_TF, htfBias, tsz)
- f_biasRow(biasTable, 2, STF_TF, stfBias, tsz)
- f_biasRow(biasTable, 3, EXEC_TF, execBias, tsz)
- alertcondition(newDolEvent, "New DOL Target Active", "TradeAxis DOL: A new highest-scoring Draw on Liquidity target is now active.")
- alertcondition(newIfvgEvent, "New iFVG Formed", "TradeAxis DOL: A Fair Value Gap was invalidated and flipped into an active Inversion Gap.")
- alertcondition(liveSweep, "DOL Target Swept", "TradeAxis DOL: Price touched the currently active Draw on Liquidity target zone.")
- if newDolEvent and not na(activeLv)
- alert("TradeAxis DOL | New DOL Target Active: " + activeLv.kind + " @ " + str.tostring(activeLv.px, format.mintick), alert.freq_once_per_bar_close)
- if newIfvgEvent
- alert("TradeAxis DOL | New iFVG Formed: " + ifvgMsg, alert.freq_once_per_bar_close)
- if liveSweep
- 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