Order Block Detector [LuxAlgo] Modified to my way of trading

cando13579

Active member
VIP
Code:
# Order Block Detector [LuxAlgo] - ES Quality Engine V2.2
# Original work:
# https://creativecommons.org/licenses/by-nc-sa/4.0/
# Copyright (c) LuxAlgo
#
# ThinkScript V2 adaptation:
# - Preserves the confirmed volume-pivot and swing-state logic.
# - Preserves bullish/bearish half-candle block coordinates.
# - Adds ATR width and displacement filters.
# - Adds a 0-100 quality score that decays with repeated tests.
# - Tracks FRESH / TEST 1 / TEST 2 / WEAK state.
# - Replaces overlapping same-direction zones only when the newcomer
#   has an equal or better quality score.
# - Adds confirmed midpoint and full-zone rejection markers.
# - Uses three active slots per direction for practical TOS performance.
# - Uses plot wrappers for AddCloud compatibility with recursive state.
# - Does not use future references. A block commits on its confirmation bar.
# - V2.1 adds qualification presets so quality filters cannot silently make
#   the default chart excessively sparse.
# - V2.2 makes all score, overlap, and recursive-state gates NaN-safe.

declare upper;

#==============================================================================
# HELPER SCRIPTS
#==============================================================================

script FreshnessScore {
    input touches = 0;

    plot Score =
        if touches <= 0 then 15
        else if touches == 1 then 12
        else if touches == 2 then 8
        else if touches == 3 then 4
        else 0;
}

script OverlapFraction {
    input newTop = 0.0;
    input newBottom = 0.0;
    input oldTop = 0.0;
    input oldBottom = 0.0;

    def intersection =
        Max(0, Min(newTop, oldTop) - Max(newBottom, oldBottom));
    def smallerWidth =
        Min(Max(0, newTop - newBottom),
            Max(0, oldTop - oldBottom));

    plot Fraction =
        if smallerWidth > 0
        then intersection / smallerWidth
        else 0;
}

script Select3 {
    input value1 = 0.0;
    input value2 = 0.0;
    input value3 = 0.0;
    input keep1 = no;
    input keep2 = no;
    input keep3 = no;
    input which = 1;

    def rank1 = if keep1 then 1 else 0;
    def rank2 = rank1 + (if keep2 then 1 else 0);
    def rank3 = rank2 + (if keep3 then 1 else 0);

    plot Selected =
        if keep1 and rank1 == which then value1
        else if keep2 and rank2 == which then value2
        else if keep3 and rank3 == which then value3
        else Double.NaN;
}

#==============================================================================
# INPUTS
#==============================================================================

input volumePivotLength = 5;

input showBullishOrderBlocks = yes;
input bullishOBsToShow = 3;
input showBearishOrderBlocks = yes;
input bearishOBsToShow = 3;

input mitigationMethod = {default Wick, Close};

# Quality engine
input qualificationMode = {Off, default Balanced, Strict, Custom};
input atrLength = 14;
input relativeVolumeLength = 20;
input fullVolumeScoreRatio = 1.50;
input fullDisplacementScoreATR = 1.50;

input useATRWidthFilter = yes;
input minimumZoneWidthATR = 0.10;
input idealZoneWidthATR = 0.30;
input maximumZoneWidthATR = 0.60;

input useDisplacementFilter = yes;
input minimumDisplacementATR = 0.75;
input minimumBirthScore = 50;

# Touches, reactions, and aging
input reactionWindowBars = 3;
input maximumTouchesBeforeRemoval = 0;
input maximumBlockAgeBars = 0;

# Same-direction overlap control
input suppressOverlappingBlocks = yes;
input overlapThreshold = 0.50;
input replacementScoreMargin = 0;

# Display
input showClouds = yes;
input showBorders = yes;
input borderLineWeight = 1;
input showAverageLines = yes;
input averageLineStyle = {default Solid, Dashed, Dotted};
input averageLineWeight = 1;

input showFormationMarkers = no;
input showBirthBubbles = no;
input showReactionMarkers = yes;
input showMitigationMarkers = no;
input showNearestBlockLabels = yes;
input showDiagnosticLabel = yes;
input showStatusLabel = no;
input enableAlerts = no;

#==============================================================================
# COLORS
#==============================================================================

DefineGlobalColor("Bull APlus", CreateColor(0, 255, 80));
DefineGlobalColor("Bull A", CreateColor(55, 205, 80));
DefineGlobalColor("Bull B", CreateColor(180, 210, 40));
DefineGlobalColor("Bull Weak", CreateColor(85, 120, 85));
DefineGlobalColor("Bull Cloud", CreateColor(18, 76, 30));

DefineGlobalColor("Bear APlus", CreateColor(255, 35, 35));
DefineGlobalColor("Bear A", CreateColor(235, 90, 65));
DefineGlobalColor("Bear B", CreateColor(225, 165, 45));
DefineGlobalColor("Bear Weak", CreateColor(135, 85, 85));
DefineGlobalColor("Bear Cloud", CreateColor(105, 24, 24));

DefineGlobalColor("Average", CreateColor(155, 158, 168));
DefineGlobalColor("Mitigated", CreateColor(255, 180, 0));
DefineGlobalColor("Reaction", CreateColor(255, 255, 255));

#==============================================================================
# CORE LUXALGO DETECTION
#==============================================================================

def bn = BarNumber();

def upper = Highest(high, volumePivotLength);
def lower = Lowest(low, volumePivotLength);

def swingState = CompoundValue(
    1,
    if high[volumePivotLength] > upper then 0
    else if low[volumePivotLength] < lower then 1
    else swingState[1],
    0
);

def enoughPivotData =
    bn > 2 * volumePivotLength and
    !IsNaN(volume[volumePivotLength]);

def volumePivotHigh =
    !IsNaN(close) and
    enoughPivotData and
    volume[volumePivotLength] ==
        Highest(volume, 2 * volumePivotLength + 1);

def bullishOBRaw = volumePivotHigh and swingState == 1;
def bearishOBRaw = volumePivotHigh and swingState == 0;

def sourceHigh = high[volumePivotLength];
def sourceLow = low[volumePivotLength];
def sourceOpen = open[volumePivotLength];
def sourceClose = close[volumePivotLength];
def sourceHL2 = (sourceHigh + sourceLow) / 2;

def newBullTop = sourceHL2;
def newBullBottom = sourceLow;
def newBearTop = sourceHigh;
def newBearBottom = sourceHL2;

#==============================================================================
# ATR, DISPLACEMENT, AND QUALITY SCORE
#==============================================================================

def atr = MovingAverage(
    AverageType.WILDERS,
    TrueRange(high, close, low),
    atrLength
);

def sourceATR = atr[volumePivotLength];
def sourceAverageVolume =
    Average(volume, relativeVolumeLength)[volumePivotLength];

def relativeVolume =
    if IsNaN(sourceAverageVolume) or
       IsNaN(volume[volumePivotLength])
    then 0
    else if sourceAverageVolume > 0
    then volume[volumePivotLength] / sourceAverageVolume
    else 0;

def volumeScore =
    Max(
        0,
        Min(
            25,
            if fullVolumeScoreRatio > 0
            then 25 * relativeVolume / fullVolumeScoreRatio
            else 25
        )
    );

def validSourceATR =
    if IsNaN(sourceATR)
    then no
    else sourceATR > 0;

def zoneWidth = (sourceHigh - sourceLow) / 2;
def zoneWidthATR =
    if validSourceATR and !IsNaN(zoneWidth)
    then zoneWidth / sourceATR
    else 0;

def widthLowerSpan =
    Max(0.01, idealZoneWidthATR - minimumZoneWidthATR);
def widthUpperSpan =
    Max(0.01, maximumZoneWidthATR - idealZoneWidthATR);

def widthScoreRaw =
    if zoneWidthATR <= idealZoneWidthATR
    then 20 * (1 -
        AbsValue(zoneWidthATR - idealZoneWidthATR) / widthLowerSpan)
    else 20 * (1 -
        AbsValue(zoneWidthATR - idealZoneWidthATR) / widthUpperSpan);

def widthScore =
    if IsNaN(widthScoreRaw) or
       zoneWidthATR < minimumZoneWidthATR or
       zoneWidthATR > maximumZoneWidthATR
    then 0
    else Max(0, Min(20, widthScoreRaw));

def bullDisplacement =
    if IsNaN(newBullTop)
    then 0
    else Max(0, Highest(high, volumePivotLength) - newBullTop);
def bearDisplacement =
    if IsNaN(newBearBottom)
    then 0
    else Max(0, newBearBottom - Lowest(low, volumePivotLength));

def bullDisplacementATR =
    if validSourceATR and !IsNaN(bullDisplacement)
    then bullDisplacement / sourceATR
    else 0;
def bearDisplacementATR =
    if validSourceATR and !IsNaN(bearDisplacement)
    then bearDisplacement / sourceATR
    else 0;

def bullDisplacementScore =
    Max(
        0,
        Min(
            30,
            if fullDisplacementScoreATR > 0
            then 30 * bullDisplacementATR / fullDisplacementScoreATR
            else 30
        )
    );

def bearDisplacementScore =
    Max(
        0,
        Min(
            30,
            if fullDisplacementScoreATR > 0
            then 30 * bearDisplacementATR / fullDisplacementScoreATR
            else 30
        )
    );

# Traditional origin-candle direction receives the full 10 points.
def bullOriginScore =
    if IsNaN(sourceClose) or IsNaN(sourceOpen)
    then 5
    else if sourceClose < sourceOpen then 10
    else 5;
def bearOriginScore =
    if IsNaN(sourceClose) or IsNaN(sourceOpen)
    then 5
    else if sourceClose > sourceOpen then 10
    else 5;

# Base score excludes the dynamic 0-15 freshness component.
def bullBaseScoreRaw =
    volumeScore +
    widthScore +
    bullDisplacementScore +
    bullOriginScore;

def bearBaseScoreRaw =
    volumeScore +
    widthScore +
    bearDisplacementScore +
    bearOriginScore;

def bullBaseScore =
    if IsNaN(bullBaseScoreRaw)
    then 0
    else Round(bullBaseScoreRaw, 0);

def bearBaseScore =
    if IsNaN(bearBaseScoreRaw)
    then 0
    else Round(bearBaseScoreRaw, 0);

def bullBirthScore = bullBaseScore + 15;
def bearBirthScore = bearBaseScore + 15;

# Qualification presets:
# Off      = original detector behavior, without quality rejection.
# Balanced = lenient ES defaults; scoring does most of the ranking.
# Strict   = the original V2 hard filters.
# Custom   = user inputs above.
def widthGateEnabled =
    qualificationMode == qualificationMode.Balanced or
    qualificationMode == qualificationMode.Strict or
    (qualificationMode == qualificationMode.Custom and
     useATRWidthFilter);

def displacementGateEnabled =
    qualificationMode == qualificationMode.Balanced or
    qualificationMode == qualificationMode.Strict or
    (qualificationMode == qualificationMode.Custom and
     useDisplacementFilter);

def effectiveMinimumWidthATR =
    if qualificationMode == qualificationMode.Balanced then 0.05
    else if qualificationMode == qualificationMode.Strict then 0.10
    else minimumZoneWidthATR;

def effectiveMaximumWidthATR =
    if qualificationMode == qualificationMode.Balanced then 1.25
    else if qualificationMode == qualificationMode.Strict then 0.60
    else maximumZoneWidthATR;

def effectiveMinimumDisplacementATR =
    if qualificationMode == qualificationMode.Balanced then 0.20
    else if qualificationMode == qualificationMode.Strict then 0.75
    else minimumDisplacementATR;

def effectiveMinimumBirthScore =
    if qualificationMode == qualificationMode.Off then 0
    else if qualificationMode == qualificationMode.Balanced then 30
    else if qualificationMode == qualificationMode.Strict then 50
    else minimumBirthScore;

def widthAccepted =
    if !widthGateEnabled
    then yes
    else if IsNaN(zoneWidthATR)
    then no
    else zoneWidthATR >= effectiveMinimumWidthATR and
         zoneWidthATR <= effectiveMaximumWidthATR;

def bullDisplacementAccepted =
    if !displacementGateEnabled
    then yes
    else if IsNaN(bullDisplacementATR)
    then no
    else bullDisplacementATR >= effectiveMinimumDisplacementATR;

def bearDisplacementAccepted =
    if !displacementGateEnabled
    then yes
    else if IsNaN(bearDisplacementATR)
    then no
    else bearDisplacementATR >= effectiveMinimumDisplacementATR;

# Exact rolling-window mitigation logic from the source study.
def bullMitigationTarget =
    if mitigationMethod == mitigationMethod.Close
    then Lowest(close, volumePivotLength)
    else Lowest(low, volumePivotLength);

def bearMitigationTarget =
    if mitigationMethod == mitigationMethod.Close
    then Highest(close, volumePivotLength)
    else Highest(high, volumePivotLength);

def newBullNotMitigated =
    if !bullishOBRaw or
       IsNaN(bullMitigationTarget) or
       IsNaN(newBullBottom)
    then no
    else bullMitigationTarget >= newBullBottom;
def newBearNotMitigated =
    if !bearishOBRaw or
       IsNaN(bearMitigationTarget) or
       IsNaN(newBearTop)
    then no
    else bearMitigationTarget <= newBearTop;

def bullCandidate =
    if !bullishOBRaw or !newBullNotMitigated
    then no
    else if qualificationMode == qualificationMode.Off
    then yes
    else if IsNaN(bullBirthScore)
    then no
    else widthAccepted and
         bullDisplacementAccepted and
         bullBirthScore >= effectiveMinimumBirthScore;

def bearCandidate =
    if !bearishOBRaw or !newBearNotMitigated
    then no
    else if qualificationMode == qualificationMode.Off
    then yes
    else if IsNaN(bearBirthScore)
    then no
    else widthAccepted and
         bearDisplacementAccepted and
         bearBirthScore >= effectiveMinimumBirthScore;

#==============================================================================
# BULLISH ACTIVE STATE
#==============================================================================

def bTop1;
def bBottom1;
def bBase1;
def bTouches1;
def bBorn1;
def bInTouch1;
def bArmAge1;

def bTop2;
def bBottom2;
def bBase2;
def bTouches2;
def bBorn2;
def bInTouch2;
def bArmAge2;

def bTop3;
def bBottom3;
def bBase3;
def bTouches3;
def bBorn3;
def bInTouch3;
def bArmAge3;

def bActive1 = !IsNaN(bBottom1[1]);
def bActive2 = !IsNaN(bBottom2[1]);
def bActive3 = !IsNaN(bBottom3[1]);

def bOldScore1 =
    if bActive1 and
       !IsNaN(bBase1[1]) and
       !IsNaN(bTouches1[1])
    then bBase1[1] + FreshnessScore(touches = bTouches1[1])
    else 0;
def bOldScore2 =
    if bActive2 and
       !IsNaN(bBase2[1]) and
       !IsNaN(bTouches2[1])
    then bBase2[1] + FreshnessScore(touches = bTouches2[1])
    else 0;
def bOldScore3 =
    if bActive3 and
       !IsNaN(bBase3[1]) and
       !IsNaN(bTouches3[1])
    then bBase3[1] + FreshnessScore(touches = bTouches3[1])
    else 0;

def bMitigationOK1 =
    if !bActive1 then no
    else if IsNaN(close) then yes
    else bullMitigationTarget >= bBottom1[1];
def bMitigationOK2 =
    if !bActive2 then no
    else if IsNaN(close) then yes
    else bullMitigationTarget >= bBottom2[1];
def bMitigationOK3 =
    if !bActive3 then no
    else if IsNaN(close) then yes
    else bullMitigationTarget >= bBottom3[1];

def bAgeOK1 =
    if !bActive1 then no
    else if IsNaN(close) or maximumBlockAgeBars <= 0 then yes
    else if IsNaN(bBorn1[1]) then no
    else bn - bBorn1[1] <= maximumBlockAgeBars;
def bAgeOK2 =
    if !bActive2 then no
    else if IsNaN(close) or maximumBlockAgeBars <= 0 then yes
    else if IsNaN(bBorn2[1]) then no
    else bn - bBorn2[1] <= maximumBlockAgeBars;
def bAgeOK3 =
    if !bActive3 then no
    else if IsNaN(close) or maximumBlockAgeBars <= 0 then yes
    else if IsNaN(bBorn3[1]) then no
    else bn - bBorn3[1] <= maximumBlockAgeBars;

def bKeepPre1 = bActive1 and bMitigationOK1 and bAgeOK1;
def bKeepPre2 = bActive2 and bMitigationOK2 and bAgeOK2;
def bKeepPre3 = bActive3 and bMitigationOK3 and bAgeOK3;

def bOverlap1 =
    if suppressOverlappingBlocks and bullCandidate and bKeepPre1
    then OverlapFraction(
            newTop = newBullTop,
            newBottom = newBullBottom,
            oldTop = bTop1[1],
            oldBottom = bBottom1[1]
         ) >= overlapThreshold
    else no;

def bOverlap2 =
    if suppressOverlappingBlocks and bullCandidate and bKeepPre2
    then OverlapFraction(
            newTop = newBullTop,
            newBottom = newBullBottom,
            oldTop = bTop2[1],
            oldBottom = bBottom2[1]
         ) >= overlapThreshold
    else no;

def bOverlap3 =
    if suppressOverlappingBlocks and bullCandidate and bKeepPre3
    then OverlapFraction(
            newTop = newBullTop,
            newBottom = newBullBottom,
            oldTop = bTop3[1],
            oldBottom = bBottom3[1]
         ) >= overlapThreshold
    else no;

def bullHasOverlap = bOverlap1 or bOverlap2 or bOverlap3;

def bullBestOverlapScore =
    Max(
        if bOverlap1 then bOldScore1 else 0,
        Max(
            if bOverlap2 then bOldScore2 else 0,
            if bOverlap3 then bOldScore3 else 0
        )
    );

