Indicator · Pine Script v6 · On the chart

VP RSD Automatic Local Node Edge Consensus Diagnostic

by 345-strategies· code credited to TheStratSuite contributors

This research diagnostic draws a volume histogram and paired-node consensus structures on the price chart.

View on GitHub

Repaints

GitHub stars5on the repository
Pine versionv6current
Lines of code4,145
Settings28inputs
LicenceMPL-2.0
Last update2 days ago26 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new indicator, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart, then adjust the settings with the gear icon next to its name.

Source Code

4,145 lines of Pine Script v6 from pine/research/VP_RSD_Automatic_Local_Node_Edge_Consensus_Diagnostic_v0.6.0.pine, published under MPL-2.0. Keep the author's credit and licence lines when you reuse it.

VP_RSD_Automatic_Local_Node_Edge_Consensus_Diagnostic_v0.6.0.pine
// This source code is subject to the terms of the Mozilla Public License 2.0
// at https://mozilla.org/MPL/2.0/
// © 2026 TheStratSuite contributors
//@version=6

// RESEARCH DIAGNOSTIC ONLY.
//
// This successor joins the two previously separate research components:
//
//   1. the confirmed RSD v1.7 Macro broadening-wall selector; and
//   2. the v0.5.1 local paired-node consensus detector.
//
// The newest eligible Macro wall automatically supplies the immutable profile
// interval. Its same-side Far/Prior pivot is the start and its Outer pivot is
// the included end. Macro candle timestamps are refined to the exact 15-minute
// bars that printed the pivot prices. If either endpoint cannot be refined, the
// indicator abstains. No manual dates are required.
//
// The RSD adapter intentionally matches the v1.7 swing path with HTF confluence
// OFF. It uses confirmed pivots only, the pullback-tolerant two-sided wall gate,
// the Far-versus-Prior containment rule, and the existing steep-wall filter.
// The filter's ATR snapshot is latched when the confirmed Macro pivot tuple
// changes so an already-selected profile cannot churn on ordinary ATR drift.
// When both walls qualify, the wall with the newest endpoint wins; an equal
// endpoint prefers the longer span.
//
// Every retained profile boundary keeps the direction of its dense side.
// Starting at that anchor, each grid scans outward on the dense side and accepts
// the nearest material local maximum in opposite-direction clean strength that
// encloses a local volume bulge. A node is drawn only when the base-grid pair is
// complete and at least one neighboring grid agrees on both endpoints.
//
//   fine   = round(base row ticks * 0.8)
//   base   = base row ticks
//   coarse = round(base row ticks * 1.2)
//
// Each profile allocates every source bar's total volume by exact high/low tick
// overlap. The existing provisional local log-jump gates are applied to each
// grid independently. Anchor clustering keeps its configurable radius, while
// mate endpoints use the stricter fixed radius of one base row. Neighbor grids
// are evaluated pair-aware instead of inheriting the preselected standalone
// neighbor. Stable pairs rank by grid support, worst cross-grid node prominence,
// then the minimum anchor z score. Unpaired consensus anchors remain eligible
// as standalones. A selected pair consumes consensus anchors inside the node or
// within one consensus radius of either edge.
//
// Optional structural bounds can suppress otherwise-valid consensus shelves
// that are too close to the RSD range low or high. They are suppression inputs,
// not additional evidence.
//
// Source and endpoint contract:
//   standard 15-minute chart OHLCV only;
//   [Start 15m bar time, End 15m bar time + 15 minutes)
//
// This script does not create entries, exits, or support/resistance claims.
// It tests whether both edges of a volume node survive row-size perturbation.
indicator(
     "VP RSD Automatic Local Node Edge Consensus Diagnostic v0.6.0",
     shorttitle = "VP RSD AUTO 0.6",
     overlay = true,
     max_bars_back = 5000,
     max_lines_count = 500,
     max_boxes_count = 10,
     max_labels_count = 100)


// ============================================================================
// INPUTS
// ============================================================================

string rangeGroup = "1. Automatic RSD Macro range"
string macroTFInput = input.string(
     "240",
     "Macro timeframe",
     options = ["240", "60"],
     group = rangeGroup,
     tooltip = "Use 240 to match the normal locked 4-hour Macro structure.")
bool useMultiNInput = input.bool(
     false,
     "Multi-N swing union",
     group = rangeGroup,
     tooltip = "Must match RSD. The first comparison protocol keeps this OFF.")
int nFastInput = input.int(
     3,
     "N fast (left bars)",
     minval = 2,
     maxval = 10,
     group = rangeGroup)
int nMediumInput = input.int(
     5,
     "N medium (left bars)",
     minval = 2,
     maxval = 20,
     group = rangeGroup)
int rightBarsInput = input.int(
     2,
     "Right bars (confirmation)",
     minval = 1,
     maxval = 10,
     group = rangeGroup)
bool wallRequireBothSidesInput = input.bool(
     true,
     "Require two-sided broadening",
     group = rangeGroup,
     tooltip = "Matches the corresponding RSD wall setting.")
bool hideSteepWallsInput = input.bool(
     true,
     "Suppress steep walls",
     group = rangeGroup)
float maximumWallSlopeInput = input.float(
     0.05,
     "Maximum wall slope (ATR / 15m bar)",
     minval = 0.0,
     step = 0.01,
     group = rangeGroup,
     tooltip = "Uses the RSD steep-wall test with a confirmed ATR snapshot latched to each Macro pivot tuple, keeping the selected profile stable until structure changes.")

string constructionGroup = "2. Multi-resolution construction"
int baseTicksInput = input.int(
     25,
     "Preferred base ticks per row",
     minval = 5,
     maxval = 500,
     group = constructionGroup,
     tooltip = "The other grids are round(base × 0.8) and round(base × 1.2).")
bool widenRowsToCapacityInput = input.bool(
     true,
     "Automatically widen rows when required",
     group = constructionGroup,
     tooltip = "Raises the effective base row only when the fine grid would exceed the 400-row safety cap.")
float valueAreaPercentInput = input.float(
     70.0,
     "Base-grid Value Area target (%)",
     minval = 1.0,
     maxval = 100.0,
     step = 0.5,
     group = constructionGroup)

string scoringGroup = "3. Provisional local geometry gates"
int candidateCapPerGridInput = input.int(
     12,
     "Candidate cap per grid",
     minval = 1,
     maxval = 20,
     group = scoringGroup)
float minimumRatioInput = input.float(
     1.75,
     "Minimum dense/thin ratio",
     minval = 1.0,
     step = 0.05,
     group = scoringGroup)
float maximumNoiseFractionInput = input.float(
     0.50,
     "Maximum W / J",
     minval = 0.0,
     step = 0.05,
     group = scoringGroup)
float minimumDenseFractionInput = input.float(
     0.20,
     "Minimum dense side / grid max row",
     minval = 0.0,
     maxval = 1.0,
     step = 0.05,
     group = scoringGroup)
float minimumRobustZInput = input.float(
     2.50,
     "Minimum robust z",
     minval = 0.0,
     step = 0.25,
     group = scoringGroup)
int localClusterRowsInput = input.int(
     2,
     "Within-grid cluster radius (grid rows)",
     minval = 0,
     maxval = 10,
     group = scoringGroup)

string consensusGroup = "4. Cross-grid consensus"
float consensusClusterBaseRowsInput = input.float(
     1.0,
     "Cross-grid cluster radius (base rows)",
     minval = 0.25,
     maxval = 5.0,
     step = 0.25,
     group = consensusGroup)
int maximumStructuresInput = input.int(
     2,
     "Maximum structures",
     minval = 1,
     maxval = 2,
     group = consensusGroup)
float maximumNodeWidthBaseRowsInput = input.float(
     12.0,
     "Maximum paired-node width (base rows)",
     minval = 3.0,
     maxval = 50.0,
     step = 0.5,
     group = consensusGroup,
     tooltip = "Local-node guard. A mate farther than this is not paired with the anchor; the anchor may remain a standalone shelf.")
bool extendStructuresInput = input.bool(
     true,
     "Extend structures to current bar",
     group = consensusGroup)

string structureGroup = "5. Optional structural-bound suppression"
bool useStructuralBoundsInput = input.bool(
     false,
     "Suppress near structural low / high",
     group = structureGroup)
float structuralLowInput = input.price(
     0.0,
     "Structural low",
     group = structureGroup)
float structuralHighInput = input.price(
     0.0,
     "Structural high",
     group = structureGroup)
float structuralDistanceBaseRowsInput = input.float(
     1.0,
     "Suppression distance (base rows)",
     minval = 0.0,
     maxval = 20.0,
     step = 0.25,
     group = structureGroup)

string displayGroup = "6. Diagnostic display"
float histogramWidthInput = input.float(
     24.0,
     "Base histogram width (% of range)",
     minval = 5.0,
     maxval = 50.0,
     group = displayGroup)
color rangeColorInput = input.color(
     #26c6da,
     "Range / base histogram",
     group = displayGroup)
color consensusColorInput = input.color(
     #ffd54f,
     "Consensus structures",
     group = displayGroup)


// ============================================================================
// CONSTANTS AND HELPERS
// ============================================================================

const int MINUTE_MS = 60000
const int PROFILE_BAR_MS = 15 * MINUTE_MS
const int SOURCE_BAR_MS = 15 * MINUTE_MS
const int GRID_ORIGIN_TICKS = 0
const int MAX_PROFILE_BINS = 400
const int MAX_PROFILE_SOURCE_BARS = 2000
const int MAX_ALLOCATION_TOUCHES = 120000
const int SHELF_SIDE_ROWS = 3
const int MIN_NODE_ROWS = 3
const float MIN_MATE_TO_ANCHOR_CLEAN = 0.10
const int MAX_RANKED_DIAGNOSTICS = 60
const int MIN_CONSENSUS_GRIDS = 2

priceToTicks(float price) =>
    na(price) ? na : int(math.round(price / syminfo.mintick))

binVolume(map<int, float> bins, int bin) =>
    bins.contains(bin) ? bins.get(bin) : 0.0

// Most recent chart bar at or before an HTF candle's opening timestamp.
// Copied semantically from RSD v1.7. The chart contract is fixed at 15m.
htfTimeToBar(int pivotTime) =>
    int maxOffset = math.min(bar_index, 4999)
    int result = bar_index
    if not na(pivotTime) and pivotTime > 0
        result := bar_index - maxOffset
        for offset = 0 to maxOffset
            if time[offset] <= pivotTime
                result := bar_index - offset
                break
    result

// Confirmed RSD v1.7 Macro swing path with HTF confluence OFF.
findMacroPivots() =>
    bool highMediumCondition =
         not na(ta.pivothigh(
             high,
             nMediumInput,
             rightBarsInput))
    bool lowMediumCondition =
         not na(ta.pivotlow(
             low,
             nMediumInput,
             rightBarsInput))

    float high0Medium = ta.valuewhen(
         highMediumCondition,
         high[rightBarsInput],
         0)[1]
    int highTime0Medium = ta.valuewhen(
         highMediumCondition,
         time[rightBarsInput],
         0)[1]
    float high1Medium = ta.valuewhen(
         highMediumCondition,
         high[rightBarsInput],
         1)[1]
    int highTime1Medium = ta.valuewhen(
         highMediumCondition,
         time[rightBarsInput],
         1)[1]
    float high2Medium = ta.valuewhen(
         highMediumCondition,
         high[rightBarsInput],
         2)[1]
    int highTime2Medium = ta.valuewhen(
         highMediumCondition,
         time[rightBarsInput],
         2)[1]

    float low0Medium = ta.valuewhen(
         lowMediumCondition,
         low[rightBarsInput],
         0)[1]
    int lowTime0Medium = ta.valuewhen(
         lowMediumCondition,
         time[rightBarsInput],
         0)[1]
    float low1Medium = ta.valuewhen(
         lowMediumCondition,
         low[rightBarsInput],
         1)[1]
    int lowTime1Medium = ta.valuewhen(
         lowMediumCondition,
         time[rightBarsInput],
         1)[1]
    float low2Medium = ta.valuewhen(
         lowMediumCondition,
         low[rightBarsInput],
         2)[1]
    int lowTime2Medium = ta.valuewhen(
         lowMediumCondition,
         time[rightBarsInput],
         2)[1]

    bool highFastCondition =
         not na(ta.pivothigh(
             high,
             nFastInput,
             rightBarsInput))
    bool lowFastCondition =
         not na(ta.pivotlow(
             low,
             nFastInput,
             rightBarsInput))

    float high0Fast = useMultiNInput ?
         ta.valuewhen(
             highFastCondition,
             high[rightBarsInput],
             0)[1] : na
    int highTime0Fast = useMultiNInput ?
         ta.valuewhen(
             highFastCondition,
             time[rightBarsInput],
             0)[1] : na
    float high1Fast = useMultiNInput ?
         ta.valuewhen(
             highFastCondition,
             high[rightBarsInput],
             1)[1] : na
    int highTime1Fast = useMultiNInput ?
         ta.valuewhen(
             highFastCondition,
             time[rightBarsInput],
             1)[1] : na
    float high2Fast = useMultiNInput ?
         ta.valuewhen(
             highFastCondition,
             high[rightBarsInput],
             2)[1] : na
    int highTime2Fast = useMultiNInput ?
         ta.valuewhen(
             highFastCondition,
             time[rightBarsInput],
             2)[1] : na

    float low0Fast = useMultiNInput ?
         ta.valuewhen(
             lowFastCondition,
             low[rightBarsInput],
             0)[1] : na
    int lowTime0Fast = useMultiNInput ?
         ta.valuewhen(
             lowFastCondition,
             time[rightBarsInput],
             0)[1] : na
    float low1Fast = useMultiNInput ?
         ta.valuewhen(
             lowFastCondition,
             low[rightBarsInput],
             1)[1] : na
    int lowTime1Fast = useMultiNInput ?
         ta.valuewhen(
             lowFastCondition,
             time[rightBarsInput],
             1)[1] : na
    float low2Fast = useMultiNInput ?
         ta.valuewhen(
             lowFastCondition,
             low[rightBarsInput],
             2)[1] : na
    int lowTime2Fast = useMultiNInput ?
         ta.valuewhen(
             lowFastCondition,
             time[rightBarsInput],
             2)[1] : na

    [high0Medium, highTime0Medium,
     high1Medium, highTime1Medium,
     high2Medium, highTime2Medium,
     low0Medium, lowTime0Medium,
     low1Medium, lowTime1Medium,
     low2Medium, lowTime2Medium,
     high0Fast, highTime0Fast,
     high1Fast, highTime1Fast,
     high2Fast, highTime2Fast,
     low0Fast, lowTime0Fast,
     low1Fast, lowTime1Fast,
     low2Fast, lowTime2Fast]

