Order Block Detector [LuxAlgo] Modified to my way of trading
mod note:
One of the greatest challenges traders face is deciding which support and resistance levels deserve their attention. This indicator attempts to reduce that clutter by highlighting only those price areas that exhibit characteristics commonly associated with institutional participation.
Rather than treating every block equally; the quality engine scores each block based on
mod note:
One of the greatest challenges traders face is deciding which support and resistance levels deserve their attention. This indicator attempts to reduce that clutter by highlighting only those price areas that exhibit characteristics commonly associated with institutional participation.
Rather than treating every block equally; the quality engine scores each block based on
▸ relative volume
▸ displacement
▸ zone width
▸ origin candle
▸ freshness
This a substantial improvement.
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
);
Last edited by a moderator: