Strategy · Pine Script v6 · On the chart

Delta Break and Retest Stage 8.0.2 Profile and Entry Fix

by rosijay17-cmd

A strategy meant for a 5-minute chart that detects a break of a delta-based level on a 15-minute context, waits for a retest from the correct side, then enters on a reclaim candle.

View on GitHub

Repaints

GitHub stars1on the repository
Pine versionv6current
Lines of code2,474
Settings40inputs
LicenceGPL-3.0
Last update7 days ago22 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 strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

2,474 lines of Pine Script v6 from delta_break_retest/Stage8_ProfileEntryFix.pine, published under GPL-3.0. Keep the author's credit and licence lines when you reuse it.

Stage8_ProfileEntryFix.pine
//@version=6
strategy(
     title = "Delta Break & Retest - Stage 8.0.2 Profile + Entry Fix",
     shorttitle = "DBR S8.0.2",
     overlay = true,
     max_bars_back = 5000,
     max_boxes_count = 500,
     max_lines_count = 500,
     max_labels_count = 300,
     default_qty_type = strategy.fixed,
     default_qty_value = 1,
     calc_on_order_fills = false,
     calc_on_every_tick = true,
     process_orders_on_close = true,
     initial_capital = 100000,
     margin_long = 3,
     margin_short = 3
)

// ============================================================================
// DELTA BREAK & RETEST - STAGE 8
// ----------------------------------------------------------------------------
// RUN ON MNQ 5m.
//
// 15m = break-context / POI event.
// 4H  = directional bias.
// 1H  = active trend quality.
// 5m  = retest + reclaim + execution.
//
// ENTRY SEQUENCE:
// BREAK
// -> RETEST FROM CORRECT SIDE
// -> PRESSURE ROTATION
// -> RECLAIM
// -> 4H + 1H AGREEMENT
// -> ENTRY
//
// IMPORTANT:
// Pine does not expose exchange-native bid/ask aggressor delta here.
// All delta/pressure values below are estimated from OHLCV candle pressure.
// ============================================================================


// ============================================================================
// HELPERS
// ============================================================================

f_clamp(float v, float lo, float hi) =>
    math.max(lo, math.min(hi, v))

f_delta(float o, float h, float l, float c, float v) =>
    float safeRange = math.max(h - l, syminfo.mintick)
    float pressure = f_clamp((c - o) / safeRange, -1.0, 1.0)
    v * pressure

f_typeCodeName(int code) =>
    code == 1 ? "Delta POC" :
     code == 2 ? "Delta Extreme +" :
     code == 3 ? "Delta Extreme -" :
     code == 4 ? "Delta Flip" :
     code == 5 ? "Absorption Node" :
     "?"

float barDelta = f_delta(open, high, low, close, nz(volume, 0.0))
float atr5m = math.max(nz(ta.atr(14), ta.tr(true)), syminfo.mintick)


// ============================================================================
// 01 - 15m BREAK CONTEXT INPUTS
// ============================================================================

string G_BREAK = "01 - 15m Break Context"

string breakContextTimeframeInput = input.timeframe(
     "15",
     "Break-Context Timeframe",
     group = G_BREAK
)

int profileRowsInput = input.int(
     40,
     "POI Extraction Rows",
     minval = 10,
     maxval = 120,
     group = G_BREAK
)

float poiAtrMultInput = input.float(
     0.25,
     "POI Zone Half-Width (x ATR)",
     minval = 0.05,
     maxval = 2.0,
     step = 0.05,
     group = G_BREAK
)

int minEndedSessionBarsInput = input.int(
     10,
     "Minimum Bars To Finalize Session",
     minval = 3,
     maxval = 100,
     group = G_BREAK
)

bool showAbsorptionInput = input.bool(
     true,
     "Track Absorption Node",
     group = G_BREAK
)

float minBreakAtrMultInput = input.float(
     0.10,
     "Minimum Break Buffer (x ATR)",
     minval = 0.0,
     maxval = 1.0,
     step = 0.05,
     group = G_BREAK
)

bool requireBreakDeltaConfirmationInput = input.bool(
     true,
     "Require Estimated Delta On 15m Break",
     group = G_BREAK
)


// ============================================================================
// 02 - RETEST / TRIGGER INPUTS
// ============================================================================

string G_EXEC = "02 - Retest / Trigger"

float retestWindowHoursInput = input.float(
     6.0,
     "Maximum Break-To-Retest Window (Hours)",
     minval = 0.5,
     maxval = 48.0,
     step = 0.5,
     group = G_EXEC
)

int minBarsAfterRetestInput = input.int(
     0,
     "Minimum Bars After Retest Before Trigger",
     minval = 0,
     maxval = 5,
     tooltip = "0 lets the trigger check run on the same bar as the retest touch itself, so a diamond can print on the same bar as its circle whenever reclaim/candle-quality already line up there -- the trigger always fires on the EARLIEST qualifying bar in its window, never a later one, so lowering this is what pulls diamonds as close as possible to circles.",
     group = G_EXEC
)

int maxBarsAfterRetestInput = input.int(
     4,
     "Maximum Bars After Retest To Trigger",
     minval = 1,
     maxval = 12,
     group = G_EXEC
)

float maxRetestOvershootAtrInput = input.float(
     0.10,
     "Maximum Retest Overshoot Beyond Far Edge (ATR)",
     minval = 0.0,
     maxval = 1.0,
     step = 0.05,
     group = G_EXEC
)

float reclaimBufferAtrInput = input.float(
     0.05,
     "Minimum Reclaim Beyond Zone Edge (ATR)",
     minval = 0.0,
     maxval = 0.50,
     step = 0.01,
     group = G_EXEC
)

float maxEntryExtensionAtrInput = input.float(
     0.50,
     "Maximum Entry Extension From Zone (ATR)",
     minval = 0.10,
     maxval = 1.50,
     step = 0.05,
     group = G_EXEC
)

float minimumTriggerBodyFractionInput = input.float(
     0.30,
     "Minimum Trigger Candle Body / Range",
     minval = 0.0,
     maxval = 1.0,
     step = 0.05,
     group = G_EXEC
)

float minimumTriggerCloseLocationInput = input.float(
     0.58,
     "Minimum Trigger Close Location",
     minval = 0.50,
     maxval = 0.95,
     step = 0.05,
     group = G_EXEC
)

bool requireTriggerDeltaConfirmationInput = input.bool(
     false,
     "Require Pressure Rotation On Trigger",
     tooltip = "OFF by default: on-device funnel diagnostics showed this gate (an OHLCV-estimated pressure proxy, not real order-flow delta) blocking ~76% of every retest attempt on MNQ 5m, far more than any other single gate. Turn back on only after re-tuning its thresholds/window against fresh funnel data -- do not just flip it on blind.",
     group = G_EXEC
)

int executionDeltaWindowInput = input.int(
     3,
     "Execution Pressure Window",
     minval = 1,
     maxval = 8,
     group = G_EXEC
)

float minimumDeltaPressureInput = input.float(
     8.0,
     "Minimum Trigger Pressure %",
     minval = 0.0,
     maxval = 60.0,
     step = 1.0,
     group = G_EXEC
)

float minimumDeltaRotationInput = input.float(
     10.0,
     "Minimum Pressure Rotation From Retest %",
     minval = 0.0,
     maxval = 80.0,
     step = 1.0,
     group = G_EXEC
)

bool requireRvolOnTriggerInput = input.bool(
     false,
     "Require RVOL On Trigger",
     group = G_EXEC
)

int triggerRvolLengthInput = input.int(
     20,
     "Trigger RVOL Length",
     minval = 5,
     maxval = 100,
     group = G_EXEC
)

float minimumTriggerRvolInput = input.float(
     1.05,
     "Minimum Trigger RVOL",
     minval = 0.50,
     maxval = 3.0,
     step = 0.05,
     group = G_EXEC
)


// ============================================================================
// 03 - MTF CONTEXT INPUTS
// ============================================================================

string G_MTF = "03 - MTF Context"

string biasTimeframeInput = input.timeframe(
     "240",
     "4H Bias Timeframe",
     group = G_MTF
)

int pivotLeftInput = input.int(
     3,
     "4H Pivot Left",
     minval = 1,
     maxval = 20,
     group = G_MTF
)

int pivotRightInput = input.int(
     3,
     "4H Pivot Right",
     minval = 1,
     maxval = 20,
     group = G_MTF
)

int biasEmaLengthInput = input.int(
     50,
     "4H EMA Length",
     minval = 2,
     group = G_MTF
)

int biasSlopeLookbackInput = input.int(
     5,
     "4H EMA Slope Lookback",
     minval = 1,
     maxval = 50,
     group = G_MTF
)

string trendTimeframeInput = input.timeframe(
     "60",
     "1H Trend Timeframe",
     group = G_MTF
)

int adxLengthInput = input.int(
     14,
     "1H ADX / DI Length",
     minval = 1,
     group = G_MTF
)

float adxMinimumInput = input.float(
     20.0,
     "1H Minimum ADX",
     minval = 0.0,
     step = 0.5,
     group = G_MTF
)

int fastEmaInput = input.int(
     21,
     "1H Fast EMA",
     minval = 1,
     group = G_MTF
)

int slowEmaInput = input.int(
     50,
     "1H Slow EMA",
     minval = 2,
     group = G_MTF
)

int erLengthInput = input.int(
     10,
     "1H Efficiency Ratio Length",
     minval = 2,
     group = G_MTF
)

float erMinimumInput = input.float(
     0.30,
     "1H Minimum Efficiency Ratio",
     minval = 0.0,
     maxval = 1.0,
     step = 0.05,
     group = G_MTF
)

bool require1hTrendAgreementInput = input.bool(
     true,
     "Require 1H Trend Agreement",
     group = G_MTF
)


// ============================================================================
// 04 - COOLDOWN / ORDERS / RISK
// ============================================================================

string G_RISK = "04 - Cooldown / Orders / Risk"

int globalCooldownWinBarsInput = input.int(
     6,
     "Global Cooldown After Win",
     minval = 0,
     group = G_RISK
)

int globalCooldownLossBarsInput = input.int(
     12,
     "Global Cooldown After Loss",
     minval = 0,
     group = G_RISK
)

int directionCooldownBarsInput = input.int(
     12,
     "Direction Cooldown After Loss",
     minval = 0,
     group = G_RISK
)

int consecutiveLossLimitInput = input.int(
     2,
     "Consecutive Loss Session Limit",
     minval = 1,
     group = G_RISK
)

bool requireAlignedEntryInput = input.bool(
     true,
     "Require Full Trend Alignment",
     group = G_RISK
)

bool enableDeltaFlipEntriesInput = input.bool(
     false,
     "Enable Delta Flip POI Entries",
     group = G_RISK
)

float stopBufferAtrMultInput = input.float(
     0.10,
     "Stop Buffer Beyond Zone (x ATR)",
     minval = 0.0,
     maxval = 1.0,
     step = 0.05,
     group = G_RISK
)

float maximumEntryRiskAtrInput = input.float(
     1.25,
     "Maximum Entry-To-Stop Risk (ATR)",
     minval = 0.25,
     maxval = 4.0,
     step = 0.05,
     group = G_RISK
)

float rMultipleInput = input.float(
     2.0,
     "Target R-Multiple",
     minval = 0.5,
     maxval = 10.0,
     step = 0.5,
     group = G_RISK
)

int contractsInput = input.int(
     1,
     "Contracts Per Entry",
     minval = 1,
     maxval = 100,
     group = G_RISK
)


// ============================================================================
// 05 - SIGNAL VISUALS
// ============================================================================

string G_SIG = "05 - Signal Visuals"

bool showRetestTouchMarkerInput = input.bool(
     true,
     "Show Retest Touch Marker",
     group = G_SIG
)

bool showEntrySignalInput = input.bool(
     true,
     "Show Actual Entry Signal",
     group = G_SIG
)

bool showQualifiedTriggerInput = input.bool(
     true,
     "Show Qualified Retest Trigger",
     tooltip = "Diamond = price/pressure retest trigger. Triangle = actual strategy entry after trend, cooldown, POI-type and risk gates.",
     group = G_SIG
)

string entrySignalSizeInput = input.string(
     "Normal",
     "Entry Signal Size",
     options = ["Tiny", "Small", "Normal", "Large", "Huge"],
     group = G_SIG
)

color longEntryColorInput = input.color(
     color.aqua,
     "Long Entry Color",
     group = G_SIG
)

color shortEntryColorInput = input.color(
     color.orange,
     "Short Entry Color",
     group = G_SIG
)

color longTriggerColorInput = input.color(
     color.rgb(70, 160, 255),
     "Long Qualified Trigger Color",
     group = G_SIG
)

color shortTriggerColorInput = input.color(
     color.rgb(255, 120, 70),
     "Short Qualified Trigger Color",
     group = G_SIG
)

color retestLongColorInput = input.color(
     color.new(color.aqua, 20),
     "Long Retest Touch Color",
     group = G_SIG
)

color retestShortColorInput = input.color(
     color.new(color.orange, 20),
     "Short Retest Touch Color",
     group = G_SIG
)

bool highlightEntryBarInput = input.bool(
     true,
     "Highlight Entry Candle",
     group = G_SIG
)


// ============================================================================
// 06 - VOLUME DELTA PROFILE INPUTS
// ============================================================================

string G_PROFILE = "06 - Volume Delta Profile"

bool showVolumeDeltaProfileInput = input.bool(
     true,
     "Show Volume Delta Profile",
     group = G_PROFILE
)

int deltaProfileLookbackInput = input.int(
     360,
     "Profile Lookback Bars",
     minval = 50,
     maxval = 1500,
     step = 10,
     group = G_PROFILE
)

int deltaProfileRowsInput = input.int(
     40,
     "Profile Rows",
     minval = 10,
     maxval = 100,
     step = 5,
     group = G_PROFILE
)

int deltaProfileWidthInput = input.int(
     24,
     "Profile Width (Bars)",
     minval = 8,
     maxval = 80,
     group = G_PROFILE
)

string deltaProfilePlacementInput = input.string(
     "Right Side",
     "Profile Placement",
     options = ["Overlay Left", "Right Side"],
     tooltip = "Right Side draws the profile into the chart's blank right margin, past the last candle -- set the offset below to at least the Profile Width so it fully clears price instead of sitting on top of it. Overlay Left instead draws it directly over the last N historical candles (kept for anyone who prefers that compact look on a narrow phone screen), which is why it was the old default.",
     group = G_PROFILE
)

int deltaProfileOffsetInput = input.int(
     36,
     "Profile Horizontal Offset",
     minval = 0,
     maxval = 60,
     tooltip = "In Right Side mode this is measured from the current bar back to the LEFT edge of the profile -- keep it >= Profile Width so the box lands entirely in blank space past the last candle instead of overlapping price history.",
     group = G_PROFILE
)

string deltaProfileMethodInput = input.string(
     "Candle Pressure",
     "Delta Estimation Method",
     options = ["Candle Pressure", "Bar Polarity"],
     group = G_PROFILE
)

bool showTotalVolumeFrameInput = input.bool(
     true,
     "Show Total Volume Frame",
     group = G_PROFILE
)

bool showDeltaBarsInput = input.bool(
     true,
     "Show Delta Bars",
     group = G_PROFILE
)

bool showProfilePocInput = input.bool(
     true,
     "Show Profile POC",
     group = G_PROFILE
)

color profileBullColorInput = input.color(
     color.rgb(55, 155, 255),
     "Positive Delta Color",
     group = G_PROFILE
)

color profileBearColorInput = input.color(
     color.rgb(245, 82, 95),
     "Negative Delta Color",
     group = G_PROFILE
)

color profileTotalColorInput = input.color(
     color.new(color.gray, 75),
     "Total Volume Frame Color",
     group = G_PROFILE
)

color profilePocColorInput = input.color(
     color.yellow,
     "Profile POC Color",
     group = G_PROFILE
)

int profileTransparencyInput = input.int(
     35,
     "Delta Bar Transparency",
     minval = 0,
     maxval = 90,
     group = G_PROFILE
)


// ============================================================================
// 07 - DASHBOARD
// ============================================================================

string G_DASH = "07 - Dashboard"

bool showDashboardInput = input.bool(
     true,
     "Show Dashboard",
     group = G_DASH
)

int deltaStrengthWindowInput = input.int(
     20,
     "Buyer / Seller Strength Window",
     minval = 5,
     maxval = 200,
     group = G_DASH
)

bool showFunnelDiagnosticsInput = input.bool(
     true,
     "Show Retest Funnel Diagnostics",
     tooltip = "Second table: counts how many break events reach each stage of the retest/trigger chain, and which gate blocks a RETESTED bar most often. Use this to find where signals are dying without Strategy Tester access.",
     group = G_DASH
)

string dashboardSizeInput = input.string(
     "Small",
     "Dashboard Text Size",
     options = ["Tiny", "Small", "Normal", "Large"],
     tooltip = "Shrinks both tables' text (and therefore their footprint) without hiding any row -- use Tiny on a small phone screen.",
     group = G_DASH
)

string dashboardPositionInput = input.string(
     "Bottom Right",
     "Main Dashboard Position",
     options = ["Top Left", "Top Center", "Top Right", "Middle Left", "Middle Center", "Middle Right", "Bottom Left", "Bottom Center", "Bottom Right"],
     group = G_DASH
)

string funnelPositionInput = input.string(
     "Bottom Left",
     "Funnel Diagnostics Position",
     options = ["Top Left", "Top Center", "Top Right", "Middle Left", "Middle Center", "Middle Right", "Bottom Left", "Bottom Center", "Bottom Right"],
     tooltip = "Keep this different from Main Dashboard Position or the two tables will stack on top of each other.",
     group = G_DASH
)

f_tablePosition(string label) =>
    switch label
        "Top Left" => position.top_left
        "Top Center" => position.top_center
        "Top Right" => position.top_right
        "Middle Left" => position.middle_left
        "Middle Center" => position.middle_center
        "Middle Right" => position.middle_right
        "Bottom Left" => position.bottom_left
        "Bottom Center" => position.bottom_center
        "Bottom Right" => position.bottom_right
        => position.bottom_right

f_tableTextSize(string label) =>
    switch label
        "Tiny" => size.tiny
        "Small" => size.small
        "Normal" => size.normal
        "Large" => size.large
        => size.small

tableTextSize = f_tableTextSize(dashboardSizeInput)


// ============================================================================
// EXECUTION PRESSURE / CANDLE QUALITY
// ============================================================================

float executionDeltaSum = 0.0
float executionVolumeSum = 0.0

for i = 0 to executionDeltaWindowInput - 1
    float execVolume = nz(volume[i], 0.0)
    executionDeltaSum += f_delta(open[i], high[i], low[i], close[i], execVolume)
    executionVolumeSum += execVolume

float executionDeltaPressure = (
     executionVolumeSum > 0 ?
     executionDeltaSum / executionVolumeSum * 100.0 :
     0.0
)

float triggerVolumeAverage = ta.sma(volume, triggerRvolLengthInput)
float triggerRvol = triggerVolumeAverage > 0 ? volume / triggerVolumeAverage : 0.0
float triggerRange = math.max(high - low, syminfo.mintick)
float triggerBodyFraction = math.abs(close - open) / triggerRange
float triggerCloseLocation = (close - low) / triggerRange


