// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/ // © dkcodenut // © dkcodenut.com //@version=6 indicator("Intrabar X-Ray Profile by [dk_codenut]", overlay = true, max_boxes_count = 500, max_labels_count = 500, max_lines_count = 250, calc_bars_count = 500) // ───────────────────────────────────────────────────────────────────────────── // Intrabar Volume Profile // Builds a per-candle volume profile from lower-timeframe data and renders it as horizontal bars inside each candle, colored by buy/sell delta. // Features: POC highlight, value area dimming, imbalance detection, optional per-level value labels (footprint layout), candle delta summary,and a stepped POC connector line. // ───────────────────────────────────────────────────────────────────────────── // ── Profile ── gp = "Profile" gran = input.string("1-Minute", "Granularity", options = ["5-Minute", "1-Minute", "1-Second", "1-Tick"], group = gp, tooltip = "Lower timeframe used to build each candle's profile. 1-Second and 1-Tick require the matching TradingView data plan. On most stocks and higher chart timeframes, 1-Minute is the best balance of detail and coverage.") rows = input.int(12, "Profile Rows", minval = 5, maxval = 30, group = gp, tooltip = "Number of price levels per candle. More rows = finer detail but smaller bars.") maxBars = input.int(30, "Max Candles Back", minval = 5, maxval = 40, group = gp, tooltip = "How many recent candles get a profile. Kept modest so drawings stay within TradingView limits.") profW = input.int(85, "Profile Width, % of Candle", minval = 30, maxval = 100, group = gp, tooltip = "Maximum bar length as a share of the candle's width. Lower values leave a visual gap between candles.") // ── POC & Value Area ── gv = "POC & Value Area" showPOC = input.bool(true, "Highlight POC", inline = "poc", group = gv) pocCol = input.color(#e2b93b, "", inline = "poc", group = gv, tooltip = "Point of Control — the level with the highest traded volume in the candle.") showVA = input.bool(true, "Dim Outside Value Area", inline = "va", group = gv) vaCol = input.color(#50535e, "", inline = "va", group = gv, tooltip = "Levels outside the value area are drawn in this neutral color so the value area stands out.") vaPct = input.float(70, "Value Area %", minval = 50, maxval = 95, step = 5, group = gv) // ── Imbalance ── gi = "Imbalance Detection" showImb = input.bool(true, "Mark Imbalanced Levels", group = gi, tooltip = "Flags a level when one side controls at least the Dominance % of that level's volume.") imbRatio = input.float(75, "Dominance %", minval = 55, maxval = 95, step = 5, group = gi) imbBuy = input.color(#00c853, "Buy / Sell Imbalance", inline = "im", group = gi) imbSel = input.color(#ff1744, "", inline = "im", group = gi) // ── Numbers & Data ── gn = "Numbers & Data" lblVal = input.string("Delta", "Label Value", options = ["Delta", "Volume"], group = gn, tooltip = "Which value the number labels print for each level.") showFoot = input.bool(true, "Values At End Of Each Bar", group = gn, tooltip = "Footprint style — prints each level's value just past the tip of its bar.") showStats = input.bool(true, "Candle Delta Summary", group = gn, tooltip = "Net delta and delta % under each candle.") minLblPct = input.float(10, "Hide Values Below % Of Max", minval = 0, maxval = 50, step = 5, group = gn, tooltip = "Skips number labels on levels with little volume. Cuts clutter dramatically — set to 0 to label every level.") lblSizeOpt = input.string("Tiny", "Label Text Size", options = ["Tiny", "Small", "Normal"], group = gn) footByDlt = input.bool(true, "Color Numbers By Delta", group = gn) footCol = input.color(#d1d4dc, "Neutral Text Color", group = gn) // ── Style ── gs = "Style" buyHi = input.color(#089981, "Buy strong → weak", inline = "b", group = gs) buyLo = input.color(#b3d9d1, "", inline = "b", group = gs) selHi = input.color(#f23645, "Sell strong → weak", inline = "s", group = gs) selLo = input.color(#f5c6cb, "", inline = "s", group = gs) transp = input.int(20, "Transparency", minval = 0, maxval = 90, group = gs) // ── POC Connector ── gc = "POC Connector" showLine = input.bool(true, "Connect POC Across Candles", inline = "pl", group = gc) lineCol = input.color(#787b86, "", inline = "pl", group = gc) lineSty = input.string("Dotted", "Style", options = ["Solid", "Dashed", "Dotted"], inline = "pl2", group = gc) lineWid = input.int(1, "Width", minval = 1, maxval = 4, inline = "pl2", group = gc) tf = switch gran "5-Minute" => "5" "1-Minute" => "1" "1-Second" => "1S" => "1T" lblSize = switch lblSizeOpt "Tiny" => size.tiny "Small" => size.small => size.normal lStyle = switch lineSty "Solid" => line.style_solid "Dashed" => line.style_dashed => line.style_dotted dir() => math.sign(close - close[1]) // "+1.2K" / "-830" — signed compact number signedVol(float x) => (x > 0 ? "+" : "") + str.tostring(x, format.volume) // ── State ── var float pPoc = na var line liveH = na var line liveV = na var array liveBoxes = array.new() var array