reduceTopThreeByTime(
     float price0,
     int time0,
     float price1,
     int time1,
     float price2,
     int time2,
     float price3,
     int time3,
     float price4,
     int time4,
     float price5,
     int time5) =>
    array<float> prices = array.from(
         price0,
         price1,
         price2,
         price3,
         price4,
         price5)
    array<int> times = array.from(
         time0,
         time1,
         time2,
         time3,
         time4,
         time5)
    array<float> validPrices =
         array.new_float()
    array<int> validTimes =
         array.new_int()

    for index = 0 to 5
        float candidatePrice =
             prices.get(index)
        int candidateTime =
             times.get(index)
        if not na(candidatePrice) and
         not na(candidateTime) and
         candidateTime > 0
            bool duplicate = false
            int validCount =
                 validTimes.size()
            if validCount > 0
                for validIndex =
                 0 to validCount - 1
                    if math.abs(
                         candidateTime -
                         validTimes.get(
                             validIndex)) <
                         MINUTE_MS and
                     math.abs(
                         candidatePrice -
                         validPrices.get(
                             validIndex)) <
                         syminfo.mintick
                        duplicate := true
                        break
            if not duplicate
                validPrices.push(
                     candidatePrice)
                validTimes.push(
                     candidateTime)

    int sortCount = validTimes.size()
    if sortCount > 1
        for index = 1 to sortCount - 1
            int candidateTime =
                 validTimes.get(index)
            float candidatePrice =
                 validPrices.get(index)
            int insertionIndex = index - 1
            while insertionIndex >= 0 and
             validTimes.get(
                 insertionIndex) <
              candidateTime
                validTimes.set(
                     insertionIndex + 1,
                     validTimes.get(
                         insertionIndex))
                validPrices.set(
                     insertionIndex + 1,
                     validPrices.get(
                         insertionIndex))
                insertionIndex -= 1
            validTimes.set(
                 insertionIndex + 1,
                 candidateTime)
            validPrices.set(
                 insertionIndex + 1,
                 candidatePrice)

    float newestPrice = na
    int newestTime = na
    float priorPrice = na
    int priorTime = na
    float farPrice = na
    int farTime = na
    int resultCount = validTimes.size()
    if resultCount >= 1
        newestPrice := validPrices.get(0)
        newestTime := validTimes.get(0)
    if resultCount >= 2
        priorPrice := validPrices.get(1)
        priorTime := validTimes.get(1)
    if resultCount >= 3
        farPrice := validPrices.get(2)
        farTime := validTimes.get(2)
    [newestPrice,
     newestTime,
     priorPrice,
     priorTime,
     farPrice,
     farTime]

median3(float a, float b, float c) =>
    a + b + c -
     math.min(a, math.min(b, c)) -
     math.max(a, math.max(b, c))

mad3(float a, float b, float c, float center) =>
    median3(
         math.abs(a - center),
         math.abs(b - center),
         math.abs(c - center))

medianSorted(array<float> values) =>
    int count = values.size()
    float result = na
    if count > 0
        int middle = int(math.floor(count / 2.0))
        result := count % 2 == 1 ?
             values.get(middle) :
             math.avg(
                 values.get(middle - 1),
                 values.get(middle))
    result

timeText(int value) =>
    na(value) ? "NA" :
     str.format_time(
         value,
         "yyyy-MM-dd HH:mm",
         syminfo.timezone)

floatText(float value) =>
    na(value) ? "NA" :
     str.tostring(value, "#.########")

clearLines(array<line> drawings) =>
    int count = drawings.size()
    if count > 0
        for index = 0 to count - 1
            line.delete(drawings.get(index))
    drawings.clear()

clearLabels(array<label> drawings) =>
    int count = drawings.size()
    if count > 0
        for index = 0 to count - 1
            label.delete(drawings.get(index))
    drawings.clear()

diagnosticRow(
     table target,
     int row,
     string key,
     string value,
     color background) =>
    table.cell(
         target,
         0,
         row,
         key,
         text_color = color.silver,
         text_size = size.tiny,
         bgcolor = background,
         text_halign = text.align_left)
    table.cell(
         target,
         1,
         row,
         value,
         text_color = color.white,
         text_size = size.tiny,
         bgcolor = background,
         text_halign = text.align_left)

boundedPut(
     map<int, float> bins,
     int key,
     float addedVolume,
     int currentMin,
     int currentMax) =>
    bool alreadyPresent = bins.contains(key)
    int candidateMin = na(currentMin) ?
         key : math.min(currentMin, key)
    int candidateMax = na(currentMax) ?
         key : math.max(currentMax, key)
    bool overflow =
         candidateMax - candidateMin + 1 >
          MAX_PROFILE_BINS or
         (not alreadyPresent and
          bins.size() >= MAX_PROFILE_BINS)
    int nextMin = currentMin
    int nextMax = currentMax
    if not overflow
        bins.put(
             key,
             binVolume(bins, key) + addedVolume)
        nextMin := candidateMin
        nextMax := candidateMax
    [nextMin, nextMax, overflow]

allocateBarToGrid(
     map<int, float> bins,
     int sourceLow,
     int sourceHigh,
     float sourceVolume,
     int rowTicks,
     int currentMin,
     int currentMax) =>
    int nextMin = currentMin
    int nextMax = currentMax
    float allocatedTotal = 0.0
    bool overflow = false
    int touchCount = 0
    int sourceTickCount =
         sourceHigh - sourceLow + 1
    int sourceLowBin = int(math.floor(
         (sourceLow - GRID_ORIGIN_TICKS) /
         float(rowTicks)))
    int sourceHighBin = int(math.floor(
         (sourceHigh - GRID_ORIGIN_TICKS) /
         float(rowTicks)))
    if sourceTickCount > 0
        for outputBin =
         sourceLowBin to sourceHighBin
            int binLowTick =
                 GRID_ORIGIN_TICKS +
                 outputBin * rowTicks
            int binHighTick =
                 binLowTick + rowTicks - 1
            int overlapLow =
                 math.max(sourceLow, binLowTick)
            int overlapHigh =
                 math.min(sourceHigh, binHighTick)
            int overlapTicks =
                 math.max(
                     0,
                     overlapHigh -
                     overlapLow + 1)
            if overlapTicks > 0
                float allocatedVolume =
                     sourceVolume *
                     overlapTicks /
                     sourceTickCount
                [putMin,
                 putMax,
                 putOverflow] =
                     boundedPut(
                         bins,
                         outputBin,
                         allocatedVolume,
                         nextMin,
                         nextMax)
                nextMin := putMin
                nextMax := putMax
                overflow :=
                     overflow or putOverflow
                allocatedTotal +=
                     allocatedVolume
                touchCount += 1
    [nextMin,
     nextMax,
     allocatedTotal,
     overflow,
     touchCount]

betterConsensusCombination(
     int support,
     float minimumZ,
     int totalDistance,
     int incumbentSupport,
     float incumbentMinimumZ,
     int incumbentDistance) =>
    support > incumbentSupport or
     (
         support == incumbentSupport and
         minimumZ > incumbentMinimumZ) or
     (
         support == incumbentSupport and
         minimumZ == incumbentMinimumZ and
         totalDistance < incumbentDistance)

calculateProfile(
     map<int, float> bins,
     int minBin,
     int maxBin,
     float totalVolume,
     int rowTicks) =>
    bool valid =
         not na(minBin) and
         not na(maxBin) and
         maxBin >= minBin and
         maxBin - minBin + 1 <= MAX_PROFILE_BINS and
         bins.size() > 0 and
         totalVolume > 0.0
    int pocBin = na
    int valueAreaLowBin = na
    int valueAreaHighBin = na
    float achievedPercent = na
    float maximumVolume = na

    if valid
        float weightedCenter2 = 0.0
        for bin = minBin to maxBin
            float volumeAtBin = binVolume(bins, bin)
            int center2 =
                 2 * (
                     GRID_ORIGIN_TICKS +
                     bin * rowTicks) +
                 rowTicks
            weightedCenter2 +=
                 volumeAtBin * center2
            maximumVolume := na(maximumVolume) ?
                 volumeAtBin :
                 math.max(
                     maximumVolume,
                     volumeAtBin)

        float meanCenter2 =
             weightedCenter2 / totalVolume
        float bestDistance = na
        float tieTolerance = math.max(
             0.000000001,
             math.abs(maximumVolume) *
              0.000000000001)
        for bin = minBin to maxBin
            float volumeAtBin =
                 binVolume(bins, bin)
            if math.abs(
                 volumeAtBin -
                 maximumVolume) <= tieTolerance
                int center2 =
                     2 * (
                         GRID_ORIGIN_TICKS +
                         bin * rowTicks) +
                     rowTicks
                float distance =
                     math.abs(center2 - meanCenter2)
                if na(bestDistance) or
                 distance <
                  bestDistance - 0.000000001 or
                 (math.abs(
                      distance -
                      bestDistance) <=
                   0.000000001 and
                  bin < pocBin)
                    pocBin := bin
                    bestDistance := distance

        if not na(pocBin)
            valueAreaLowBin := pocBin
            valueAreaHighBin := pocBin
            float includedVolume =
                 binVolume(bins, pocBin)
            float targetVolume =
                 totalVolume *
                 valueAreaPercentInput /
                 100.0
            float tolerance = math.max(
                 0.000000001,
                 math.abs(totalVolume) *
                  0.000000000001)
            int steps = 0
            while includedVolume <
             targetVolume - tolerance and
             steps < MAX_PROFILE_BINS
                bool hasLower =
                     valueAreaLowBin > minBin
                bool hasUpper =
                     valueAreaHighBin < maxBin
                if not hasLower and not hasUpper
                    break
                int lowerCandidate =
                     valueAreaLowBin - 1
                int upperCandidate =
                     valueAreaHighBin + 1
                float lowerVolume = hasLower ?
                     binVolume(
                         bins,
                         lowerCandidate) : na
                float upperVolume = hasUpper ?
                     binVolume(
                         bins,
                         upperCandidate) : na
                bool chooseUpper = not hasLower
                if hasLower and hasUpper
                    chooseUpper :=
                         upperVolume >
                          lowerVolume or
                         (upperVolume ==
                           lowerVolume and
                          math.abs(
                              upperCandidate -
                              pocBin) <=
                           math.abs(
                               lowerCandidate -
                               pocBin))
                float selectedVolume =
                     chooseUpper ?
                     upperVolume : lowerVolume
                if includedVolume +
                 selectedVolume >
                 targetVolume + tolerance
                    break
                if chooseUpper
                    valueAreaHighBin :=
                         upperCandidate
                else
                    valueAreaLowBin :=
                         lowerCandidate
                includedVolume += selectedVolume
                steps += 1
            achievedPercent :=
                 includedVolume /
                 totalVolume *
                 100.0

    [valid and not na(pocBin),
     pocBin,
     valueAreaLowBin,
     valueAreaHighBin,
     achievedPercent,
     maximumVolume]

scoreGatedCandidates(
     map<int, float> bins,
     int minBin,
     int maxBin,
     int rowTicks,
     float maximumVolume,
     float minimumRatio,
     float maximumNoiseFraction,
     float minimumDenseFraction,
     float minimumRobustZ,
     int localClusterRows,
     int candidateCap) =>
    array<int> rawBins = array.new_int()
    array<float> rawJumps = array.new_float()
    array<float> rawNoise = array.new_float()
    array<float> rawClean = array.new_float()
    array<float> rawRatios = array.new_float()
    array<float> rawDenseVolumes =
         array.new_float()
    array<float> rawZ = array.new_float()
    array<int> rawDenseDirections =
         array.new_int()
    array<float> positiveVolumes =
         array.new_float()
    array<int> selectedTicks = array.new_int()
    array<float> selectedClean =
         array.new_float()
    array<float> selectedZ =
         array.new_float()
    array<int> selectedDenseDirections =
         array.new_int()
    float cleanMad = na

    if not na(minBin) and
     not na(maxBin) and
     not na(maximumVolume) and
     maximumVolume > 0.0
        for bin = minBin to maxBin
            float volumeAtBin =
                 binVolume(bins, bin)
            if volumeAtBin > 0.0
                positiveVolumes.push(
                     volumeAtBin)
        positiveVolumes.sort(order.ascending)
        float logEpsilon =
             positiveVolumes.size() > 0 ?
             math.max(
                 medianSorted(
                     positiveVolumes) *
                  0.01,
                 0.000000001) : na

        int firstBoundary =
             minBin + SHELF_SIDE_ROWS
        int lastBoundary =
             maxBin - SHELF_SIDE_ROWS + 1
        if not na(logEpsilon) and
         firstBoundary <= lastBoundary
            for boundary =
             firstBoundary to lastBoundary
                float l0 = math.log(
                     binVolume(
                         bins,
                         boundary - 3) +
                     logEpsilon)
                float l1 = math.log(
                     binVolume(
                         bins,
                         boundary - 2) +
                     logEpsilon)
                float l2 = math.log(
                     binVolume(
                         bins,
                         boundary - 1) +
                     logEpsilon)
                float r0 = math.log(
                     binVolume(
                         bins,
                         boundary) +
                     logEpsilon)
                float r1 = math.log(
                     binVolume(
                         bins,
                         boundary + 1) +
                     logEpsilon)
                float r2 = math.log(
                     binVolume(
                         bins,
                         boundary + 2) +
                     logEpsilon)
                float leftMedian =
                     median3(l0, l1, l2)
                float rightMedian =
                     median3(r0, r1, r2)
                float jump = math.abs(
                     rightMedian -
                     leftMedian)
                float noise =
                     mad3(
                         l0,
                         l1,
                         l2,
                         leftMedian) +
                     mad3(
                         r0,
                         r1,
                         r2,
                         rightMedian)
                float cleanJump =
                     math.max(
                         0.0,
                         jump - noise)
                float denseVolume =
                     math.max(
                         0.0,
                         math.exp(
                             math.max(
                                 leftMedian,
                                 rightMedian)) -
                         logEpsilon)
                rawBins.push(boundary)
                rawJumps.push(jump)
                rawNoise.push(noise)
                rawClean.push(cleanJump)
                rawRatios.push(
                     math.exp(jump))
                rawDenseVolumes.push(
                     denseVolume)
                rawDenseDirections.push(
                     rightMedian >
                      leftMedian ? 1 : -1)

        if rawClean.size() > 0
            array<float> cleanSorted =
                 rawClean.copy()
            cleanSorted.sort(order.ascending)
            float cleanMedian =
                 medianSorted(cleanSorted)
            array<float> deviations =
                 array.new_float()
            for index =
             0 to rawClean.size() - 1
                deviations.push(
                     math.abs(
                         rawClean.get(index) -
                         cleanMedian))
            deviations.sort(order.ascending)
            cleanMad :=
                 medianSorted(deviations)
            float robustScale =
                 math.max(
                     1.4826 * cleanMad,
                     0.000000001)
            for index =
             0 to rawClean.size() - 1
                rawZ.push(
                     (
                         rawClean.get(index) -
                         cleanMedian) /
                     robustScale)

    array<int> rankedIndices =
         array.new_int()
    array<bool> consumed =
         array.new_bool(
             rawClean.size(),
             false)
    int rankLimit = math.min(
         rawClean.size(),
         MAX_RANKED_DIAGNOSTICS)
    if rankLimit > 0
        for rank = 0 to rankLimit - 1
            int bestIndex = -1
            float bestClean = na
            int bestBoundary = na
            for index =
             0 to rawClean.size() - 1
                if not consumed.get(index)
                    float candidateClean =
                         rawClean.get(index)
                    int candidateBoundary =
                         rawBins.get(index)
                    if na(bestClean) or
                     candidateClean > bestClean or
                     (candidateClean ==
                       bestClean and
                      candidateBoundary <
                       bestBoundary)
                        bestIndex := index
                        bestClean :=
                             candidateClean
                        bestBoundary :=
                             candidateBoundary
            if bestIndex >= 0
                consumed.set(
                     bestIndex,
                     true)
                rankedIndices.push(
                     bestIndex)

    if rankedIndices.size() > 0
        for rankedPosition =
         0 to rankedIndices.size() - 1
            int index =
                 rankedIndices.get(
                     rankedPosition)
            bool passes =
                 rawRatios.get(index) >=
                  minimumRatio and
                 rawNoise.get(index) <=
                  maximumNoiseFraction *
                  rawJumps.get(index) and
                 rawDenseVolumes.get(index) >=
                  minimumDenseFraction *
                  maximumVolume and
                 rawZ.get(index) >=
                  minimumRobustZ
            int boundary =
                 rawBins.get(index)
            bool clustered = false
            if passes and
             selectedTicks.size() > 0
                for selectedIndex =
                 0 to selectedTicks.size() - 1
                    int selectedBoundary =
                         int(math.round(
                             selectedTicks.get(
                                 selectedIndex) /
                             float(rowTicks)))
                    if math.abs(
                         boundary -
                         selectedBoundary) <=
                         localClusterRows
                        clustered := true
                        break
            if passes and
             not clustered and
             selectedTicks.size() <
              candidateCap
                selectedTicks.push(
                     GRID_ORIGIN_TICKS +
                     boundary * rowTicks)
                selectedClean.push(
                     rawClean.get(index))
                selectedZ.push(
                     rawZ.get(index))
                selectedDenseDirections.push(
                     rawDenseDirections.get(
                         index))

    [selectedTicks,
     selectedClean,
     selectedZ,
     selectedDenseDirections,
     rawClean.size(),
     cleanMad]