// ============================================================================
// SESSION POI EXTRACTION
// ============================================================================

f_extractSessionPois(int barsBack, int rows) =>
    float scanHigh = -1.0e20
    float scanLow = 1.0e20

    for i = 1 to barsBack
        scanHigh := math.max(scanHigh, high[i])
        scanLow := math.min(scanLow, low[i])

    float rowStep = math.max((scanHigh - scanLow) / rows, syminfo.mintick)

    array<float> rowDelta = array.new_float(rows, 0.0)
    array<float> rowRange = array.new_float(rows, 0.0)
    array<float> rowVolume = array.new_float(rows, 0.0)

    for i = 1 to barsBack
        float d = f_delta(open[i], high[i], low[i], close[i], nz(volume[i], 0.0))
        int row = int(math.floor((close[i] - scanLow) / rowStep))
        row := math.max(0, math.min(rows - 1, row))
        array.set(rowDelta, row, array.get(rowDelta, row) + d)
        array.set(rowRange, row, array.get(rowRange, row) + (high[i] - low[i]))
        array.set(rowVolume, row, array.get(rowVolume, row) + nz(volume[i], 0.0))

    float maxAbs = -1.0
    int pocRow = -1

    for row = 0 to rows - 1
        float d = array.get(rowDelta, row)
        if math.abs(d) > maxAbs
            maxAbs := math.abs(d)
            pocRow := row

    float pocPrice = pocRow >= 0 ? scanLow + (pocRow + 0.5) * rowStep : na

    float maxPos = 0.0
    int maxPosRow = -1
    float maxNeg = 0.0
    int maxNegRow = -1

    for row = 0 to rows - 1
        float d = array.get(rowDelta, row)
        if d > maxPos
            maxPos := d
            maxPosRow := row
        if d < maxNeg
            maxNeg := d
            maxNegRow := row

    float extremeHighPrice = maxPosRow >= 0 ? scanLow + (maxPosRow + 0.5) * rowStep : na
    float extremeLowPrice = maxNegRow >= 0 ? scanLow + (maxNegRow + 0.5) * rowStep : na

    float cum = 0.0
    float prevCum = 0.0
    float flipPrice = na

    for row = 0 to rows - 1
        prevCum := cum
        cum := cum + array.get(rowDelta, row)
        if row > 0 and ((prevCum <= 0 and cum > 0) or (prevCum >= 0 and cum < 0))
            flipPrice := scanLow + row * rowStep

    float totalVol = 0.0

    for row = 0 to rows - 1
        totalVol += array.get(rowVolume, row)

    float avgVol = totalVol / rows
    float bestRatio = -1.0
    int absorptionRow = -1

    for row = 0 to rows - 1
        if row != pocRow and array.get(rowVolume, row) > avgVol * 0.5
            float rng = array.get(rowRange, row)
            float ratio = rng > 0 ? math.abs(array.get(rowDelta, row)) / rng : 0.0
            if ratio > bestRatio
                bestRatio := ratio
                absorptionRow := row

    float absorptionPrice = absorptionRow >= 0 ? scanLow + (absorptionRow + 0.5) * rowStep : na

    [pocPrice, extremeHighPrice, extremeLowPrice, flipPrice, absorptionPrice]


// ============================================================================
// 15m BREAK CONTEXT
// ============================================================================

f_get15mBreakContextRaw() =>
    float atr15Local = ta.atr(14)
    bool newSessionLocal = ta.change(time("D")) != 0
    var int sessionStartBarLocal = bar_index
    int barsIntoSessionLocal = bar_index - sessionStartBarLocal + 1

    var float pocLevel = na
    var bool pocBroken = false
    var float exHighLevel = na
    var bool exHighBroken = false
    var float exLowLevel = na
    var bool exLowBroken = false
    var float flipLevel = na
    var bool flipBroken = false
    var float absLevel = na
    var bool absBroken = false

    float eventDirection = na
    float eventTypeCode = na
    float eventZoneLow = na
    float eventZoneHigh = na

    if newSessionLocal
        if bar_index > 0 and barsIntoSessionLocal > 1
            int endedBarsLocal = bar_index - sessionStartBarLocal

            if endedBarsLocal >= minEndedSessionBarsInput and not na(atr15Local)
                [pocPx, exHighPx, exLowPx, flipPx, absPx] = f_extractSessionPois(
                     endedBarsLocal,
                     profileRowsInput
                )

                if not na(pocPx)
                    pocLevel := pocPx
                    pocBroken := false

                if not na(exHighPx)
                    exHighLevel := exHighPx
                    exHighBroken := false

                if not na(exLowPx)
                    exLowLevel := exLowPx
                    exLowBroken := false

                if not na(flipPx)
                    flipLevel := flipPx
                    flipBroken := false

                if showAbsorptionInput and not na(absPx)
                    absLevel := absPx
                    absBroken := false

        sessionStartBarLocal := bar_index

    float localBarDelta = f_delta(open, high, low, close, nz(volume, 0.0))
    float buffer = not na(atr15Local) ? atr15Local * minBreakAtrMultInput : 0.0
    float halfWidth = not na(atr15Local) ? atr15Local * poiAtrMultInput : na
    bool deltaOkUp = not requireBreakDeltaConfirmationInput or localBarDelta > 0
    bool deltaOkDown = not requireBreakDeltaConfirmationInput or localBarDelta < 0

    if not na(pocLevel) and not pocBroken and not na(halfWidth)
        float zLow = pocLevel - halfWidth
        float zHigh = pocLevel + halfWidth
        bool brokeUp = close > zHigh + buffer and close[1] <= zHigh + buffer
        bool brokeDown = close < zLow - buffer and close[1] >= zLow - buffer

        if brokeUp and deltaOkUp
            pocBroken := true
            eventDirection := 1.0
            eventTypeCode := 1.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh
        else if brokeDown and deltaOkDown
            pocBroken := true
            eventDirection := -1.0
            eventTypeCode := 1.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh

    if not na(exHighLevel) and not exHighBroken and not na(halfWidth)
        float zLow = exHighLevel - halfWidth
        float zHigh = exHighLevel + halfWidth
        bool brokeUp = close > zHigh + buffer and close[1] <= zHigh + buffer
        bool brokeDown = close < zLow - buffer and close[1] >= zLow - buffer

        if brokeUp and deltaOkUp
            exHighBroken := true
            eventDirection := 1.0
            eventTypeCode := 2.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh
        else if brokeDown and deltaOkDown
            exHighBroken := true
            eventDirection := -1.0
            eventTypeCode := 2.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh

    if not na(exLowLevel) and not exLowBroken and not na(halfWidth)
        float zLow = exLowLevel - halfWidth
        float zHigh = exLowLevel + halfWidth
        bool brokeUp = close > zHigh + buffer and close[1] <= zHigh + buffer
        bool brokeDown = close < zLow - buffer and close[1] >= zLow - buffer

        if brokeUp and deltaOkUp
            exLowBroken := true
            eventDirection := 1.0
            eventTypeCode := 3.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh
        else if brokeDown and deltaOkDown
            exLowBroken := true
            eventDirection := -1.0
            eventTypeCode := 3.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh

    if enableDeltaFlipEntriesInput and not na(flipLevel) and not flipBroken and not na(halfWidth)
        float zLow = flipLevel - halfWidth
        float zHigh = flipLevel + halfWidth
        bool brokeUp = close > zHigh + buffer and close[1] <= zHigh + buffer
        bool brokeDown = close < zLow - buffer and close[1] >= zLow - buffer

        if brokeUp and deltaOkUp
            flipBroken := true
            eventDirection := 1.0
            eventTypeCode := 4.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh
        else if brokeDown and deltaOkDown
            flipBroken := true
            eventDirection := -1.0
            eventTypeCode := 4.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh

    if showAbsorptionInput and not na(absLevel) and not absBroken and not na(halfWidth)
        float zLow = absLevel - halfWidth
        float zHigh = absLevel + halfWidth
        bool brokeUp = close > zHigh + buffer and close[1] <= zHigh + buffer
        bool brokeDown = close < zLow - buffer and close[1] >= zLow - buffer

        if brokeUp and deltaOkUp
            absBroken := true
            eventDirection := 1.0
            eventTypeCode := 5.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh
        else if brokeDown and deltaOkDown
            absBroken := true
            eventDirection := -1.0
            eventTypeCode := 5.0
            eventZoneLow := zLow
            eventZoneHigh := zHigh

    [eventZoneLow, eventZoneHigh, eventDirection, eventTypeCode, float(time)]

f_get15mBreakContext() =>
    [zoneLow, zoneHigh, direction, typeCode, eventTime] = f_get15mBreakContextRaw()
    [zoneLow[1], zoneHigh[1], direction[1], typeCode[1], eventTime[1]]

[breakZoneLow, breakZoneHigh, breakDirectionRaw, breakTypeCodeRaw, breakEventTimeRaw] = request.security(
     syminfo.tickerid,
     breakContextTimeframeInput,
     f_get15mBreakContext(),
     gaps = barmerge.gaps_off,
     lookahead = barmerge.lookahead_on
)

bool haveBrokenAny = not na(breakDirectionRaw)
int breakDirection = haveBrokenAny ? int(breakDirectionRaw) : 0
int breakTypeCode = haveBrokenAny ? int(breakTypeCodeRaw) : 0
int breakEventTime = haveBrokenAny ? int(breakEventTimeRaw) : na


// ============================================================================
// 4H BIAS
// ============================================================================

f_get4hContext() =>
    float ph = ta.pivothigh(high, pivotLeftInput, pivotRightInput)
    float pl = ta.pivotlow(low, pivotLeftInput, pivotRightInput)

    float latestHigh = ta.valuewhen(not na(ph), ph, 0)
    float previousHigh = ta.valuewhen(not na(ph), ph, 1)
    float latestLow = ta.valuewhen(not na(pl), pl, 0)
    float previousLow = ta.valuewhen(not na(pl), pl, 1)

    float ema = ta.ema(close, biasEmaLengthInput)
    bool aboveEma = close > ema
    bool slopeUp = ema > ema[biasSlopeLookbackInput]
    bool slopeDown = ema < ema[biasSlopeLookbackInput]

    [latestHigh[1], previousHigh[1], latestLow[1], previousLow[1], aboveEma[1], slopeUp[1], slopeDown[1]]

[lastPivotHigh, prevPivotHigh, lastPivotLow, prevPivotLow, closeAboveEma4h, emaSlopeUp4h, emaSlopeDown4h] = request.security(
     syminfo.tickerid,
     biasTimeframeInput,
     f_get4hContext(),
     gaps = barmerge.gaps_off,
     lookahead = barmerge.lookahead_on
)

bool haveEnoughPivots = (
     not na(lastPivotHigh) and
     not na(prevPivotHigh) and
     not na(lastPivotLow) and
     not na(prevPivotLow)
)

bool higherHigh = haveEnoughPivots and lastPivotHigh > prevPivotHigh
bool lowerHigh = haveEnoughPivots and lastPivotHigh < prevPivotHigh
bool higherLow = haveEnoughPivots and lastPivotLow > prevPivotLow
bool lowerLow = haveEnoughPivots and lastPivotLow < prevPivotLow

bool structureUp = higherHigh and higherLow
bool structureDown = lowerHigh and lowerLow
bool slowFilterUp = closeAboveEma4h and emaSlopeUp4h
bool slowFilterDown = not closeAboveEma4h and emaSlopeDown4h

string bias = (
     structureUp and slowFilterUp ?
     "LONG_ONLY" :
     structureDown and slowFilterDown ?
     "SHORT_ONLY" :
     "NO_TRADE"
)


// ============================================================================
// 1H TREND
// ============================================================================

f_efficiencyRatio(int length) =>
    float netMove = math.abs(close - close[length])
    float sumMoves = 0.0

    for i = 0 to length - 1
        sumMoves += math.abs(close[i] - close[i + 1])

    sumMoves > 0 ? netMove / sumMoves : 0.0

f_get1hContext() =>
    [plusDi, minusDi, adx] = ta.dmi(adxLengthInput, adxLengthInput)
    float emaFast = ta.ema(close, fastEmaInput)
    float emaSlow = ta.ema(close, slowEmaInput)
    float er = f_efficiencyRatio(erLengthInput)

    [adx[1], emaFast[1], emaSlow[1], er[1]]

[adx1h, emaFast1h, emaSlow1h, er1h] = request.security(
     syminfo.tickerid,
     trendTimeframeInput,
     f_get1hContext(),
     gaps = barmerge.gaps_off,
     lookahead = barmerge.lookahead_on
)

bool adxOk = adx1h >= adxMinimumInput
bool erOk = er1h >= erMinimumInput
bool emaStackBullish1h = emaFast1h > emaSlow1h
bool emaStackBearish1h = emaFast1h < emaSlow1h

bool long1hTrendOk = (
     emaStackBullish1h and
     adxOk and
     erOk
)

bool short1hTrendOk = (
     emaStackBearish1h and
     adxOk and
     erOk
)

bool fullLongContext = (
     bias == "LONG_ONLY" and
     (
          not require1hTrendAgreementInput or
          long1hTrendOk
     )
)

bool fullShortContext = (
     bias == "SHORT_ONLY" and
     (
          not require1hTrendAgreementInput or
          short1hTrendOk
     )
)


// ============================================================================
// COOLDOWN MODULE
// ============================================================================

type CooldownState
    int lastExitBarIndex = na
    bool lastExitWasWin = false
    int lastLongLossBar = na
    int lastShortLossBar = na
    int lossesThisSession = 0
    array<string> usedPoiIds

f_poiUsed(array<string> usedIds, string poiId) =>
    bool found = false

    if array.size(usedIds) > 0
        for i = 0 to array.size(usedIds) - 1
            if array.get(usedIds, i) == poiId
                found := true

    found

f_canTrade(
     CooldownState state,
     string direction,
     string poiId,
     int barIdx,
     int winBars,
     int lossBars,
     int dirBars,
     int lossLimit
) =>
    string reason = "OK"
    bool tradeable = true

    if state.lossesThisSession >= lossLimit
        tradeable := false
        reason := "CONSECUTIVE_LOSS_LOCKOUT"

    if tradeable and not na(state.lastExitBarIndex)
        int requiredBars = state.lastExitWasWin ? winBars : lossBars

        if barIdx - state.lastExitBarIndex <= requiredBars
            tradeable := false
            reason := "GLOBAL_POST_TRADE"

    if tradeable and f_poiUsed(state.usedPoiIds, poiId)
        tradeable := false
        reason := "POI_LOCKOUT"

    if tradeable
        int lastDirLoss = (
             direction == "long" ?
             state.lastLongLossBar :
             state.lastShortLossBar
        )

        if not na(lastDirLoss) and barIdx - lastDirLoss <= dirBars
            tradeable := false
            reason := "DIRECTION_LOCKOUT"

    [tradeable, reason]

f_recordExit(
     CooldownState state,
     int barIdx,
     bool isWin,
     string direction,
     string poiId
) =>
    state.lastExitBarIndex := barIdx
    state.lastExitWasWin := isWin

    if not isWin
        if direction == "long"
            state.lastLongLossBar := barIdx
        else
            state.lastShortLossBar := barIdx

        state.lossesThisSession += 1

    if not f_poiUsed(state.usedPoiIds, poiId)
        array.push(state.usedPoiIds, poiId)

f_resetSession(CooldownState state) =>
    state.lossesThisSession := 0
    array.clear(state.usedPoiIds)

var CooldownState cd = CooldownState.new(
     usedPoiIds = array.new_string()
)

bool newDay5m = ta.change(time("D")) != 0

if barstate.isconfirmed and newDay5m
    f_resetSession(cd)


// ============================================================================
// RETEST / TRIGGER STATE MACHINE
// ============================================================================

var float activeZoneLow = na
var float activeZoneHigh = na
var int activeDirection = 0
var int activeTypeCode = 0
var int activeEventTime = na
var string retestState = "NONE"
var bool activeTriggerAligned = false
var int retestTouchBar = na
var float retestTouchPressure = na

// -- retest funnel diagnostics: count where events die in the chain --
var int cEvents = 0
var int cRetested = 0
var int cTriggered = 0
var int cExpired = 0
var int cInvalidated = 0
var int cEvalBars = 0
var int cReclaimFail = 0
var int cExtensionFail = 0
var int cBodyFail = 0
var int cLocationFail = 0
var int cDeltaFail = 0
var int cRvolFail = 0

bool newBreakEvent = (
     breakDirection != 0 and
     (
          na(activeEventTime) or
          breakEventTime != activeEventTime
     )
)

if newBreakEvent
    cEvents += 1
    activeZoneLow := breakZoneLow
    activeZoneHigh := breakZoneHigh
    activeDirection := breakDirection
    activeTypeCode := breakTypeCode
    activeEventTime := breakEventTime
    retestState := "WATCHING"
    activeTriggerAligned := false
    retestTouchBar := na
    retestTouchPressure := na

int hoursSinceEvent = (
     na(activeEventTime) ?
     na :
     int((time - activeEventTime) / (60 * 60 * 1000))
)

bool windowExpired = (
     not na(activeEventTime) and
     hoursSinceEvent > retestWindowHoursInput
)

bool retestLongTouchNow = false
bool retestShortTouchNow = false

if retestState == "WATCHING"
    if windowExpired
        retestState := "EXPIRED"
        cExpired += 1
    else
        bool failedBeforeRetestLong = (
             activeDirection == 1 and
             close < activeZoneLow
        )

        bool failedBeforeRetestShort = (
             activeDirection == -1 and
             close > activeZoneHigh
        )

        if failedBeforeRetestLong or failedBeforeRetestShort
            retestState := "INVALIDATED"
            cInvalidated += 1
        else
            bool validLongTouch = (
                 activeDirection == 1 and
                 close[1] > activeZoneHigh and
                 low <= activeZoneHigh and
                 high >= activeZoneLow and
                 low >= activeZoneLow -
                 atr5m * maxRetestOvershootAtrInput
            )

            bool validShortTouch = (
                 activeDirection == -1 and
                 close[1] < activeZoneLow and
                 high >= activeZoneLow and
                 low <= activeZoneHigh and
                 high <= activeZoneHigh +
                 atr5m * maxRetestOvershootAtrInput
            )

            if validLongTouch or validShortTouch
                retestState := "RETESTED"
                cRetested += 1
                retestTouchBar := bar_index
                retestTouchPressure := executionDeltaPressure
                retestLongTouchNow := validLongTouch
                retestShortTouchNow := validShortTouch

bool triggerUpNow = false
bool triggerDownNow = false

bool chartIsRecommended5m = timeframe.in_seconds(timeframe.period) == 300

