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
);