def insertBull =
    if !bullCandidate
    then no
    else if !bullHasOverlap
    then yes
    else if IsNaN(bullBirthScore)
    then no
    else bullBirthScore >=
         bullBestOverlapScore + replacementScoreMargin;

def bKeepNoOverlap1 =
    bKeepPre1 and !(insertBull and bOverlap1);
def bKeepNoOverlap2 =
    bKeepPre2 and !(insertBull and bOverlap2);
def bKeepNoOverlap3 =
    bKeepPre3 and !(insertBull and bOverlap3);

def bTouchNow1 =
    if bKeepNoOverlap1 and !IsNaN(close)
    then low <= bTop1[1] and high >= bBottom1[1]
    else no;
def bTouchNow2 =
    if bKeepNoOverlap2 and !IsNaN(close)
    then low <= bTop2[1] and high >= bBottom2[1]
    else no;
def bTouchNow3 =
    if bKeepNoOverlap3 and !IsNaN(close)
    then low <= bTop3[1] and high >= bBottom3[1]
    else no;

def bNewTouch1 =
    if !bTouchNow1 or
       IsNaN(bInTouch1[1]) or
       IsNaN(bBorn1[1])
    then no
    else bInTouch1[1] != 1 and bn > bBorn1[1];
def bNewTouch2 =
    if !bTouchNow2 or
       IsNaN(bInTouch2[1]) or
       IsNaN(bBorn2[1])
    then no
    else bInTouch2[1] != 1 and bn > bBorn2[1];
def bNewTouch3 =
    if !bTouchNow3 or
       IsNaN(bInTouch3[1]) or
       IsNaN(bBorn3[1])
    then no
    else bInTouch3[1] != 1 and bn > bBorn3[1];

def bNextTouches1 =
    if !bKeepNoOverlap1 then 0
    else (if IsNaN(bTouches1[1]) then 0 else bTouches1[1]) +
         (if bNewTouch1 then 1 else 0);
def bNextTouches2 =
    if !bKeepNoOverlap2 then 0
    else (if IsNaN(bTouches2[1]) then 0 else bTouches2[1]) +
         (if bNewTouch2 then 1 else 0);
def bNextTouches3 =
    if !bKeepNoOverlap3 then 0
    else (if IsNaN(bTouches3[1]) then 0 else bTouches3[1]) +
         (if bNewTouch3 then 1 else 0);

def bTouchCountOK1 =
    maximumTouchesBeforeRemoval <= 0 or
    bNextTouches1 <= maximumTouchesBeforeRemoval;
def bTouchCountOK2 =
    maximumTouchesBeforeRemoval <= 0 or
    bNextTouches2 <= maximumTouchesBeforeRemoval;
def bTouchCountOK3 =
    maximumTouchesBeforeRemoval <= 0 or
    bNextTouches3 <= maximumTouchesBeforeRemoval;

def bKeep1 = bKeepNoOverlap1 and bTouchCountOK1;
def bKeep2 = bKeepNoOverlap2 and bTouchCountOK2;
def bKeep3 = bKeepNoOverlap3 and bTouchCountOK3;

def bNextScore1 =
    bBase1[1] + FreshnessScore(touches = bNextTouches1);
def bNextScore2 =
    bBase2[1] + FreshnessScore(touches = bNextTouches2);
def bNextScore3 =
    bBase3[1] + FreshnessScore(touches = bNextTouches3);

def bReactionArmed1 =
    if bNewTouch1
    then yes
    else if IsNaN(bArmAge1[1])
    then no
    else bArmAge1[1] >= 0 and
         bArmAge1[1] < reactionWindowBars;
def bReactionArmed2 =
    if bNewTouch2
    then yes
    else if IsNaN(bArmAge2[1])
    then no
    else bArmAge2[1] >= 0 and
         bArmAge2[1] < reactionWindowBars;
def bReactionArmed3 =
    if bNewTouch3
    then yes
    else if IsNaN(bArmAge3[1])
    then no
    else bArmAge3[1] >= 0 and
         bArmAge3[1] < reactionWindowBars;

def bReaction1 =
    if bKeep1 and bReactionArmed1
    then close > (bTop1[1] + bBottom1[1]) / 2 and
         close > open
    else no;
def bReaction2 =
    if bKeep2 and bReactionArmed2
    then close > (bTop2[1] + bBottom2[1]) / 2 and
         close > open
    else no;
def bReaction3 =
    if bKeep3 and bReactionArmed3
    then close > (bTop3[1] + bBottom3[1]) / 2 and
         close > open
    else no;

def bStrongReaction1 =
    if bReaction1 then close > bTop1[1] else no;
def bStrongReaction2 =
    if bReaction2 then close > bTop2[1] else no;
def bStrongReaction3 =
    if bReaction3 then close > bTop3[1] else no;

def bNextInTouch1 =
    if IsNaN(close) then bInTouch1[1]
    else if bKeep1 then bTouchNow1
    else 0;
def bNextInTouch2 =
    if IsNaN(close) then bInTouch2[1]
    else if bKeep2 then bTouchNow2
    else 0;
def bNextInTouch3 =
    if IsNaN(close) then bInTouch3[1]
    else if bKeep3 then bTouchNow3
    else 0;

def bNextArmAge1 =
    if IsNaN(close) then bArmAge1[1]
    else if !bKeep1 or bReaction1 then -1
    else if bNewTouch1 then 0
    else if bArmAge1[1] >= 0 and
            bArmAge1[1] < reactionWindowBars
         then bArmAge1[1] + 1
    else -1;

def bNextArmAge2 =
    if IsNaN(close) then bArmAge2[1]
    else if !bKeep2 or bReaction2 then -1
    else if bNewTouch2 then 0
    else if bArmAge2[1] >= 0 and
            bArmAge2[1] < reactionWindowBars
         then bArmAge2[1] + 1
    else -1;

def bNextArmAge3 =
    if IsNaN(close) then bArmAge3[1]
    else if !bKeep3 or bReaction3 then -1
    else if bNewTouch3 then 0
    else if bArmAge3[1] >= 0 and
            bArmAge3[1] < reactionWindowBars
         then bArmAge3[1] + 1
    else -1;

# Compact surviving bullish slots.
def bSelTop1 = Select3(
    value1 = bTop1[1], value2 = bTop2[1], value3 = bTop3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 1);
def bSelTop2 = Select3(
    value1 = bTop1[1], value2 = bTop2[1], value3 = bTop3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 2);
def bSelTop3 = Select3(
    value1 = bTop1[1], value2 = bTop2[1], value3 = bTop3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 3);

def bSelBottom1 = Select3(
    value1 = bBottom1[1], value2 = bBottom2[1], value3 = bBottom3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 1);
def bSelBottom2 = Select3(
    value1 = bBottom1[1], value2 = bBottom2[1], value3 = bBottom3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 2);
def bSelBottom3 = Select3(
    value1 = bBottom1[1], value2 = bBottom2[1], value3 = bBottom3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 3);

def bSelBase1 = Select3(
    value1 = bBase1[1], value2 = bBase2[1], value3 = bBase3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 1);
def bSelBase2 = Select3(
    value1 = bBase1[1], value2 = bBase2[1], value3 = bBase3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 2);
def bSelBase3 = Select3(
    value1 = bBase1[1], value2 = bBase2[1], value3 = bBase3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 3);

def bSelTouches1 = Select3(
    value1 = bNextTouches1, value2 = bNextTouches2, value3 = bNextTouches3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 1);
def bSelTouches2 = Select3(
    value1 = bNextTouches1, value2 = bNextTouches2, value3 = bNextTouches3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 2);
def bSelTouches3 = Select3(
    value1 = bNextTouches1, value2 = bNextTouches2, value3 = bNextTouches3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 3);

def bSelBorn1 = Select3(
    value1 = bBorn1[1], value2 = bBorn2[1], value3 = bBorn3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 1);
def bSelBorn2 = Select3(
    value1 = bBorn1[1], value2 = bBorn2[1], value3 = bBorn3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 2);
def bSelBorn3 = Select3(
    value1 = bBorn1[1], value2 = bBorn2[1], value3 = bBorn3[1],
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 3);

def bSelInTouch1 = Select3(
    value1 = bNextInTouch1, value2 = bNextInTouch2, value3 = bNextInTouch3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 1);
def bSelInTouch2 = Select3(
    value1 = bNextInTouch1, value2 = bNextInTouch2, value3 = bNextInTouch3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 2);
def bSelInTouch3 = Select3(
    value1 = bNextInTouch1, value2 = bNextInTouch2, value3 = bNextInTouch3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 3);

def bSelArmAge1 = Select3(
    value1 = bNextArmAge1, value2 = bNextArmAge2, value3 = bNextArmAge3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 1);
def bSelArmAge2 = Select3(
    value1 = bNextArmAge1, value2 = bNextArmAge2, value3 = bNextArmAge3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 2);
def bSelArmAge3 = Select3(
    value1 = bNextArmAge1, value2 = bNextArmAge2, value3 = bNextArmAge3,
    keep1 = bKeep1, keep2 = bKeep2, keep3 = bKeep3, which = 3);