if retestState == "RETESTED"
    int barsAfterRetest = (
         na(retestTouchBar) ?
         100000 :
         bar_index - retestTouchBar
    )

    bool retestTooOld = (
         barsAfterRetest > maxBarsAfterRetestInput
    )

    bool invalidateLong = (
         activeDirection == 1 and
         close <
         activeZoneLow -
         atr5m * maxRetestOvershootAtrInput
    )

    bool invalidateShort = (
         activeDirection == -1 and
         close >
         activeZoneHigh +
         atr5m * maxRetestOvershootAtrInput
    )

    if windowExpired or retestTooOld
        retestState := "EXPIRED"
        cExpired += 1
    else if invalidateLong or invalidateShort
        retestState := "INVALIDATED"
        cInvalidated += 1
    else if barsAfterRetest >= minBarsAfterRetestInput
        float reclaimBuffer = atr5m * reclaimBufferAtrInput
        float maxExtension = atr5m * maxEntryExtensionAtrInput

        bool priceReclaimLong = (
             activeDirection == 1 and
             close > activeZoneHigh + reclaimBuffer
        )

        bool priceReclaimShort = (
             activeDirection == -1 and
             close < activeZoneLow - reclaimBuffer
        )

        bool extensionLongOk = (
             close - activeZoneHigh <= maxExtension
        )

        bool extensionShortOk = (
             activeZoneLow - close <= maxExtension
        )

        bool candleBodyOk = (
             triggerBodyFraction >= minimumTriggerBodyFractionInput
        )

        bool candleLocationLongOk = (
             triggerCloseLocation >= minimumTriggerCloseLocationInput
        )

        bool candleLocationShortOk = (
             triggerCloseLocation <= 1.0 - minimumTriggerCloseLocationInput
        )

        float touchPressure = nz(
             retestTouchPressure,
             0.0
        )

        bool deltaLongOk = (
             not requireTriggerDeltaConfirmationInput or
             (
                  executionDeltaPressure >= minimumDeltaPressureInput and

                  executionDeltaPressure - touchPressure >= minimumDeltaRotationInput
             )
        )

        bool deltaShortOk = (
             not requireTriggerDeltaConfirmationInput or
             (
                  executionDeltaPressure <= -minimumDeltaPressureInput and

                  touchPressure - executionDeltaPressure >= minimumDeltaRotationInput
             )
        )

        bool rvolOk = (
             not requireRvolOnTriggerInput or
             triggerRvol >= minimumTriggerRvolInput
        )

        triggerUpNow := (
             priceReclaimLong and
             extensionLongOk and
             candleBodyOk and
             candleLocationLongOk and
             deltaLongOk and
             rvolOk
        )

        triggerDownNow := (
             priceReclaimShort and
             extensionShortOk and
             candleBodyOk and
             candleLocationShortOk and
             deltaShortOk and
             rvolOk
        )

        // -- funnel diagnostics: tally which gate(s) blocked this bar's attempt,
        // resolved to the active event's own direction so a long event isn't
        // penalized by the (always-false) short-side conditions and vice versa --
        cEvalBars += 1

        bool reclaimOkDir = activeDirection == 1 ? priceReclaimLong : priceReclaimShort
        bool extensionOkDir = activeDirection == 1 ? extensionLongOk : extensionShortOk
        bool locationOkDir = activeDirection == 1 ? candleLocationLongOk : candleLocationShortOk
        bool deltaOkDir = activeDirection == 1 ? deltaLongOk : deltaShortOk

        if not reclaimOkDir
            cReclaimFail += 1
        if not extensionOkDir
            cExtensionFail += 1
        if not candleBodyOk
            cBodyFail += 1
        if not locationOkDir
            cLocationFail += 1
        if not deltaOkDir
            cDeltaFail += 1
        if not rvolOk
            cRvolFail += 1

        if triggerUpNow or triggerDownNow
            retestState := "TRIGGERED"
            cTriggered += 1

            activeTriggerAligned := (
                 (
                      triggerUpNow and
                      fullLongContext
                 ) or
                 (
                      triggerDownNow and
                      fullShortContext
                 )
            )


// ============================================================================
// ORDERS
// ============================================================================

var int lastActedEventTime = na
var string openTradeDirection = ""
var string openTradePoiId = ""
var int openTradeTypeCode = 0
var int entryCallCount = 0
var int processedClosedTrades = 0

bool actualLongEntrySignal = false
bool actualShortEntrySignal = false

bool freshTrigger = (
     retestState == "TRIGGERED" and
     (
          na(lastActedEventTime) or
          activeEventTime != lastActedEventTime
     )
)

if barstate.isconfirmed and freshTrigger and strategy.position_size == 0
    string directionStr = (
         activeDirection == 1 ?
         "long" :
         "short"
    )

    string poiId = (
         f_typeCodeName(activeTypeCode) +
         "_" +
         str.tostring(activeEventTime)
    )

    // -- checked LIVE against current bias, not the frozen activeTriggerAligned
    // snapshot from the (possibly much earlier) trigger bar -- retestState stays
    // "TRIGGERED" until a new break event arrives, so if a prior position was
    // still open at trigger time, entry can fire many bars later once flat; using
    // a stale alignment reading from the original trigger bar could let a
    // counter-trend entry through if bias flipped in that gap --
    bool alignedOk = (
         not requireAlignedEntryInput or
         (
              directionStr == "long" ?
              fullLongContext :
              fullShortContext
         )
    )

    bool typeEnabled = (
         activeTypeCode == 4 ?
         enableDeltaFlipEntriesInput :
         true
    )

    [tradeable, reason] = f_canTrade(
         cd,
         directionStr,
         poiId,
         bar_index,
         globalCooldownWinBarsInput,
         globalCooldownLossBarsInput,
         directionCooldownBarsInput,
         consecutiveLossLimitInput
    )

    lastActedEventTime := activeEventTime

    float stopPrice = (
         directionStr == "long" ?
         activeZoneLow -
         stopBufferAtrMultInput * atr5m :
         activeZoneHigh +
         stopBufferAtrMultInput * atr5m
    )

    float riskPerUnit = math.abs(
         close - stopPrice
    )

    float riskAtr = (
         atr5m > 0 ?
         riskPerUnit / atr5m :
         999.0
    )

    bool riskOk = (
         riskAtr <= maximumEntryRiskAtrInput
    )

    if alignedOk and typeEnabled and tradeable and riskOk
        float targetPrice = (
             directionStr == "long" ?
             close +
             riskPerUnit * rMultipleInput :
             close -
             riskPerUnit * rMultipleInput
        )

        string entryId = (
             directionStr == "long" ?
             "Long" :
             "Short"
        )

        openTradeDirection := directionStr
        openTradePoiId := poiId
        openTradeTypeCode := activeTypeCode

        if directionStr == "long"
            strategy.entry(
                 entryId,
                 strategy.long,
                 qty = contractsInput
            )
            actualLongEntrySignal := true
        else
            strategy.entry(
                 entryId,
                 strategy.short,
                 qty = contractsInput
            )
            actualShortEntrySignal := true

        strategy.exit(
             entryId + " Exit",
             entryId,
             stop = stopPrice,
             limit = targetPrice
        )

        entryCallCount += 1


// ============================================================================
// BROKER-VERIFIED EXIT DETECTION
// ============================================================================

if strategy.closedtrades > processedClosedTrades
    int closedIdx = strategy.closedtrades - 1
    string closedEntryId = strategy.closedtrades.entry_id(closedIdx)
    float closedProfit = strategy.closedtrades.profit(closedIdx)
    bool isWin = closedProfit > 0
    string closedDirection = closedEntryId == "Long" ? "long" : "short"
    int closedExitBar = strategy.closedtrades.exit_bar_index(closedIdx)

    f_recordExit(
         cd,
         closedExitBar,
         isWin,
         closedDirection,
         openTradePoiId
    )

    processedClosedTrades := strategy.closedtrades


// ============================================================================
// ACTIVE RETEST ZONE
// ============================================================================

var box activeZoneBox = na

if barstate.islast
    if not na(activeZoneBox)
        box.delete(activeZoneBox)

    if retestState == "WATCHING" or retestState == "RETESTED"
        color zoneColor = (
             activeDirection == 1 ?
             retestLongColorInput :
             retestShortColorInput
        )

        activeZoneBox := box.new(
             left = bar_index - 40,
             top = activeZoneHigh,
             right = bar_index + 5,
             bottom = activeZoneLow,
             xloc = xloc.bar_index,
             bgcolor = color.new(zoneColor, 87),
             border_color = zoneColor
        )


// ============================================================================
// QUALIFIED RETEST TRIGGER MARKERS
// ----------------------------------------------------------------------------
// Diamond = retest/reclaim/pressure trigger occurred.
// This is intentionally separate from the actual strategy entry triangle.
// ============================================================================

plotshape(
     showQualifiedTriggerInput and triggerUpNow,
     title = "Qualified Long Retest Trigger",
     style = shape.diamond,
     location = location.belowbar,
     size = size.small,
     color = longTriggerColorInput,
     text = "T",
     textcolor = color.white
)

plotshape(
     showQualifiedTriggerInput and triggerDownNow,
     title = "Qualified Short Retest Trigger",
     style = shape.diamond,
     location = location.abovebar,
     size = size.small,
     color = shortTriggerColorInput,
     text = "T",
     textcolor = color.white
)

// ============================================================================
// RETEST TOUCH MARKERS
// ============================================================================

plotshape(
     showRetestTouchMarkerInput and retestLongTouchNow,
     title = "Long Retest Touch",
     style = shape.circle,
     location = location.belowbar,
     size = size.tiny,
     color = retestLongColorInput
)

plotshape(
     showRetestTouchMarkerInput and retestShortTouchNow,
     title = "Short Retest Touch",
     style = shape.circle,
     location = location.abovebar,
     size = size.tiny,
     color = retestShortColorInput
)


// ============================================================================
// ENTRY MARKERS - INPUT-CONTROLLED COLOR + SIZE
// ============================================================================