profileLogEpsilon(
     map<int, float> bins,
     int minBin,
     int maxBin) =>
    array<float> positiveVolumes =
         array.new_float()
    if not na(minBin) and
     not na(maxBin) and
     minBin <= maxBin
        for bin = minBin to maxBin
            float volumeAtBin =
                 binVolume(bins, bin)
            if volumeAtBin > 0.0
                positiveVolumes.push(
                     volumeAtBin)
    positiveVolumes.sort(order.ascending)
    positiveVolumes.size() > 0 ?
     math.max(
         medianSorted(
             positiveVolumes) *
          0.01,
         0.000000001) : na

boundaryGeometry(
     map<int, float> bins,
     int boundary,
     float logEpsilon) =>
    float l0 = math.log(
         binVolume(
             bins,
             boundary - 3) +
         logEpsilon)
    float l1 = math.log(
         binVolume(
             bins,
             boundary - 2) +
         logEpsilon)
    float l2 = math.log(
         binVolume(
             bins,
             boundary - 1) +
         logEpsilon)
    float r0 = math.log(
         binVolume(
             bins,
             boundary) +
         logEpsilon)
    float r1 = math.log(
         binVolume(
             bins,
             boundary + 1) +
         logEpsilon)
    float r2 = math.log(
         binVolume(
             bins,
             boundary + 2) +
         logEpsilon)
    float leftMedian =
         median3(l0, l1, l2)
    float rightMedian =
         median3(r0, r1, r2)
    float jump = math.abs(
         rightMedian -
         leftMedian)
    float noise =
         mad3(
             l0,
             l1,
             l2,
             leftMedian) +
         mad3(
             r0,
             r1,
             r2,
             rightMedian)
    float clean =
         math.max(
             0.0,
             jump - noise)
    int denseDirection =
         rightMedian >
          leftMedian ? 1 : -1
    [leftMedian,
     rightMedian,
     clean,
     denseDirection]

smoothedLogVolume(
     map<int, float> bins,
     int row,
     float logEpsilon) =>
    median3(
         math.log(
             binVolume(
                 bins,
                 row - 1) +
             logEpsilon),
         math.log(
             binVolume(
                 bins,
                 row) +
             logEpsilon),
         math.log(
             binVolume(
                 bins,
                 row + 1) +
             logEpsilon))

traceNodeMate(
     map<int, float> bins,
     int minBin,
     int maxBin,
     int rowTicks,
     int anchorTick,
     int retainedDenseDirection,
     float maximumWidthTicks,
     float logEpsilon) =>
    bool pairValid = false
    int mateTick = na
    float prominence = na
    int widthRows = 0
    int boundary = int(math.round(
         (
             anchorTick -
             GRID_ORIGIN_TICKS) /
         float(rowTicks)))
    int firstBoundary =
         minBin + SHELF_SIDE_ROWS
    int lastBoundary =
         maxBin - SHELF_SIDE_ROWS + 1
    int maximumWidthRows =
         math.max(
             MIN_NODE_ROWS,
             int(math.floor(
                 maximumWidthTicks /
                 rowTicks)))

    if not na(logEpsilon) and
     (
         retainedDenseDirection == 1 or
         retainedDenseDirection == -1) and
     boundary >= firstBoundary and
     boundary <= lastBoundary
        [anchorLeft,
         anchorRight,
         anchorClean,
         anchorDirection] =
             boundaryGeometry(
                 bins,
                 boundary,
                 logEpsilon)
        float thinAnchor =
             retainedDenseDirection == 1 ?
             anchorLeft :
             anchorRight
        float denseAnchor =
             retainedDenseDirection == 1 ?
             anchorRight :
             anchorLeft
        int firstDenseRow =
             retainedDenseDirection == 1 ?
             boundary :
             boundary - 1
        bool anchorConsistent =
             anchorClean > 0.0 and
             anchorDirection ==
              retainedDenseDirection and
             denseAnchor >
              thinAnchor and
             smoothedLogVolume(
                 bins,
                 firstDenseRow,
                 logEpsilon) >=
              thinAnchor

        if anchorConsistent
            int candidateWidth =
                 MIN_NODE_ROWS
            bool searching = true
            while searching and
             candidateWidth <=
              maximumWidthRows
                int exitBoundary =
                     boundary +
                     retainedDenseDirection *
                      candidateWidth
                int nearBoundary =
                     boundary +
                     retainedDenseDirection *
                      (
                          candidateWidth -
                          1)
                int farBoundary =
                     boundary +
                     retainedDenseDirection *
                      (
                          candidateWidth +
                          1)
                bool tripletHasContext =
                     nearBoundary >=
                      firstBoundary and
                     nearBoundary <=
                      lastBoundary and
                     exitBoundary >=
                      firstBoundary and
                     exitBoundary <=
                      lastBoundary and
                     farBoundary >=
                      firstBoundary and
                     farBoundary <=
                      lastBoundary
                if not tripletHasContext
                    searching := false
                else
                    [nearLeft,
                     nearRight,
                     nearClean,
                     nearDenseDirection] =
                         boundaryGeometry(
                             bins,
                             nearBoundary,
                             logEpsilon)
                    [exitLeft,
                     exitRight,
                     exitClean,
                     exitDenseDirection] =
                         boundaryGeometry(
                             bins,
                             exitBoundary,
                             logEpsilon)
                    [farLeft,
                     farRight,
                     farClean,
                     farDenseDirection] =
                         boundaryGeometry(
                             bins,
                             farBoundary,
                             logEpsilon)
                    float nearOppositeClean =
                         nearDenseDirection ==
                          -retainedDenseDirection ?
                         nearClean : 0.0
                    float exitOppositeClean =
                         exitDenseDirection ==
                          -retainedDenseDirection ?
                         exitClean : 0.0
                    float farOppositeClean =
                         farDenseDirection ==
                          -retainedDenseDirection ?
                         farClean : 0.0
                    bool localOppositePeak =
                         exitOppositeClean >=
                          anchorClean *
                           MIN_MATE_TO_ANCHOR_CLEAN and
                         exitOppositeClean >=
                          nearOppositeClean and
                         exitOppositeClean >=
                          farOppositeClean and
                         (
                             exitOppositeClean >
                              nearOppositeClean or
                             exitOppositeClean >
                              farOppositeClean) and
                         exitDenseDirection ==
                          -retainedDenseDirection
                    if localOppositePeak
                        // The nearest material peak owns the local decision.
                        // If it does not enclose a bulge, do not jump across it
                        // to manufacture a broader composite pair.
                        searching := false
                        array<float> interior =
                             array.new_float()
                        for interiorIndex =
                         0 to candidateWidth - 1
                            int interiorRow =
                                 firstDenseRow +
                                 retainedDenseDirection *
                                  interiorIndex
                            interior.push(
                                 smoothedLogVolume(
                                     bins,
                                     interiorRow,
                                     logEpsilon))
                        interior.sort(
                             order.ascending)
                        float interiorMedian =
                             medianSorted(interior)
                        float mateExterior =
                             retainedDenseDirection == 1 ?
                             exitRight :
                             exitLeft
                        float localProminence =
                             interiorMedian -
                             math.max(
                                 thinAnchor,
                                 mateExterior)
                        if localProminence > 0.0
                            pairValid := true
                            mateTick :=
                                 GRID_ORIGIN_TICKS +
                                 exitBoundary *
                                  rowTicks
                            prominence :=
                                 localProminence
                            widthRows :=
                                 candidateWidth
                    candidateWidth += 1

    [pairValid,
     mateTick,
     prominence,
     widthRows]

betterNode(
     int support,
     float worstProminence,
     float minimumZ,
     int incumbentSupport,
     float incumbentWorstProminence,
     float incumbentMinimumZ) =>
    support > incumbentSupport or
     (
         support == incumbentSupport and
         (
             na(incumbentWorstProminence) or
             worstProminence >
              incumbentWorstProminence)) or
     (
         support == incumbentSupport and
         worstProminence ==
          incumbentWorstProminence and
         (
             na(incumbentMinimumZ) or
             minimumZ >
              incumbentMinimumZ))


// ============================================================================
// CONFIRMED RSD MACRO RANGE AND RETROSPECTIVE 15-MINUTE PROFILE CACHE
// ============================================================================

[macroHigh0Medium,
 macroHighTime0Medium,
 macroHigh1Medium,
 macroHighTime1Medium,
 macroHigh2Medium,
 macroHighTime2Medium,
 macroLow0Medium,
 macroLowTime0Medium,
 macroLow1Medium,
 macroLowTime1Medium,
 macroLow2Medium,
 macroLowTime2Medium,
 macroHigh0Fast,
 macroHighTime0Fast,
 macroHigh1Fast,
 macroHighTime1Fast,
 macroHigh2Fast,
 macroHighTime2Fast,
 macroLow0Fast,
 macroLowTime0Fast,
 macroLow1Fast,
 macroLowTime1Fast,
 macroLow2Fast,
 macroLowTime2Fast] = request.security(
     syminfo.tickerid,
     macroTFInput,
     findMacroPivots(),
     lookahead = barmerge.lookahead_on)

[macroOuterHigh,
 macroOuterHighTime,
 macroPriorHigh,
 macroPriorHighTime,
 macroFarHigh,
 macroFarHighTime] = reduceTopThreeByTime(
     macroHigh0Medium,
     macroHighTime0Medium,
     macroHigh1Medium,
     macroHighTime1Medium,
     macroHigh2Medium,
     macroHighTime2Medium,
     macroHigh0Fast,
     macroHighTime0Fast,
     macroHigh1Fast,
     macroHighTime1Fast,
     macroHigh2Fast,
     macroHighTime2Fast)

[macroOuterLow,
 macroOuterLowTime,
 macroPriorLow,
 macroPriorLowTime,
 macroFarLow,
 macroFarLowTime] = reduceTopThreeByTime(
     macroLow0Medium,
     macroLowTime0Medium,
     macroLow1Medium,
     macroLowTime1Medium,
     macroLow2Medium,
     macroLowTime2Medium,
     macroLow0Fast,
     macroLowTime0Fast,
     macroLow1Fast,
     macroLowTime1Fast,
     macroLow2Fast,
     macroLowTime2Fast)