if bn == 1 {
    bTop1 = Double.NaN;
    bBottom1 = Double.NaN;
    bBase1 = Double.NaN;
    bTouches1 = Double.NaN;
    bBorn1 = Double.NaN;
    bInTouch1 = Double.NaN;
    bArmAge1 = Double.NaN;

    bTop2 = Double.NaN;
    bBottom2 = Double.NaN;
    bBase2 = Double.NaN;
    bTouches2 = Double.NaN;
    bBorn2 = Double.NaN;
    bInTouch2 = Double.NaN;
    bArmAge2 = Double.NaN;

    bTop3 = Double.NaN;
    bBottom3 = Double.NaN;
    bBase3 = Double.NaN;
    bTouches3 = Double.NaN;
    bBorn3 = Double.NaN;
    bInTouch3 = Double.NaN;
    bArmAge3 = Double.NaN;
} else if insertBull {
    bTop1 = newBullTop;
    bBottom1 = newBullBottom;
    bBase1 = bullBaseScore;
    bTouches1 = 0;
    bBorn1 = bn;
    bInTouch1 = 0;
    bArmAge1 = -1;

    bTop2 = bSelTop1;
    bBottom2 = bSelBottom1;
    bBase2 = bSelBase1;
    bTouches2 = bSelTouches1;
    bBorn2 = bSelBorn1;
    bInTouch2 = bSelInTouch1;
    bArmAge2 = bSelArmAge1;

    bTop3 = bSelTop2;
    bBottom3 = bSelBottom2;
    bBase3 = bSelBase2;
    bTouches3 = bSelTouches2;
    bBorn3 = bSelBorn2;
    bInTouch3 = bSelInTouch2;
    bArmAge3 = bSelArmAge2;
} else {
    bTop1 = bSelTop1;
    bBottom1 = bSelBottom1;
    bBase1 = bSelBase1;
    bTouches1 = bSelTouches1;
    bBorn1 = bSelBorn1;
    bInTouch1 = bSelInTouch1;
    bArmAge1 = bSelArmAge1;

    bTop2 = bSelTop2;
    bBottom2 = bSelBottom2;
    bBase2 = bSelBase2;
    bTouches2 = bSelTouches2;
    bBorn2 = bSelBorn2;
    bInTouch2 = bSelInTouch2;
    bArmAge2 = bSelArmAge2;

    bTop3 = bSelTop3;
    bBottom3 = bSelBottom3;
    bBase3 = bSelBase3;
    bTouches3 = bSelTouches3;
    bBorn3 = bSelBorn3;
    bInTouch3 = bSelInTouch3;
    bArmAge3 = bSelArmAge3;
}

#==============================================================================
# BEARISH ACTIVE STATE
#==============================================================================

def sTop1;
def sBottom1;
def sBase1;
def sTouches1;
def sBorn1;
def sInTouch1;
def sArmAge1;

def sTop2;
def sBottom2;
def sBase2;
def sTouches2;
def sBorn2;
def sInTouch2;
def sArmAge2;

def sTop3;
def sBottom3;
def sBase3;
def sTouches3;
def sBorn3;
def sInTouch3;
def sArmAge3;

def sActive1 = !IsNaN(sTop1[1]);
def sActive2 = !IsNaN(sTop2[1]);
def sActive3 = !IsNaN(sTop3[1]);

def sOldScore1 =
    if sActive1 and
       !IsNaN(sBase1[1]) and
       !IsNaN(sTouches1[1])
    then sBase1[1] + FreshnessScore(touches = sTouches1[1])
    else 0;
def sOldScore2 =
    if sActive2 and
       !IsNaN(sBase2[1]) and
       !IsNaN(sTouches2[1])
    then sBase2[1] + FreshnessScore(touches = sTouches2[1])
    else 0;
def sOldScore3 =
    if sActive3 and
       !IsNaN(sBase3[1]) and
       !IsNaN(sTouches3[1])
    then sBase3[1] + FreshnessScore(touches = sTouches3[1])
    else 0;

def sMitigationOK1 =
    if !sActive1 then no
    else if IsNaN(close) then yes
    else bearMitigationTarget <= sTop1[1];
def sMitigationOK2 =
    if !sActive2 then no
    else if IsNaN(close) then yes
    else bearMitigationTarget <= sTop2[1];
def sMitigationOK3 =
    if !sActive3 then no
    else if IsNaN(close) then yes
    else bearMitigationTarget <= sTop3[1];

def sAgeOK1 =
    if !sActive1 then no
    else if IsNaN(close) or maximumBlockAgeBars <= 0 then yes
    else if IsNaN(sBorn1[1]) then no
    else bn - sBorn1[1] <= maximumBlockAgeBars;
def sAgeOK2 =
    if !sActive2 then no
    else if IsNaN(close) or maximumBlockAgeBars <= 0 then yes
    else if IsNaN(sBorn2[1]) then no
    else bn - sBorn2[1] <= maximumBlockAgeBars;
def sAgeOK3 =
    if !sActive3 then no
    else if IsNaN(close) or maximumBlockAgeBars <= 0 then yes
    else if IsNaN(sBorn3[1]) then no
    else bn - sBorn3[1] <= maximumBlockAgeBars;

def sKeepPre1 = sActive1 and sMitigationOK1 and sAgeOK1;
def sKeepPre2 = sActive2 and sMitigationOK2 and sAgeOK2;
def sKeepPre3 = sActive3 and sMitigationOK3 and sAgeOK3;

def sOverlap1 =
    if suppressOverlappingBlocks and bearCandidate and sKeepPre1
    then OverlapFraction(
            newTop = newBearTop,
            newBottom = newBearBottom,
            oldTop = sTop1[1],
            oldBottom = sBottom1[1]
         ) >= overlapThreshold
    else no;

def sOverlap2 =
    if suppressOverlappingBlocks and bearCandidate and sKeepPre2
    then OverlapFraction(
            newTop = newBearTop,
            newBottom = newBearBottom,
            oldTop = sTop2[1],
            oldBottom = sBottom2[1]
         ) >= overlapThreshold
    else no;

def sOverlap3 =
    if suppressOverlappingBlocks and bearCandidate and sKeepPre3
    then OverlapFraction(
            newTop = newBearTop,
            newBottom = newBearBottom,
            oldTop = sTop3[1],
            oldBottom = sBottom3[1]
         ) >= overlapThreshold
    else no;

def bearHasOverlap = sOverlap1 or sOverlap2 or sOverlap3;

def bearBestOverlapScore =
    Max(
        if sOverlap1 then sOldScore1 else 0,
        Max(
            if sOverlap2 then sOldScore2 else 0,
            if sOverlap3 then sOldScore3 else 0
        )
    );

def insertBear =
    if !bearCandidate
    then no
    else if !bearHasOverlap
    then yes
    else if IsNaN(bearBirthScore)
    then no
    else bearBirthScore >=
         bearBestOverlapScore + replacementScoreMargin;

def sKeepNoOverlap1 =
    sKeepPre1 and !(insertBear and sOverlap1);
def sKeepNoOverlap2 =
    sKeepPre2 and !(insertBear and sOverlap2);
def sKeepNoOverlap3 =
    sKeepPre3 and !(insertBear and sOverlap3);

def sTouchNow1 =
    if sKeepNoOverlap1 and !IsNaN(close)
    then high >= sBottom1[1] and low <= sTop1[1]
    else no;
def sTouchNow2 =
    if sKeepNoOverlap2 and !IsNaN(close)
    then high >= sBottom2[1] and low <= sTop2[1]
    else no;
def sTouchNow3 =
    if sKeepNoOverlap3 and !IsNaN(close)
    then high >= sBottom3[1] and low <= sTop3[1]
    else no;

def sNewTouch1 =
    if !sTouchNow1 or
       IsNaN(sInTouch1[1]) or
       IsNaN(sBorn1[1])
    then no
    else sInTouch1[1] != 1 and bn > sBorn1[1];
def sNewTouch2 =
    if !sTouchNow2 or
       IsNaN(sInTouch2[1]) or
       IsNaN(sBorn2[1])
    then no
    else sInTouch2[1] != 1 and bn > sBorn2[1];
def sNewTouch3 =
    if !sTouchNow3 or
       IsNaN(sInTouch3[1]) or
       IsNaN(sBorn3[1])
    then no
    else sInTouch3[1] != 1 and bn > sBorn3[1];

def sNextTouches1 =
    if !sKeepNoOverlap1 then 0
    else (if IsNaN(sTouches1[1]) then 0 else sTouches1[1]) +
         (if sNewTouch1 then 1 else 0);
def sNextTouches2 =
    if !sKeepNoOverlap2 then 0
    else (if IsNaN(sTouches2[1]) then 0 else sTouches2[1]) +
         (if sNewTouch2 then 1 else 0);
def sNextTouches3 =
    if !sKeepNoOverlap3 then 0
    else (if IsNaN(sTouches3[1]) then 0 else sTouches3[1]) +
         (if sNewTouch3 then 1 else 0);