bool showLongEntry = showEntrySignalInput and actualLongEntrySignal
bool showShortEntry = showEntrySignalInput and actualShortEntrySignal

plotshape(
     showLongEntry and entrySignalSizeInput == "Tiny",
     title = "Long Entry Tiny",
     style = shape.triangleup,
     location = location.belowbar,
     size = size.tiny,
     color = longEntryColorInput,
     text = "LONG",
     textcolor = color.white
)

plotshape(
     showLongEntry and entrySignalSizeInput == "Small",
     title = "Long Entry Small",
     style = shape.triangleup,
     location = location.belowbar,
     size = size.small,
     color = longEntryColorInput,
     text = "LONG",
     textcolor = color.white
)

plotshape(
     showLongEntry and entrySignalSizeInput == "Normal",
     title = "Long Entry Normal",
     style = shape.triangleup,
     location = location.belowbar,
     size = size.normal,
     color = longEntryColorInput,
     text = "LONG",
     textcolor = color.white
)

plotshape(
     showLongEntry and entrySignalSizeInput == "Large",
     title = "Long Entry Large",
     style = shape.triangleup,
     location = location.belowbar,
     size = size.large,
     color = longEntryColorInput,
     text = "LONG",
     textcolor = color.white
)

plotshape(
     showLongEntry and entrySignalSizeInput == "Huge",
     title = "Long Entry Huge",
     style = shape.triangleup,
     location = location.belowbar,
     size = size.huge,
     color = longEntryColorInput,
     text = "LONG",
     textcolor = color.white
)

plotshape(
     showShortEntry and entrySignalSizeInput == "Tiny",
     title = "Short Entry Tiny",
     style = shape.triangledown,
     location = location.abovebar,
     size = size.tiny,
     color = shortEntryColorInput,
     text = "SHORT",
     textcolor = color.white
)

plotshape(
     showShortEntry and entrySignalSizeInput == "Small",
     title = "Short Entry Small",
     style = shape.triangledown,
     location = location.abovebar,
     size = size.small,
     color = shortEntryColorInput,
     text = "SHORT",
     textcolor = color.white
)

plotshape(
     showShortEntry and entrySignalSizeInput == "Normal",
     title = "Short Entry Normal",
     style = shape.triangledown,
     location = location.abovebar,
     size = size.normal,
     color = shortEntryColorInput,
     text = "SHORT",
     textcolor = color.white
)

plotshape(
     showShortEntry and entrySignalSizeInput == "Large",
     title = "Short Entry Large",
     style = shape.triangledown,
     location = location.abovebar,
     size = size.large,
     color = shortEntryColorInput,
     text = "SHORT",
     textcolor = color.white
)

plotshape(
     showShortEntry and entrySignalSizeInput == "Huge",
     title = "Short Entry Huge",
     style = shape.triangledown,
     location = location.abovebar,
     size = size.huge,
     color = shortEntryColorInput,
     text = "SHORT",
     textcolor = color.white
)

barcolor(
     highlightEntryBarInput and actualLongEntrySignal ?
     color.new(longEntryColorInput, 35) :
     highlightEntryBarInput and actualShortEntrySignal ?
     color.new(shortEntryColorInput, 35) :
     na
)


// ============================================================================
// FIXED-RANGE VOLUME DELTA PROFILE
// ----------------------------------------------------------------------------
// Compact mobile-safe profile.
//
// Layout:
// - Entire profile occupies ONE configured width instead of extending 2x width.
// - Overlay Left keeps all boxes on visible historical bars.
// - Right Side only extends by the requested offset.
// - POC is a short segment across the profile itself, not a 360-bar ray.
// - High/low are scanned explicitly so the profile is stable inside
//   barstate.islast.
// ============================================================================

var array<box> profileBoxes = array.new_box()
var array<line> profileLines = array.new_line()

if barstate.islast
    if array.size(profileBoxes) > 0
        for i = 0 to array.size(profileBoxes) - 1
            box.delete(array.get(profileBoxes, i))

    array.clear(profileBoxes)

    if array.size(profileLines) > 0
        for i = 0 to array.size(profileLines) - 1
            line.delete(array.get(profileLines, i))

    array.clear(profileLines)

    if showVolumeDeltaProfileInput
        int profileBars = math.min(deltaProfileLookbackInput, bar_index + 1)

        if profileBars >= 10
            float pHigh = -1.0e20
            float pLow = 1.0e20

            for i = 0 to profileBars - 1
                pHigh := math.max(pHigh, high[i])
                pLow := math.min(pLow, low[i])

            float pStep = math.max(
                 (pHigh - pLow) / deltaProfileRowsInput,
                 syminfo.mintick
            )

            array<float> rowTotal = array.new_float(
                 deltaProfileRowsInput,
                 0.0
            )

            array<float> rowDelta = array.new_float(
                 deltaProfileRowsInput,
                 0.0
            )

            for i = 0 to profileBars - 1
                float bHigh = high[i]
                float bLow = low[i]
                float bOpen = open[i]
                float bClose = close[i]
                float bVol = nz(volume[i], 0.0)
                float bRange = bHigh - bLow

                float signedDelta = (
                     deltaProfileMethodInput == "Bar Polarity" ?
                     (bClose > bOpen ? bVol : -bVol) :
                     f_delta(
                          bOpen,
                          bHigh,
                          bLow,
                          bClose,
                          bVol
                     )
                )

                if bRange <= syminfo.mintick
                    int row = int(
                         math.floor(
                              (bClose - pLow) /
                              pStep
                         )
                    )

                    row := math.max(
                         0,
                         math.min(
                              deltaProfileRowsInput - 1,
                              row
                         )
                    )

                    array.set(
                         rowTotal,
                         row,
                         array.get(rowTotal, row) +
                         bVol
                    )

                    array.set(
                         rowDelta,
                         row,
                         array.get(rowDelta, row) +
                         signedDelta
                    )

                else
                    int firstRow = int(
                         math.floor(
                              (bLow - pLow) /
                              pStep
                         )
                    )

                    int lastRow = int(
                         math.floor(
                              (bHigh - pLow) /
                              pStep
                         )
                    )

                    firstRow := math.max(
                         0,
                         math.min(
                              deltaProfileRowsInput - 1,
                              firstRow
                         )
                    )

                    lastRow := math.max(
                         0,
                         math.min(
                              deltaProfileRowsInput - 1,
                              lastRow
                         )
                    )

                    for row = firstRow to lastRow
                        float rowLow = (
                             pLow +
                             row * pStep
                        )

                        float rowHigh = (
                             rowLow +
                             pStep
                        )

                        float overlap = math.max(
                             0.0,
                             math.min(
                                  bHigh,
                                  rowHigh
                             ) -
                             math.max(
                                  bLow,
                                  rowLow
                             )
                        )

                        float fraction = (
                             overlap /
                             bRange
                        )

                        if fraction > 0
                            array.set(
                                 rowTotal,
                                 row,
                                 array.get(
                                      rowTotal,
                                      row
                                 ) +
                                 bVol * fraction
                            )

                            array.set(
                                 rowDelta,
                                 row,
                                 array.get(
                                      rowDelta,
                                      row
                                 ) +
                                 signedDelta * fraction
                            )

            float maxTotal = 0.0
            float maxAbsDelta = 0.0
            int pocRow = 0

            for row = 0 to deltaProfileRowsInput - 1
                float totalV = array.get(
                     rowTotal,
                     row
                )

                float absDeltaV = math.abs(
                     array.get(
                          rowDelta,
                          row
                     )
                )

                if totalV > maxTotal
                    maxTotal := totalV
                    pocRow := row

                maxAbsDelta := math.max(
                     maxAbsDelta,
                     absDeltaV
                )

            int profileRightX = (
                 deltaProfilePlacementInput == "Right Side" ?
                 bar_index + deltaProfileOffsetInput :
                 bar_index - deltaProfileOffsetInput
            )

            int profileLeftX = (
                 profileRightX -
                 deltaProfileWidthInput
            )

            int profileCenterX = (
                 profileLeftX +
                 int(
                      math.floor(
                           deltaProfileWidthInput *
                           0.5
                      )
                 )
            )

            int deltaHalfWidth = math.max(
                 1,
                 int(
                      math.floor(
                           deltaProfileWidthInput *
                           0.5
                      )
                 )
            )

            for row = 0 to deltaProfileRowsInput - 1
                float rowLow = (
                     pLow +
                     row * pStep
                )

                float rowHigh = (
                     rowLow +
                     pStep
                )

                float rowMid = (
                     rowLow +
                     rowHigh
                ) * 0.5

                float totalV = array.get(
                     rowTotal,
                     row
                )

                float deltaV = array.get(
                     rowDelta,
                     row
                )

                int totalWidth = (
                     maxTotal > 0 ?
                     int(
                          math.round(
                               deltaProfileWidthInput *
                               totalV /
                               maxTotal
                          )
                     ) :
                     0
                )

                int deltaWidth = (
                     maxAbsDelta > 0 ?
                     int(
                          math.round(
                               deltaHalfWidth *
                               math.abs(deltaV) /
                               maxAbsDelta
                          )
                     ) :
                     0
                )

                float halfHeight = (
                     pStep *
                     0.36
                )

                if showTotalVolumeFrameInput and totalWidth > 0
                    int totalLeftX = (
                         profileRightX -
                         totalWidth
                    )

                    box totalBox = box.new(
                         left = totalLeftX,
                         top = rowMid + halfHeight,
                         right = profileRightX,
                         bottom = rowMid - halfHeight,
                         xloc = xloc.bar_index,
                         bgcolor = color.new(
                              profileTotalColorInput,
                              88
                         ),
                         border_color = color.new(
                              profileTotalColorInput,
                              65
                         )
                    )

                    array.push(
                         profileBoxes,
                         totalBox
                    )

                if showDeltaBarsInput and deltaWidth > 0
                    color deltaColor = (
                         deltaV >= 0 ?
                         profileBullColorInput :
                         profileBearColorInput
                    )

                    int deltaLeftX = (
                         deltaV >= 0 ?
                         profileCenterX :
                         profileCenterX -
                         deltaWidth
                    )

                    int deltaRightX = (
                         deltaV >= 0 ?
                         profileCenterX +
                         deltaWidth :
                         profileCenterX
                    )

                    box deltaBox = box.new(
                         left = deltaLeftX,
                         top = rowMid + halfHeight,
                         right = deltaRightX,
                         bottom = rowMid - halfHeight,
                         xloc = xloc.bar_index,
                         bgcolor = color.new(
                              deltaColor,
                              profileTransparencyInput
                         ),
                         border_color = color.new(
                              deltaColor,
                              20
                         )
                    )

                    array.push(
                         profileBoxes,
                         deltaBox
                    )

            if showProfilePocInput
                float profilePocPrice = (
                     pLow +
                     (pocRow + 0.5) *
                     pStep
                )

                line pocLine = line.new(
                     x1 = profileLeftX,
                     y1 = profilePocPrice,
                     x2 = profileRightX,
                     y2 = profilePocPrice,
                     xloc = xloc.bar_index,
                     color = profilePocColorInput,
                     width = 2
                )

                array.push(
                     profileLines,
                     pocLine
                )