resolveAutomaticRange(float currentAtr) =>
    float maximumSlopeAbsolute =
         maximumWallSlopeInput *
         nz(currentAtr, 0.0)

    bool primaryHighWall =
         not na(macroOuterHigh) and
         not na(macroOuterHighTime) and
         not na(macroPriorHigh) and
         not na(macroPriorHighTime) and
         macroOuterHigh > macroPriorHigh
    bool shiftedHighWall =
         not primaryHighWall and
         not na(macroPriorHigh) and
         not na(macroPriorHighTime) and
         not na(macroFarHigh) and
         not na(macroFarHighTime) and
         macroPriorHigh > macroFarHigh
    bool primaryLowWall =
         not na(macroOuterLow) and
         not na(macroOuterLowTime) and
         not na(macroPriorLow) and
         not na(macroPriorLowTime) and
         macroOuterLow < macroPriorLow
    bool shiftedLowWall =
         not primaryLowWall and
         not na(macroPriorLow) and
         not na(macroPriorLowTime) and
         not na(macroFarLow) and
         not na(macroFarLowTime) and
         macroPriorLow < macroFarLow

    bool highExpansion =
         not na(macroOuterHigh) and
         not na(macroPriorHigh) and
         not na(macroFarHigh) and
         math.max(
             macroOuterHigh,
             macroPriorHigh) >
          macroFarHigh
    bool lowExpansion =
         not na(macroOuterLow) and
         not na(macroPriorLow) and
         not na(macroFarLow) and
         math.min(
             macroOuterLow,
             macroPriorLow) <
          macroFarLow
    bool wallsAllowed =
         not wallRequireBothSidesInput or
         (highExpansion and lowExpansion)

    bool upperCandidateValid = false
    int upperStartTime = na
    int upperEndTime = na
    float upperStartPrice = na
    float upperEndPrice = na
    bool lowerCandidateValid = false
    int lowerStartTime = na
    int lowerEndTime = na
    float lowerStartPrice = na
    float lowerEndPrice = na

    if wallsAllowed and primaryHighWall
        int outerBar =
             htfTimeToBar(macroOuterHighTime)
        int priorBar =
             htfTimeToBar(macroPriorHighTime)
        bool haveFar =
             not na(macroFarHigh) and
             not na(macroFarHighTime) and
             macroFarHigh < macroOuterHigh
        bool useFar = haveFar
        if haveFar
            int farBar =
                 htfTimeToBar(macroFarHighTime)
            if farBar != outerBar
                float spanSlope =
                     (macroOuterHigh -
                      macroFarHigh) /
                     (outerBar - farBar)
                float lineAtPrior =
                     macroFarHigh +
                     spanSlope *
                     (priorBar - farBar)
                useFar :=
                     macroPriorHigh <=
                     lineAtPrior +
                     syminfo.mintick
        float anchorPrice =
             useFar ?
             macroFarHigh :
             macroPriorHigh
        int anchorTime =
             useFar ?
             macroFarHighTime :
             macroPriorHighTime
        int anchorBar =
             htfTimeToBar(anchorTime)
        if anchorBar != outerBar
            float slope =
                 (macroOuterHigh -
                  anchorPrice) /
                 (outerBar - anchorBar)
            upperCandidateValid :=
                 not hideSteepWallsInput or
                 math.abs(slope) <=
                  maximumSlopeAbsolute
            upperStartTime := anchorTime
            upperEndTime := macroOuterHighTime
            upperStartPrice := anchorPrice
            upperEndPrice := macroOuterHigh
    else if wallsAllowed and shiftedHighWall
        int anchorBar =
             htfTimeToBar(macroFarHighTime)
        int endBar =
             htfTimeToBar(macroPriorHighTime)
        if anchorBar != endBar
            float slope =
                 (macroPriorHigh -
                  macroFarHigh) /
                 (endBar - anchorBar)
            upperCandidateValid :=
                 not hideSteepWallsInput or
                 math.abs(slope) <=
                  maximumSlopeAbsolute
            upperStartTime := macroFarHighTime
            upperEndTime := macroPriorHighTime
            upperStartPrice := macroFarHigh
            upperEndPrice := macroPriorHigh

    if wallsAllowed and primaryLowWall
        int outerBar =
             htfTimeToBar(macroOuterLowTime)
        int priorBar =
             htfTimeToBar(macroPriorLowTime)
        bool haveFar =
             not na(macroFarLow) and
             not na(macroFarLowTime) and
             macroFarLow > macroOuterLow
        bool useFar = haveFar
        if haveFar
            int farBar =
                 htfTimeToBar(macroFarLowTime)
            if farBar != outerBar
                float spanSlope =
                     (macroOuterLow -
                      macroFarLow) /
                     (outerBar - farBar)
                float lineAtPrior =
                     macroFarLow +
                     spanSlope *
                     (priorBar - farBar)
                useFar :=
                     macroPriorLow >=
                     lineAtPrior -
                     syminfo.mintick
        float anchorPrice =
             useFar ?
             macroFarLow :
             macroPriorLow
        int anchorTime =
             useFar ?
             macroFarLowTime :
             macroPriorLowTime
        int anchorBar =
             htfTimeToBar(anchorTime)
        if anchorBar != outerBar
            float slope =
                 (macroOuterLow -
                  anchorPrice) /
                 (outerBar - anchorBar)
            lowerCandidateValid :=
                 not hideSteepWallsInput or
                 math.abs(slope) <=
                  maximumSlopeAbsolute
            lowerStartTime := anchorTime
            lowerEndTime := macroOuterLowTime
            lowerStartPrice := anchorPrice
            lowerEndPrice := macroOuterLow
    else if wallsAllowed and shiftedLowWall
        int anchorBar =
             htfTimeToBar(macroFarLowTime)
        int endBar =
             htfTimeToBar(macroPriorLowTime)
        if anchorBar != endBar
            float slope =
                 (macroPriorLow -
                  macroFarLow) /
                 (endBar - anchorBar)
            lowerCandidateValid :=
                 not hideSteepWallsInput or
                 math.abs(slope) <=
                  maximumSlopeAbsolute
            lowerStartTime := macroFarLowTime
            lowerEndTime := macroPriorLowTime
            lowerStartPrice := macroFarLow
            lowerEndPrice := macroPriorLow

    bool useLowerCandidate =
         lowerCandidateValid and
         (
             not upperCandidateValid or
             lowerEndTime > upperEndTime or
             (
                 lowerEndTime == upperEndTime and
                 lowerEndTime - lowerStartTime >=
                  upperEndTime - upperStartTime))
    bool wallSelected =
         upperCandidateValid or
         lowerCandidateValid
    int selectedSide =
         useLowerCandidate ? -1 : 1
    int selectedStartMacroTime =
         useLowerCandidate ?
         lowerStartTime :
         upperStartTime
    int selectedEndMacroTime =
         useLowerCandidate ?
         lowerEndTime :
         upperEndTime
    float selectedStartPrice =
         useLowerCandidate ?
         lowerStartPrice :
         upperStartPrice
    float selectedEndPrice =
         useLowerCandidate ?
         lowerEndPrice :
         upperEndPrice
    int selectedStartTime = na
    int selectedEndBarTime = na
    bool startRefined = false
    bool endRefined = false
    int macroDurationMs = int(
         timeframe.in_seconds(
             macroTFInput) * 1000)

    if wallSelected
        int refinementBars =
             math.min(bar_index, 4999)
        for offset = 0 to refinementBars
            bool inStartMacroBar =
                 time[offset] >=
                  selectedStartMacroTime and
                 time[offset] <
                  selectedStartMacroTime +
                  macroDurationMs
            bool inEndMacroBar =
                 time[offset] >=
                  selectedEndMacroTime and
                 time[offset] <
                  selectedEndMacroTime +
                  macroDurationMs
            bool startPriceMatch =
                 selectedSide < 0 ?
                 priceToTicks(low[offset]) ==
                  priceToTicks(selectedStartPrice) :
                 priceToTicks(high[offset]) ==
                  priceToTicks(selectedStartPrice)
            bool endPriceMatch =
                 selectedSide < 0 ?
                 priceToTicks(low[offset]) ==
                  priceToTicks(selectedEndPrice) :
                 priceToTicks(high[offset]) ==
                  priceToTicks(selectedEndPrice)
            if inStartMacroBar and
             startPriceMatch
                selectedStartTime := time[offset]
                startRefined := true
            if inEndMacroBar and
             endPriceMatch
                selectedEndBarTime := time[offset]
                endRefined := true

    int selectedEndExclusive =
         endRefined ?
         selectedEndBarTime +
          PROFILE_BAR_MS : na
    bool endpointRefined =
         wallSelected and
         startRefined and
         endRefined and
         selectedStartTime <
          selectedEndExclusive
    [wallSelected,
     endpointRefined,
     selectedSide,
     selectedStartMacroTime,
     selectedEndMacroTime,
     selectedStartTime,
     selectedEndBarTime,
     selectedEndExclusive,
     selectedStartPrice,
     selectedEndPrice,
     wallsAllowed]

bool chartSupported =
     chart.is_standard and
     timeframe.isminutes and
     timeframe.in_seconds() ==
      15 * 60
float chartAtr = ta.atr(14)
bool selectorTupleChanged =
     barstate.isfirst or
     nz(macroOuterHighTime, -1) !=
      nz(macroOuterHighTime[1], -1) or
     nz(macroPriorHighTime, -1) !=
      nz(macroPriorHighTime[1], -1) or
     nz(macroFarHighTime, -1) !=
      nz(macroFarHighTime[1], -1) or
     nz(macroOuterLowTime, -1) !=
      nz(macroOuterLowTime[1], -1) or
     nz(macroPriorLowTime, -1) !=
      nz(macroPriorLowTime[1], -1) or
     nz(macroFarLowTime, -1) !=
      nz(macroFarLowTime[1], -1)
float selectorAtr = nz(
     ta.valuewhen(
         selectorTupleChanged,
         chartAtr[1],
         0),
     chartAtr)

var map<int, float> fineBins =
     map.new<int, float>()
var map<int, float> baseBins =
     map.new<int, float>()
var map<int, float> coarseBins =
     map.new<int, float>()

var int fineMinBin = na
var int fineMaxBin = na
var int baseMinBin = na
var int baseMaxBin = na
var int coarseMinBin = na
var int coarseMaxBin = na
var int fineTicks = na
var int effectiveBaseTicks = na
var int coarseTicks = na
var bool gridConfigurationValid = false

var float sourceTotalVolume = 0.0
var float fineAllocatedVolume = 0.0
var float baseAllocatedVolume = 0.0
var float coarseAllocatedVolume = 0.0
var int includedSourceBars = 0
var int firstIncludedSourceTime = na
var int lastIncludedSourceTime = na
var int previousIncludedSourceTime = na
var int invalidSourceBars = 0
var bool sourceOrderIssue = false
var bool fineOverflow = false
var bool baseOverflow = false
var bool coarseOverflow = false
var bool rangeHistoryCovered = false
var bool rangeTooLong = false
var bool allocationWorkCapFail = false
var int allocationTouches = 0
var float cachedOutlineHigh = na
var float cachedOutlineLow = na

var bool cacheInitialized = false
var bool cachedWallSelected = false
var bool cachedEndpointRefined = false
var bool cachedWallsAllowed = false
var int cachedSide = 0
var int cachedStartMacroTime = na
var int cachedEndMacroTime = na
var int cachedProfileStartTime = na
var int cachedProfileEndBarTime = na
var int cachedProfileEndExclusive = na
var float cachedStartPrice = na
var float cachedEndPrice = na

bool rebuildTrigger =
     barstate.islastconfirmedhistory or
     (barstate.islast and barstate.isconfirmed)