def sTouchCountOK1 =
    maximumTouchesBeforeRemoval <= 0 or
    sNextTouches1 <= maximumTouchesBeforeRemoval;
def sTouchCountOK2 =
    maximumTouchesBeforeRemoval <= 0 or
    sNextTouches2 <= maximumTouchesBeforeRemoval;
def sTouchCountOK3 =
    maximumTouchesBeforeRemoval <= 0 or
    sNextTouches3 <= maximumTouchesBeforeRemoval;

def sKeep1 = sKeepNoOverlap1 and sTouchCountOK1;
def sKeep2 = sKeepNoOverlap2 and sTouchCountOK2;
def sKeep3 = sKeepNoOverlap3 and sTouchCountOK3;

def sNextScore1 =
    sBase1[1] + FreshnessScore(touches = sNextTouches1);
def sNextScore2 =
    sBase2[1] + FreshnessScore(touches = sNextTouches2);
def sNextScore3 =
    sBase3[1] + FreshnessScore(touches = sNextTouches3);

def sReactionArmed1 =
    if sNewTouch1
    then yes
    else if IsNaN(sArmAge1[1])
    then no
    else sArmAge1[1] >= 0 and
         sArmAge1[1] < reactionWindowBars;
def sReactionArmed2 =
    if sNewTouch2
    then yes
    else if IsNaN(sArmAge2[1])
    then no
    else sArmAge2[1] >= 0 and
         sArmAge2[1] < reactionWindowBars;
def sReactionArmed3 =
    if sNewTouch3
    then yes
    else if IsNaN(sArmAge3[1])
    then no
    else sArmAge3[1] >= 0 and
         sArmAge3[1] < reactionWindowBars;

def sReaction1 =
    if sKeep1 and sReactionArmed1
    then close < (sTop1[1] + sBottom1[1]) / 2 and
         close < open
    else no;
def sReaction2 =
    if sKeep2 and sReactionArmed2
    then close < (sTop2[1] + sBottom2[1]) / 2 and
         close < open
    else no;
def sReaction3 =
    if sKeep3 and sReactionArmed3
    then close < (sTop3[1] + sBottom3[1]) / 2 and
         close < open
    else no;

def sStrongReaction1 =
    if sReaction1 then close < sBottom1[1] else no;
def sStrongReaction2 =
    if sReaction2 then close < sBottom2[1] else no;
def sStrongReaction3 =
    if sReaction3 then close < sBottom3[1] else no;

def sNextInTouch1 =
    if IsNaN(close) then sInTouch1[1]
    else if sKeep1 then sTouchNow1
    else 0;
def sNextInTouch2 =
    if IsNaN(close) then sInTouch2[1]
    else if sKeep2 then sTouchNow2
    else 0;
def sNextInTouch3 =
    if IsNaN(close) then sInTouch3[1]
    else if sKeep3 then sTouchNow3
    else 0;

def sNextArmAge1 =
    if IsNaN(close) then sArmAge1[1]
    else if !sKeep1 or sReaction1 then -1
    else if sNewTouch1 then 0
    else if sArmAge1[1] >= 0 and
            sArmAge1[1] < reactionWindowBars
         then sArmAge1[1] + 1
    else -1;

def sNextArmAge2 =
    if IsNaN(close) then sArmAge2[1]
    else if !sKeep2 or sReaction2 then -1
    else if sNewTouch2 then 0
    else if sArmAge2[1] >= 0 and
            sArmAge2[1] < reactionWindowBars
         then sArmAge2[1] + 1
    else -1;

def sNextArmAge3 =
    if IsNaN(close) then sArmAge3[1]
    else if !sKeep3 or sReaction3 then -1
    else if sNewTouch3 then 0
    else if sArmAge3[1] >= 0 and
            sArmAge3[1] < reactionWindowBars
         then sArmAge3[1] + 1
    else -1;

# Compact surviving bearish slots.
def sSelTop1 = Select3(
    value1 = sTop1[1], value2 = sTop2[1], value3 = sTop3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 1);
def sSelTop2 = Select3(
    value1 = sTop1[1], value2 = sTop2[1], value3 = sTop3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 2);
def sSelTop3 = Select3(
    value1 = sTop1[1], value2 = sTop2[1], value3 = sTop3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 3);

def sSelBottom1 = Select3(
    value1 = sBottom1[1], value2 = sBottom2[1], value3 = sBottom3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 1);
def sSelBottom2 = Select3(
    value1 = sBottom1[1], value2 = sBottom2[1], value3 = sBottom3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 2);
def sSelBottom3 = Select3(
    value1 = sBottom1[1], value2 = sBottom2[1], value3 = sBottom3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 3);

def sSelBase1 = Select3(
    value1 = sBase1[1], value2 = sBase2[1], value3 = sBase3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 1);
def sSelBase2 = Select3(
    value1 = sBase1[1], value2 = sBase2[1], value3 = sBase3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 2);
def sSelBase3 = Select3(
    value1 = sBase1[1], value2 = sBase2[1], value3 = sBase3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 3);

def sSelTouches1 = Select3(
    value1 = sNextTouches1, value2 = sNextTouches2, value3 = sNextTouches3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 1);
def sSelTouches2 = Select3(
    value1 = sNextTouches1, value2 = sNextTouches2, value3 = sNextTouches3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 2);
def sSelTouches3 = Select3(
    value1 = sNextTouches1, value2 = sNextTouches2, value3 = sNextTouches3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 3);

def sSelBorn1 = Select3(
    value1 = sBorn1[1], value2 = sBorn2[1], value3 = sBorn3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 1);
def sSelBorn2 = Select3(
    value1 = sBorn1[1], value2 = sBorn2[1], value3 = sBorn3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 2);
def sSelBorn3 = Select3(
    value1 = sBorn1[1], value2 = sBorn2[1], value3 = sBorn3[1],
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 3);

def sSelInTouch1 = Select3(
    value1 = sNextInTouch1, value2 = sNextInTouch2, value3 = sNextInTouch3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 1);
def sSelInTouch2 = Select3(
    value1 = sNextInTouch1, value2 = sNextInTouch2, value3 = sNextInTouch3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 2);
def sSelInTouch3 = Select3(
    value1 = sNextInTouch1, value2 = sNextInTouch2, value3 = sNextInTouch3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 3);

def sSelArmAge1 = Select3(
    value1 = sNextArmAge1, value2 = sNextArmAge2, value3 = sNextArmAge3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 1);
def sSelArmAge2 = Select3(
    value1 = sNextArmAge1, value2 = sNextArmAge2, value3 = sNextArmAge3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 2);
def sSelArmAge3 = Select3(
    value1 = sNextArmAge1, value2 = sNextArmAge2, value3 = sNextArmAge3,
    keep1 = sKeep1, keep2 = sKeep2, keep3 = sKeep3, which = 3);

if bn == 1 {
    sTop1 = Double.NaN;
    sBottom1 = Double.NaN;
    sBase1 = Double.NaN;
    sTouches1 = Double.NaN;
    sBorn1 = Double.NaN;
    sInTouch1 = Double.NaN;
    sArmAge1 = Double.NaN;

    sTop2 = Double.NaN;
    sBottom2 = Double.NaN;
    sBase2 = Double.NaN;
    sTouches2 = Double.NaN;
    sBorn2 = Double.NaN;
    sInTouch2 = Double.NaN;
    sArmAge2 = Double.NaN;

    sTop3 = Double.NaN;
    sBottom3 = Double.NaN;
    sBase3 = Double.NaN;
    sTouches3 = Double.NaN;
    sBorn3 = Double.NaN;
    sInTouch3 = Double.NaN;
    sArmAge3 = Double.NaN;
} else if insertBear {
    sTop1 = newBearTop;
    sBottom1 = newBearBottom;
    sBase1 = bearBaseScore;
    sTouches1 = 0;
    sBorn1 = bn;
    sInTouch1 = 0;
    sArmAge1 = -1;

    sTop2 = sSelTop1;
    sBottom2 = sSelBottom1;
    sBase2 = sSelBase1;
    sTouches2 = sSelTouches1;
    sBorn2 = sSelBorn1;
    sInTouch2 = sSelInTouch1;
    sArmAge2 = sSelArmAge1;

    sTop3 = sSelTop2;
    sBottom3 = sSelBottom2;
    sBase3 = sSelBase2;
    sTouches3 = sSelTouches2;
    sBorn3 = sSelBorn2;
    sInTouch3 = sSelInTouch2;
    sArmAge3 = sSelArmAge2;
} else {
    sTop1 = sSelTop1;
    sBottom1 = sSelBottom1;
    sBase1 = sSelBase1;
    sTouches1 = sSelTouches1;
    sBorn1 = sSelBorn1;
    sInTouch1 = sSelInTouch1;
    sArmAge1 = sSelArmAge1;

    sTop2 = sSelTop2;
    sBottom2 = sSelBottom2;
    sBase2 = sSelBase2;
    sTouches2 = sSelTouches2;
    sBorn2 = sSelBorn2;
    sInTouch2 = sSelInTouch2;
    sArmAge2 = sSelArmAge2;

    sTop3 = sSelTop3;
    sBottom3 = sSelBottom3;
    sBase3 = sSelBase3;
    sTouches3 = sSelTouches3;
    sBorn3 = sSelBorn3;
    sInTouch3 = sSelInTouch3;
    sArmAge3 = sSelArmAge3;
}

