// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 // https://mozilla.org/MPL/2.0/ //@version=6 // ============================================================================ // Sweep Reversal Map [Herman] — HTF x2 + opacity fix + TF text in boxes // Original sweep / reclaim / structure-break logic retained. // HTF values use ONLY completed HTF candles (no future data / no repaint). // ============================================================================ indicator("Sweep Reversal Map [Herman]", shorttitle = "Sweep Reversal Map [Herman]", overlay = true, max_boxes_count = 500, max_lines_count = 500, max_labels_count = 500, calc_bars_count = 10000) // --- Groups --- const string G_DETECT = "Detection" const string G_CONFIRM = "Confirmation" const string G_LAYERS = "Timeframes" const string G_STYLE = "Style / Opacity" // --- Detection / confirmation (same defaults as the original) --- int swingLengthInput = input.int(5, "Swing length", minval = 2, maxval = 50, group = G_DETECT, tooltip = "Bars on either side of a confirmed swing.") int atrLengthInput = input.int(14, "ATR length", minval = 1, group = G_DETECT) float minPenetrationInput = input.float(0.0, "Minimum sweep penetration (ATR)", minval = 0.0, step = 0.05, group = G_DETECT) int structureLengthInput = input.int(3, "Local structure length", minval = 1, maxval = 20, group = G_CONFIRM) int maxConfirmationBarsInput = input.int(12, "Maximum confirmation bars", minval = 1, maxval = 100, group = G_CONFIRM) float minDisplacementInput = input.float(0.2, "Minimum displacement body (ATR)", minval = 0.0, step = 0.05, group = G_CONFIRM) // --- Independent visibility controls --- bool showChartInput = input.bool(true, "Chart TF reversal zones", group = G_LAYERS) bool showHtf1Input = input.bool(true, "HTF 1 zones", inline = "htf1", group = G_LAYERS) string htf1Input = input.timeframe("5", "", inline = "htf1", group = G_LAYERS) bool showHtf2Input = input.bool(false, "HTF 2 zones", inline = "htf2", group = G_LAYERS) string htf2Input = input.timeframe("15", "", inline = "htf2", group = G_LAYERS) bool showLongsInput = input.bool(true, "Show LONGS", group = G_LAYERS) bool showShortsInput = input.bool(true, "Show SHORTS", group = G_LAYERS) // --- Visuals: defaults reproduce the original on the chart TF --- bool showDevelopingInput = input.bool(true, "Show developing reversals", group = G_STYLE) int confirmedExtensionInput = input.int(2, "Confirmed box extension (source-TF bars)", minval = 0, maxval = 50, group = G_STYLE) int maxHistoryInput = input.int(80, "Historical setups PER LAYER", minval = 1, maxval = 150, group = G_STYLE) color zoneColorInput = input.color(#FF9F43, "Reversal zone color", group = G_STYLE) color levelColorInput = input.color(#7F1D1D, "Sweep level / marker color", group = G_STYLE) int devFillOpacityInput = input.int(88, "Developing fill opacity", minval = 0, maxval = 100, group = G_STYLE, tooltip = "0 = opaque, 100 = invisible. Also respects transparency in the color picker.") int devBorderOpacityInput = input.int(65, "Developing border opacity", minval = 0, maxval = 100, group = G_STYLE) int confFillOpacityInput = input.int(35, "Confirmed fill opacity", minval = 0, maxval = 100, group = G_STYLE) int confBorderOpacityInput = input.int(5, "Confirmed border opacity", minval = 0, maxval = 100, group = G_STYLE) int devLevelOpacityInput = input.int(75, "Developing level opacity", minval = 0, maxval = 100, group = G_STYLE) int confLevelOpacityInput = input.int(20, "Confirmed level opacity", minval = 0, maxval = 100, group = G_STYLE) int devMarkerOpacityInput = input.int(70, "Developing marker opacity", minval = 0, maxval = 100, group = G_STYLE) int confMarkerOpacityInput = input.int(0, "Confirmed marker opacity", minval = 0, maxval = 100, group = G_STYLE) // HTF origin name inside every HTF reversal box, at its right-hand edge. bool showHtfBoxTextInput = input.bool(true, "Show HTF name inside box", group = G_STYLE) color htfBoxTextColorInput = input.color(#7F1D1D, "HTF box text color", group = G_STYLE) string htfBoxTextSizeInput = input.string("Small", "HTF box text size", options = ["Tiny", "Small", "Normal"], group = G_STYLE) string htfBoxTextSize = htfBoxTextSizeInput == "Tiny" ? size.tiny : htfBoxTextSizeInput == "Normal" ? size.normal : size.small // TradingView minute timeframes are stored as "5", "15", "60", etc. // Convert them into concise readable labels: HTF 5min, HTF 15min, HTF 1h. f_htfLabel(string sourceTf) => float minuteNumber = str.tonumber(sourceTf) string displayName = "HTF " + sourceTf if not na(minuteNumber) int minutes = int(minuteNumber) if minutes > 0 and minutes % 60 == 0 displayName := "HTF " + str.tostring(int(minutes / 60)) + "h" else displayName := "HTF " + str.tostring(minutes) + "min" displayName // A second opacity percentage is applied *over* the opacity in input.color. // This means edits to EITHER control actually affect rendered objects. // With default color transparency = 0%, the values exactly match the old code. f_opacity(color baseColor, int extraOpacity) => float baseTransparency = color.t(baseColor) int finalTransparency = int(math.round(baseTransparency + (100.0 - baseTransparency) * extraOpacity / 100.0)) color.new(baseColor, finalTransparency) color devFillColor = showDevelopingInput ? f_opacity(zoneColorInput, devFillOpacityInput) : color.new(zoneColorInput, 100) color devBorderColor = showDevelopingInput ? f_opacity(zoneColorInput, devBorderOpacityInput) : color.new(zoneColorInput, 100) color confFillColor = f_opacity(zoneColorInput, confFillOpacityInput) color confBorderColor = f_opacity(zoneColorInput, confBorderOpacityInput) color devLineColor = showDevelopingInput ? f_opacity(levelColorInput, devLevelOpacityInput) : color.new(levelColorInput, 100) color confLineColor = f_opacity(levelColorInput, confLevelOpacityInput) color devMarkerColor = showDevelopingInput ? f_opacity(levelColorInput, devMarkerOpacityInput) : color.new(levelColorInput, 100) color confMarkerColor = f_opacity(levelColorInput, confMarkerOpacityInput) color labelBackground = color.new(color.black, 100) // --- Compact state snapshot for all three independently computed timeframes --- // Event 0 = none, 2 = reversal confirmed, 3 = candidate expired. // Developing is determined by active == true; same-bar start+confirm is supported. type SweepState int barTime = na int barCloseTime = na int bearEvent = 0 bool bearActive = false int bearStartTime = na int bearPivotTime = na float bearLevel = na float bearExtreme = na int bullEvent = 0 bool bullActive = false int bullStartTime = na int bullPivotTime = na float bullLevel = na float bullExtreme = na // Identical state machine runs in the chart, 5m and 15m data contexts. // Calling this function from request.security evaluates actual HTF OHLC/ATR/pivots. f_engine() => float atrValue = ta.atr(atrLengthInput) float pivotHighValue = ta.pivothigh(high, swingLengthInput, swingLengthInput) float pivotLowValue = ta.pivotlow(low, swingLengthInput, swingLengthInput) float priorStructureLow = ta.lowest(low, structureLengthInput)[1] float priorStructureHigh = ta.highest(high, structureLengthInput)[1] bool displacementPass = not na(atrValue) and math.abs(close - open) >= atrValue * minDisplacementInput float minimumPenetration = nz(atrValue) * minPenetrationInput var float latestSwingHigh = na var float latestSwingLow = na var int latestSwingHighTime = na var int latestSwingLowTime = na var bool swingHighAvailable = false var bool swingLowAvailable = false if not na(pivotHighValue) latestSwingHigh := pivotHighValue latestSwingHighTime := time[swingLengthInput] swingHighAvailable := true if not na(pivotLowValue) latestSwingLow := pivotLowValue latestSwingLowTime := time[swingLengthInput] swingLowAvailable := true var bool bearishActive = false var bool bearishReclaimed = false var int bearishStartBar = na var int bearishStartTime = na var int bearishPivotTime = na var float bearishLevel = na var float bearishExtreme = na var float bearishConfirmationLevel = na var bool bullishActive = false var bool bullishReclaimed = false var int bullishStartBar = na var int bullishStartTime = na var int bullishPivotTime = na var float bullishLevel = na var float bullishExtreme = na var float bullishConfirmationLevel = na int bearEvent = 0 int bullEvent = 0 // Bearish: confirmed high sweep -> reclaim -> close below saved structure. bool bearishSweep = not bearishActive and swingHighAvailable and not na(latestSwingHigh) and not na(priorStructureLow) and high >= latestSwingHigh + minimumPenetration if bearishSweep bearishActive := true bearishReclaimed := close < latestSwingHigh bearishStartBar := bar_index bearishStartTime := time bearishPivotTime := latestSwingHighTime bearishLevel := latestSwingHigh bearishExtreme := high bearishConfirmationLevel := priorStructureLow swingHighAvailable := false if bearishActive bearishExtreme := math.max(bearishExtreme, high) bearishReclaimed := bearishReclaimed or close < bearishLevel bool confirmBearish = bearishReclaimed and close < bearishConfirmationLevel and displacementPass bool expireBearish = bar_index - bearishStartBar > maxConfirmationBarsInput if confirmBearish bearEvent := 2 bearishActive := false else if expireBearish bearEvent := 3 bearishActive := false // Bullish: confirmed low sweep -> reclaim -> close above saved structure. bool bullishSweep = not bullishActive and swingLowAvailable and not na(latestSwingLow) and not na(priorStructureHigh) and low <= latestSwingLow - minimumPenetration if bullishSweep bullishActive := true bullishReclaimed := close > latestSwingLow bullishStartBar := bar_index bullishStartTime := time bullishPivotTime := latestSwingLowTime bullishLevel := latestSwingLow bullishExtreme := low bullishConfirmationLevel := priorStructureHigh swingLowAvailable := false if bullishActive bullishExtreme := math.min(bullishExtreme, low) bullishReclaimed := bullishReclaimed or close > bullishLevel bool confirmBullish = bullishReclaimed and close > bullishConfirmationLevel and displacementPass bool expireBullish = bar_index - bullishStartBar > maxConfirmationBarsInput if confirmBullish bullEvent := 2 bullishActive := false else if expireBullish bullEvent := 3 bullishActive := false SweepState.new(time, time_close, bearEvent, bearishActive, bearishStartTime, bearishPivotTime, bearishLevel, bearishExtreme, bullEvent, bullishActive, bullishStartTime, bullishPivotTime, bullishLevel, bullishExtreme) // Snapshot delayed by ONE source bar; lookahead_on then provides only CLOSED HTF // bars on the first bar of the next HTF period, in history AND in realtime. f_confirmedHtfEngine() => SweepState snapshot = f_engine() snapshot[1] // Each syntactically distinct call site has its OWN persistent arrays and IDs. // Thus chart TF, HTF1 and HTF2 maintain separate history and developing boxes. f_render(SweepState s, bool enabled, bool gate, int projectedRight, int historyLimit, string sourceLabel) => var array confirmedBoxes = array.new() var array confirmedLines = array.new() var array