if rebuildTrigger
    [rebuildWallSelected,
     rebuildEndpointRefined,
     rebuildSide,
     rebuildStartMacroTime,
     rebuildEndMacroTime,
     rebuildStartTime,
     rebuildEndBarTime,
     rebuildEndExclusive,
     rebuildStartPrice,
     rebuildEndPrice,
     rebuildWallsAllowed] =
         resolveAutomaticRange(selectorAtr)
    bool rangeIdentityChanged =
         not cacheInitialized or
         rebuildWallSelected !=
          cachedWallSelected or
         rebuildWallsAllowed !=
          cachedWallsAllowed or
         rebuildEndpointRefined !=
          cachedEndpointRefined or
         rebuildSide != cachedSide or
         rebuildStartMacroTime !=
          cachedStartMacroTime or
         rebuildEndMacroTime !=
          cachedEndMacroTime or
         nz(rebuildStartTime, -1) !=
          nz(cachedProfileStartTime, -1) or
         nz(rebuildEndBarTime, -1) !=
          nz(cachedProfileEndBarTime, -1) or
         nz(rebuildEndExclusive, -1) !=
          nz(cachedProfileEndExclusive, -1) or
         (
             rebuildEndpointRefined and
             cachedEndpointRefined and
             (
                 priceToTicks(
                     rebuildStartPrice) !=
                  priceToTicks(
                     cachedStartPrice) or
                 priceToTicks(
                     rebuildEndPrice) !=
                  priceToTicks(
                     cachedEndPrice)))

    if rangeIdentityChanged
        fineBins.clear()
        baseBins.clear()
        coarseBins.clear()
        fineMinBin := na
        fineMaxBin := na
        baseMinBin := na
        baseMaxBin := na
        coarseMinBin := na
        coarseMaxBin := na
        fineTicks := na
        effectiveBaseTicks := na
        coarseTicks := na
        gridConfigurationValid := false
        sourceTotalVolume := 0.0
        fineAllocatedVolume := 0.0
        baseAllocatedVolume := 0.0
        coarseAllocatedVolume := 0.0
        includedSourceBars := 0
        firstIncludedSourceTime := na
        lastIncludedSourceTime := na
        previousIncludedSourceTime := na
        invalidSourceBars := 0
        sourceOrderIssue := false
        fineOverflow := false
        baseOverflow := false
        coarseOverflow := false
        rangeHistoryCovered := false
        rangeTooLong := false
        allocationWorkCapFail := false
        allocationTouches := 0
        cachedOutlineHigh := na
        cachedOutlineLow := na

        cacheInitialized := true
        cachedWallSelected :=
             rebuildWallSelected
        cachedEndpointRefined :=
             rebuildEndpointRefined
        cachedWallsAllowed :=
             rebuildWallsAllowed
        cachedSide := rebuildSide
        cachedStartMacroTime :=
             rebuildStartMacroTime
        cachedEndMacroTime :=
             rebuildEndMacroTime
        cachedProfileStartTime :=
             rebuildStartTime
        cachedProfileEndBarTime :=
             rebuildEndBarTime
        cachedProfileEndExclusive :=
             rebuildEndExclusive
        cachedStartPrice :=
             rebuildStartPrice
        cachedEndPrice :=
             rebuildEndPrice

        int rangeMinTick = na
        int rangeMaxTick = na
        int scanBars = math.min(
             bar_index,
             4999)
        if chartSupported and
         rebuildEndpointRefined
            for offset = scanBars to 0
                int sourceTime = time[offset]
                bool useForProfile =
                     sourceTime >=
                      rebuildStartTime and
                     sourceTime <
                      rebuildEndExclusive
                if useForProfile
                    int sourceHigh =
                         priceToTicks(high[offset])
                    int sourceLow =
                         priceToTicks(low[offset])
                    float sourceVolume =
                         volume[offset]
                    firstIncludedSourceTime :=
                         includedSourceBars == 0 ?
                         sourceTime :
                         firstIncludedSourceTime
                    sourceOrderIssue :=
                         sourceOrderIssue or
                         (
                             not na(
                                 previousIncludedSourceTime) and
                             sourceTime <=
                              previousIncludedSourceTime)
                    previousIncludedSourceTime :=
                         sourceTime
                    lastIncludedSourceTime :=
                         sourceTime
                    includedSourceBars += 1
                    bool sourceValid =
                         not na(sourceHigh) and
                         not na(sourceLow) and
                         not na(sourceVolume) and
                         sourceVolume >= 0.0 and
                         sourceHigh >= sourceLow
                    invalidSourceBars +=
                         sourceValid ? 0 : 1
                    if sourceValid
                        sourceTotalVolume +=
                             sourceVolume
                        rangeMinTick :=
                             na(rangeMinTick) ?
                             sourceLow :
                             math.min(
                                 rangeMinTick,
                                 sourceLow)
                        rangeMaxTick :=
                             na(rangeMaxTick) ?
                             sourceHigh :
                             math.max(
                                 rangeMaxTick,
                                 sourceHigh)
                        cachedOutlineHigh :=
                             na(cachedOutlineHigh) ?
                             high[offset] :
                             math.max(
                                 cachedOutlineHigh,
                                 high[offset])
                        cachedOutlineLow :=
                             na(cachedOutlineLow) ?
                             low[offset] :
                             math.min(
                                 cachedOutlineLow,
                                 low[offset])

            rangeHistoryCovered :=
                 includedSourceBars > 0 and
                 firstIncludedSourceTime ==
                  rebuildStartTime and
                 lastIncludedSourceTime +
                  SOURCE_BAR_MS ==
                  rebuildEndExclusive
            rangeTooLong :=
                 includedSourceBars >
                  MAX_PROFILE_SOURCE_BARS

            if rangeHistoryCovered and
             not rangeTooLong and
             invalidSourceBars == 0 and
             not sourceOrderIssue and
             not na(rangeMinTick) and
             not na(rangeMaxTick)
                effectiveBaseTicks :=
                     baseTicksInput
                fineTicks := math.max(
                     1,
                     int(math.round(
                         effectiveBaseTicks *
                         0.8)))
                coarseTicks := math.max(
                     1,
                     int(math.round(
                         effectiveBaseTicks *
                         1.2)))
                int fineSpan =
                     int(math.floor(
                         (rangeMaxTick -
                          GRID_ORIGIN_TICKS) /
                         float(fineTicks))) -
                     int(math.floor(
                         (rangeMinTick -
                          GRID_ORIGIN_TICKS) /
                         float(fineTicks))) +
                     1
                if widenRowsToCapacityInput
                    while fineSpan >
                     MAX_PROFILE_BINS and
                     effectiveBaseTicks < 500
                        effectiveBaseTicks += 1
                        fineTicks := math.max(
                             1,
                             int(math.round(
                                 effectiveBaseTicks *
                                 0.8)))
                        coarseTicks := math.max(
                             1,
                             int(math.round(
                                 effectiveBaseTicks *
                                 1.2)))
                        fineSpan :=
                             int(math.floor(
                                 (rangeMaxTick -
                                  GRID_ORIGIN_TICKS) /
                                 float(fineTicks))) -
                             int(math.floor(
                                 (rangeMinTick -
                                  GRID_ORIGIN_TICKS) /
                                 float(fineTicks))) +
                             1

                gridConfigurationValid :=
                     fineTicks > 0 and
                     effectiveBaseTicks > 0 and
                     coarseTicks > 0 and
                     fineTicks !=
                      effectiveBaseTicks and
                     fineTicks != coarseTicks and
                     effectiveBaseTicks !=
                      coarseTicks

                if gridConfigurationValid
                    for offset = scanBars to 0
                        int sourceTime = time[offset]
                        if sourceTime >=
                         rebuildStartTime and
                         sourceTime <
                         rebuildEndExclusive
                            int sourceHigh =
                                 priceToTicks(
                                     high[offset])
                            int sourceLow =
                                 priceToTicks(
                                     low[offset])
                            int fineLowBin = int(
                                 math.floor(
                                     (sourceLow -
                                      GRID_ORIGIN_TICKS) /
                                     float(fineTicks)))
                            int fineHighBin = int(
                                 math.floor(
                                     (sourceHigh -
                                      GRID_ORIGIN_TICKS) /
                                     float(fineTicks)))
                            int baseLowBin = int(
                                 math.floor(
                                     (sourceLow -
                                      GRID_ORIGIN_TICKS) /
                                     float(
                                         effectiveBaseTicks)))
                            int baseHighBin = int(
                                 math.floor(
                                     (sourceHigh -
                                      GRID_ORIGIN_TICKS) /
                                     float(
                                         effectiveBaseTicks)))
                            int coarseLowBin = int(
                                 math.floor(
                                     (sourceLow -
                                      GRID_ORIGIN_TICKS) /
                                     float(coarseTicks)))
                            int coarseHighBin = int(
                                 math.floor(
                                     (sourceHigh -
                                      GRID_ORIGIN_TICKS) /
                                     float(coarseTicks)))
                            allocationTouches +=
                                 fineHighBin -
                                 fineLowBin + 1 +
                                 baseHighBin -
                                 baseLowBin + 1 +
                                 coarseHighBin -
                                 coarseLowBin + 1
                    allocationWorkCapFail :=
                         allocationTouches >
                          MAX_ALLOCATION_TOUCHES

                if gridConfigurationValid and
                 not allocationWorkCapFail
                    for offset = scanBars to 0
                        int sourceTime = time[offset]
                        if sourceTime >=
                         rebuildStartTime and
                         sourceTime <
                         rebuildEndExclusive
                            int sourceHigh =
                                 priceToTicks(
                                     high[offset])
                            int sourceLow =
                                 priceToTicks(
                                     low[offset])
                            float sourceVolume =
                                 volume[offset]
                            [nextFineMin,
                             nextFineMax,
                             fineAdded,
                             finePutOverflow,
                             fineTouches] =
                                 allocateBarToGrid(
                                     fineBins,
                                     sourceLow,
                                     sourceHigh,
                                     sourceVolume,
                                     fineTicks,
                                     fineMinBin,
                                     fineMaxBin)
                            fineMinBin :=
                                 nextFineMin
                            fineMaxBin :=
                                 nextFineMax
                            fineAllocatedVolume +=
                                 fineAdded
                            fineOverflow :=
                                 fineOverflow or
                                 finePutOverflow

                            [nextBaseMin,
                             nextBaseMax,
                             baseAdded,
                             basePutOverflow,
                             baseTouches] =
                                 allocateBarToGrid(
                                     baseBins,
                                     sourceLow,
                                     sourceHigh,
                                     sourceVolume,
                                     effectiveBaseTicks,
                                     baseMinBin,
                                     baseMaxBin)
                            baseMinBin :=
                                 nextBaseMin
                            baseMaxBin :=
                                 nextBaseMax
                            baseAllocatedVolume +=
                                 baseAdded
                            baseOverflow :=
                                 baseOverflow or
                                 basePutOverflow

                            [nextCoarseMin,
                             nextCoarseMax,
                             coarseAdded,
                             coarsePutOverflow,
                             coarseTouches] =
                                 allocateBarToGrid(
                                     coarseBins,
                                     sourceLow,
                                     sourceHigh,
                                     sourceVolume,
                                     coarseTicks,
                                     coarseMinBin,
                                     coarseMaxBin)
                            coarseMinBin :=
                                 nextCoarseMin
                            coarseMaxBin :=
                                 nextCoarseMax
                            coarseAllocatedVolume +=
                                 coarseAdded
                            coarseOverflow :=
                                 coarseOverflow or
                                 coarsePutOverflow


// ============================================================================
// DRAWING STATE
// ============================================================================

var box rangeBox = na
var line pocLine = na
var line valueAreaHighLine = na
var line valueAreaLowLine = na
var array<line> histogramLines =
     array.new_line()
var array<line> consensusLines =
     array.new_line()
var array<label> consensusLabels =
     array.new_label()
var table diagnosticTable = table.new(
     position.top_right,
     2,
     28,
     frame_color =
      color.new(color.gray, 35),
     frame_width = 1,
     border_color =
      color.new(color.gray, 70),
     border_width = 1)


// ============================================================================
// LAST-BAR PROFILE, CONSENSUS, AND VISUALS
// ============================================================================