#==============================================================================
# CURRENT SCORES AND EVENTS
#==============================================================================

def bScore1 = bBase1 + FreshnessScore(touches = bTouches1);
def bScore2 = bBase2 + FreshnessScore(touches = bTouches2);
def bScore3 = bBase3 + FreshnessScore(touches = bTouches3);

def sScore1 = sBase1 + FreshnessScore(touches = sTouches1);
def sScore2 = sBase2 + FreshnessScore(touches = sTouches2);
def sScore3 = sBase3 + FreshnessScore(touches = sTouches3);

def activeBullCount =
    (if !IsNaN(bBottom1) then 1 else 0) +
    (if !IsNaN(bBottom2) then 1 else 0) +
    (if !IsNaN(bBottom3) then 1 else 0);

def activeBearCount =
    (if !IsNaN(sTop1) then 1 else 0) +
    (if !IsNaN(sTop2) then 1 else 0) +
    (if !IsNaN(sTop3) then 1 else 0);

def rawDetectionIncrement =
    if bullishOBRaw or bearishOBRaw then 1 else 0;

def qualifiedDetectionIncrement =
    if insertBull or insertBear then 1 else 0;

def rawDetectionCount = CompoundValue(
    1,
    (if IsNaN(rawDetectionCount[1])
     then 0
     else rawDetectionCount[1]) +
    rawDetectionIncrement,
    0
);

def qualifiedDetectionCount = CompoundValue(
    1,
    (if IsNaN(qualifiedDetectionCount[1])
     then 0
     else qualifiedDetectionCount[1]) +
    qualifiedDetectionIncrement,
    0
);

def bullishOBMitigated =
    (bActive1 and !bMitigationOK1) or
    (bActive2 and !bMitigationOK2) or
    (bActive3 and !bMitigationOK3) or
    (bullishOBRaw and !newBullNotMitigated);

def bearishOBMitigated =
    (sActive1 and !sMitigationOK1) or
    (sActive2 and !sMitigationOK2) or
    (sActive3 and !sMitigationOK3) or
    (bearishOBRaw and !newBearNotMitigated);

def bullReactionAny = bReaction1 or bReaction2 or bReaction3;
def bullStrongReactionAny =
    bStrongReaction1 or bStrongReaction2 or bStrongReaction3;

def bearReactionAny = sReaction1 or sReaction2 or sReaction3;
def bearStrongReactionAny =
    sStrongReaction1 or sStrongReaction2 or sStrongReaction3;

#==============================================================================
# DISPLAY SELECTION
#==============================================================================

def bullDisplayCount =
    if bullishOBsToShow < 1 then 0
    else if bullishOBsToShow > 3 then 3
    else bullishOBsToShow;

def bearDisplayCount =
    if bearishOBsToShow < 1 then 0
    else if bearishOBsToShow > 3 then 3
    else bearishOBsToShow;

def showB1 =
    showBullishOrderBlocks and bullDisplayCount >= 1 and !IsNaN(bBottom1);
def showB2 =
    showBullishOrderBlocks and bullDisplayCount >= 2 and !IsNaN(bBottom2);
def showB3 =
    showBullishOrderBlocks and bullDisplayCount >= 3 and !IsNaN(bBottom3);

def showS1 =
    showBearishOrderBlocks and bearDisplayCount >= 1 and !IsNaN(sTop1);
def showS2 =
    showBearishOrderBlocks and bearDisplayCount >= 2 and !IsNaN(sTop2);
def showS3 =
    showBearishOrderBlocks and bearDisplayCount >= 3 and !IsNaN(sTop3);

#==============================================================================
# CLOUD WRAPPERS
#==============================================================================

plot BullCloudTop1 =
    if showClouds and showB1 then bTop1 else Double.NaN;
plot BullCloudBottom1 =
    if showClouds and showB1 then bBottom1 else Double.NaN;
plot BullCloudTop2 =
    if showClouds and showB2 then bTop2 else Double.NaN;
plot BullCloudBottom2 =
    if showClouds and showB2 then bBottom2 else Double.NaN;
plot BullCloudTop3 =
    if showClouds and showB3 then bTop3 else Double.NaN;
plot BullCloudBottom3 =
    if showClouds and showB3 then bBottom3 else Double.NaN;

BullCloudTop1.Hide();
BullCloudBottom1.Hide();
BullCloudTop2.Hide();
BullCloudBottom2.Hide();
BullCloudTop3.Hide();
BullCloudBottom3.Hide();

AddCloud(
    BullCloudTop1,
    BullCloudBottom1,
    GlobalColor("Bull Cloud"),
    GlobalColor("Bull Cloud")
);
AddCloud(
    BullCloudTop2,
    BullCloudBottom2,
    GlobalColor("Bull Cloud"),
    GlobalColor("Bull Cloud")
);
AddCloud(
    BullCloudTop3,
    BullCloudBottom3,
    GlobalColor("Bull Cloud"),
    GlobalColor("Bull Cloud")
);

plot BearCloudTop1 =
    if showClouds and showS1 then sTop1 else Double.NaN;
plot BearCloudBottom1 =
    if showClouds and showS1 then sBottom1 else Double.NaN;
plot BearCloudTop2 =
    if showClouds and showS2 then sTop2 else Double.NaN;
plot BearCloudBottom2 =
    if showClouds and showS2 then sBottom2 else Double.NaN;
plot BearCloudTop3 =
    if showClouds and showS3 then sTop3 else Double.NaN;
plot BearCloudBottom3 =
    if showClouds and showS3 then sBottom3 else Double.NaN;

BearCloudTop1.Hide();
BearCloudBottom1.Hide();
BearCloudTop2.Hide();
BearCloudBottom2.Hide();
BearCloudTop3.Hide();
BearCloudBottom3.Hide();

AddCloud(
    BearCloudTop1,
    BearCloudBottom1,
    GlobalColor("Bear Cloud"),
    GlobalColor("Bear Cloud")
);
AddCloud(
    BearCloudTop2,
    BearCloudBottom2,
    GlobalColor("Bear Cloud"),
    GlobalColor("Bear Cloud")
);
AddCloud(
    BearCloudTop3,
    BearCloudBottom3,
    GlobalColor("Bear Cloud"),
    GlobalColor("Bear Cloud")
);

#==============================================================================
# BORDERS
#==============================================================================

plot BullTop1 = if showBorders and showB1 then bTop1 else Double.NaN;
plot BullBottom1 = if showBorders and showB1 then bBottom1 else Double.NaN;
plot BullTop2 = if showBorders and showB2 then bTop2 else Double.NaN;
plot BullBottom2 = if showBorders and showB2 then bBottom2 else Double.NaN;
plot BullTop3 = if showBorders and showB3 then bTop3 else Double.NaN;
plot BullBottom3 = if showBorders and showB3 then bBottom3 else Double.NaN;

plot BearTop1 = if showBorders and showS1 then sTop1 else Double.NaN;
plot BearBottom1 = if showBorders and showS1 then sBottom1 else Double.NaN;
plot BearTop2 = if showBorders and showS2 then sTop2 else Double.NaN;
plot BearBottom2 = if showBorders and showS2 then sBottom2 else Double.NaN;
plot BearTop3 = if showBorders and showS3 then sTop3 else Double.NaN;
plot BearBottom3 = if showBorders and showS3 then sBottom3 else Double.NaN;

BullTop1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BullBottom1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BullTop2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BullBottom2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BullTop3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BullBottom3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

BearTop1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BearBottom1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BearTop2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BearBottom2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BearTop3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BearBottom3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

BullTop1.SetLineWeight(borderLineWeight);
BullBottom1.SetLineWeight(borderLineWeight);
BullTop2.SetLineWeight(borderLineWeight);
BullBottom2.SetLineWeight(borderLineWeight);
BullTop3.SetLineWeight(borderLineWeight);
BullBottom3.SetLineWeight(borderLineWeight);

BearTop1.SetLineWeight(borderLineWeight);
BearBottom1.SetLineWeight(borderLineWeight);
BearTop2.SetLineWeight(borderLineWeight);
BearBottom2.SetLineWeight(borderLineWeight);
BearTop3.SetLineWeight(borderLineWeight);
BearBottom3.SetLineWeight(borderLineWeight);

BullTop1.AssignValueColor(
    if bScore1 >= 80 then GlobalColor("Bull APlus")
    else if bScore1 >= 65 then GlobalColor("Bull A")
    else if bScore1 >= 50 then GlobalColor("Bull B")
    else GlobalColor("Bull Weak")
);
BullBottom1.AssignValueColor(
    if bScore1 >= 80 then GlobalColor("Bull APlus")
    else if bScore1 >= 65 then GlobalColor("Bull A")
    else if bScore1 >= 50 then GlobalColor("Bull B")
    else GlobalColor("Bull Weak")
);
BullTop2.AssignValueColor(
    if bScore2 >= 80 then GlobalColor("Bull APlus")
    else if bScore2 >= 65 then GlobalColor("Bull A")
    else if bScore2 >= 50 then GlobalColor("Bull B")
    else GlobalColor("Bull Weak")
);
BullBottom2.AssignValueColor(
    if bScore2 >= 80 then GlobalColor("Bull APlus")
    else if bScore2 >= 65 then GlobalColor("Bull A")
    else if bScore2 >= 50 then GlobalColor("Bull B")
    else GlobalColor("Bull Weak")
);
BullTop3.AssignValueColor(
    if bScore3 >= 80 then GlobalColor("Bull APlus")
    else if bScore3 >= 65 then GlobalColor("Bull A")
    else if bScore3 >= 50 then GlobalColor("Bull B")
    else GlobalColor("Bull Weak")
);
BullBottom3.AssignValueColor(
    if bScore3 >= 80 then GlobalColor("Bull APlus")
    else if bScore3 >= 65 then GlobalColor("Bull A")
    else if bScore3 >= 50 then GlobalColor("Bull B")
    else GlobalColor("Bull Weak")
);

BearTop1.AssignValueColor(
    if sScore1 >= 80 then GlobalColor("Bear APlus")
    else if sScore1 >= 65 then GlobalColor("Bear A")
    else if sScore1 >= 50 then GlobalColor("Bear B")
    else GlobalColor("Bear Weak")
);
BearBottom1.AssignValueColor(
    if sScore1 >= 80 then GlobalColor("Bear APlus")
    else if sScore1 >= 65 then GlobalColor("Bear A")
    else if sScore1 >= 50 then GlobalColor("Bear B")
    else GlobalColor("Bear Weak")
);
BearTop2.AssignValueColor(
    if sScore2 >= 80 then GlobalColor("Bear APlus")
    else if sScore2 >= 65 then GlobalColor("Bear A")
    else if sScore2 >= 50 then GlobalColor("Bear B")
    else GlobalColor("Bear Weak")
);
BearBottom2.AssignValueColor(
    if sScore2 >= 80 then GlobalColor("Bear APlus")
    else if sScore2 >= 65 then GlobalColor("Bear A")
    else if sScore2 >= 50 then GlobalColor("Bear B")
    else GlobalColor("Bear Weak")
);
BearTop3.AssignValueColor(
    if sScore3 >= 80 then GlobalColor("Bear APlus")
    else if sScore3 >= 65 then GlobalColor("Bear A")
    else if sScore3 >= 50 then GlobalColor("Bear B")
    else GlobalColor("Bear Weak")
);
BearBottom3.AssignValueColor(
    if sScore3 >= 80 then GlobalColor("Bear APlus")
    else if sScore3 >= 65 then GlobalColor("Bear A")
    else if sScore3 >= 50 then GlobalColor("Bear B")
    else GlobalColor("Bear Weak")
);

#==============================================================================
# AVERAGE LINES
#==============================================================================

plot BullAverage1 =
    if showAverageLines and showB1
    then (bTop1 + bBottom1) / 2
    else Double.NaN;
plot BullAverage2 =
    if showAverageLines and showB2
    then (bTop2 + bBottom2) / 2
    else Double.NaN;
plot BullAverage3 =
    if showAverageLines and showB3
    then (bTop3 + bBottom3) / 2
    else Double.NaN;

plot BearAverage1 =
    if showAverageLines and showS1
    then (sTop1 + sBottom1) / 2
    else Double.NaN;
plot BearAverage2 =
    if showAverageLines and showS2
    then (sTop2 + sBottom2) / 2
    else Double.NaN;
plot BearAverage3 =
    if showAverageLines and showS3
    then (sTop3 + sBottom3) / 2
    else Double.NaN;

BullAverage1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BullAverage2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BullAverage3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BearAverage1.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BearAverage2.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);
BearAverage3.SetPaintingStrategy(PaintingStrategy.HORIZONTAL);

BullAverage1.SetDefaultColor(GlobalColor("Average"));
BullAverage2.SetDefaultColor(GlobalColor("Average"));
BullAverage3.SetDefaultColor(GlobalColor("Average"));
BearAverage1.SetDefaultColor(GlobalColor("Average"));
BearAverage2.SetDefaultColor(GlobalColor("Average"));
BearAverage3.SetDefaultColor(GlobalColor("Average"));

BullAverage1.SetLineWeight(averageLineWeight);
BullAverage2.SetLineWeight(averageLineWeight);
BullAverage3.SetLineWeight(averageLineWeight);
BearAverage1.SetLineWeight(averageLineWeight);
BearAverage2.SetLineWeight(averageLineWeight);
BearAverage3.SetLineWeight(averageLineWeight);

BullAverage1.SetStyle(
    if averageLineStyle == averageLineStyle.Solid then Curve.FIRM
    else if averageLineStyle == averageLineStyle.Dashed
         then Curve.SHORT_DASH
    else Curve.POINTS
);
BullAverage2.SetStyle(
    if averageLineStyle == averageLineStyle.Solid then Curve.FIRM
    else if averageLineStyle == averageLineStyle.Dashed
         then Curve.SHORT_DASH
    else Curve.POINTS
);
BullAverage3.SetStyle(
    if averageLineStyle == averageLineStyle.Solid then Curve.FIRM
    else if averageLineStyle == averageLineStyle.Dashed
         then Curve.SHORT_DASH
    else Curve.POINTS
);
BearAverage1.SetStyle(
    if averageLineStyle == averageLineStyle.Solid then Curve.FIRM
    else if averageLineStyle == averageLineStyle.Dashed
         then Curve.SHORT_DASH
    else Curve.POINTS
);
BearAverage2.SetStyle(
    if averageLineStyle == averageLineStyle.Solid then Curve.FIRM
    else if averageLineStyle == averageLineStyle.Dashed
         then Curve.SHORT_DASH
    else Curve.POINTS
);
BearAverage3.SetStyle(
    if averageLineStyle == averageLineStyle.Solid then Curve.FIRM
    else if averageLineStyle == averageLineStyle.Dashed
         then Curve.SHORT_DASH
    else Curve.POINTS
);

#==============================================================================
# EVENT MARKERS
#==============================================================================

plot BullFormation = showFormationMarkers and insertBull;
BullFormation.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
BullFormation.SetDefaultColor(GlobalColor("Bull A"));
BullFormation.SetLineWeight(1);

plot BearFormation = showFormationMarkers and insertBear;
BearFormation.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
BearFormation.SetDefaultColor(GlobalColor("Bear A"));
BearFormation.SetLineWeight(1);

plot BullReaction =
    showReactionMarkers and bullReactionAny and !bullStrongReactionAny;
BullReaction.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
BullReaction.SetDefaultColor(GlobalColor("Reaction"));
BullReaction.SetLineWeight(1);

plot BullStrongReaction =
    showReactionMarkers and bullStrongReactionAny;
BullStrongReaction.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_UP);
BullStrongReaction.SetDefaultColor(GlobalColor("Bull APlus"));
BullStrongReaction.SetLineWeight(2);

plot BearReaction =
    showReactionMarkers and bearReactionAny and !bearStrongReactionAny;
BearReaction.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
BearReaction.SetDefaultColor(GlobalColor("Reaction"));
BearReaction.SetLineWeight(1);

plot BearStrongReaction =
    showReactionMarkers and bearStrongReactionAny;
BearStrongReaction.SetPaintingStrategy(PaintingStrategy.BOOLEAN_ARROW_DOWN);
BearStrongReaction.SetDefaultColor(GlobalColor("Bear APlus"));
BearStrongReaction.SetLineWeight(2);

plot BullMitigation =
    if showMitigationMarkers and bullishOBMitigated and !IsNaN(close)
    then bullMitigationTarget
    else Double.NaN;
BullMitigation.SetPaintingStrategy(PaintingStrategy.POINTS);
BullMitigation.SetDefaultColor(GlobalColor("Mitigated"));
BullMitigation.SetLineWeight(3);

plot BearMitigation =
    if showMitigationMarkers and bearishOBMitigated and !IsNaN(close)
    then bearMitigationTarget
    else Double.NaN;
BearMitigation.SetPaintingStrategy(PaintingStrategy.POINTS);
BearMitigation.SetDefaultColor(GlobalColor("Mitigated"));
BearMitigation.SetLineWeight(3);

AddChartBubble(
    showBirthBubbles and insertBull,
    low,
    "B " +
    (if bullBirthScore >= 80 then "A+"
     else if bullBirthScore >= 65 then "A"
     else if bullBirthScore >= 50 then "B"
     else "C") +
    " " + bullBirthScore,
    GlobalColor("Bull A"),
    no
);

AddChartBubble(
    showBirthBubbles and insertBear,
    high,
    "S " +
    (if bearBirthScore >= 80 then "A+"
     else if bearBirthScore >= 65 then "A"
     else if bearBirthScore >= 50 then "B"
     else "C") +
    " " + bearBirthScore,
    GlobalColor("Bear A"),
    yes
);

#==============================================================================
# NEAREST-BLOCK LABELS
#==============================================================================

def bDistance1 =
    if showB1
    then if close > bTop1 then close - bTop1
         else if close < bBottom1 then bBottom1 - close
         else 0
    else Double.POSITIVE_INFINITY;

def bDistance2 =
    if showB2
    then if close > bTop2 then close - bTop2
         else if close < bBottom2 then bBottom2 - close
         else 0
    else Double.POSITIVE_INFINITY;

def bDistance3 =
    if showB3
    then if close > bTop3 then close - bTop3
         else if close < bBottom3 then bBottom3 - close
         else 0
    else Double.POSITIVE_INFINITY;

def nearestBullIndex =
    if !showB1 and !showB2 and !showB3 then 0
    else if bDistance1 <= bDistance2 and bDistance1 <= bDistance3 then 1
    else if bDistance2 <= bDistance3 then 2
    else 3;

def nearestBullTop =
    if nearestBullIndex == 1 then bTop1
    else if nearestBullIndex == 2 then bTop2
    else if nearestBullIndex == 3 then bTop3
    else Double.NaN;

def nearestBullBottom =
    if nearestBullIndex == 1 then bBottom1
    else if nearestBullIndex == 2 then bBottom2
    else if nearestBullIndex == 3 then bBottom3
    else Double.NaN;

def nearestBullScore =
    if nearestBullIndex == 1 then bScore1
    else if nearestBullIndex == 2 then bScore2
    else if nearestBullIndex == 3 then bScore3
    else Double.NaN;

def nearestBullTouches =
    if nearestBullIndex == 1 then bTouches1
    else if nearestBullIndex == 2 then bTouches2
    else if nearestBullIndex == 3 then bTouches3
    else Double.NaN;

def nearestBullDistance =
    if nearestBullIndex == 1 then bDistance1
    else if nearestBullIndex == 2 then bDistance2
    else if nearestBullIndex == 3 then bDistance3
    else Double.NaN;

def sDistance1 =
    if showS1
    then if close > sTop1 then close - sTop1
         else if close < sBottom1 then sBottom1 - close
         else 0
    else Double.POSITIVE_INFINITY;

def sDistance2 =
    if showS2
    then if close > sTop2 then close - sTop2
         else if close < sBottom2 then sBottom2 - close
         else 0
    else Double.POSITIVE_INFINITY;

def sDistance3 =
    if showS3
    then if close > sTop3 then close - sTop3
         else if close < sBottom3 then sBottom3 - close
         else 0
    else Double.POSITIVE_INFINITY;

def nearestBearIndex =
    if !showS1 and !showS2 and !showS3 then 0
    else if sDistance1 <= sDistance2 and sDistance1 <= sDistance3 then 1
    else if sDistance2 <= sDistance3 then 2
    else 3;

def nearestBearTop =
    if nearestBearIndex == 1 then sTop1
    else if nearestBearIndex == 2 then sTop2
    else if nearestBearIndex == 3 then sTop3
    else Double.NaN;

def nearestBearBottom =
    if nearestBearIndex == 1 then sBottom1
    else if nearestBearIndex == 2 then sBottom2
    else if nearestBearIndex == 3 then sBottom3
    else Double.NaN;

def nearestBearScore =
    if nearestBearIndex == 1 then sScore1
    else if nearestBearIndex == 2 then sScore2
    else if nearestBearIndex == 3 then sScore3
    else Double.NaN;

def nearestBearTouches =
    if nearestBearIndex == 1 then sTouches1
    else if nearestBearIndex == 2 then sTouches2
    else if nearestBearIndex == 3 then sTouches3
    else Double.NaN;

def nearestBearDistance =
    if nearestBearIndex == 1 then sDistance1
    else if nearestBearIndex == 2 then sDistance2
    else if nearestBearIndex == 3 then sDistance3
    else Double.NaN;

AddLabel(
    showNearestBlockLabels and nearestBullIndex > 0,
    "BULL " +
    (if nearestBullScore >= 80 then "A+"
     else if nearestBullScore >= 65 then "A"
     else if nearestBullScore >= 50 then "B"
     else "C") +
    " " + nearestBullScore +
    " | " + AsPrice(nearestBullBottom) +
    "-" + AsPrice(nearestBullTop) +
    " | " +
    (if nearestBullTouches <= 0 then "FRESH"
     else if nearestBullTouches == 1 then "TEST 1"
     else if nearestBullTouches == 2 then "TEST 2"
     else "WEAK " + nearestBullTouches) +
    " | " + Round(nearestBullDistance, 1) + " pts",
    if nearestBullScore >= 80 then GlobalColor("Bull APlus")
    else if nearestBullScore >= 65 then GlobalColor("Bull A")
    else if nearestBullScore >= 50 then GlobalColor("Bull B")
    else GlobalColor("Bull Weak")
);

AddLabel(
    showNearestBlockLabels and nearestBearIndex > 0,
    "BEAR " +
    (if nearestBearScore >= 80 then "A+"
     else if nearestBearScore >= 65 then "A"
     else if nearestBearScore >= 50 then "B"
     else "C") +
    " " + nearestBearScore +
    " | " + AsPrice(nearestBearBottom) +
    "-" + AsPrice(nearestBearTop) +
    " | " +
    (if nearestBearTouches <= 0 then "FRESH"
     else if nearestBearTouches == 1 then "TEST 1"
     else if nearestBearTouches == 2 then "TEST 2"
     else "WEAK " + nearestBearTouches) +
    " | " + Round(nearestBearDistance, 1) + " pts",
    if nearestBearScore >= 80 then GlobalColor("Bear APlus")
    else if nearestBearScore >= 65 then GlobalColor("Bear A")
    else if nearestBearScore >= 50 then GlobalColor("Bear B")
    else GlobalColor("Bear Weak")
);

AddLabel(
    showDiagnosticLabel,
    "OB V2.2 " +
    (if qualificationMode == qualificationMode.Off then "OFF"
     else if qualificationMode == qualificationMode.Balanced then "BALANCED"
     else if qualificationMode == qualificationMode.Strict then "STRICT"
     else "CUSTOM") +
    " | Active B " + activeBullCount +
    " / S " + activeBearCount +
    " | Raw " + rawDetectionCount +
    " / Q " + qualifiedDetectionCount,
    if activeBullCount + activeBearCount > 0
    then Color.GRAY
    else Color.ORANGE
);

AddLabel(
    showStatusLabel and
    (bullishOBsToShow > 3 or bearishOBsToShow > 3),
    "V2 display is capped at 3 blocks per side",
    Color.ORANGE
);

#==============================================================================
# ALERTS
#==============================================================================

Alert(
    enableAlerts and insertBull,
    "Qualified bullish order block detected",
    Alert.BAR,
    Sound.Ding
);

Alert(
    enableAlerts and insertBear,
    "Qualified bearish order block detected",
    Alert.BAR,
    Sound.Ding
);

Alert(
    enableAlerts and bullReactionAny,
    "Bullish order-block rejection confirmed",
    Alert.BAR,
    Sound.Ring
);

Alert(
    enableAlerts and bearReactionAny,
    "Bearish order-block rejection confirmed",
    Alert.BAR,
    Sound.Ring
);

Alert(
    enableAlerts and bullishOBMitigated,
    "Bullish order block mitigated",
    Alert.BAR,
    Sound.Bell
);

Alert(
    enableAlerts and bearishOBMitigated,
    "Bearish order block mitigated",
    Alert.BAR,
    Sound.Bell
);
 

Join useThinkScript to post your question to a community of 21,000+ developers and traders.

Similar threads

Not the exact question you're looking for?

Start a new thread and receive assistance from our community.

87k+ Posts
1330 Online
Create Post

Similar threads

Similar threads

The Market Trading Game Changer

Join 2,500+ subscribers inside the useThinkScript VIP Membership Club
  • Exclusive indicators
  • Proven strategies & setups
  • Private Discord community
  • ‘Buy The Dip’ signal alerts
  • Exclusive members-only content
  • Add-ons and resources
  • 1 full year of unlimited support

Frequently Asked Questions

What is useThinkScript?

useThinkScript is the #1 community of stock market investors using indicators and other tools to power their trading strategies. Traders of all skill levels use our forums to learn about scripting and indicators, help each other, and discover new ways to gain an edge in the markets.

How do I get started?

We get it. Our forum can be intimidating, if not overwhelming. With thousands of topics, tens of thousands of posts, our community has created an incredibly deep knowledge base for stock traders. No one can ever exhaust every resource provided on our site.

If you are new, or just looking for guidance, here are some helpful links to get you started.

What are the benefits of VIP Membership?
VIP members get exclusive access to these proven and tested premium indicators: Buy the Dip, Advanced Market Moves 2.0, Take Profit, and Volatility Trading Range. In addition, VIP members get access to over 50 VIP-only custom indicators, add-ons, and strategies, private VIP-only forums, private Discord channel to discuss trades and strategies in real-time, customer support, trade alerts, and much more. Learn all about VIP membership here.
How can I access the premium indicators?
To access the premium indicators, which are plug and play ready, sign up for VIP membership here.
Back
Top