Pine Script OrderFlowTapeV23.txt
Copy
// This Pine Script® code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © Blendoxius
//@version=6
indicator("ORDERFLOW BREAK TAPE v24", overlay=true, max_lines_count=500, max_labels_count=500)
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 1: MAIN SETTINGS
// ════════════════════════════════════════════════════════════════════════════════
swingLookback = input. int(5, "Swing Lookback", minval=1, maxval=50, group="1. Main Settings")
maxSwings = input.int(50, "Max Swings", minval=10, maxval=500, group="1. Main Settings")
avgLookback = input.int(100, "Average Lookback", minval=1, maxval=5000, group="1. Main Settings")
enableChoch = input.bool(true, "Enable CHoCH", group="1. Main Settings")
enableBos = input.bool(true, "Enable BOS", group="1. Main Settings")
enableLiq = input.bool(true, "Enable LIQ", group="1. Main Settings")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 2: VOLUME STRENGTH FILTER
// ════════════════════════════════════════════════════════════════════════════════
enableVolumeFilter = input.bool(true, "Enable Volume Filter", group="2. Volume Filter")
volumeCompareMode = input.string("Custom Bars", "Compare Mode", options=["Custom Bars", "Tape Average"], group="2. Volume Filter")
volumeCompareBars = input.int(3, "Compare to Last X Bars", minval=1, maxval=50, group="2. Volume Filter")
volumeStrengthThreshold = input.float(1.0, "Strength Threshold", minval=0.5, maxval=5.0, step=0.1, group="2. Volume Filter")
applyFilterToChoch = input.bool(true, "Apply to CHoCH", group="2. Volume Filter")
applyFilterToBos = input.bool(true, "Apply to BOS", group="2. Volume Filter")
showWeakChoch = input.bool(true, "Show Weak CHoCH", group="2. Volume Filter")
showWeakBos = input.bool(true, "Show Weak BOS", group="2. Volume Filter")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 3-10: SWING LINE SETTINGS (unchanged)
// ════════════════════════════════════════════════════════════════════════════════
swingHighActiveColor = input.color(color.rgb(244,67,54), "Active Color", group="3. Swing High Active", inline="sha")
swingHighActiveWidth = input.int(1, "Width", minval=1, maxval=10, group="3. Swing High Active", inline="sha")
swingHighActiveStyle = input.string("solid", "Style", options=["solid", "dashed", "dotted"], group="3. Swing High Active", inline="sha")
swingHighBrokenStrongColor = input.color(color. rgb(0,255,0), "Strong Color", group="4. Swing High Broken Strong", inline="shbs")
swingHighBrokenStrongWidth = input.int(2, "Width", minval=1, maxval=10, group="4. Swing High Broken Strong", inline="shbs")
swingHighBrokenStrongStyle = input.string("solid", "Style", options=["solid", "dashed", "dotted"], group="4. Swing High Broken Strong", inline="shbs")
swingHighBrokenWeakColor = input.color(color. rgb(100,100,100), "Weak Color", group="5. Swing High Broken Weak", inline="shbw")
swingHighBrokenWeakWidth = input.int(1, "Width", minval=1, maxval=10, group="5. Swing High Broken Weak", inline="shbw")
swingHighBrokenWeakStyle = input.string("dotted", "Style", options=["solid", "dashed", "dotted"], group="5. Swing High Broken Weak", inline="shbw")
swingHighTouchedColor = input.color(color.rgb(255,193,7), "Touched Color", group="6. Swing High Touched", inline="sht")
swingHighTouchedWidth = input.int(1, "Width", minval=1, maxval=10, group="6. Swing High Touched", inline="sht")
swingHighTouchedStyle = input. string("dashed", "Style", options=["solid", "dashed", "dotted"], group="6. Swing High Touched", inline="sht")
swingLowActiveColor = input.color(color.rgb(76,175,80), "Active Color", group="7. Swing Low Active", inline="sla")
swingLowActiveWidth = input.int(1, "Width", minval=1, maxval=10, group="7. Swing Low Active", inline="sla")
swingLowActiveStyle = input.string("solid", "Style", options=["solid", "dashed", "dotted"], group="7. Swing Low Active", inline="sla")
swingLowBrokenStrongColor = input.color(color.rgb(255,0,0), "Strong Color", group="8. Swing Low Broken Strong", inline="slbs")
swingLowBrokenStrongWidth = input. int(2, "Width", minval=1, maxval=10, group="8. Swing Low Broken Strong", inline="slbs")
swingLowBrokenStrongStyle = input.string("solid", "Style", options=["solid", "dashed", "dotted"], group="8. Swing Low Broken Strong", inline="slbs")
swingLowBrokenWeakColor = input.color(color.rgb(100,100,100), "Weak Color", group="9. Swing Low Broken Weak", inline="slbw")
swingLowBrokenWeakWidth = input. int(1, "Width", minval=1, maxval=10, group="9. Swing Low Broken Weak", inline="slbw")
swingLowBrokenWeakStyle = input.string("dotted", "Style", options=["solid", "dashed", "dotted"], group="9. Swing Low Broken Weak", inline="slbw")
swingLowTouchedColor = input.color(color. rgb(255,193,7), "Touched Color", group="10. Swing Low Touched", inline="slt")
swingLowTouchedWidth = input.int(1, "Width", minval=1, maxval=10, group="10. Swing Low Touched", inline="slt")
swingLowTouchedStyle = input.string("dashed", "Style", options=["solid", "dashed", "dotted"], group="10. Swing Low Touched", inline="slt")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 11-13: LABEL SETTINGS (unchanged)
// ════════════════════════════════════════════════════════════════════════════════
showChochLabels = input.bool(true, "Show CHoCH Labels", group="11. CHoCH Labels")
chochUpStrongColor = input.color(color.rgb(0,255,255), "Up Strong", group="11. CHoCH Labels", inline="chu")
chochUpWeakColor = input.color(color.rgb(0,120,120), "Up Weak", group="11. CHoCH Labels", inline="chu")
chochDownStrongColor = input.color(color.rgb(255,165,0), "Down Strong", group="11. CHoCH Labels", inline="chd")
chochDownWeakColor = input.color(color.rgb(150,100,0), "Down Weak", group="11. CHoCH Labels", inline="chd")
chochLabelSizeStr = input.string("small", "Label Size", options=["tiny", "small", "normal", "large"], group="11. CHoCH Labels")
chochLabelPosition = input.string("Break Point", "Label Position", options=["Break Point", "Center of Line"], group="11. CHoCH Labels")
showBosLabels = input.bool(true, "Show BOS Labels", group="12. BOS Labels")
bosUpStrongColor = input.color(color.rgb(0,255,0), "Up Strong", group="12. BOS Labels", inline="bosu")
bosUpWeakColor = input.color(color.rgb(0,120,0), "Up Weak", group="12. BOS Labels", inline="bosu")
bosDownStrongColor = input.color(color.rgb(255,0,0), "Down Strong", group="12. BOS Labels", inline="bosd")
bosDownWeakColor = input.color(color.rgb(120,0,0), "Down Weak", group="12. BOS Labels", inline="bosd")
bosLabelSizeStr = input.string("tiny", "Label Size", options=["tiny", "small", "normal", "large"], group="12. BOS Labels")
bosLabelPosition = input.string("Break Point", "Label Position", options=["Break Point", "Center of Line"], group="12. BOS Labels")
showLiqLabels = input. bool(true, "Show LIQ Labels", group="13. LIQ Labels")
liqUpColor = input.color(color.rgb(255,235,59), "Up Color", group="13. LIQ Labels", inline="liq")
liqDownColor = input.color(color.rgb(255,235,59), "Down Color", group="13. LIQ Labels", inline="liq")
liqLabelSizeStr = input.string("tiny", "Label Size", options=["tiny", "small", "normal", "large"], group="13. LIQ Labels")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 14: TABLE AND SCROLL SETTINGS
// ════════════════════════════════════════════════════════════════════════════════
showTable = input.bool(true, "Show Table", group="14. Table & Scroll")
tablePosition = input.string("Top Right", "Table Position", options=["Top Left", "Top Center", "Top Right", "Middle Left", "Middle Center", "Middle Right", "Bottom Left", "Bottom Center", "Bottom Right"], group="14. Table & Scroll")
tableTextSize = input.string("small", "Text Size", options=["tiny", "small", "normal", "large"], group="14. Table & Scroll")
visibleRows = input.int(15, "Visible Rows", minval=5, maxval=50, group="14. Table & Scroll")
scrollOffset = input.int(0, "Scroll Offset", minval=0, maxval=500, group="14. Table & Scroll", tooltip="0 = newest first, increase to scroll back")
tableFilterMode = input.string("All Candles", "Filter Mode", options=["All Candles", "Events Only", "CHoCH Only", "BOS Only", "LIQ Only"], group="14. Table & Scroll")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 15: TABLE COLORS
// ════════════════════════════════════════════════════════════════════════════════
tableBgColor = input.color(color.rgb(18,18,18), "Background", group="15. Table Colors")
headerBgColor = input.color(color.rgb(38,38,38), "Header Background", group="15. Table Colors")
groupHeaderBgColor = input.color(color.rgb(28,28,38), "Group Header Background", group="15. Table Colors")
footerBgColor = input.color(color.rgb(28,28,28), "Footer Background", group="15. Table Colors")
textColor = input.color(color. rgb(220,220,220), "Text Color", group="15. Table Colors")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 16: RANKING BORDER SETTINGS (NEU)
// ════════════════════════════════════════════════════════════════════════════════
rankHighColor1 = input.color(color. rgb(255,215,0), "Rank 1 (Highest) Color", group="16. Ranking Borders", inline="r1")
rankHighColor2 = input.color(color.rgb(255,185,0), "Rank 2 Color", group="16. Ranking Borders", inline="r1")
rankLowColor = input.color(color.rgb(65,105,225), "Rank 3 (Lowest) Color", group="16. Ranking Borders", inline="r2")
rankBorderWidth = input.int(2, "Border Width", minval=1, maxval=5, group="16. Ranking Borders", inline="r2")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 17: SPREAD WINDOW SETTINGS
// ════════════════════════════════════════════════════════════════════════════════
showSpreadWindow = input.bool(true, "Show Spread Window", group="17. Spread Window")
spreadWindowPosition = input.string("Bottom Right", "Position", options=["Top Left", "Top Center", "Top Right", "Middle Left", "Middle Center", "Middle Right", "Bottom Left", "Bottom Center", "Bottom Right"], group="17. Spread Window")
spreadWindowSize = input.string("small", "Size", options=["tiny", "small", "normal", "large"], group="17. Spread Window")
showSpreadAsPercent = input.bool(true, "Show as Percent", group="17. Spread Window")
spreadColorNormal = input.color(color.rgb(76,175,80), "Normal Color", group="17. Spread Window")
spreadColorHigh = input.color(color.rgb(255,82,82), "High Volatility Color", group="17. Spread Window")
spreadColorCompression = input.color(color.rgb(33,150,243), "Compression Color", group="17. Spread Window")
spreadHighThreshold = input.float(1.5, "High Threshold", minval=1.0, maxval=5.0, step=0.1, group="17. Spread Window")
spreadLowThreshold = input. float(0.5, "Compression Threshold", minval=0.1, maxval=1.0, step=0.1, group="17. Spread Window")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 18: ROLLING WINDOWS
// ════════════════════════════════════════════════════════════════════════════════
showRollingWindows = input.bool(true, "Show Rolling Windows", group="18. Rolling Windows")
window1 = input.int(5, "Window 1", minval=0, maxval=500, group="18. Rolling Windows", inline="w1")
window2 = input.int(10, "Window 2", minval=0, maxval=500, group="18. Rolling Windows", inline="w1")
window3 = input. int(20, "Window 3", minval=0, maxval=500, group="18. Rolling Windows", inline="w2")
window4 = input. int(50, "Window 4", minval=0, maxval=500, group="18. Rolling Windows", inline="w2")
window5 = input.int(0, "Window 5", minval=0, maxval=500, group="18. Rolling Windows", inline="w3")
window6 = input.int(0, "Window 6", minval=0, maxval=500, group="18. Rolling Windows", inline="w3")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 19: LEVEL THRESHOLDS
// ════════════════════════════════════════════════════════════════════════════════
sprdLvl1 = input.float(0.5, "Spread Level 1 (Empty)", minval=0.1, maxval=2.0, step=0.1, group="19. Level Thresholds")
sprdLvl2 = input.float(1.0, "Spread Level 2 (Normal)", minval=0.5, maxval=3.0, step=0.1, group="19. Level Thresholds")
sprdLvl3 = input.float(1.5, "Spread Level 3 (Move)", minval=1.0, maxval=4.0, step=0.1, group="19. Level Thresholds")
sprdLvl4 = input.float(2.0, "Spread Level 4 (Power)", minval=1.5, maxval=5.0, step=0.1, group="19. Level Thresholds")
volLvl1 = input. float(0.5, "Volume Level 1 (Empty)", minval=0.1, maxval=2.0, step=0.1, group="19. Level Thresholds")
volLvl2 = input.float(1.0, "Volume Level 2 (Normal)", minval=0.5, maxval=3.0, step=0.1, group="19. Level Thresholds")
volLvl3 = input.float(1.5, "Volume Level 3 (Move)", minval=1.0, maxval=4.0, step=0.1, group="19. Level Thresholds")
volLvl4 = input.float(2.0, "Volume Level 4 (Power)", minval=1.5, maxval=5.0, step=0.1, group="19. Level Thresholds")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 20: CONTROL THRESHOLDS
// ════════════════════════════════════════════════════════════════════════════════
ctrlWeakAbove = input.float(60.0, "Control Weak: Above %", minval=50.0, maxval=75.0, step=5.0, group="20. Control Thresholds")
ctrlStrongAbove = input.float(80.0, "Control Strong: Above %", minval=70.0, maxval=90.0, step=5.0, group="20. Control Thresholds")
ctrlMaxAbove = input.float(80.0, "Control Max (Maru): Above %", minval=75.0, maxval=95.0, step=5.0, group="20. Control Thresholds")
// ════════════════════════════════════════════════════════════════════════════════
// SECTION 21: FLOW/TYPE COLORS
// ════════════════════════════════════════════════════════════════════════════════
colorAbsorb = input.color(color.rgb(33,150,243), "Absorb Color", group="21. Flow Colors")
colorManip = input.color(color.rgb(255,235,59), "Manipulation Color", group="21. Flow Colors")
colorBull = input.color(color.rgb(76,175,80), "Bull Color", group="21. Flow Colors")
colorBear = input.color(color.rgb(255,82,82), "Bear Color", group="21. Flow Colors")
colorHigh = input.color(color. rgb(255,82,82), "High Color", group="21. Flow Colors")
colorMid = input.color(color.rgb(255,167,38), "Mid Color", group="21. Flow Colors")
colorNorm = input.color(color.rgb(76,175,80), "Normal Color", group="21. Flow Colors")
colorNeut = input.color(color.rgb(158,158,158), "Neutral Color", group="21. Flow Colors")
// ════════════════════════════════════════════════════════════════════════════════
// HELPER FUNCTIONS
// ════════════════════════════════════════════════════════════════════════════════
getLineStyle(string s) =>
s == "solid" ? line.style_solid : s == "dashed" ? line. style_dashed : line.style_dotted
getLabelSize(string s) =>
s == "tiny" ? size.tiny : s == "small" ? size.small : s == "large" ? size.large : size. normal
getTextSize() =>
tableTextSize == "tiny" ? size.tiny : tableTextSize == "small" ? size.small : tableTextSize == "large" ? size.large : size. normal
getTablePosition() =>
tablePosition == "Top Left" ? position.top_left : tablePosition == "Top Center" ? position.top_center : tablePosition == "Top Right" ? position.top_right : tablePosition == "Middle Left" ? position.middle_left : tablePosition == "Middle Center" ? position.middle_center : tablePosition == "Middle Right" ? position.middle_right : tablePosition == "Bottom Left" ? position.bottom_left : tablePosition == "Bottom Center" ? position.bottom_center : position.bottom_right
getSpreadWindowPosition() =>
spreadWindowPosition == "Top Left" ? position.top_left : spreadWindowPosition == "Top Center" ? position.top_center : spreadWindowPosition == "Top Right" ? position.top_right : spreadWindowPosition == "Middle Left" ? position.middle_left : spreadWindowPosition == "Middle Center" ? position.middle_center : spreadWindowPosition == "Middle Right" ? position. middle_right : spreadWindowPosition == "Bottom Left" ? position.bottom_left : spreadWindowPosition == "Bottom Center" ? position.bottom_center : position.bottom_right
getSpreadWindowSize() =>
spreadWindowSize == "tiny" ? size. tiny : spreadWindowSize == "small" ? size.small : spreadWindowSize == "large" ? size.large : size.normal
formatTime(t) =>
str.tostring(hour(t, "Europe/Berlin"), "00") + ":" + str.tostring(minute(t, "Europe/Berlin"), "00")
formatPct(p) =>
str.tostring(p, "#.#") + "%"
shouldShowRow(chB, chS, bosB, bosS, liqB, liqS) =>
if tableFilterMode == "All Candles"
true
else if tableFilterMode == "Events Only"
chB > 0 or chS > 0 or bosB > 0 or bosS > 0 or liqB > 0 or liqS > 0
else if tableFilterMode == "CHoCH Only"
chB > 0 or chS > 0
else if tableFilterMode == "BOS Only"
bosB > 0 or bosS > 0
else if tableFilterMode == "LIQ Only"
liqB > 0 or liqS > 0
else
true
// ════════════════════════════════════════════════════════════════════════════════
// LEVEL FUNCTIONS - SPRD/VOL jetzt in PROZENT
// ════════════════════════════════════════════════════════════════════════════════
getSprdLevel(mult) =>
if mult < sprdLvl1
0
else if mult < sprdLvl2
1
else if mult < sprdLvl3
2
else if mult < sprdLvl4
3
else
4
getVolLevel(mult) =>
if mult < volLvl1
0
else if mult < volLvl2
1
else if mult < volLvl3
2
else if mult < volLvl4
3
else
4
// NEU: SPRD als Prozent (Multiplikator * 100)
getSprdPctLabel(mult) =>
str.tostring(mult * 100, "#.#") + "%"
// NEU: VOL als Prozent (Multiplikator * 100)
getVolPctLabel(mult) =>
str.tostring(mult * 100, "#.#") + "%"
getSprdColor(mult) =>
int lvl = getSprdLevel(mult)
lvl == 0 ? colorNeut : lvl == 1 ? colorNorm : lvl == 2 ? colorMid : lvl == 3 ? colorHigh : colorHigh
getVolColor(mult) =>
int lvl = getVolLevel(mult)
lvl == 0 ? colorNeut : lvl == 1 ? colorNorm : lvl == 2 ? colorMid : lvl == 3 ? colorHigh : colorHigh
// ════════════════════════════════════════════════════════════════════════════════
// CANDLE ANATOMY FUNCTIONS
// ════════════════════════════════════════════════════════════════════════════════
calcCandleAnatomy() =>
float candleRange = high - low
float bodySize = math.abs(close - open)
float upperWick = high - math.max(close, open)
float lowerWick = math.min(close, open) - low
float upperWickPct = candleRange > 0 ? (upperWick / candleRange) * 100 : 0
float bodyPct = candleRange > 0 ? (bodySize / candleRange) * 100 : 0
float lowerWickPct = candleRange > 0 ? (lowerWick / candleRange) * 100 : 0
bool isBull = close >= open
[upperWickPct, bodyPct, lowerWickPct, isBull]
// NEU: Ranking für H/WK, BODY, L/WK - returns [rank1_idx, rank2_idx, rank3_idx]
getRanking(upperWickPct, bodyPct, lowerWickPct) =>
array<float> vals = array.from(upperWickPct, bodyPct, lowerWickPct)
array<int> ranks = array.from(0, 1, 2)
// Simple bubble sort
for i = 0 to 1
for j = 0 to 1 - i
if array.get(vals, j) < array.get(vals, j + 1)
float tempVal = array.get(vals, j)
array.set(vals, j, array.get(vals, j + 1))
array. set(vals, j + 1, tempVal)
int tempRank = array.get(ranks, j)
array.set(ranks, j, array.get(ranks, j + 1))
array. set(ranks, j + 1, tempRank)
[array.get(ranks, 0), array.get(ranks, 1), array.get(ranks, 2)]
// Gibt Border-Farbe basierend auf Ranking zurück (0=H/WK, 1=BODY, 2=L/WK)
getRankBorderColor(idx, rank1, rank2, rank3) =>
idx == rank1 ? rankHighColor1 : idx == rank2 ? rankHighColor2 : idx == rank3 ? rankLowColor : na
getWickColor(pct) =>
pct >= 50 ? colorHigh : pct >= 30 ? colorMid : pct >= 15 ? colorNorm : colorNeut
getBodyColor(pct, isBull) =>
if pct >= 80
isBull ? colorBull : colorBear
else if pct >= 60
isBull ? colorBull : colorBear
else if pct >= 40
colorMid
else
colorNeut
// ════════════════════════════════════════════════════════════════════════════════
// DIFF FUNCTIONS - FLOW Farben integriert in DIFF
// ════════════════════════════════════════════════════════════════════════════════
getDiffValue(sprdMult, volMult) =>
float diff = volMult - sprdMult
float diffPct = (diff / math.max(sprdMult, 0.01)) * 100
diffPct
getDiffPctLabel(sprdMult, volMult) =>
float diffPct = getDiffValue(sprdMult, volMult)
string prefix = diffPct >= 0 ? "+" : ""
prefix + str.tostring(diffPct, "#.#") + "%"
// FLOW-Logik jetzt in DIFF-Farbe integriert
getDiffColorWithFlow(sprdMult, volMult) =>
int sprdLevel = getSprdLevel(sprdMult)
int volLevel = getVolLevel(volMult)
int diff = volLevel - sprdLevel
if diff >= 2
colorAbsorb // ABSORB++
else if diff == 1
color.new(colorAbsorb, 40) // ABSORB+
else if diff == 0
colorNorm // NORMAL
else if diff == -1
color. new(colorManip, 40) // MANIP+
else
colorManip // MANIP++
// ════════════════════════════════════════════════════════════════════════════════
// CANDLE TYPE FUNCTIONS - ALLE TYPEN FARBIG (kein Grau)
// ════════════════════════════════════════════════════════════════════════════════
getCandleType(upperWickPct, bodyPct, lowerWickPct, isBull) =>
string candleType = ""
float bullControl = bodyPct + lowerWickPct
float bearControl = bodyPct + upperWickPct
bool isUpperRejection = upperWickPct > bodyPct and upperWickPct > lowerWickPct
bool isLowerRejection = lowerWickPct > bodyPct and lowerWickPct > upperWickPct
if isUpperRejection
if bearControl >= ctrlMaxAbove
candleType := "BIG REJ DN"
else if bearControl >= ctrlWeakAbove
candleType := "REJ DN"
else
candleType := "WEAK REJ"
else if isLowerRejection
if bullControl >= ctrlMaxAbove
candleType := "BIG REJ UP"
else if bullControl >= ctrlWeakAbove
candleType := "REJ UP"
else
candleType := "WEAK REJ"
else
if isBull
if bodyPct >= ctrlMaxAbove
candleType := "MARU BULL"
else if bullControl >= ctrlStrongAbove
candleType := "STRONG"
else if bullControl >= ctrlWeakAbove
candleType := "STD BULL"
else
candleType := "WEAK BULL"
else
if bodyPct >= ctrlMaxAbove
candleType := "MARU BEAR"
else if bearControl >= ctrlStrongAbove
candleType := "STRONG"
else if bearControl >= ctrlWeakAbove
candleType := "STD BEAR"
else
candleType := "WEAK BEAR"
candleType
// NEU: Alle Types in Farbe - kein Grau mehr
getCandleTypeColor(candleType, isBull) =>
if str.contains(candleType, "MARU") or str.contains(candleType, "BIG REJ")
colorHigh
else if candleType == "STRONG"
colorMid
else if str.contains(candleType, "STD") or str.contains(candleType, "REJ UP") or str.contains(candleType, "REJ DN")
colorNorm
else if str.contains(candleType, "WEAK")
isBull ? color.new(colorBull, 50) : color.new(colorBear, 50)
else
colorNeut
// ════════════════════════════════════════════════════════════════════════════════
// CONTROL FUNCTIONS - Umbenannt zu BULL/BEAR/NEUT (ohne ++)
// ════════════════════════════════════════════════════════════════════════════════
getControlLabel(upperWickPct, bodyPct, lowerWickPct, isBull) =>
float bullControl = bodyPct + lowerWickPct
float bearControl = bodyPct + upperWickPct
bool isUpperRejection = upperWickPct > bodyPct and upperWickPct > lowerWickPct
bool isLowerRejection = lowerWickPct > bodyPct and lowerWickPct > upperWickPct
string ctrl = "NEUT"
if isUpperRejection
if bearControl >= ctrlWeakAbove
ctrl := "BEAR"
else
ctrl := "NEUT"
else if isLowerRejection
if bullControl >= ctrlWeakAbove
ctrl := "BULL"
else
ctrl := "NEUT"
else if isBull
if bullControl >= ctrlWeakAbove
ctrl := "BULL"
else
ctrl := "NEUT"
else
if bearControl >= ctrlWeakAbove
ctrl := "BEAR"
else
ctrl := "NEUT"
ctrl
getControlColor(ctrl) =>
if ctrl == "BULL"
colorBull
else if ctrl == "BEAR"
colorBear
else
colorNeut
getControlBuyScore(ctrl) =>
ctrl == "BULL" ? 1 : 0
getControlSellScore(ctrl) =>
ctrl == "BEAR" ? 1 : 0
// ════════════════════════════════════════════════════════════════════════════════
// VOLUME STRENGTH FUNCTION
// ════════════════════════════════════════════════════════════════════════════════
calculateVolumeStrength(startBar, endBar) =>
float moveVolume = 0.0
float compareVolume = 0.0
int barsInMove = endBar - startBar
if barsInMove > 0
for i = 0 to barsInMove - 1
moveVolume += volume[i]
moveVolume := moveVolume / barsInMove
if volumeCompareMode == "Custom Bars"
for i = 0 to volumeCompareBars - 1
compareVolume += volume[barsInMove + i]
compareVolume := compareVolume / volumeCompareBars
else
compareVolume := ta.sma(volume, avgLookback)
bool isStrong = compareVolume > 0 ? (moveVolume / compareVolume) >= volumeStrengthThreshold : true
[moveVolume, compareVolume, isStrong]
// ════════════════════════════════════════════════════════════════════════════════
// AVERAGE CALCULATIONS
// ════════════════════════════════════════════════════════════════════════════════
float avgSpread = ta.sma(high - low, avgLookback)
float avgVolume = ta.sma(volume, avgLookback)
float currentSpread = high - low
float currentSpreadPct = close > 0 ? (currentSpread / close) * 100 : 0
float avgSpreadPct = ta.sma(currentSpreadPct, avgLookback)
float curSprdMult = avgSpread > 0 ? currentSpread / avgSpread : 1
float curVolMult = avgVolume > 0 ? volume / avgVolume : 1
[curUpperWickPct, curBodyPct, curLowerWickPct, curIsBull] = calcCandleAnatomy()
string curCandleType = getCandleType(curUpperWickPct, curBodyPct, curLowerWickPct, curIsBull)
string curControl = getControlLabel(curUpperWickPct, curBodyPct, curLowerWickPct, curIsBull)
// ════════════════════════════════════════════════════════════════════════════════
// SPREAD WINDOW CALCULATIONS
// ════════════════════════════════════════════════════════════════════════════════
float currentSpreadVal = showSpreadAsPercent ? currentSpreadPct : currentSpread
float avgSpreadWindow = showSpreadAsPercent ? avgSpreadPct : avgSpread
float spreadRatio = avgSpreadWindow > 0 ? currentSpreadVal / avgSpreadWindow : 1
string volatilityRegime = spreadRatio >= spreadHighThreshold ? "HIGH VOLA" : spreadRatio <= spreadLowThreshold ? "LOW VOLA" : "NORMAL"
color spreadThresholdColor = spreadRatio >= spreadHighThreshold ? spreadColorHigh : spreadRatio <= spreadLowThreshold ? spreadColorCompression : spreadColorNormal
// ════════════════════════════════════════════════════════════════════════════════
// END OF PART 1
// ════════════════════════════════════════════════════════════════════════════════
// ════════════════════════════════════════════════════════════════════════════════
// SWING TRACKING ARRAYS
// ════════════════════════════════════════════════════════════════════════════════
var array<float> swingHighVals = array.new_float(0)
var array<int> swingHighBars = array.new_int(0)
var array<bool> swingHighActive = array.new_bool(0)
var array<bool> swingHighTouched = array.new_bool(0)
var array<line> swingHighLines = array.new_line(0)
var array<float> swingLowVals = array. new_float(0)
var array<int> swingLowBars = array.new_int(0)
var array<bool> swingLowActive = array.new_bool(0)
var array<bool> swingLowTouched = array.new_bool(0)
var array<line> swingLowLines = array.new_line(0)
var int currentTrend = 0
// ════════════════════════════════════════════════════════════════════════════════
// SWING DETECTION
// ════════════════════════════════════════════════════════════════════════════════
bool enoughBars = bar_index >= swingLookback * 2
float highestInWindow = ta.highest(high, swingLookback * 2 + 1)
float lowestInWindow = ta.lowest(low, swingLookback * 2 + 1)
bool isSwingHigh = enoughBars and high[swingLookback] == highestInWindow
bool isSwingLow = enoughBars and low[swingLookback] == lowestInWindow
if isSwingHigh
float val = high[swingLookback]
int bar = bar_index - swingLookback
line l = line.new(bar, val, bar_index, val, color=swingHighActiveColor, width=swingHighActiveWidth, style=getLineStyle(swingHighActiveStyle))
array.push(swingHighVals, val)
array.push(swingHighBars, bar)
array.push(swingHighActive, true)
array.push(swingHighTouched, false)
array.push(swingHighLines, l)
if array.size(swingHighVals) > maxSwings
line. delete(array.shift(swingHighLines))
array.shift(swingHighVals)
array.shift(swingHighBars)
array.shift(swingHighActive)
array.shift(swingHighTouched)
if isSwingLow
float val = low[swingLookback]
int bar = bar_index - swingLookback
line l = line. new(bar, val, bar_index, val, color=swingLowActiveColor, width=swingLowActiveWidth, style=getLineStyle(swingLowActiveStyle))
array.push(swingLowVals, val)
array.push(swingLowBars, bar)
array.push(swingLowActive, true)
array.push(swingLowTouched, false)
array.push(swingLowLines, l)
if array.size(swingLowVals) > maxSwings
line.delete(array.shift(swingLowLines))
array.shift(swingLowVals)
array. shift(swingLowBars)
array.shift(swingLowActive)
array.shift(swingLowTouched)
// ════════════════════════════════════════════════════════════════════════════════
// EVENT DETECTION
// ════════════════════════════════════════════════════════════════════════════════
int curChochBull = 0
int curChochBear = 0
int curBosBull = 0
int curBosBear = 0
int curLiqBull = 0
int curLiqBear = 0
bool hasAnyEvent = false
bool curChochBullStrong = false
bool curChochBearStrong = false
bool curBosBullStrong = false
bool curBosBearStrong = false
// Check Swing High Breaks
if array.size(swingHighVals) > 0
for i = 0 to array.size(swingHighVals) - 1
if array.get(swingHighActive, i)
float y = array.get(swingHighVals, i)
int x1 = array.get(swingHighBars, i)
line l = array.get(swingHighLines, i)
bool closeAbove = close > y
bool highAbove = high > y
bool broken = closeAbove and highAbove
if broken
array.set(swingHighActive, i, false)
bool isStrong = true
if enableVolumeFilter
[moveVol, compareVol, volStrong] = calculateVolumeStrength(x1, bar_index)
isStrong := volStrong
bool isChoch = currentTrend == -1
if isChoch and enableChoch
curChochBull += 1
curChochBullStrong := isStrong
hasAnyEvent := true
if not na(l)
if isStrong
line.set_color(l, swingHighBrokenStrongColor)
line.set_width(l, swingHighBrokenStrongWidth)
line.set_style(l, getLineStyle(swingHighBrokenStrongStyle))
else
line.set_color(l, swingHighBrokenWeakColor)
line. set_width(l, swingHighBrokenWeakWidth)
line.set_style(l, getLineStyle(swingHighBrokenWeakStyle))
line.set_x2(l, bar_index)
if showChochLabels and (isStrong or showWeakChoch)
color labelColor = isStrong ? chochUpStrongColor : chochUpWeakColor
string labelText = isStrong ? "CHoCH" : "choch"
int labelBar = chochLabelPosition == "Center of Line" ? int((x1 + bar_index) / 2) : bar_index
label.new(labelBar, y, labelText, color=color.new(color. white, 100), textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=getLabelSize(chochLabelSizeStr))
currentTrend := 1
else if enableBos
curBosBull += 1
curBosBullStrong := isStrong
hasAnyEvent := true
if not na(l)
if isStrong
line.set_color(l, swingHighBrokenStrongColor)
line.set_width(l, swingHighBrokenStrongWidth)
line.set_style(l, getLineStyle(swingHighBrokenStrongStyle))
else
line.set_color(l, swingHighBrokenWeakColor)
line.set_width(l, swingHighBrokenWeakWidth)
line. set_style(l, getLineStyle(swingHighBrokenWeakStyle))
line.set_x2(l, bar_index)
if showBosLabels and (isStrong or showWeakBos)
color labelColor = isStrong ? bosUpStrongColor : bosUpWeakColor
string labelText = isStrong ? "BOS" : "bos"
int labelBar = bosLabelPosition == "Center of Line" ? int((x1 + bar_index) / 2) : bar_index
label.new(labelBar, y, labelText, color=color.new(color.white, 100), textcolor=labelColor, style=label. style_none, yloc=yloc.price, size=getLabelSize(bosLabelSizeStr))
currentTrend := 1
else if highAbove and not closeAbove and enableLiq
if not array.get(swingHighTouched, i)
array.set(swingHighTouched, i, true)
curLiqBull += 1
hasAnyEvent := true
if showLiqLabels
label.new(bar_index, y, "LIQ", color=color.new(color.white, 100), textcolor=liqUpColor, style=label. style_none, yloc=yloc.price, size=getLabelSize(liqLabelSizeStr))
if not na(l)
line.set_color(l, swingHighTouchedColor)
line.set_width(l, swingHighTouchedWidth)
line.set_style(l, getLineStyle(swingHighTouchedStyle))
if not na(l)
line.set_x2(l, bar_index)
else
if not na(l)
line. set_x2(l, bar_index)
// Check Swing Low Breaks
if array.size(swingLowVals) > 0
for i = 0 to array.size(swingLowVals) - 1
if array.get(swingLowActive, i)
float y = array.get(swingLowVals, i)
int x1 = array. get(swingLowBars, i)
line l = array.get(swingLowLines, i)
bool closeBelow = close < y
bool lowBelow = low < y
bool broken = closeBelow and lowBelow
if broken
array.set(swingLowActive, i, false)
bool isStrong = true
if enableVolumeFilter
[moveVol, compareVol, volStrong] = calculateVolumeStrength(x1, bar_index)
isStrong := volStrong
bool isChoch = currentTrend == 1
if isChoch and enableChoch
curChochBear += 1
curChochBearStrong := isStrong
hasAnyEvent := true
if not na(l)
if isStrong
line.set_color(l, swingLowBrokenStrongColor)
line.set_width(l, swingLowBrokenStrongWidth)
line.set_style(l, getLineStyle(swingLowBrokenStrongStyle))
else
line.set_color(l, swingLowBrokenWeakColor)
line.set_width(l, swingLowBrokenWeakWidth)
line.set_style(l, getLineStyle(swingLowBrokenWeakStyle))
line.set_x2(l, bar_index)
if showChochLabels and (isStrong or showWeakChoch)
color labelColor = isStrong ? chochDownStrongColor : chochDownWeakColor
string labelText = isStrong ? "CHoCH" : "choch"
int labelBar = chochLabelPosition == "Center of Line" ? int((x1 + bar_index) / 2) : bar_index
label.new(labelBar, y, labelText, color=color.new(color.white, 100), textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=getLabelSize(chochLabelSizeStr))
currentTrend := -1
else if enableBos
curBosBear += 1
curBosBearStrong := isStrong
hasAnyEvent := true
if not na(l)
if isStrong
line.set_color(l, swingLowBrokenStrongColor)
line. set_width(l, swingLowBrokenStrongWidth)
line.set_style(l, getLineStyle(swingLowBrokenStrongStyle))
else
line.set_color(l, swingLowBrokenWeakColor)
line.set_width(l, swingLowBrokenWeakWidth)
line. set_style(l, getLineStyle(swingLowBrokenWeakStyle))
line.set_x2(l, bar_index)
if showBosLabels and (isStrong or showWeakBos)
color labelColor = isStrong ? bosDownStrongColor : bosDownWeakColor
string labelText = isStrong ? "BOS" : "bos"
int labelBar = bosLabelPosition == "Center of Line" ? int((x1 + bar_index) / 2) : bar_index
label. new(labelBar, y, labelText, color=color.new(color.white, 100), textcolor=labelColor, style=label.style_none, yloc=yloc.price, size=getLabelSize(bosLabelSizeStr))
currentTrend := -1
else if lowBelow and not closeBelow and enableLiq
if not array.get(swingLowTouched, i)
array.set(swingLowTouched, i, true)
curLiqBear += 1
hasAnyEvent := true
if showLiqLabels
label.new(bar_index, y, "LIQ", color=color.new(color.white, 100), textcolor=liqDownColor, style=label.style_none, yloc=yloc.price, size=getLabelSize(liqLabelSizeStr))
if not na(l)
line.set_color(l, swingLowTouchedColor)
line.set_width(l, swingLowTouchedWidth)
line.set_style(l, getLineStyle(swingLowTouchedStyle))
if not na(l)
line. set_x2(l, bar_index)
else
if not na(l)
line.set_x2(l, bar_index)
// ════════════════════════════════════════════════════════════════════════════════
// EVENT STORAGE ARRAYS
// ════════════════════════════════════════════════════════════════════════════════
var array<int> evtTime = array.new_int(0)
var array<int> evtChochBull = array.new_int(0)
var array<int> evtChochBear = array.new_int(0)
var array<int> evtBosBull = array.new_int(0)
var array<int> evtBosBear = array.new_int(0)
var array<int> evtLiqBull = array.new_int(0)
var array<int> evtLiqBear = array.new_int(0)
var array<float> evtSprdMult = array.new_float(0)
var array<float> evtVolMult = array.new_float(0)
var array<float> evtUpperWickPct = array.new_float(0)
var array<float> evtBodyPct = array.new_float(0)
var array<float> evtLowerWickPct = array.new_float(0)
var array<bool> evtIsBull = array.new_bool(0)
var array<string> evtCandleType = array.new_string(0)
var array<string> evtControl = array.new_string(0)
if barstate.ishistory or barstate.isconfirmed
array.unshift(evtTime, time)
array.unshift(evtChochBull, curChochBull)
array.unshift(evtChochBear, curChochBear)
array.unshift(evtBosBull, curBosBull)
array.unshift(evtBosBear, curBosBear)
array.unshift(evtLiqBull, curLiqBull)
array.unshift(evtLiqBear, curLiqBear)
array.unshift(evtSprdMult, curSprdMult)
array.unshift(evtVolMult, curVolMult)
array.unshift(evtUpperWickPct, curUpperWickPct)
array.unshift(evtBodyPct, curBodyPct)
array.unshift(evtLowerWickPct, curLowerWickPct)
array.unshift(evtIsBull, curIsBull)
array. unshift(evtCandleType, curCandleType)
array.unshift(evtControl, curControl)
int maxArraySize = math.max(avgLookback, 5000)
if array.size(evtTime) > maxArraySize
array. pop(evtTime)
array.pop(evtChochBull)
array.pop(evtChochBear)
array.pop(evtBosBull)
array.pop(evtBosBear)
array.pop(evtLiqBull)
array. pop(evtLiqBear)
array.pop(evtSprdMult)
array.pop(evtVolMult)
array.pop(evtUpperWickPct)
array.pop(evtBodyPct)
array. pop(evtLowerWickPct)
array.pop(evtIsBull)
array.pop(evtCandleType)
array. pop(evtControl)
// ════════════════════════════════════════════════════════════════════════════════
// ROLLING WINDOW STATS FUNCTION
// ════════════════════════════════════════════════════════════════════════════════
calcWindowStats(windowSize) =>
int chB = 0
int chS = 0
int bosB = 0
int bosS = 0
int liqB = 0
int liqS = 0
int buyScore = 0
int sellScore = 0
int evtCount = math.min(array.size(evtChochBull), windowSize)
if evtCount > 0
for i = 0 to evtCount - 1
chB += array.get(evtChochBull, i)
chS += array.get(evtChochBear, i)
bosB += array.get(evtBosBull, i)
bosS += array.get(evtBosBear, i)
liqB += array.get(evtLiqBull, i)
liqS += array. get(evtLiqBear, i)
string ctrl = array.get(evtControl, i)
buyScore += getControlBuyScore(ctrl)
sellScore += getControlSellScore(ctrl)
[chB, chS, bosB, bosS, liqB, liqS, buyScore, sellScore]
// ════════════════════════════════════════════════════════════════════════════════
// SPREAD WINDOW TABLE
// ════════════════════════════════════════════════════════════════════════════════
var table spreadTable = table.new(getSpreadWindowPosition(), 2, 12, bgcolor=color.rgb(18,18,18), border_width=1, border_color=color.new(color.gray, 50))
if showSpreadWindow and barstate.islast
swSize = getSpreadWindowSize()
table.cell(spreadTable, 0, 0, "SPREAD", bgcolor=color.rgb(38,38,38), text_color=color.white, text_size=swSize)
table.cell(spreadTable, 1, 0, curIsBull ? "BULL" : "BEAR", bgcolor=curIsBull ? colorBull : colorBear, text_color=color.white, text_size=swSize)
table.cell(spreadTable, 0, 1, "Current:", text_color=color.gray, text_size=swSize, bgcolor=color.rgb(28,28,28))
table.cell(spreadTable, 1, 1, str. tostring(currentSpreadVal, "#. ###") + (showSpreadAsPercent ? "%" : ""), bgcolor=spreadThresholdColor, text_color=color.white, text_size=swSize)
table.cell(spreadTable, 0, 2, "Mean:", text_color=color.gray, text_size=swSize, bgcolor=color.rgb(28,28,28))
table. cell(spreadTable, 1, 2, str.tostring(avgSpreadWindow, "#.###") + (showSpreadAsPercent ? "%" : ""), bgcolor=color.rgb(50,50,50), text_color=color.white, text_size=swSize)
float spreadMult = avgSpreadWindow > 0 ? currentSpreadVal / avgSpreadWindow : 1
table.cell(spreadTable, 0, 3, "Mult:", text_color=color. gray, text_size=swSize, bgcolor=color.rgb(28,28,28))
table.cell(spreadTable, 1, 3, str.tostring(spreadMult, "#.##") + "x", bgcolor=spreadThresholdColor, text_color=color. white, text_size=swSize)
table.cell(spreadTable, 0, 4, "Regime:", text_color=color.gray, text_size=swSize, bgcolor=color.rgb(28,28,28))
color regimeColor = volatilityRegime == "HIGH VOLA" ? spreadColorHigh : volatilityRegime == "LOW VOLA" ? spreadColorCompression : spreadColorNormal
table.cell(spreadTable, 1, 4, volatilityRegime, bgcolor=regimeColor, text_color=color.white, text_size=swSize)
table.cell(spreadTable, 0, 5, "DIFF:", text_color=color.gray, text_size=swSize, bgcolor=color.rgb(28,28,28))
table. cell(spreadTable, 1, 5, getDiffPctLabel(curSprdMult, curVolMult), text_color=getDiffColorWithFlow(curSprdMult, curVolMult), text_size=swSize, bgcolor=color.rgb(28,28,28))
// ════════════════════════════════════════════════════════════════════════════════
// MAIN TABLE - NEU MIT GRUPPEN-HEADER
// ════════════════════════════════════════════════════════════════════════════════
// Spalten: TIME | CH BOS LIQ | SPRD% DIFF% VOL% | H/WK BODY L/WK | TYPE | BULL BEAR NEUT
// Columns: 0 | 1 2 3 | 4 5 6 | 7 8 9 | 10 | 11 12 13
int tableColumns = 14
var table tbl = table.new(getTablePosition(), tableColumns, 90, bgcolor=tableBgColor, border_width=1, border_color=color.new(color.gray, 80))
if showTable and barstate.islast
tSize = getTextSize()
int evtCount = array.size(evtTime)
int currentRow = 0
int effectiveOffset = math.min(scrollOffset, math.max(0, evtCount - visibleRows))
// ═══════════════════════════════════════════════════════════════════════════
// ROW 0: TITLE
// ═══════════════════════════════════════════════════════════════════════════
string titleText = "ORDERFLOW BREAK TAPE v24"
string filterText = tableFilterMode != "All Candles" ? " [" + tableFilterMode + "]" : ""
string settingsText = "SW:" + str.tostring(swingLookback) + " AVG:" + str.tostring(avgLookback) + filterText
table.cell(tbl, 0, currentRow, titleText, bgcolor=headerBgColor, text_color=textColor, text_size=tSize, text_halign=text. align_left)
table.merge_cells(tbl, 0, currentRow, 6, currentRow)
table.cell(tbl, 7, currentRow, settingsText, bgcolor=headerBgColor, text_color=colorNeut, text_size=tSize, text_halign=text. align_right)
table.merge_cells(tbl, 7, currentRow, 13, currentRow)
currentRow += 1
// ═══════════════════════════════════════════════════════════════════════════
// ROLLING WINDOWS (if enabled)
// ═══════════════════════════════════════════════════════════════════════════
if showRollingWindows
windowSizes = array.from(window1, window2, window3, window4, window5, window6)
for idx = 0 to 5
int winSize = array.get(windowSizes, idx)
if winSize > 0
[chB, chS, bosB, bosS, liqB, liqS, buyScore, sellScore] = calcWindowStats(winSize)
string winLabel = str.tostring(winSize)
string bullText = "UP CH:" + str.tostring(chB) + " BOS:" + str.tostring(bosB) + " LIQ:" + str.tostring(liqB)
string bearText = "DN CH:" + str.tostring(chS) + " BOS:" + str.tostring(bosS) + " LIQ:" + str.tostring(liqS)
string ctrlText = "BULL:" + str.tostring(buyScore) + " | BEAR:" + str.tostring(sellScore)
int totalBull = chB + bosB + liqB
int totalBear = chS + bosS + liqS
color winColor = totalBull > totalBear ? colorBull : totalBear > totalBull ? colorBear : colorNeut
color ctrlColor = buyScore > sellScore ? colorBull : sellScore > buyScore ? colorBear : colorNeut
table. cell(tbl, 0, currentRow, winLabel, bgcolor=color.new(winColor, 85), text_color=winColor, text_size=tSize, text_halign=text. align_center)
table.cell(tbl, 1, currentRow, bullText, bgcolor=color.new(colorBull, 90), text_color=colorBull, text_size=tSize, text_halign=text.align_left)
table.merge_cells(tbl, 1, currentRow, 5, currentRow)
table. cell(tbl, 6, currentRow, bearText, bgcolor=color.new(colorBear, 90), text_color=colorBear, text_size=tSize, text_halign=text.align_left)
table.merge_cells(tbl, 6, currentRow, 10, currentRow)
table.cell(tbl, 11, currentRow, ctrlText, bgcolor=color.new(ctrlColor, 85), text_color=ctrlColor, text_size=tSize, text_halign=text. align_center)
table. merge_cells(tbl, 11, currentRow, 13, currentRow)
currentRow += 1
// ═══════════════════════════════════════════════════════════════════════════
// ROW: GROUP HEADERS (übergreifende Namen)
// ═══════════════════════════════════════════════════════════════════════════
table.cell(tbl, 0, currentRow, "───", bgcolor=groupHeaderBgColor, text_color=color.rgb(100,200,255), text_size=tSize)
table.cell(tbl, 1, currentRow, "══ EVENTS ══", bgcolor=groupHeaderBgColor, text_color=color.rgb(255,200,100), text_size=tSize)
table.merge_cells(tbl, 1, currentRow, 3, currentRow)
table. cell(tbl, 4, currentRow, "══ VOLUME ══", bgcolor=groupHeaderBgColor, text_color=color.rgb(150,255,150), text_size=tSize)
table.merge_cells(tbl, 4, currentRow, 6, currentRow)
table.cell(tbl, 7, currentRow, "══ ANATOMY ══", bgcolor=groupHeaderBgColor, text_color=color.rgb(255,150,255), text_size=tSize)
table.merge_cells(tbl, 7, currentRow, 9, currentRow)
table. cell(tbl, 10, currentRow, "───", bgcolor=groupHeaderBgColor, text_color=color.rgb(255,220,100), text_size=tSize)
table.cell(tbl, 11, currentRow, "══ CONTROL ══", bgcolor=groupHeaderBgColor, text_color=color.rgb(200,200,255), text_size=tSize)
table.merge_cells(tbl, 11, currentRow, 13, currentRow)
currentRow += 1
// ═══════════════════════════════════════════════════════════════════════════
// ROW: COLUMN HEADERS
// ═══════════════════════════════════════════════════════════════════════════
table.cell(tbl, 0, currentRow, "TIME", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 1, currentRow, "CH", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 2, currentRow, "BOS", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 3, currentRow, "LIQ", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 4, currentRow, "SPRD%", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 5, currentRow, "DIFF%", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 6, currentRow, "VOL%", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 7, currentRow, "H/WK", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 8, currentRow, "BODY", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 9, currentRow, "L/WK", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 10, currentRow, "TYPE", bgcolor=headerBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 11, currentRow, "BULL", bgcolor=headerBgColor, text_color=colorBull, text_size=tSize)
table.cell(tbl, 12, currentRow, "BEAR", bgcolor=headerBgColor, text_color=colorBear, text_size=tSize)
table.cell(tbl, 13, currentRow, "NEUT", bgcolor=headerBgColor, text_color=colorNeut, text_size=tSize)
currentRow += 1
// ═══════════════════════════════════════════════════════════════════════════
// LIVE ROW
// ═══════════════════════════════════════════════════════════════════════════
if effectiveOffset == 0 and barstate.isrealtime
// Get ranking for anatomy
[liveRank1, liveRank2, liveRank3] = getRanking(curUpperWickPct, curBodyPct, curLowerWickPct)
// CH text
string chTextLive = ""
if curChochBull > 0 and curChochBear > 0
chTextLive := str.tostring(curChochBull) + "U " + str.tostring(curChochBear) + "D"
else if curChochBull > 0
chTextLive := str.tostring(curChochBull) + "U"
else if curChochBear > 0
chTextLive := str.tostring(curChochBear) + "D"
color chColorLive = curChochBull > 0 and curChochBear > 0 ? colorMid : curChochBull > 0 ? chochUpStrongColor : curChochBear > 0 ? chochDownStrongColor : tableBgColor
// BOS text
string bosTextLive = ""
if curBosBull > 0 and curBosBear > 0
bosTextLive := str.tostring(curBosBull) + "U " + str.tostring(curBosBear) + "D"
else if curBosBull > 0
bosTextLive := str.tostring(curBosBull) + "U"
else if curBosBear > 0
bosTextLive := str.tostring(curBosBear) + "D"
color bosColorLive = curBosBull > 0 and curBosBear > 0 ? colorMid : curBosBull > 0 ? bosUpStrongColor : curBosBear > 0 ? bosDownStrongColor : tableBgColor
// LIQ text
string liqTextLive = ""
if curLiqBull > 0 and curLiqBear > 0
liqTextLive := str.tostring(curLiqBull) + "U " + str.tostring(curLiqBear) + "D"
else if curLiqBull > 0
liqTextLive := str.tostring(curLiqBull) + "U"
else if curLiqBear > 0
liqTextLive := str.tostring(curLiqBear) + "D"
color liqColorLive = curLiqBull > 0 and curLiqBear > 0 ? colorMid : curLiqBull > 0 or curLiqBear > 0 ? liqUpColor : tableBgColor
// Ranking border colors
color hwkBorderLive = getRankBorderColor(0, liveRank1, liveRank2, liveRank3)
color bodyBorderLive = getRankBorderColor(1, liveRank1, liveRank2, liveRank3)
color lwkBorderLive = getRankBorderColor(2, liveRank1, liveRank2, liveRank3)
// Control
string liveBullCtrl = curControl == "BULL" ? "●" : ""
string liveBearCtrl = curControl == "BEAR" ? "●" : ""
string liveNeutCtrl = curControl == "NEUT" ? "●" : ""
table.cell(tbl, 0, currentRow, formatTime(time), bgcolor=hasAnyEvent ? color.new(colorMid, 80) : tableBgColor, text_color=color.rgb(0,255,0), text_size=tSize)
table.cell(tbl, 1, currentRow, chTextLive, bgcolor=color.new(chColorLive, 90), text_color=chColorLive, text_size=tSize)
table.cell(tbl, 2, currentRow, bosTextLive, bgcolor=color.new(bosColorLive, 90), text_color=bosColorLive, text_size=tSize)
table.cell(tbl, 3, currentRow, liqTextLive, bgcolor=color.new(liqColorLive, 90), text_color=liqColorLive, text_size=tSize)
table.cell(tbl, 4, currentRow, getSprdPctLabel(curSprdMult), bgcolor=tableBgColor, text_color=getSprdColor(curSprdMult), text_size=tSize)
table.cell(tbl, 5, currentRow, getDiffPctLabel(curSprdMult, curVolMult), bgcolor=tableBgColor, text_color=getDiffColorWithFlow(curSprdMult, curVolMult), text_size=tSize)
table.cell(tbl, 6, currentRow, getVolPctLabel(curVolMult), bgcolor=tableBgColor, text_color=getVolColor(curVolMult), text_size=tSize)
table.cell(tbl, 7, currentRow, formatPct(curUpperWickPct), bgcolor=color.new(hwkBorderLive, 80), text_color=getWickColor(curUpperWickPct), text_size=tSize)
table.cell(tbl, 8, currentRow, formatPct(curBodyPct), bgcolor=color.new(bodyBorderLive, 80), text_color=getBodyColor(curBodyPct, curIsBull), text_size=tSize)
table.cell(tbl, 9, currentRow, formatPct(curLowerWickPct), bgcolor=color.new(lwkBorderLive, 80), text_color=getWickColor(curLowerWickPct), text_size=tSize)
table.cell(tbl, 10, currentRow, curCandleType, bgcolor=tableBgColor, text_color=getCandleTypeColor(curCandleType, curIsBull), text_size=tSize)
table. cell(tbl, 11, currentRow, liveBullCtrl, bgcolor=curControl == "BULL" ? color.new(colorBull, 70) : tableBgColor, text_color=colorBull, text_size=tSize)
table.cell(tbl, 12, currentRow, liveBearCtrl, bgcolor=curControl == "BEAR" ? color.new(colorBear, 70) : tableBgColor, text_color=colorBear, text_size=tSize)
table.cell(tbl, 13, currentRow, liveNeutCtrl, bgcolor=curControl == "NEUT" ? color.new(colorNeut, 70) : tableBgColor, text_color=colorNeut, text_size=tSize)
currentRow += 1
// ═══════════════════════════════════════════════════════════════════════════
// HISTORICAL ROWS
// ═══════════════════════════════════════════════════════════════════════════
int rowsShown = 0
int arrayIdx = effectiveOffset
while rowsShown < visibleRows and arrayIdx < evtCount
int chB = array.get(evtChochBull, arrayIdx)
int chS = array.get(evtChochBear, arrayIdx)
int bosB = array.get(evtBosBull, arrayIdx)
int bosS = array. get(evtBosBear, arrayIdx)
int liqB = array.get(evtLiqBull, arrayIdx)
int liqS = array.get(evtLiqBear, arrayIdx)
if shouldShowRow(chB, chS, bosB, bosS, liqB, liqS)
int t = array.get(evtTime, arrayIdx)
float sprd = array.get(evtSprdMult, arrayIdx)
float vol = array.get(evtVolMult, arrayIdx)
float upperWick = array.get(evtUpperWickPct, arrayIdx)
float body = array.get(evtBodyPct, arrayIdx)
float lowerWick = array.get(evtLowerWickPct, arrayIdx)
bool isBull = array.get(evtIsBull, arrayIdx)
string candleType = array.get(evtCandleType, arrayIdx)
string control = array.get(evtControl, arrayIdx)
// Get ranking for anatomy
[rank1, rank2, rank3] = getRanking(upperWick, body, lowerWick)
// CH text
string chText = ""
if chB > 0 and chS > 0
chText := str. tostring(chB) + "U " + str.tostring(chS) + "D"
else if chB > 0
chText := str.tostring(chB) + "U"
else if chS > 0
chText := str.tostring(chS) + "D"
color chColor = chB > 0 and chS > 0 ? colorMid : chB > 0 ? chochUpStrongColor : chS > 0 ? chochDownStrongColor : tableBgColor
// BOS text
string bosText = ""
if bosB > 0 and bosS > 0
bosText := str. tostring(bosB) + "U " + str.tostring(bosS) + "D"
else if bosB > 0
bosText := str.tostring(bosB) + "U"
else if bosS > 0
bosText := str.tostring(bosS) + "D"
color bosColor = bosB > 0 and bosS > 0 ? colorMid : bosB > 0 ? bosUpStrongColor : bosS > 0 ? bosDownStrongColor : tableBgColor
// LIQ text
string liqText = ""
if liqB > 0 and liqS > 0
liqText := str.tostring(liqB) + "U " + str.tostring(liqS) + "D"
else if liqB > 0
liqText := str.tostring(liqB) + "U"
else if liqS > 0
liqText := str.tostring(liqS) + "D"
color liqColorCell = liqB > 0 and liqS > 0 ? colorMid : liqB > 0 or liqS > 0 ? liqUpColor : tableBgColor
// Ranking border colors
color hwkBorder = getRankBorderColor(0, rank1, rank2, rank3)
color bodyBorder = getRankBorderColor(1, rank1, rank2, rank3)
color lwkBorder = getRankBorderColor(2, rank1, rank2, rank3)
// Control
string bullCtrl = control == "BULL" ? "●" : ""
string bearCtrl = control == "BEAR" ? "●" : ""
string neutCtrl = control == "NEUT" ? "●" : ""
// Time text
string timeText = ""
if tableFilterMode != "All Candles"
timeText := "#" + str.tostring(arrayIdx) + " " + formatTime(t)
else if effectiveOffset > 0
timeText := str.tostring(arrayIdx) + "|" + formatTime(t)
else
timeText := formatTime(t)
table.cell(tbl, 0, currentRow, timeText, bgcolor=tableBgColor, text_color=textColor, text_size=tSize)
table.cell(tbl, 1, currentRow, chText, bgcolor=color.new(chColor, 90), text_color=chColor, text_size=tSize)
table.cell(tbl, 2, currentRow, bosText, bgcolor=color.new(bosColor, 90), text_color=bosColor, text_size=tSize)
table.cell(tbl, 3, currentRow, liqText, bgcolor=color. new(liqColorCell, 90), text_color=liqColorCell, text_size=tSize)
table.cell(tbl, 4, currentRow, getSprdPctLabel(sprd), bgcolor=tableBgColor, text_color=getSprdColor(sprd), text_size=tSize)
table.cell(tbl, 5, currentRow, getDiffPctLabel(sprd, vol), bgcolor=tableBgColor, text_color=getDiffColorWithFlow(sprd, vol), text_size=tSize)
table.cell(tbl, 6, currentRow, getVolPctLabel(vol), bgcolor=tableBgColor, text_color=getVolColor(vol), text_size=tSize)
table.cell(tbl, 7, currentRow, formatPct(upperWick), bgcolor=color.new(hwkBorder, 80), text_color=getWickColor(upperWick), text_size=tSize)
table.cell(tbl, 8, currentRow, formatPct(body), bgcolor=color. new(bodyBorder, 80), text_color=getBodyColor(body, isBull), text_size=tSize)
table.cell(tbl, 9, currentRow, formatPct(lowerWick), bgcolor=color.new(lwkBorder, 80), text_color=getWickColor(lowerWick), text_size=tSize)
table.cell(tbl, 10, currentRow, candleType, bgcolor=tableBgColor, text_color=getCandleTypeColor(candleType, isBull), text_size=tSize)
table. cell(tbl, 11, currentRow, bullCtrl, bgcolor=control == "BULL" ? color. new(colorBull, 70) : tableBgColor, text_color=colorBull, text_size=tSize)
table.cell(tbl, 12, currentRow, bearCtrl, bgcolor=control == "BEAR" ? color.new(colorBear, 70) : tableBgColor, text_color=colorBear, text_size=tSize)
table.cell(tbl, 13, currentRow, neutCtrl, bgcolor=control == "NEUT" ? color.new(colorNeut, 70) : tableBgColor, text_color=colorNeut, text_size=tSize)
currentRow += 1
rowsShown += 1
arrayIdx += 1
// ═══════════════════════════════════════════════════════════════════════════
// FOOTER
// ═══════════════════════════════════════════════════════════════════════════
int footerRow = currentRow + 1
int filteredCount = 0
if evtCount > 0
for i = 0 to evtCount - 1
int chB = array.get(evtChochBull, i)
int chS = array. get(evtChochBear, i)
int bosB = array.get(evtBosBull, i)
int bosS = array.get(evtBosBear, i)
int liqB = array. get(evtLiqBull, i)
int liqS = array.get(evtLiqBear, i)
if shouldShowRow(chB, chS, bosB, bosS, liqB, liqS)
filteredCount += 1
[fChB, fChS, fBosB, fBosS, fLiqB, fLiqS, fBuyScore, fSellScore] = calcWindowStats(avgLookback)
int totalBull = fChB + fBosB + fLiqB
int totalBear = fChS + fBosS + fLiqS
int totalEvents = totalBull + totalBear
float bullPct = totalEvents > 0 ? (float(totalBull) / float(totalEvents)) * 100 : 50
float bearPct = totalEvents > 0 ? (float(totalBear) / float(totalEvents)) * 100 : 50
string filterInfo = tableFilterMode != "All Candles" ? " | FILTER: " + str.tostring(filteredCount) : ""
string footerText = "BULL:" + str.tostring(bullPct, "#.#") + "% | BEAR:" + str. tostring(bearPct, "#.#") + "% | CTRL B:" + str.tostring(fBuyScore) + " S:" + str.tostring(fSellScore) + filterInfo
color footerColor = bullPct > 55 ? colorBull : bearPct > 55 ? colorBear : colorNeut
table.cell(tbl, 0, footerRow, footerText, bgcolor=footerBgColor, text_color=footerColor, text_size=tSize, text_halign=text. align_center)
table.merge_cells(tbl, 0, footerRow, 13, footerRow)
// ════════════════════════════════════════════════════════════════════════════════
// ALERTS
// ════════════════════════════════════════════════════════════════════════════════
alertcondition(curChochBull > 0 and curChochBullStrong, title="CHoCH Bullish Strong", message="STRONG CHoCH UP - Bullish Change of Character!")
alertcondition(curChochBull > 0 and not curChochBullStrong, title="CHoCH Bullish Weak", message="weak choch up - Bullish Change of Character")
alertcondition(curChochBear > 0 and curChochBearStrong, title="CHoCH Bearish Strong", message="STRONG CHoCH DN - Bearish Change of Character!")
alertcondition(curChochBear > 0 and not curChochBearStrong, title="CHoCH Bearish Weak", message="weak choch dn - Bearish Change of Character")
alertcondition(curBosBull > 0 and curBosBullStrong, title="BOS Bullish Strong", message="STRONG BOS UP - Bullish Break of Structure!")
alertcondition(curBosBull > 0 and not curBosBullStrong, title="BOS Bullish Weak", message="weak bos up - Bullish Break of Structure")
alertcondition(curBosBear > 0 and curBosBearStrong, title="BOS Bearish Strong", message="STRONG BOS DN - Bearish Break of Structure!")
alertcondition(curBosBear > 0 and not curBosBearStrong, title="BOS Bearish Weak", message="weak bos dn - Bearish Break of Structure")
alertcondition(curLiqBull > 0, title="LIQ Bullish", message="LIQ UP - Liquidity Sweep Above!")
alertcondition(curLiqBear > 0, title="LIQ Bearish", message="LIQ DN - Liquidity Sweep Below!")
alertcondition(curLiqBull > 0 and curLiqBear > 0, title="DUAL LIQ", message="DUAL LIQ - Both Sides Swept!")
// ════════════════════════════════════════════════════════════════════════════════
// END OF SCRIPT v24
// ════════════════════════════════════════════════════════════════════════════════
Show all 1,168 lines