// ============================================================================
// DASHBOARD
// ============================================================================

var table statusTable = table.new(
     f_tablePosition(dashboardPositionInput),
     2,
     13,
     bgcolor = color.new(color.rgb(15, 20, 27), 10),
     border_width = 1
)

if barstate.islast and showDashboardInput
    string regime = (
         not adxOk or not erOk ?
         "CHOPPY" :
         fullLongContext ?
         "TRENDING UP" :
         fullShortContext ?
         "TRENDING DOWN" :
         "TRANSITIONAL"
    )

    float rollingBuyDelta = 0.0
    float rollingSellDelta = 0.0

    for i = 0 to deltaStrengthWindowInput - 1
        float d = f_delta(
             open[i],
             high[i],
             low[i],
             close[i],
             nz(volume[i], 0.0)
        )

        if d > 0
            rollingBuyDelta += d
        else
            rollingSellDelta += -d

    float totalPressure = rollingBuyDelta + rollingSellDelta

    float buyRatio = (
         totalPressure > 0 ?
         rollingBuyDelta / totalPressure :
         0.5
    )

    float sellRatio = 1.0 - buyRatio

    string queryDirection = (
         activeDirection == 1 ?
         "long" :
         activeDirection == -1 ?
         "short" :
         "long"
    )

    string queryPoiId = (
         na(activeEventTime) ?
         "none" :
         f_typeCodeName(activeTypeCode) +
         "_" +
         str.tostring(activeEventTime)
    )

    [cooldownOk, cooldownReason] = f_canTrade(
         cd,
         queryDirection,
         queryPoiId,
         bar_index,
         globalCooldownWinBarsInput,
         globalCooldownLossBarsInput,
         directionCooldownBarsInput,
         consecutiveLossLimitInput
    )

    string positionDisplay = (
         strategy.position_size == 0 ?
         "FLAT" :
         strategy.position_size > 0 ?
         "LONG" :
         "SHORT"
    )

    table.cell(statusTable, 0, 0, "DBR STAGE 8.0.2 [r8]", text_color = color.white, bgcolor = color.rgb(22, 52, 86), text_size = tableTextSize)
    table.cell(statusTable, 1, 0, syminfo.ticker + " " + timeframe.period, text_color = color.white, bgcolor = color.rgb(22, 52, 86), text_size = tableTextSize)

    table.cell(statusTable, 0, 1, "4H Bias", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 1, bias, text_color = bias == "LONG_ONLY" ? color.aqua : bias == "SHORT_ONLY" ? color.orange : color.gray, text_size = tableTextSize)

    table.cell(statusTable, 0, 2, "1H Trend", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 2, long1hTrendOk ? "BULL" : short1hTrendOk ? "BEAR" : "MIXED", text_color = long1hTrendOk ? color.aqua : short1hTrendOk ? color.orange : color.gray, text_size = tableTextSize)

    table.cell(statusTable, 0, 3, "Regime", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 3, regime, text_color = regime == "TRENDING UP" ? color.aqua : regime == "TRENDING DOWN" ? color.orange : color.gray, text_size = tableTextSize)

    table.cell(statusTable, 0, 4, "Retest", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 4, retestState + " " + f_typeCodeName(activeTypeCode), text_color = retestState == "TRIGGERED" ? color.white : color.gray, text_size = tableTextSize)

    table.cell(statusTable, 0, 5, "Pressure", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 5, str.tostring(executionDeltaPressure, "#.0") + "%", text_color = executionDeltaPressure >= 0 ? color.aqua : color.orange, text_size = tableTextSize)

    table.cell(statusTable, 0, 6, "RVOL", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 6, str.tostring(triggerRvol, "#.##") + "x", text_color = triggerRvol >= minimumTriggerRvolInput ? color.white : color.gray, text_size = tableTextSize)

    table.cell(statusTable, 0, 7, "Buyers", text_color = color.aqua, text_size = tableTextSize)
    table.cell(statusTable, 1, 7, str.tostring(int(math.round(buyRatio * 100.0))) + "%", text_color = color.aqua, text_size = tableTextSize)

    table.cell(statusTable, 0, 8, "Sellers", text_color = color.orange, text_size = tableTextSize)
    table.cell(statusTable, 1, 8, str.tostring(int(math.round(sellRatio * 100.0))) + "%", text_color = color.orange, text_size = tableTextSize)

    table.cell(statusTable, 0, 9, "Position", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 9, positionDisplay, text_color = strategy.position_size > 0 ? color.aqua : strategy.position_size < 0 ? color.orange : color.gray, text_size = tableTextSize)

    table.cell(statusTable, 0, 10, "Cooldown", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 10, cooldownOk ? "READY" : cooldownReason, text_color = cooldownOk ? color.aqua : color.orange, text_size = tableTextSize)

    table.cell(statusTable, 0, 11, "Broker Trades", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 11, str.tostring(strategy.opentrades) + " / " + str.tostring(strategy.closedtrades), text_color = color.white, text_size = tableTextSize)

    table.cell(statusTable, 0, 12, "Execution Chart", text_color = color.white, text_size = tableTextSize)
    table.cell(statusTable, 1, 12, chartIsRecommended5m ? "5m RECOMMENDED" : timeframe.period + "m - USE 5m FOR EXEC", text_color = chartIsRecommended5m ? color.aqua : color.orange, text_size = tableTextSize)


// ============================================================================
// RETEST FUNNEL DIAGNOSTICS
// ----------------------------------------------------------------------------
// Separate table so it can be toggled off independently of the main
// dashboard. Shows how many break events reached each stage of the
// WATCHING -> RETESTED -> TRIGGERED chain, and -- for bars where the
// RETESTED trigger logic actually ran -- which single gate blocked it most.
// ============================================================================

var table funnelTable = table.new(
     f_tablePosition(funnelPositionInput),
     2,
     9,
     bgcolor = color.new(color.rgb(15, 20, 27), 10),
     border_width = 1
)

if barstate.islast and showDashboardInput and showFunnelDiagnosticsInput
    table.cell(funnelTable, 0, 0, "RETEST FUNNEL", text_color = color.white, bgcolor = color.rgb(22, 52, 86), text_size = tableTextSize)
    table.cell(funnelTable, 1, 0, "", text_color = color.white, bgcolor = color.rgb(22, 52, 86), text_size = tableTextSize)

    table.cell(funnelTable, 0, 1, "Break Events", text_color = color.white, text_size = tableTextSize)
    table.cell(funnelTable, 1, 1, str.tostring(cEvents), text_color = color.white, text_size = tableTextSize)

    table.cell(funnelTable, 0, 2, "-> Retested", text_color = color.white, text_size = tableTextSize)
    table.cell(funnelTable, 1, 2, str.tostring(cRetested), text_color = cRetested > 0 ? color.aqua : color.gray, text_size = tableTextSize)

    table.cell(funnelTable, 0, 3, "-> Triggered", text_color = color.white, text_size = tableTextSize)
    table.cell(funnelTable, 1, 3, str.tostring(cTriggered), text_color = cTriggered > 0 ? color.aqua : color.gray, text_size = tableTextSize)

    table.cell(funnelTable, 0, 4, "Expired / Invalid", text_color = color.white, text_size = tableTextSize)
    table.cell(funnelTable, 1, 4, str.tostring(cExpired) + " / " + str.tostring(cInvalidated), text_color = color.orange, text_size = tableTextSize)

    table.cell(funnelTable, 0, 5, "Eval Bars (RETESTED)", text_color = color.white, text_size = tableTextSize)
    table.cell(funnelTable, 1, 5, str.tostring(cEvalBars), text_color = color.gray, text_size = tableTextSize)

    table.cell(funnelTable, 0, 6, "Fail: Reclaim / Ext", text_color = color.white, text_size = tableTextSize)
    table.cell(funnelTable, 1, 6, str.tostring(cReclaimFail) + " / " + str.tostring(cExtensionFail), text_color = color.orange, text_size = tableTextSize)

    table.cell(funnelTable, 0, 7, "Fail: Body / Loc", text_color = color.white, text_size = tableTextSize)
    table.cell(funnelTable, 1, 7, str.tostring(cBodyFail) + " / " + str.tostring(cLocationFail), text_color = color.orange, text_size = tableTextSize)

    table.cell(funnelTable, 0, 8, "Fail: Delta / RVOL", text_color = color.white, text_size = tableTextSize)
    table.cell(funnelTable, 1, 8, str.tostring(cDeltaFail) + " / " + str.tostring(cRvolFail), text_color = color.orange, text_size = tableTextSize)


// ============================================================================
// ALERTS
// ============================================================================

alertcondition(
     actualLongEntrySignal,
     title = "BULL LONG RETEST ENTRY",
     message = "BULL | LONG ENTRY | BREAK RETEST | {{ticker}} {{interval}} @ {{close}}"
)

alertcondition(
     actualShortEntrySignal,
     title = "BEAR SHORT RETEST ENTRY",
     message = "BEAR | SHORT ENTRY | BREAK RETEST | {{ticker}} {{interval}} @ {{close}}"
)


// ============================================================================
// DATA WINDOW
// ============================================================================

plot(barDelta, title = "Per-Bar Estimated Delta", display = display.data_window)
plot(executionDeltaPressure, title = "Execution Pressure %", display = display.data_window)
plot(triggerRvol, title = "Trigger RVOL", display = display.data_window)
plot(activeDirection, title = "Active Retest Direction", display = display.data_window)
plot(strategy.position_size, title = "Position Size", display = display.data_window)
plot(strategy.opentrades, title = "Open Trades", display = display.data_window)
plot(strategy.closedtrades, title = "Closed Trades", display = display.data_window)
plot(entryCallCount, title = "Entry Calls", display = display.data_window)
plot(triggerUpNow ? 1 : 0, title = "Qualified Long Trigger", display = display.data_window)
plot(triggerDownNow ? 1 : 0, title = "Qualified Short Trigger", display = display.data_window)
plot(actualLongEntrySignal ? 1 : 0, title = "Actual Long Entry", display = display.data_window)
plot(actualShortEntrySignal ? 1 : 0, title = "Actual Short Entry", display = display.data_window)

// ============================================================================
// RECOMMENDED STARTING SETTINGS - MNQ 5m [r3]
// ----------------------------------------------------------------------------
// [r3] update: on-device retest-funnel diagnostics (bottom-left table, see
// "Show Retest Funnel Diagnostics") on real MNQ1! 5m history showed the
// ORIGINAL defaults below let only 1 trigger through 188 RETESTED eval bars
// (0.5%) -- the pressure-rotation gate alone was blocking ~76% of every
// attempt, with close-location and entry-extension as the next two largest
// blockers. Defaults changed below reflect that data. This is a first-pass,
// data-informed loosening on a ~200-event sample across a couple weeks of
// history -- NOT a validated edge. Re-run the funnel after any further
// change, and treat these as a starting point for a real quantor
// walk-forward validation before sizing real risk off them.
//
// 4H Bias TF:                     240
// 1H Trend TF:                    60
// Require 1H Trend Agreement:     ON
//
// Break-to-retest window:         4-6 hours
// Min bars after retest:          1
// Max bars after retest:          4          (was 3)
// Max retest overshoot:           0.10 ATR
// Reclaim buffer:                 0.05 ATR
// Max entry extension:            0.50 ATR   (was 0.35 -- 2nd/3rd largest funnel blocker)
// Min trigger body/range:         0.30
// Min trigger close location:     0.58       (was 0.65 -- 2nd largest funnel blocker, 63% fail)
//
// Pressure window:                3
// Minimum pressure:               8%
// Minimum pressure rotation:      10%
// Require Pressure Rotation:      OFF        (was ON -- confirmed dominant blocker, 76% fail)
// RVOL requirement:               OFF initially
//
// Max entry risk:                 1.25 ATR
// Target:                         2.0R
//
// Volume Delta Profile:
// Lookback:                       360 bars
// Rows:                           40
// Placement:                      Right Side  (was Overlay Left -- sat on top of candles)
// Width:                          24 bars
// Offset:                         36 bars     (was 2 -- must be >= Width to clear price)
// ============================================================================

Overview

Gates include estimated pressure rotation, candle body and close location, entry extension limits, optional relative volume, and 4-hour and 1-hour agreement. Delta is estimated from candle data, not true order flow. It calculates on every tick and pulls higher timeframe data, so live signals may differ.

Details

Published by

rosijay17-cmd on GitHub

Type

Strategy, Pine Script v6

Draws

On the price chart

Category

Volume, Breakout, Support & resistance

Markets

Indices

Timeframes

M1-M5

Risk Notes

  • Signals can change on the live bar or after it closes (repainting)
  • Reads higher-timeframe data with lookahead on, so the history can show signals that were not there in real time

Settings

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

SettingTypeDefaultVariable
Break-Context Timeframetimeframe15breakContextTimeframeInput
POI Extraction Rowsint40profileRowsInput
POI Zone Half-Width (x ATR)float0.25poiAtrMultInput
Minimum Bars To Finalize Sessionint10minEndedSessionBarsInput
Track Absorption NodebooltrueshowAbsorptionInput
Minimum Break Buffer (x ATR)float0.10minBreakAtrMultInput
Require Estimated Delta On 15m BreakbooltruerequireBreakDeltaConfirmationInput
Maximum Break-To-Retest Window (Hours)float6.0retestWindowHoursInput
Minimum Bars After Retest Before Triggerint0minBarsAfterRetestInput
Maximum Bars After Retest To Triggerint4maxBarsAfterRetestInput
Maximum Retest Overshoot Beyond Far Edge (ATR)float0.10maxRetestOvershootAtrInput
Minimum Reclaim Beyond Zone Edge (ATR)float0.05reclaimBufferAtrInput
Show all 40 settings
SettingTypeDefaultVariable
Maximum Entry Extension From Zone (ATR)float0.50maxEntryExtensionAtrInput
Minimum Trigger Candle Body / Rangefloat0.30minimumTriggerBodyFractionInput
Minimum Trigger Close Locationfloat0.58minimumTriggerCloseLocationInput
Require Pressure Rotation On TriggerboolfalserequireTriggerDeltaConfirmationInput
Execution Pressure Windowint3executionDeltaWindowInput
Minimum Trigger Pressure %float8.0minimumDeltaPressureInput
Minimum Pressure Rotation From Retest %float10.0minimumDeltaRotationInput
Require RVOL On TriggerboolfalserequireRvolOnTriggerInput
Trigger RVOL Lengthint20triggerRvolLengthInput
Minimum Trigger RVOLfloat1.05minimumTriggerRvolInput
4H Bias Timeframetimeframe240biasTimeframeInput
4H Pivot Leftint3pivotLeftInput
4H Pivot Rightint3pivotRightInput
4H EMA Lengthint50biasEmaLengthInput
4H EMA Slope Lookbackint5biasSlopeLookbackInput
1H Trend Timeframetimeframe60trendTimeframeInput
1H ADX / DI Lengthint14adxLengthInput
1H Minimum ADXfloat20.0adxMinimumInput
1H Fast EMAint21fastEmaInput
1H Slow EMAint50slowEmaInput
1H Efficiency Ratio Lengthint10erLengthInput
1H Minimum Efficiency Ratiofloat0.30erMinimumInput
Require 1H Trend Agreementbooltruerequire1hTrendAgreementInput
Global Cooldown After Winint6globalCooldownWinBarsInput
Global Cooldown After Lossint12globalCooldownLossBarsInput
Direction Cooldown After Lossint12directionCooldownBarsInput
Consecutive Loss Session Limitint2consecutiveLossLimitInput
Require Full Trend AlignmentbooltruerequireAlignedEntryInput
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

HH, LL, HL, LH Indicator

by akash-yellgetti
1 stars

A strategy-type script that draws the high, low and midpoint of an opening window each day, plus pivot-based support and resistance lines from left and right bar settings. It prints buy or sell labels when the close breaks a pivot level while an EMA-based volu

Strategy v5 Support & resistanceBreakout
Updated 2 years ago · None stated GitHub repository of HH, LL, HL, LH Indicator
1 stars

VABOAlgo is a Pine Script v5 strategy that detects breakouts from a value area. It uses VWAP as a POC proxy and ATR to calculate VAH and VAL, requiring volume above average for confirmation and prior bar consolidation within the VA. Long entries trigger on bre

Strategy v5 BreakoutVolume
Updated 8 months ago · None stated GitHub repository of VABOAlgo (Value Area Breakout)

This trend-following strategy executes a classic Donchian channel breakout system designed to cross-validate backtest results against external framework benchmarks. It triggers a long entry when the closing price breaks above the highest high of the prior entr

Strategy v6 BreakoutTrend
Updated yesterday · AGPL-3.0 GitHub repository of Forven S01509 - Simple Donchian 20/10 Breakout
257 stars

This strategy plots running pivot highs as red R circles and pivot lows as blue S circles directly on the price chart. It computes an EMA 3 and a Cto trend line from close prices, then generates long signals on upward EMA-Cto crossovers combined with price pos

Strategy v6 TrendMoving averages Repaints
Updated 6 weeks ago · None stated GitHub repository of Best Chart 1m Strategy Candle Bar

STRG-HOLP

by harryguiacorn
219 stars

STRG-HOLP is a trading strategy that identifies High of Low Period (HOLP) and Low of High Period (LOHP) breakout setups. It tracks the lowest low or highest high over a user-defined lookback window. A long trade opens when the close breaks above the high of th

Strategy v5 BreakoutSupport & resistance
Updated 1 year ago · None stated GitHub repository of STRG-HOLP

More strategys

Trade Your Charts With a Regulated Broker

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

Compare brokers