if barstate.islast
    if not na(rangeBox)
        box.delete(rangeBox)
        rangeBox := na
    if not na(pocLine)
        line.delete(pocLine)
        pocLine := na
    if not na(valueAreaHighLine)
        line.delete(valueAreaHighLine)
        valueAreaHighLine := na
    if not na(valueAreaLowLine)
        line.delete(valueAreaLowLine)
        valueAreaLowLine := na
    clearLines(histogramLines)
    clearLines(consensusLines)
    clearLabels(consensusLabels)

    [liveWallSelected,
     liveEndpointRefined,
     liveSide,
     liveStartMacroTime,
     liveEndMacroTime,
     liveStartTime,
     liveEndBarTime,
     liveEndExclusive,
     liveStartPrice,
     liveEndPrice,
     liveWallsAllowed] =
         resolveAutomaticRange(selectorAtr)
    bool liveMatchesCache =
         cacheInitialized and
         liveWallSelected ==
          cachedWallSelected and
         liveEndpointRefined ==
          cachedEndpointRefined and
         liveSide == cachedSide and
         liveStartMacroTime ==
          cachedStartMacroTime and
         liveEndMacroTime ==
          cachedEndMacroTime and
         nz(liveStartTime, -1) ==
          nz(cachedProfileStartTime, -1) and
         nz(liveEndBarTime, -1) ==
          nz(cachedProfileEndBarTime, -1) and
         nz(liveEndExclusive, -1) ==
          nz(cachedProfileEndExclusive, -1) and
         (
             not liveEndpointRefined or
             (
                 priceToTicks(
                     liveStartPrice) ==
                  priceToTicks(
                     cachedStartPrice) and
                 priceToTicks(
                     liveEndPrice) ==
                  priceToTicks(
                     cachedEndPrice)))
    bool rangeUpdatePending =
         liveWallSelected and
         liveEndpointRefined and
         not liveMatchesCache
    bool activeRangeValid =
         chartSupported and
         liveWallSelected and
         liveEndpointRefined and
         liveMatchesCache
    int profileStartTime =
         activeRangeValid ?
         cachedProfileStartTime :
         liveStartTime
    int profileEndBarTime =
         activeRangeValid ?
         cachedProfileEndBarTime :
         liveEndBarTime
    int activeProfileEndExclusive =
         activeRangeValid ?
         cachedProfileEndExclusive :
         liveEndExclusive

    float outlineHigh =
         activeRangeValid ?
         cachedOutlineHigh : na
    float outlineLow =
         activeRangeValid ?
         cachedOutlineLow : na
    if chartSupported and
     liveEndpointRefined and
     not activeRangeValid
        int outlineScanBars =
             math.min(bar_index, 4999)
        for offset = 0 to outlineScanBars
            if time[offset] >=
             liveStartTime and
             time[offset] <
             liveEndExclusive
                outlineHigh :=
                     na(outlineHigh) ?
                     high[offset] :
                     math.max(
                         outlineHigh,
                         high[offset])
                outlineLow :=
                     na(outlineLow) ?
                     low[offset] :
                     math.min(
                         outlineLow,
                         low[offset])
    if chartSupported and
     liveEndpointRefined and
     not na(outlineHigh)
        rangeBox := box.new(
             left = liveStartTime,
             top = outlineHigh,
             right = liveEndExclusive,
             bottom = outlineLow,
             xloc = xloc.bar_time,
             border_color = rangeColorInput,
             border_width = 2,
             border_style =
              line.style_dashed,
             bgcolor =
              color.new(rangeColorInput, 97))

    bool endpointsComplete =
         activeRangeValid and
         rangeHistoryCovered and
         firstIncludedSourceTime ==
          cachedProfileStartTime and
         lastIncludedSourceTime +
          SOURCE_BAR_MS ==
          cachedProfileEndExclusive
    float reconciliationTolerance =
         math.max(
             0.000001,
             math.abs(sourceTotalVolume) *
              0.000000001)
    bool fineReconciliationValid =
         math.abs(
             fineAllocatedVolume -
             sourceTotalVolume) <=
         reconciliationTolerance
    bool baseReconciliationValid =
         math.abs(
             baseAllocatedVolume -
             sourceTotalVolume) <=
         reconciliationTolerance
    bool coarseReconciliationValid =
         math.abs(
             coarseAllocatedVolume -
             sourceTotalVolume) <=
         reconciliationTolerance
    bool constructionComplete =
         chartSupported and
         activeRangeValid and
         gridConfigurationValid and
         time >= cachedProfileEndExclusive and
         endpointsComplete and
         includedSourceBars > 0 and
         not rangeTooLong and
         not allocationWorkCapFail and
         invalidSourceBars == 0 and
         not sourceOrderIssue and
         not fineOverflow and
         not baseOverflow and
         not coarseOverflow and
         fineReconciliationValid and
         baseReconciliationValid and
         coarseReconciliationValid

    [fineAlgorithmValid,
     finePocBin,
     fineValueAreaLowBin,
     fineValueAreaHighBin,
     fineAchievedValueAreaPercent,
     fineMaximumBinVolume] =
         calculateProfile(
             fineBins,
             fineMinBin,
             fineMaxBin,
             fineAllocatedVolume,
             fineTicks)
    [baseAlgorithmValid,
     basePocBin,
     baseValueAreaLowBin,
     baseValueAreaHighBin,
     baseAchievedValueAreaPercent,
     baseMaximumBinVolume] =
         calculateProfile(
             baseBins,
             baseMinBin,
             baseMaxBin,
             baseAllocatedVolume,
             effectiveBaseTicks)
    [coarseAlgorithmValid,
     coarsePocBin,
     coarseValueAreaLowBin,
     coarseValueAreaHighBin,
     coarseAchievedValueAreaPercent,
     coarseMaximumBinVolume] =
         calculateProfile(
             coarseBins,
             coarseMinBin,
             coarseMaxBin,
             coarseAllocatedVolume,
             coarseTicks)
    bool multiProfileValid =
         constructionComplete and
         fineAlgorithmValid and
         baseAlgorithmValid and
         coarseAlgorithmValid

    float basePocPrice =
         multiProfileValid ?
         (
             GRID_ORIGIN_TICKS +
             basePocBin *
              effectiveBaseTicks +
             effectiveBaseTicks *
              0.5) *
          syminfo.mintick : na
    float baseValueAreaLowPrice =
         multiProfileValid ?
         (
             GRID_ORIGIN_TICKS +
             baseValueAreaLowBin *
              effectiveBaseTicks) *
          syminfo.mintick : na
    float baseValueAreaHighPrice =
         multiProfileValid ?
         (
             GRID_ORIGIN_TICKS +
             (
                 baseValueAreaHighBin +
                 1) *
              effectiveBaseTicks) *
          syminfo.mintick : na

    array<int> fineCandidateTicks =
         array.new_int()
    array<float> fineCandidateClean =
         array.new_float()
    array<float> fineCandidateZ =
         array.new_float()
    array<int> fineCandidateDirections =
         array.new_int()
    int fineRawCount = 0
    float fineCleanMad = na
    array<int> baseCandidateTicks =
         array.new_int()
    array<float> baseCandidateClean =
         array.new_float()
    array<float> baseCandidateZ =
         array.new_float()
    array<int> baseCandidateDirections =
         array.new_int()
    int baseRawCount = 0
    float baseCleanMad = na
    array<int> coarseCandidateTicks =
         array.new_int()
    array<float> coarseCandidateClean =
         array.new_float()
    array<float> coarseCandidateZ =
         array.new_float()
    array<int> coarseCandidateDirections =
         array.new_int()
    int coarseRawCount = 0
    float coarseCleanMad = na

    if multiProfileValid
        [fineSelectedTicks,
         fineSelectedClean,
         fineSelectedZ,
         fineSelectedDirections,
         fineRaw,
         fineMad] =
             scoreGatedCandidates(
                 fineBins,
                 fineMinBin,
                 fineMaxBin,
                 fineTicks,
                 fineMaximumBinVolume,
                 minimumRatioInput,
                 maximumNoiseFractionInput,
                 minimumDenseFractionInput,
                 minimumRobustZInput,
                 localClusterRowsInput,
                 candidateCapPerGridInput)
        fineCandidateTicks :=
             fineSelectedTicks
        fineCandidateClean :=
             fineSelectedClean
        fineCandidateZ :=
             fineSelectedZ
        fineCandidateDirections :=
             fineSelectedDirections
        fineRawCount := fineRaw
        fineCleanMad := fineMad

        [baseSelectedTicks,
         baseSelectedClean,
         baseSelectedZ,
         baseSelectedDirections,
         baseRaw,
         baseMad] =
             scoreGatedCandidates(
                 baseBins,
                 baseMinBin,
                 baseMaxBin,
                 effectiveBaseTicks,
                 baseMaximumBinVolume,
                 minimumRatioInput,
                 maximumNoiseFractionInput,
                 minimumDenseFractionInput,
                 minimumRobustZInput,
                 localClusterRowsInput,
                 candidateCapPerGridInput)
        baseCandidateTicks :=
             baseSelectedTicks
        baseCandidateClean :=
             baseSelectedClean
        baseCandidateZ :=
             baseSelectedZ
        baseCandidateDirections :=
             baseSelectedDirections
        baseRawCount := baseRaw
        baseCleanMad := baseMad

        [coarseSelectedTicks,
         coarseSelectedClean,
         coarseSelectedZ,
         coarseSelectedDirections,
         coarseRaw,
         coarseMad] =
             scoreGatedCandidates(
                 coarseBins,
                 coarseMinBin,
                 coarseMaxBin,
                 coarseTicks,
                 coarseMaximumBinVolume,
                 minimumRatioInput,
                 maximumNoiseFractionInput,
                 minimumDenseFractionInput,
                 minimumRobustZInput,
                 localClusterRowsInput,
                 candidateCapPerGridInput)
        coarseCandidateTicks :=
             coarseSelectedTicks
        coarseCandidateClean :=
             coarseSelectedClean
        coarseCandidateZ :=
             coarseSelectedZ
        coarseCandidateDirections :=
             coarseSelectedDirections
        coarseRawCount := coarseRaw
        coarseCleanMad := coarseMad

    // Every consensus cluster is seeded by a passing base-grid candidate.
    // Neighbors are accepted only when every pair in the cluster is within Q.
    // This is complete-linkage: a fine candidate cannot chain through the base
    // to a coarse candidate that is more than Q ticks away from it.
    array<int> clusterBaseTicks =
         array.new_int()
    array<int> clusterFineTicks =
         array.new_int()
    array<int> clusterCoarseTicks =
         array.new_int()
    array<int> clusterBaseDirections =
         array.new_int()
    array<int> clusterFineDirections =
         array.new_int()
    array<int> clusterCoarseDirections =
         array.new_int()
    array<float> clusterBaseZ =
         array.new_float()
    array<float> clusterFineZ =
         array.new_float()
    array<float> clusterCoarseZ =
         array.new_float()
    array<int> clusterSupportCounts =
         array.new_int()
    array<float> clusterMinimumZ =
         array.new_float()
    float consensusRadiusTicks =
         consensusClusterBaseRowsInput *
         effectiveBaseTicks
    float endpointRadiusTicks =
         effectiveBaseTicks
    float maximumNodeWidthTicks =
         maximumNodeWidthBaseRowsInput *
         effectiveBaseTicks

    if baseCandidateTicks.size() > 0
        for baseIndex =
         0 to baseCandidateTicks.size() - 1
            int baseTick =
                 baseCandidateTicks.get(
                     baseIndex)
            float baseZ =
                 baseCandidateZ.get(
                     baseIndex)
            int bestFineIndex = -1
            int bestCoarseIndex = -1
            int bestSupport = 1
            float bestMinimumZ = baseZ
            int bestTotalDistance = 0

            if fineCandidateTicks.size() > 0
                for fineIndex =
                 0 to fineCandidateTicks.size() - 1
                    int fineTick =
                         fineCandidateTicks.get(
                             fineIndex)
                    int fineDistance =
                         math.abs(
                             fineTick -
                             baseTick)
                    if fineDistance <=
                     consensusRadiusTicks
                        float combinationMinimumZ =
                             math.min(
                                 baseZ,
                                 fineCandidateZ.get(
                                     fineIndex))
                        if betterConsensusCombination(
                             2,
                             combinationMinimumZ,
                             fineDistance,
                             bestSupport,
                             bestMinimumZ,
                             bestTotalDistance)
                            bestFineIndex :=
                                 fineIndex
                            bestCoarseIndex := -1
                            bestSupport := 2
                            bestMinimumZ :=
                                 combinationMinimumZ
                            bestTotalDistance :=
                                 fineDistance

            if coarseCandidateTicks.size() > 0
                for coarseIndex =
                 0 to coarseCandidateTicks.size() - 1
                    int coarseTick =
                         coarseCandidateTicks.get(
                             coarseIndex)
                    int coarseDistance =
                         math.abs(
                             coarseTick -
                             baseTick)
                    if coarseDistance <=
                     consensusRadiusTicks
                        float combinationMinimumZ =
                             math.min(
                                 baseZ,
                                 coarseCandidateZ.get(
                                     coarseIndex))
                        if betterConsensusCombination(
                             2,
                             combinationMinimumZ,
                             coarseDistance,
                             bestSupport,
                             bestMinimumZ,
                             bestTotalDistance)
                            bestFineIndex := -1
                            bestCoarseIndex :=
                                 coarseIndex
                            bestSupport := 2
                            bestMinimumZ :=
                                 combinationMinimumZ
                            bestTotalDistance :=
                                 coarseDistance

            if fineCandidateTicks.size() > 0 and
             coarseCandidateTicks.size() > 0
                for fineIndex =
                 0 to fineCandidateTicks.size() - 1
                    int fineTick =
                         fineCandidateTicks.get(
                             fineIndex)
                    int fineDistance =
                         math.abs(
                             fineTick -
                             baseTick)
                    if fineDistance <=
                     consensusRadiusTicks
                        for coarseIndex =
                         0 to coarseCandidateTicks.size() - 1
                            int coarseTick =
                                 coarseCandidateTicks.get(
                                     coarseIndex)
                            int coarseDistance =
                                 math.abs(
                                     coarseTick -
                                     baseTick)
                            int neighborDistance =
                                 math.abs(
                                     fineTick -
                                     coarseTick)
                            bool completeLink =
                                 coarseDistance <=
                                  consensusRadiusTicks and
                                 neighborDistance <=
                                  consensusRadiusTicks
                            if completeLink
                                float combinationMinimumZ =
                                     math.min(
                                         baseZ,
                                         math.min(
                                             fineCandidateZ.get(
                                                 fineIndex),
                                             coarseCandidateZ.get(
                                                 coarseIndex)))
                                int totalDistance =
                                     fineDistance +
                                     coarseDistance +
                                     neighborDistance
                                if betterConsensusCombination(
                                     3,
                                     combinationMinimumZ,
                                     totalDistance,
                                     bestSupport,
                                     bestMinimumZ,
                                     bestTotalDistance)
                                    bestFineIndex :=
                                         fineIndex
                                    bestCoarseIndex :=
                                         coarseIndex
                                    bestSupport := 3
                                    bestMinimumZ :=
                                         combinationMinimumZ
                                    bestTotalDistance :=
                                         totalDistance

            clusterBaseTicks.push(baseTick)
            clusterBaseDirections.push(
                 baseCandidateDirections.get(
                     baseIndex))
            clusterBaseZ.push(baseZ)
            clusterFineTicks.push(
                 bestFineIndex >= 0 ?
                 fineCandidateTicks.get(
                     bestFineIndex) : na)
            clusterFineDirections.push(
                 bestFineIndex >= 0 ?
                 fineCandidateDirections.get(
                     bestFineIndex) : na)
            clusterFineZ.push(
                 bestFineIndex >= 0 ?
                 fineCandidateZ.get(
                     bestFineIndex) : na)
            clusterCoarseTicks.push(
                 bestCoarseIndex >= 0 ?
                 coarseCandidateTicks.get(
                     bestCoarseIndex) : na)
            clusterCoarseDirections.push(
                 bestCoarseIndex >= 0 ?
                 coarseCandidateDirections.get(
                     bestCoarseIndex) : na)
            clusterCoarseZ.push(
                 bestCoarseIndex >= 0 ?
                 coarseCandidateZ.get(
                     bestCoarseIndex) : na)
            clusterSupportCounts.push(
                 bestSupport)
            clusterMinimumZ.push(
                 bestMinimumZ)

    bool structuralBoundsValid =
         not useStructuralBoundsInput or
         structuralHighInput >
          structuralLowInput
    int structuralLowTicks =
         priceToTicks(structuralLowInput)
    int structuralHighTicks =
         priceToTicks(structuralHighInput)
    float structuralDistanceTicks =
         structuralDistanceBaseRowsInput *
         effectiveBaseTicks

    array<int> eligibleClusterIndices =
         array.new_int()
    array<bool> clusterDrawingSuppressed =
         array.new_bool(
             clusterBaseTicks.size(),
             false)
    int structurallySuppressedCount = 0
    if multiProfileValid and
     structuralBoundsValid and
     clusterBaseTicks.size() > 0
        for clusterIndex =
         0 to clusterBaseTicks.size() - 1
            int supportCount =
                 clusterSupportCounts.get(
                     clusterIndex)
            int consensusTick =
                 clusterBaseTicks.get(
                     clusterIndex)
            bool nearStructuralBound =
                 useStructuralBoundsInput and
                 (
                     math.abs(
                         consensusTick -
                         structuralLowTicks) <=
                      structuralDistanceTicks or
                     math.abs(
                         consensusTick -
                         structuralHighTicks) <=
                      structuralDistanceTicks)
            if supportCount >=
             MIN_CONSENSUS_GRIDS
                if nearStructuralBound
                    structurallySuppressedCount +=
                         1
                clusterDrawingSuppressed.set(
                     clusterIndex,
                     nearStructuralBound)
                eligibleClusterIndices.push(
                     clusterIndex)

    // Build one paired-node candidate per eligible base-seeded cluster.
    // The base pair is mandatory. Fine/coarse support counts only when its
    // retained dense direction matches the base and both pair endpoints obey
    // complete-link distance Q.
    float fineLogEpsilon =
         profileLogEpsilon(
             fineBins,
             fineMinBin,
             fineMaxBin)
    float baseLogEpsilon =
         profileLogEpsilon(
             baseBins,
             baseMinBin,
             baseMaxBin)
    float coarseLogEpsilon =
         profileLogEpsilon(
             coarseBins,
             coarseMinBin,
             coarseMaxBin)
    array<int> stableNodeClusters =
         array.new_int()
    array<int> stableNodeMates =
         array.new_int()
    array<int> stableNodeDirections =
         array.new_int()
    array<int> stableNodeSupports =
         array.new_int()
    array<float> stableNodeWorstProminence =
         array.new_float()
    array<float> stableNodeMinimumZ =
         array.new_float()
    array<int> stableNodeWidths =
         array.new_int()

    if multiProfileValid and
     eligibleClusterIndices.size() > 0
        for eligibleIndex =
         0 to eligibleClusterIndices.size() - 1
            int clusterIndex =
                 eligibleClusterIndices.get(
                     eligibleIndex)
            int baseAnchor =
                 clusterBaseTicks.get(
                     clusterIndex)
            int baseDirection =
                 clusterBaseDirections.get(
                     clusterIndex)
            [basePairValid,
             baseMate,
             baseProminence,
             baseWidth] =
                 traceNodeMate(
                     baseBins,
                     baseMinBin,
                     baseMaxBin,
                     effectiveBaseTicks,
                     baseAnchor,
                     baseDirection,
                     maximumNodeWidthTicks,
                     baseLogEpsilon)

            // Search all nearby same-direction neighbors after the base pair
            // exists. This avoids inheriting a standalone-neighbor choice that
            // is close in price but has the wrong dense direction or mate.
            array<int> agreeingFineIndices =
                 array.new_int()
            array<int> agreeingFineAnchors =
                 array.new_int()
            array<int> agreeingFineMates =
                 array.new_int()
            array<float> agreeingFineProminences =
                 array.new_float()
            array<int> agreeingCoarseIndices =
                 array.new_int()
            array<int> agreeingCoarseAnchors =
                 array.new_int()
            array<int> agreeingCoarseMates =
                 array.new_int()
            array<float> agreeingCoarseProminences =
                 array.new_float()

            if basePairValid and
             fineCandidateTicks.size() > 0
                for fineIndex =
                 0 to fineCandidateTicks.size() - 1
                    int fineAnchor =
                         fineCandidateTicks.get(
                             fineIndex)
                    int fineDirection =
                         fineCandidateDirections.get(
                             fineIndex)
                    bool anchorEligible =
                         fineDirection ==
                          baseDirection and
                         math.abs(
                             fineAnchor -
                             baseAnchor) <=
                          consensusRadiusTicks
                    if anchorEligible
                        [finePairValid,
                         fineMate,
                         fineProminence,
                         fineWidth] =
                             traceNodeMate(
                                 fineBins,
                                 fineMinBin,
                                 fineMaxBin,
                                 fineTicks,
                                 fineAnchor,
                                 fineDirection,
                                 maximumNodeWidthTicks,
                                 fineLogEpsilon)
                        if finePairValid and
                         math.abs(
                             fineMate -
                             baseMate) <=
                          endpointRadiusTicks
                            agreeingFineIndices.push(
                                 fineIndex)
                            agreeingFineAnchors.push(
                                 fineAnchor)
                            agreeingFineMates.push(
                                 fineMate)
                            agreeingFineProminences.push(
                                 fineProminence)

            if basePairValid and
             coarseCandidateTicks.size() > 0
                for coarseIndex =
                 0 to coarseCandidateTicks.size() - 1
                    int coarseAnchor =
                         coarseCandidateTicks.get(
                             coarseIndex)
                    int coarseDirection =
                         coarseCandidateDirections.get(
                             coarseIndex)
                    bool anchorEligible =
                         coarseDirection ==
                          baseDirection and
                         math.abs(
                             coarseAnchor -
                             baseAnchor) <=
                          consensusRadiusTicks
                    if anchorEligible
                        [coarsePairValid,
                         coarseMate,
                         coarseProminence,
                         coarseWidth] =
                             traceNodeMate(
                                 coarseBins,
                                 coarseMinBin,
                                 coarseMaxBin,
                                 coarseTicks,
                                 coarseAnchor,
                                 coarseDirection,
                                 maximumNodeWidthTicks,
                                 coarseLogEpsilon)
                        if coarsePairValid and
                         math.abs(
                             coarseMate -
                             baseMate) <=
                          endpointRadiusTicks
                            agreeingCoarseIndices.push(
                                 coarseIndex)
                            agreeingCoarseAnchors.push(
                                 coarseAnchor)
                            agreeingCoarseMates.push(
                                 coarseMate)
                            agreeingCoarseProminences.push(
                                 coarseProminence)

            int nodeSupport = 0
            float nodeWorstProminence = na
            float nodeMinimumZ = na
            float baseZ =
                 clusterBaseZ.get(
                     clusterIndex)

            // Two-grid alternatives.
            if agreeingFineIndices.size() > 0
                for agreeingFineIndex =
                 0 to agreeingFineIndices.size() - 1
                    int fineIndex =
                         agreeingFineIndices.get(
                             agreeingFineIndex)
                    float candidateProminence =
                         math.min(
                             baseProminence,
                             agreeingFineProminences.get(
                                 agreeingFineIndex))
                    float candidateMinimumZ =
                         math.min(
                             baseZ,
                             fineCandidateZ.get(
                                 fineIndex))
                    if betterNode(
                         2,
                         candidateProminence,
                         candidateMinimumZ,
                         nodeSupport,
                         nodeWorstProminence,
                         nodeMinimumZ)
                        nodeSupport := 2
                        nodeWorstProminence :=
                             candidateProminence
                        nodeMinimumZ :=
                             candidateMinimumZ

            if agreeingCoarseIndices.size() > 0
                for agreeingCoarseIndex =
                 0 to agreeingCoarseIndices.size() - 1
                    int coarseIndex =
                         agreeingCoarseIndices.get(
                             agreeingCoarseIndex)
                    float candidateProminence =
                         math.min(
                             baseProminence,
                             agreeingCoarseProminences.get(
                                 agreeingCoarseIndex))
                    float candidateMinimumZ =
                         math.min(
                             baseZ,
                             coarseCandidateZ.get(
                                 coarseIndex))
                    if betterNode(
                         2,
                         candidateProminence,
                         candidateMinimumZ,
                         nodeSupport,
                         nodeWorstProminence,
                         nodeMinimumZ)
                        nodeSupport := 2
                        nodeWorstProminence :=
                             candidateProminence
                        nodeMinimumZ :=
                             candidateMinimumZ

            // Three-grid alternatives retain complete linkage for both
            // anchors and mate endpoints.
            if agreeingFineIndices.size() > 0 and
             agreeingCoarseIndices.size() > 0
                for agreeingFineIndex =
                 0 to agreeingFineIndices.size() - 1
                    int fineAnchor =
                         agreeingFineAnchors.get(
                             agreeingFineIndex)
                    int fineMate =
                         agreeingFineMates.get(
                             agreeingFineIndex)
                    int fineIndex =
                         agreeingFineIndices.get(
                             agreeingFineIndex)
                    for agreeingCoarseIndex =
                     0 to agreeingCoarseIndices.size() - 1
                        int coarseAnchor =
                             agreeingCoarseAnchors.get(
                                 agreeingCoarseIndex)
                        int coarseMate =
                             agreeingCoarseMates.get(
                                 agreeingCoarseIndex)
                        bool completeLink =
                             math.abs(
                                 fineAnchor -
                                 coarseAnchor) <=
                              consensusRadiusTicks and
                             math.abs(
                                 fineMate -
                                 coarseMate) <=
                              endpointRadiusTicks
                        if completeLink
                            int coarseIndex =
                                 agreeingCoarseIndices.get(
                                     agreeingCoarseIndex)
                            float candidateProminence =
                                 math.min(
                                     baseProminence,
                                     math.min(
                                         agreeingFineProminences.get(
                                             agreeingFineIndex),
                                         agreeingCoarseProminences.get(
                                             agreeingCoarseIndex)))
                            float candidateMinimumZ =
                                 math.min(
                                     baseZ,
                                     math.min(
                                         fineCandidateZ.get(
                                             fineIndex),
                                         coarseCandidateZ.get(
                                             coarseIndex)))
                            if betterNode(
                                 3,
                                 candidateProminence,
                                 candidateMinimumZ,
                                 nodeSupport,
                                 nodeWorstProminence,
                                 nodeMinimumZ)
                                nodeSupport := 3
                                nodeWorstProminence :=
                                     candidateProminence
                                nodeMinimumZ :=
                                     candidateMinimumZ

            if basePairValid and
             nodeSupport >=
              MIN_CONSENSUS_GRIDS
                stableNodeClusters.push(
                     clusterIndex)
                stableNodeMates.push(
                     baseMate)
                stableNodeDirections.push(
                     baseDirection)
                stableNodeSupports.push(
                     nodeSupport)
                stableNodeWorstProminence.push(
                     nodeWorstProminence)
                stableNodeMinimumZ.push(
                     nodeMinimumZ)
                stableNodeWidths.push(
                     baseWidth)

    // Selected structures are stable pairs first, then only anchors for which
    // no stable mate exists. Selecting a pair consumes every consensus anchor
    // inside its interval or within Q of either edge.
    array<bool> clusterConsumed =
         array.new_bool(
             clusterBaseTicks.size(),
             false)
    array<bool> clusterHasStableNode =
         array.new_bool(
             clusterBaseTicks.size(),
             false)
    if stableNodeClusters.size() > 0
        for nodeIndex =
         0 to stableNodeClusters.size() - 1
            clusterHasStableNode.set(
                 stableNodeClusters.get(
                     nodeIndex),
                 true)

    array<int> structureKinds =
         array.new_int()
    array<int> structureClusters =
         array.new_int()
    array<int> structureAnchorTicks =
         array.new_int()
    array<int> structureMateTicks =
         array.new_int()
    array<int> structureDirections =
         array.new_int()
    array<int> structureSupports =
         array.new_int()
    array<float> structureProminences =
         array.new_float()
    array<float> structureMinimumZ =
         array.new_float()
    array<int> structureWidths =
         array.new_int()
    array<bool> stableNodeConsumed =
         array.new_bool(
             stableNodeClusters.size(),
             false)

    if stableNodeClusters.size() > 0
        for rank =
         0 to maximumStructuresInput - 1
            int bestNodeIndex = -1
            int bestSupport = -1
            float bestWorstProminence = na
            float bestMinimumZ = na
            int bestAnchor = na
            for nodeIndex =
             0 to stableNodeClusters.size() - 1
                int clusterIndex =
                     stableNodeClusters.get(
                         nodeIndex)
                bool available =
                     not stableNodeConsumed.get(
                         nodeIndex) and
                     not clusterConsumed.get(
                         clusterIndex)
                if available
                    int support =
                         stableNodeSupports.get(
                             nodeIndex)
                    float worstProminence =
                         stableNodeWorstProminence.get(
                             nodeIndex)
                    float minimumZ =
                         stableNodeMinimumZ.get(
                             nodeIndex)
                    int anchor =
                         clusterBaseTicks.get(
                             clusterIndex)
                    bool better =
                         betterNode(
                             support,
                             worstProminence,
                             minimumZ,
                             bestSupport,
                             bestWorstProminence,
                             bestMinimumZ)
                    if better or
                     (
                         support ==
                          bestSupport and
                         worstProminence ==
                          bestWorstProminence and
                         minimumZ ==
                          bestMinimumZ and
                         (
                             na(bestAnchor) or
                             anchor < bestAnchor))
                        bestNodeIndex :=
                             nodeIndex
                        bestSupport := support
                        bestWorstProminence :=
                             worstProminence
                        bestMinimumZ :=
                             minimumZ
                        bestAnchor := anchor

            if bestNodeIndex >= 0 and
             structureKinds.size() <
              maximumStructuresInput
                stableNodeConsumed.set(
                     bestNodeIndex,
                     true)
                int clusterIndex =
                     stableNodeClusters.get(
                         bestNodeIndex)
                int anchor =
                     clusterBaseTicks.get(
                         clusterIndex)
                int mate =
                     stableNodeMates.get(
                         bestNodeIndex)
                structureKinds.push(1)
                structureClusters.push(
                     clusterIndex)
                structureAnchorTicks.push(
                     anchor)
                structureMateTicks.push(
                     mate)
                structureDirections.push(
                     stableNodeDirections.get(
                         bestNodeIndex))
                structureSupports.push(
                     stableNodeSupports.get(
                         bestNodeIndex))
                structureProminences.push(
                     stableNodeWorstProminence.get(
                         bestNodeIndex))
                structureMinimumZ.push(
                     stableNodeMinimumZ.get(
                         bestNodeIndex))
                structureWidths.push(
                     stableNodeWidths.get(
                         bestNodeIndex))

                float consumeLow =
                     math.min(
                         anchor,
                         mate) -
                     consensusRadiusTicks
                float consumeHigh =
                     math.max(
                         anchor,
                         mate) +
                     consensusRadiusTicks
                if clusterBaseTicks.size() > 0
                    for consumeIndex =
                     0 to clusterBaseTicks.size() - 1
                        int candidateAnchor =
                             clusterBaseTicks.get(
                                 consumeIndex)
                        if candidateAnchor >=
                         consumeLow and
                         candidateAnchor <=
                          consumeHigh
                            clusterConsumed.set(
                                 consumeIndex,
                                 true)

    // Fill any remaining slots with v0.4 consensus anchors only when that
    // anchor had no cross-grid-stable mate.
    if eligibleClusterIndices.size() > 0
        for rank =
         0 to maximumStructuresInput - 1
            int bestCluster = -1
            int bestSupport = -1
            float bestMinimumZ = na
            int bestBaseTick = na
            if structureKinds.size() <
             maximumStructuresInput
                for eligibleIndex =
                 0 to eligibleClusterIndices.size() - 1
                    int clusterIndex =
                         eligibleClusterIndices.get(
                             eligibleIndex)
                    bool available =
                         not clusterConsumed.get(
                             clusterIndex) and
                         not clusterHasStableNode.get(
                             clusterIndex)
                    if available
                        int supportCount =
                             clusterSupportCounts.get(
                                 clusterIndex)
                        float minimumZ =
                             clusterMinimumZ.get(
                                 clusterIndex)
                        int baseTick =
                             clusterBaseTicks.get(
                                 clusterIndex)
                        if supportCount >
                         bestSupport or
                         (
                             supportCount ==
                              bestSupport and
                             (
                                 na(bestMinimumZ) or
                                 minimumZ >
                                  bestMinimumZ)) or
                         (
                             supportCount ==
                              bestSupport and
                             minimumZ ==
                              bestMinimumZ and
                             (
                                 na(bestBaseTick) or
                                 baseTick <
                                  bestBaseTick))
                            bestCluster :=
                                 clusterIndex
                            bestSupport :=
                                 supportCount
                            bestMinimumZ :=
                                 minimumZ
                            bestBaseTick :=
                                 baseTick
            if bestCluster >= 0 and
             structureKinds.size() <
              maximumStructuresInput
                clusterConsumed.set(
                     bestCluster,
                     true)
                structureKinds.push(0)
                structureClusters.push(
                     bestCluster)
                structureAnchorTicks.push(
                     clusterBaseTicks.get(
                         bestCluster))
                structureMateTicks.push(na)
                structureDirections.push(
                     clusterBaseDirections.get(
                         bestCluster))
                structureSupports.push(
                     clusterSupportCounts.get(
                         bestCluster))
                structureProminences.push(na)
                structureMinimumZ.push(
                     clusterMinimumZ.get(
                         bestCluster))
                structureWidths.push(0)

    if multiProfileValid
        int histogramWidthMs = int(
             (
                 activeProfileEndExclusive -
                 profileStartTime) *
             histogramWidthInput /
             100.0)
        for bin =
         baseMinBin to baseMaxBin
            float volumeAtBin =
                 binVolume(baseBins, bin)
            float relativeWidth =
                 baseMaximumBinVolume > 0.0 ?
                 volumeAtBin /
                  baseMaximumBinVolume :
                 0.0
            float rowCenterPrice =
                 (
                     GRID_ORIGIN_TICKS +
                     bin *
                      effectiveBaseTicks +
                     effectiveBaseTicks *
                      0.5) *
                 syminfo.mintick
            line histogramLine = line.new(
                 activeProfileEndExclusive -
                  int(
                      histogramWidthMs *
                      relativeWidth),
                 rowCenterPrice,
                 activeProfileEndExclusive,
                 rowCenterPrice,
                 xloc = xloc.bar_time,
                 color = color.new(
                     rangeColorInput,
                     65),
                 width = 2)
            histogramLines.push(
                 histogramLine)

        pocLine := line.new(
             profileStartTime,
             basePocPrice,
             activeProfileEndExclusive,
             basePocPrice,
             xloc = xloc.bar_time,
             color = color.orange,
             width = 2)
        valueAreaHighLine := line.new(
             profileStartTime,
             baseValueAreaHighPrice,
             activeProfileEndExclusive,
             baseValueAreaHighPrice,
             xloc = xloc.bar_time,
             color =
              color.new(color.silver, 20),
             style = line.style_dotted)
        valueAreaLowLine := line.new(
             profileStartTime,
             baseValueAreaLowPrice,
             activeProfileEndExclusive,
             baseValueAreaLowPrice,
             xloc = xloc.bar_time,
             color =
              color.new(color.silver, 20),
             style = line.style_dotted)

        int structureEndTime =
             extendStructuresInput ?
             time :
             activeProfileEndExclusive
        if structureKinds.size() > 0
            for selectedPosition =
             0 to structureKinds.size() - 1
                int clusterIndex =
                     structureClusters.get(
                         selectedPosition)
                int supportCount =
                     structureSupports.get(
                         selectedPosition)
                int anchorTick =
                     structureAnchorTicks.get(
                         selectedPosition)
                int mateTick =
                     structureMateTicks.get(
                         selectedPosition)
                float anchorPrice =
                     anchorTick *
                     syminfo.mintick
                bool drawingSuppressed =
                     clusterDrawingSuppressed.get(
                         clusterIndex)
                bool paired =
                     structureKinds.get(
                         selectedPosition) == 1
                int transparency =
                     supportCount == 3 ?
                     0 : 28
                if not drawingSuppressed
                    line anchorLine = line.new(
                         profileStartTime,
                         anchorPrice,
                         structureEndTime,
                         anchorPrice,
                         xloc = xloc.bar_time,
                         color = color.new(
                             consensusColorInput,
                             transparency),
                         width =
                             supportCount == 3 ?
                             3 : 2)
                    consensusLines.push(
                         anchorLine)
                    if paired
                        float matePrice =
                             mateTick *
                             syminfo.mintick
                        line mateLine = line.new(
                             profileStartTime,
                             matePrice,
                             structureEndTime,
                             matePrice,
                             xloc = xloc.bar_time,
                             color = color.new(
                                 consensusColorInput,
                                 transparency),
                             width =
                                 supportCount == 3 ?
                                 3 : 2)
                        consensusLines.push(
                             mateLine)
                string structureId =
                     (
                         paired ? "N" : "S") +
                     str.tostring(
                         selectedPosition + 1)
                string anchorLabelText =
                     structureId +
                     (
                         paired ? " A " : " ") +
                     str.tostring(
                         anchorPrice,
                         format.mintick) +
                     " | " +
                     str.tostring(
                         supportCount) +
                     "/3 | min z " +
                     str.tostring(
                         structureMinimumZ.get(
                             selectedPosition),
                         "#.00")
                if not drawingSuppressed
                    label anchorLabel =
                         label.new(
                             structureEndTime,
                             anchorPrice,
                             anchorLabelText,
                             xloc = xloc.bar_time,
                             style =
                              label.style_label_left,
                             color = color.new(
                                 color.black,
                                 78),
                             textcolor = color.new(
                                 consensusColorInput,
                                 transparency),
                             size = size.tiny)
                    consensusLabels.push(
                         anchorLabel)
                    if paired
                        float matePrice =
                             mateTick *
                             syminfo.mintick
                        string mateLabelText =
                             structureId +
                             " M " +
                             str.tostring(
                                 matePrice,
                                 format.mintick) +
                             " | P " +
                             str.tostring(
                                 structureProminences.get(
                                     selectedPosition),
                                 "#.00") +
                             " | w " +
                             str.tostring(
                                 structureWidths.get(
                                     selectedPosition)) +
                             "r"
                        label mateLabel =
                             label.new(
                                 structureEndTime,
                                 matePrice,
                                 mateLabelText,
                                 xloc = xloc.bar_time,
                                 style =
                                  label.style_label_left,
                                 color = color.new(
                                     color.black,
                                     78),
                                 textcolor =
                                  color.new(
                                     consensusColorInput,
                                     transparency),
                                 size = size.tiny)
                        consensusLabels.push(
                             mateLabel)

    string state =
         multiProfileValid and
          structuralBoundsValid ?
         "VALID / EXPERIMENTAL" :
         not chartSupported ?
         "USE STANDARD 15m CHART" :
         not liveWallSelected ?
         (
             not liveWallsAllowed ?
             "NO TWO-SIDED RSD WALL" :
             "NO ACTIVE RSD MACRO WALL") :
         not liveEndpointRefined ?
         "RSD ENDPOINT REFINE FAIL" :
         rangeUpdatePending ?
         "RANGE UPDATE PENDING" :
         not rangeHistoryCovered ?
         "RANGE OUTSIDE 5000 BARS" :
         rangeTooLong ?
         "RANGE TOO LONG" :
         not gridConfigurationValid ?
         "ROW GRIDS NOT DISTINCT" :
         allocationWorkCapFail ?
         "PROFILE WORK CAP FAIL" :
         not endpointsComplete ?
         "ENDPOINT COVERAGE FAIL" :
         invalidSourceBars > 0 ?
         "INVALID SOURCE BAR" :
         sourceOrderIssue ?
         "SOURCE ORDER FAIL" :
         fineOverflow or
          baseOverflow or
          coarseOverflow ?
         "PROFILE CAP FAIL" :
         not fineReconciliationValid or
          not baseReconciliationValid or
          not coarseReconciliationValid ?
         "VOLUME RECONCILIATION FAIL" :
         not fineAlgorithmValid or
          not baseAlgorithmValid or
          not coarseAlgorithmValid ?
         "PROFILE ALGORITHM FAIL" :
         not structuralBoundsValid ?
         "INVALID STRUCTURAL BOUNDS" :
         "INCOMPLETE"

    string gridText =
         str.tostring(fineTicks) +
         " / " +
         str.tostring(effectiveBaseTicks) +
         " / " +
         str.tostring(coarseTicks) +
         " ticks" +
         (
             not na(effectiveBaseTicks) and
             effectiveBaseTicks !=
              baseTicksInput ?
             " (preferred " +
             str.tostring(baseTicksInput) +
             ")" : "") +
         (
             gridConfigurationValid ?
             "" : " (INVALID)")
    string candidateCountText =
         str.tostring(
             fineCandidateTicks.size()) +
         " / " +
         str.tostring(
             baseCandidateTicks.size()) +
         " / " +
         str.tostring(
             coarseCandidateTicks.size())
    string rawCountText =
         str.tostring(fineRawCount) +
         " / " +
         str.tostring(baseRawCount) +
         " / " +
         str.tostring(coarseRawCount)
    string cleanMadText =
         floatText(fineCleanMad) +
         " / " +
         floatText(baseCleanMad) +
         " / " +
         floatText(coarseCleanMad)
    string structuralStateText =
         not useStructuralBoundsInput ?
         "OFF" :
         not structuralBoundsValid ?
         "INVALID: high must exceed low" :
         str.tostring(
             structuralLowInput,
             format.mintick) +
         " / " +
         str.tostring(
         structuralHighInput,
             format.mintick) +
         " ± " +
         str.tostring(
             structuralDistanceBaseRowsInput,
             "#.##") +
         " rows"
    string structureOneText = "NONE"
    string structureTwoText = "NONE"
    int visibleStructureCount = 0
    int pairedStructureCount = 0
    int standaloneStructureCount = 0
    if structureKinds.size() > 0
        for selectedPosition =
         0 to structureKinds.size() - 1
            bool paired =
                 structureKinds.get(
                     selectedPosition) == 1
            int clusterIndex =
                 structureClusters.get(
                     selectedPosition)
            bool drawingSuppressed =
                 clusterDrawingSuppressed.get(
                     clusterIndex)
            visibleStructureCount +=
                 drawingSuppressed ? 0 : 1
            pairedStructureCount +=
                 paired ? 1 : 0
            standaloneStructureCount +=
                 paired ? 0 : 1
            float anchorPrice =
                 structureAnchorTicks.get(
                     selectedPosition) *
                 syminfo.mintick
            string item =
                 (
                     paired ? "NODE " : "SHELF ") +
                 str.tostring(
                     anchorPrice,
                     format.mintick)
            if paired
                float matePrice =
                     structureMateTicks.get(
                         selectedPosition) *
                     syminfo.mintick
                item +=
                     " - " +
                     str.tostring(
                         matePrice,
                         format.mintick) +
                     " | " +
                     str.tostring(
                         structureSupports.get(
                             selectedPosition)) +
                     "/3 | P " +
                     str.tostring(
                         structureProminences.get(
                             selectedPosition),
                         "#.00") +
                     " | w " +
                     str.tostring(
                         structureWidths.get(
                             selectedPosition)) +
                     "r"
            else
                item +=
                     " | " +
                     str.tostring(
                         structureSupports.get(
                             selectedPosition)) +
                     "/3 | z " +
                     str.tostring(
                         structureMinimumZ.get(
                             selectedPosition),
                         "#.00")
            item +=
                 drawingSuppressed ?
                 " | HIDDEN" : ""
            if selectedPosition == 0
                structureOneText := item
            if selectedPosition == 1
                structureTwoText := item

    color headerBg =
         color.new(#1565c0, 10)
    color rowBg =
         color.new(color.black, 20)
    color warningBg =
         color.new(#8d6e63, 15)
    diagnosticRow(
         diagnosticTable,
         0,
         "VP RSD AUTO 0.6",
         state,
         headerBg)
    diagnosticRow(
         diagnosticTable,
         1,
         "RSD range source",
         (liveWallSelected ?
             (
                 liveSide < 0 ?
                 "LOW WALL" :
                 "HIGH WALL") :
             "NONE") +
         " | " +
         macroTFInput +
         "m swing-only",
         warningBg)
    diagnosticRow(
         diagnosticTable,
         2,
         "Automatic start",
         timeText(liveStartTime),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         3,
         "Automatic end incl.",
         timeText(liveEndBarTime),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         4,
         "Fine / base / coarse",
         gridText,
         gridConfigurationValid ?
          rowBg : warningBg)
    diagnosticRow(
         diagnosticTable,
         5,
         "Source bars",
         str.tostring(
             includedSourceBars),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         6,
         "Invalid bars",
         str.tostring(
             invalidSourceBars),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         7,
         "Source volume",
         floatText(
             sourceTotalVolume),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         8,
         "Alloc diffs F/B/C",
         floatText(
             fineAllocatedVolume -
             sourceTotalVolume) +
         " / " +
         floatText(
             baseAllocatedVolume -
             sourceTotalVolume) +
         " / " +
         floatText(
             coarseAllocatedVolume -
             sourceTotalVolume),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         9,
         "Base profile bins",
         multiProfileValid ?
         str.tostring(
             baseMaxBin -
             baseMinBin +
             1) :
         "NA",
         rowBg)
    diagnosticRow(
         diagnosticTable,
         10,
         "Base POC",
         str.tostring(
             basePocPrice,
             format.mintick),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         11,
         "Base VAL / VAH",
         str.tostring(
             baseValueAreaLowPrice,
             format.mintick) +
         " / " +
         str.tostring(
             baseValueAreaHighPrice,
             format.mintick),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         12,
         "Base VA achieved",
         str.tostring(
             baseAchievedValueAreaPercent,
             "#.0") +
         "%",
         rowBg)
    diagnosticRow(
         diagnosticTable,
         13,
         "Raw boundaries F/B/C",
         rawCountText,
         rowBg)
    diagnosticRow(
         diagnosticTable,
         14,
         "Gated candidates F/B/C",
         candidateCountText,
         rowBg)
    diagnosticRow(
         diagnosticTable,
         15,
         "Clean MAD F/B/C",
         cleanMadText,
         rowBg)
    diagnosticRow(
         diagnosticTable,
         16,
         "Base-seeded clusters",
         str.tostring(
             clusterBaseTicks.size()),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         17,
         "Stable pairs / selected",
         str.tostring(
             stableNodeClusters.size()) +
         " / " +
         str.tostring(
             structureKinds.size()),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         18,
         "Nodes / shelves / visible",
         str.tostring(
             pairedStructureCount) +
         " / " +
         str.tostring(
             standaloneStructureCount) +
         " / " +
         str.tostring(
             visibleStructureCount),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         19,
         "Structure 1",
         structureOneText,
         rowBg)
    diagnosticRow(
         diagnosticTable,
         20,
         "Structure 2",
         structureTwoText,
         rowBg)
    diagnosticRow(
         diagnosticTable,
         21,
         "Structural bounds",
         structuralStateText,
         useStructuralBoundsInput ?
          warningBg : rowBg)
    diagnosticRow(
         diagnosticTable,
         22,
         "Cluster / endpoint radii",
         str.tostring(
             consensusClusterBaseRowsInput,
             "#.##") +
         " / 1.00 base rows",
         rowBg)
    diagnosticRow(
         diagnosticTable,
         23,
         "Local pair guard",
         "nearest clean peak≥10%; P>0; 3-" +
         str.tostring(
             maximumNodeWidthBaseRowsInput,
             "#.0") +
         " base rows",
         rowBg)
    diagnosticRow(
         diagnosticTable,
         24,
         "Geometry gates",
         str.tostring(
             minimumRatioInput,
             "#.00") +
         "x; W/J≤" +
         str.tostring(
             maximumNoiseFractionInput,
             "#.00") +
         "; dense≥" +
         str.tostring(
             minimumDenseFractionInput,
             "#.00") +
         "; z≥" +
         str.tostring(
             minimumRobustZInput,
             "#.00"),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         25,
         "Suppressed at bounds",
         str.tostring(
             structurallySuppressedCount),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         26,
         "Maximum structures",
         str.tostring(
             maximumStructuresInput),
         rowBg)
    diagnosticRow(
         diagnosticTable,
         27,
         "Warning",
         "Research only; compare expert marks",
         warningBg)

Overview

VP RSD Automatic Local Node Edge Consensus Diagnostic selects an immutable profile interval from the newest confirmed macro broadening wall, then allocates each 15-minute bar's volume across fine, base, and coarse row grids. A node is kept only when both edges agree across neighboring grids after row-size perturbation. Settings change swing lengths, wall slope filters, value-area width, consensus radius, and optional structural suppression. It makes no entries or exits and abstains when wall endpoints cannot be refined to 15-minute bars.

Details

Published by

345-strategies on GitHub

Code credit

TheStratSuite contributors, as written in the script's header

Type

Indicator, Pine Script v6

Draws

On the price chart

Category

Volume, Support & resistance

Markets

Any symbol

Timeframes

M15-H1

Risk Notes

  • Reads higher-timeframe data with lookahead on, so the history can show signals that were not there in real time

Topics

indicatorpine-scriptthestrattradingtradingviewprice-actionstratpine-script-librarythestrat-suite

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
Macro timeframestring240macroTFInput
Multi-N swing unionboolfalseuseMultiNInput
N fast (left bars)int3nFastInput
N medium (left bars)int5nMediumInput
Right bars (confirmation)int2rightBarsInput
Require two-sided broadeningbooltruewallRequireBothSidesInput
Suppress steep wallsbooltruehideSteepWallsInput
Maximum wall slope (ATR / 15m bar)float0.05maximumWallSlopeInput
Preferred base ticks per rowint25baseTicksInput
Automatically widen rows when requiredbooltruewidenRowsToCapacityInput
Base-grid Value Area target (%)float70.0valueAreaPercentInput
Candidate cap per gridint12candidateCapPerGridInput
Show all 28 settings
SettingTypeDefaultVariable
Minimum dense/thin ratiofloat1.75minimumRatioInput
Maximum W / Jfloat0.50maximumNoiseFractionInput
Minimum dense side / grid max rowfloat0.20minimumDenseFractionInput
Minimum robust zfloat2.50minimumRobustZInput
Within-grid cluster radius (grid rows)int2localClusterRowsInput
Cross-grid cluster radius (base rows)float1.0consensusClusterBaseRowsInput
Maximum structuresint2maximumStructuresInput
Maximum paired-node width (base rows)float12.0maximumNodeWidthBaseRowsInput
Extend structures to current barbooltrueextendStructuresInput
Suppress near structural low / highboolfalseuseStructuralBoundsInput
Structural lowprice0.0structuralLowInput
Structural highprice0.0structuralHighInput
Suppression distance (base rows)float1.0structuralDistanceBaseRowsInput
Base histogram width (% of range)float24.0histogramWidthInput
Range / base histogramcolor#26c6darangeColorInput
Consensus structurescolor#ffd54fconsensusColorInput
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

This overlay indicator draws a fixed-range volume profile on the price chart, splitting traded activity into up and down volume at each price level. It also plots a sentiment profile, a developing point of control, and value-area high and low around a configur

Indicator v5 VolumeSupport & resistance
Updated 2 months ago · MIT GitHub repository of Volume Profile and Indicator by DGT

MGIC-tracker

by Allen1212
303 stars

The MGIC-tracker is a TradingView indicator that overlays ARK Invest trade records onto stock price charts. It plots buy and sell labels at the exact timestamp of each transaction, showing share volume and ETF weight. Users select a specific ETF type via setti

Indicator v4 Support & resistanceVolume
Updated 2 years ago · None stated GitHub repository of MGIC-tracker
218 stars

Comprehensive Volume Profile is an overlay indicator that calculates and plots volume distribution across specified time ranges such as daily sessions, weekly, monthly, or custom bar lengths. It identifies key structural price levels including the Point of Con

Indicator v6 VolumeSupport & resistance
Updated 3 months ago · None stated GitHub repository of Comprehensive Volume Profile

Moon Dev GEX Arrows

by moondevonyt
92 stars

This overlay indicator plots option strike walls and an optional session VWAP on the price chart for SPY or ES. It spaces major strikes by the selected instrument, draws a set number of strikes on each side, and marks wall-trap and sweep events after a cooldow

Indicator v5 Support & resistanceSessions & time
Updated 8 weeks ago · Custom licence GitHub repository of Moon Dev GEX Arrows

More indicators

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers