order_flow_heatmap.pine
Copy
// ══════════════════════════════════════════════════════════════════════════════
// ORDER FLOW HEATMAP - BOOKMAP STYLE
// ══════════════════════════════════════════════════════════════════════════════
// Debugged Version - Sichere Array-Handhabung
// ══════════════════════════════════════════════════════════════════════════════
//@version=6
indicator("Order Flow Heatmap", shorttitle="OF-Heatmap", overlay=true,
max_boxes_count=500, max_lines_count=500, max_labels_count=200)
// ══════════════════════════════════════════════════════════════════════════════
// KONSTANTEN
// ══════════════════════════════════════════════════════════════════════════════
const int MAX_ROWS = 50
// ══════════════════════════════════════════════════════════════════════════════
// EINGABE-PARAMETER
// ══════════════════════════════════════════════════════════════════════════════
grp_heat = "Heatmap-Einstellungen"
lookback = input.int(100, "Lookback Bars", minval=20, maxval=500, group=grp_heat)
row_count = input.int(40, "Preis-Levels (Rows)", minval=20, maxval=50, group=grp_heat)
show_heatmap = input.bool(true, "Heatmap anzeigen", group=grp_heat)
heatmap_opacity = input.int(80, "Heatmap Transparenz", minval=50, maxval=95, group=grp_heat)
heatmap_extend_right = input.int(20, "Heatmap nach rechts erweitern", minval=0, maxval=50, group=grp_heat)
grp_color = "Farbschema"
color_scheme = input.string("Bookmap Blue", "Farbschema", options=["Bookmap Blue", "Fire", "Green Matrix", "Purple", "Thermal"], group=grp_color)
intensity_mult = input.float(1.5, "Intensitäts-Multiplikator", minval=0.5, maxval=3.0, step=0.1, group=grp_color)
use_dynamic_range = input.bool(true, "Dynamische Preis-Range", group=grp_color)
grp_liq = "Liquiditäts-Levels"
show_liquidity_levels = input.bool(true, "Liquiditäts-Levels anzeigen", group=grp_liq)
liquidity_threshold = input.float(1.8, "Liquiditäts-Schwelle (x Avg)", minval=1.0, maxval=5.0, step=0.1, group=grp_liq)
show_hvn = input.bool(true, "High Volume Nodes (HVN)", group=grp_liq)
show_lvn = input.bool(true, "Low Volume Nodes (LVN)", group=grp_liq)
lvn_threshold = input.float(0.3, "LVN Schwelle (x Avg)", minval=0.1, maxval=0.5, step=0.05, group=grp_liq)
grp_bubble = "Volume Bubbles"
show_bubbles = input.bool(true, "Volume Bubbles anzeigen", group=grp_bubble)
bubble_threshold_small = input.float(1.3, "Kleine Bubble Schwelle", minval=1.0, maxval=2.0, step=0.1, group=grp_bubble)
bubble_threshold_medium = input.float(1.8, "Mittlere Bubble Schwelle", minval=1.5, maxval=3.0, step=0.1, group=grp_bubble)
bubble_threshold_large = input.float(2.5, "Große Bubble Schwelle", minval=2.0, maxval=5.0, step=0.1, group=grp_bubble)
grp_delta = "Delta & Imbalance"
show_delta_bg = input.bool(true, "Delta Hintergrund", group=grp_delta)
show_cvd = input.bool(true, "CVD (Cumulative Volume Delta)", group=grp_delta)
show_imbalance = input.bool(true, "Imbalance Marker", group=grp_delta)
imbalance_threshold = input.float(2.5, "Imbalance Ratio", minval=1.5, maxval=5.0, step=0.25, group=grp_delta)
grp_poc = "POC & Value Area"
show_poc = input.bool(true, "POC (Point of Control)", group=grp_poc)
show_value_area = input.bool(true, "Value Area", group=grp_poc)
va_percent = input.float(70.0, "Value Area %", minval=50.0, maxval=90.0, step=5.0, group=grp_poc)
poc_line_style = input.string("Solid", "POC Linien-Stil", options=["Solid", "Dashed", "Dotted"], group=grp_poc)
grp_vwap = "VWAP & Anchors"
show_vwap = input.bool(true, "Session VWAP", group=grp_vwap)
show_vwap_bands = input.bool(true, "VWAP Bänder (±1σ, ±2σ)", group=grp_vwap)
grp_stack = "Stacked Imbalances"
show_stacked = input.bool(true, "Stacked Imbalances anzeigen", group=grp_stack)
stack_count = input.int(3, "Min. aufeinanderfolgende Imbalances", minval=2, maxval=5, group=grp_stack)
// ══════════════════════════════════════════════════════════════════════════════
// SICHERE ARRAY HELPER FUNKTIONEN
// ══════════════════════════════════════════════════════════════════════════════
// Sichere array.get Funktion mit Bounds-Check
safe_array_get(array<float> arr, int idx) =>
result = 0.0
if not na(arr) and array.size(arr) > 0 and idx >= 0 and idx < array.size(arr)
result := array.get(arr, idx)
result
// Sichere array.set Funktion mit Bounds-Check
safe_array_set(array<float> arr, int idx, float val) =>
if not na(arr) and array.size(arr) > 0 and idx >= 0 and idx < array.size(arr)
array.set(arr, idx, val)
// ══════════════════════════════════════════════════════════════════════════════
// FARBPALETTEN
// ══════════════════════════════════════════════════════════════════════════════
get_heatmap_color(float intensity, string scheme, int opacity) =>
clamped = math.min(math.max(intensity, 0.0), 1.0)
color result = color.new(#0a1628, opacity)
if scheme == "Bookmap Blue"
if clamped >= 0.95
result := color.new(#f44336, opacity - 50)
else if clamped >= 0.85
result := color.new(#ff9800, opacity - 45)
else if clamped >= 0.70
result := color.new(#ffeb3b, opacity - 40)
else if clamped >= 0.55
result := color.new(#00e5ff, opacity - 30)
else if clamped >= 0.40
result := color.new(#00acc1, opacity - 20)
else if clamped >= 0.25
result := color.new(#1565c0, opacity - 10)
else if clamped >= 0.15
result := color.new(#0d3a6e, opacity - 5)
else if scheme == "Fire"
if clamped >= 0.8
result := color.new(#ffeb3b, opacity - 50)
else if clamped >= 0.6
result := color.new(#ff5722, opacity - 35)
else if clamped >= 0.4
result := color.new(#b71c1c, opacity - 20)
else if clamped >= 0.2
result := color.new(#6d0000, opacity - 10)
else if scheme == "Green Matrix"
if clamped >= 0.8
result := color.new(#00ff41, opacity - 50)
else if clamped >= 0.6
result := color.new(#00cc00, opacity - 35)
else if clamped >= 0.4
result := color.new(#006600, opacity - 20)
else if clamped >= 0.2
result := color.new(#003300, opacity - 10)
else if scheme == "Purple"
if clamped >= 0.8
result := color.new(#e040fb, opacity - 50)
else if clamped >= 0.6
result := color.new(#ba68c8, opacity - 35)
else if clamped >= 0.4
result := color.new(#6a0dad, opacity - 20)
else if clamped >= 0.2
result := color.new(#2e003e, opacity - 10)
else if scheme == "Thermal"
if clamped >= 0.8
result := color.new(#ffff00, opacity - 50)
else if clamped >= 0.65
result := color.new(#ff6600, opacity - 40)
else if clamped >= 0.5
result := color.new(#ff0066, opacity - 30)
else if clamped >= 0.35
result := color.new(#aa00aa, opacity - 20)
else if clamped >= 0.2
result := color.new(#0000aa, opacity - 10)
result
// ══════════════════════════════════════════════════════════════════════════════
// PREIS-RANGE BERECHNUNG
// ══════════════════════════════════════════════════════════════════════════════
atr_val = ta.atr(14)
safe_atr = nz(atr_val, close * 0.02)
volatility_range = safe_atr * 20
raw_highest = ta.highest(high, lookback)
raw_lowest = ta.lowest(low, lookback)
highest_price = use_dynamic_range ? math.max(raw_highest, close + volatility_range/2) : raw_highest
lowest_price = use_dynamic_range ? math.min(raw_lowest, close - volatility_range/2) : raw_lowest
price_range = math.max(highest_price - lowest_price, safe_atr * 5)
row_height = price_range / math.max(row_count, 1)
// ══════════════════════════════════════════════════════════════════════════════
// VOLUME PROFILE ARRAYS - SICHERE INITIALISIERUNG
// ══════════════════════════════════════════════════════════════════════════════
// Arrays einmalig mit var initialisieren - NICHT leeren!
var array<float> vol_profile = array.new_float(MAX_ROWS, 0.0)
var array<float> buy_vol = array.new_float(MAX_ROWS, 0.0)
var array<float> sell_vol = array.new_float(MAX_ROWS, 0.0)
var array<float> delta_profile = array.new_float(MAX_ROWS, 0.0)
// Persistent Variablen für POC/VA
var int poc_idx = 0
var float poc_price = 0.0
var float vah_price = 0.0
var float val_price = 0.0
var float max_vol_level = 0.0
var float avg_vol_level = 0.0
// ══════════════════════════════════════════════════════════════════════════════
// DELTA BERECHNUNG
// ══════════════════════════════════════════════════════════════════════════════
bar_range = high - low
close_position = bar_range > 0 ? (close - low) / bar_range : 0.5
est_buy_vol = volume * close_position
est_sell_vol = volume * (1 - close_position)
delta = est_buy_vol - est_sell_vol
delta_percent = volume > 0 ? (delta / volume) * 100 : 0
var float cvd = 0.0
cvd += nz(delta, 0)
// ══════════════════════════════════════════════════════════════════════════════
// VOLUME PROFILE BERECHNEN - NUR AUF LETZTEM BAR
// ══════════════════════════════════════════════════════════════════════════════
if barstate.islast
// Prüfen ob Arrays valide sind
if array.size(vol_profile) == MAX_ROWS
// Arrays mit 0 füllen (nicht löschen!)
for i = 0 to MAX_ROWS - 1
array.set(vol_profile, i, 0.0)
array.set(buy_vol, i, 0.0)
array.set(sell_vol, i, 0.0)
array.set(delta_profile, i, 0.0)
// Volumen auf Preis-Levels verteilen
for j = 0 to math.min(lookback - 1, 499)
bar_h = high[j]
bar_l = low[j]
bar_c = close[j]
bar_v = nz(volume[j], 0)
bar_rng = bar_h - bar_l
if bar_v > 0 and bar_rng > 0
cp = (bar_c - bar_l) / bar_rng
bv = bar_v * cp
sv = bar_v * (1 - cp)
for i = 0 to row_count - 1
level_low = lowest_price + (i * row_height)
level_high = level_low + row_height
if bar_h >= level_low and bar_l <= level_high
overlap_low = math.max(bar_l, level_low)
overlap_high = math.min(bar_h, level_high)
overlap_ratio = (overlap_high - overlap_low) / bar_rng
vol_contrib = bar_v * overlap_ratio
buy_contrib = bv * overlap_ratio
sell_contrib = sv * overlap_ratio
array.set(vol_profile, i, array.get(vol_profile, i) + vol_contrib)
array.set(buy_vol, i, array.get(buy_vol, i) + buy_contrib)
array.set(sell_vol, i, array.get(sell_vol, i) + sell_contrib)
array.set(delta_profile, i, array.get(delta_profile, i) + (buy_contrib - sell_contrib))
// POC finden
max_vol_level := 0.0
poc_idx := 0
for i = 0 to row_count - 1
v = array.get(vol_profile, i)
if v > max_vol_level
max_vol_level := v
poc_idx := i
poc_price := lowest_price + (poc_idx * row_height) + (row_height / 2)
// Durchschnitt berechnen
total_vol = 0.0
for i = 0 to row_count - 1
total_vol += array.get(vol_profile, i)
avg_vol_level := row_count > 0 ? total_vol / row_count : 0
// Value Area berechnen
if total_vol > 0
target_vol = total_vol * (va_percent / 100)
va_vol = array.get(vol_profile, poc_idx)
upper_idx = poc_idx
lower_idx = poc_idx
iterations = 0
while va_vol < target_vol and iterations < row_count
iterations += 1
upper_v = upper_idx < row_count - 1 ? array.get(vol_profile, upper_idx + 1) : 0.0
lower_v = lower_idx > 0 ? array.get(vol_profile, lower_idx - 1) : 0.0
if upper_v >= lower_v and upper_idx < row_count - 1
upper_idx += 1
va_vol += upper_v
else if lower_idx > 0
lower_idx -= 1
va_vol += lower_v
else
break
vah_price := lowest_price + ((upper_idx + 1) * row_height)
val_price := lowest_price + (lower_idx * row_height)
// ══════════════════════════════════════════════════════════════════════════════
// HEATMAP ZEICHNEN
// ══════════════════════════════════════════════════════════════════════════════
var array<box> heatmap_boxes = array.new_box(0)
if barstate.islast and show_heatmap and max_vol_level > 0
// Alte Boxes löschen
if array.size(heatmap_boxes) > 0
for i = 0 to array.size(heatmap_boxes) - 1
box.delete(array.get(heatmap_boxes, i))
array.clear(heatmap_boxes)
for i = 0 to row_count - 1
level_low = lowest_price + (i * row_height)
level_high = level_low + row_height
vol_at_level = safe_array_get(vol_profile, i)
intensity = (vol_at_level / max_vol_level) * intensity_mult
box_color = get_heatmap_color(intensity, color_scheme, heatmap_opacity)
bar_width = math.round(3 + (intensity * 15))
new_box = box.new(
left=bar_index - lookback,
top=level_high,
right=bar_index + heatmap_extend_right,
bottom=level_low,
bgcolor=box_color,
border_color=color.new(color.white, 100),
border_width=0
)
array.push(heatmap_boxes, new_box)
if intensity > 0.6
intense_box = box.new(
left=bar_index + heatmap_extend_right,
top=level_high,
right=bar_index + heatmap_extend_right + bar_width,
bottom=level_low,
bgcolor=get_heatmap_color(intensity * 1.2, color_scheme, heatmap_opacity - 20),
border_color=color.new(color.white, 100),
border_width=0
)
array.push(heatmap_boxes, intense_box)
// ══════════════════════════════════════════════════════════════════════════════
// LIQUIDITÄTS-LEVELS (HVN / LVN)
// ══════════════════════════════════════════════════════════════════════════════
var array<line> liq_lines = array.new_line(0)
var array<label> liq_labels = array.new_label(0)
if barstate.islast and show_liquidity_levels and avg_vol_level > 0 and max_vol_level > 0
// Alte löschen
if array.size(liq_lines) > 0
for i = 0 to array.size(liq_lines) - 1
line.delete(array.get(liq_lines, i))
array.clear(liq_lines)
if array.size(liq_labels) > 0
for i = 0 to array.size(liq_labels) - 1
label.delete(array.get(liq_labels, i))
array.clear(liq_labels)
for i = 0 to row_count - 1
vol_at_level = safe_array_get(vol_profile, i)
level_price = lowest_price + (i * row_height) + (row_height / 2)
delta_at_level = safe_array_get(delta_profile, i)
// HVN
if show_hvn and vol_at_level > avg_vol_level * liquidity_threshold
intensity = vol_at_level / max_vol_level
lw = intensity > 0.85 ? 3 : intensity > 0.6 ? 2 : 1
line_col = delta_at_level > 0 ? color.new(#4caf50, 30) : color.new(#ff5722, 30)
hvn_line = line.new(
x1=bar_index - lookback,
y1=level_price,
x2=bar_index + heatmap_extend_right + 30,
y2=level_price,
color=line_col,
width=lw,
style=line.style_solid
)
array.push(liq_lines, hvn_line)
hvn_label = label.new(
x=bar_index + heatmap_extend_right + 32,
y=level_price,
text="HVN " + str.tostring(vol_at_level / 1000, "#.#") + "K",
style=label.style_label_left,
color=color.new(delta_at_level > 0 ? #4caf50 : #ff5722, 70),
textcolor=delta_at_level > 0 ? #4caf50 : #ff5722,
size=size.tiny
)
array.push(liq_labels, hvn_label)
// LVN
if show_lvn and vol_at_level < avg_vol_level * lvn_threshold and vol_at_level > 0
lvn_line = line.new(
x1=bar_index - lookback,
y1=level_price,
x2=bar_index + heatmap_extend_right + 30,
y2=level_price,
color=color.new(#9c27b0, 50),
width=1,
style=line.style_dotted
)
array.push(liq_lines, lvn_line)
// ══════════════════════════════════════════════════════════════════════════════
// POC & VALUE AREA ZEICHNEN
// ══════════════════════════════════════════════════════════════════════════════
var line poc_line = na
var line vah_line = na
var line val_line = na
var box va_box = na
var label poc_label = na
poc_style = poc_line_style == "Solid" ? line.style_solid : poc_line_style == "Dashed" ? line.style_dashed : line.style_dotted
if barstate.islast and poc_price > 0
line.delete(poc_line)
line.delete(vah_line)
line.delete(val_line)
box.delete(va_box)
label.delete(poc_label)
if show_poc
poc_line := line.new(
x1=bar_index - lookback,
y1=poc_price,
x2=bar_index + heatmap_extend_right + 50,
y2=poc_price,
color=color.new(#f44336, 10),
width=3,
style=poc_style
)
poc_label := label.new(
x=bar_index + heatmap_extend_right + 52,
y=poc_price,
text="POC " + str.tostring(poc_price, "#.##"),
style=label.style_label_left,
color=color.new(#f44336, 50),
textcolor=#f44336,
size=size.small
)
if show_value_area and vah_price > 0 and val_price > 0
vah_line := line.new(
x1=bar_index - lookback,
y1=vah_price,
x2=bar_index + heatmap_extend_right + 50,
y2=vah_price,
color=color.new(#2196f3, 30),
width=2,
style=line.style_dashed
)
val_line := line.new(
x1=bar_index - lookback,
y1=val_price,
x2=bar_index + heatmap_extend_right + 50,
y2=val_price,
color=color.new(#2196f3, 30),
width=2,
style=line.style_dashed
)
va_box := box.new(
left=bar_index - lookback,
top=vah_price,
right=bar_index + heatmap_extend_right + 50,
bottom=val_price,
bgcolor=color.new(#2196f3, 95),
border_color=color.new(#2196f3, 80),
border_width=1
)
// ══════════════════════════════════════════════════════════════════════════════
// VWAP MIT BÄNDERN
// ══════════════════════════════════════════════════════════════════════════════
vwap_val = ta.vwap(hlc3)
var float sum_vol = 0.0
var float sum_vol_price = 0.0
var float sum_vol_price_sq = 0.0
if ta.change(time("D")) != 0
sum_vol := 0.0
sum_vol_price := 0.0
sum_vol_price_sq := 0.0
sum_vol += nz(volume, 0)
sum_vol_price += nz(volume, 0) * hlc3
sum_vol_price_sq += nz(volume, 0) * math.pow(hlc3, 2)
vwap_calc = sum_vol > 0 ? sum_vol_price / sum_vol : close
vwap_var = sum_vol > 0 ? math.max((sum_vol_price_sq / sum_vol) - math.pow(vwap_calc, 2), 0) : 0
vwap_std = math.sqrt(vwap_var)
vwap_upper1 = vwap_calc + vwap_std
vwap_lower1 = vwap_calc - vwap_std
vwap_upper2 = vwap_calc + (vwap_std * 2)
vwap_lower2 = vwap_calc - (vwap_std * 2)
plot(show_vwap ? vwap_calc : na, "VWAP", color=color.new(#ff9800, 20), linewidth=2)
plot(show_vwap and show_vwap_bands ? vwap_upper1 : na, "VWAP +1σ", color=color.new(#ff9800, 60), linewidth=1)
plot(show_vwap and show_vwap_bands ? vwap_lower1 : na, "VWAP -1σ", color=color.new(#ff9800, 60), linewidth=1)
plot(show_vwap and show_vwap_bands ? vwap_upper2 : na, "VWAP +2σ", color=color.new(#ff9800, 80), linewidth=1, style=plot.style_circles)
plot(show_vwap and show_vwap_bands ? vwap_lower2 : na, "VWAP -2σ", color=color.new(#ff9800, 80), linewidth=1, style=plot.style_circles)
// ══════════════════════════════════════════════════════════════════════════════
// VOLUME BUBBLES
// ══════════════════════════════════════════════════════════════════════════════
avg_volume = ta.sma(volume, 20)
vol_ratio = nz(avg_volume, 1) > 0 ? nz(volume, 0) / nz(avg_volume, 1) : 0
is_small_vol = vol_ratio >= bubble_threshold_small and vol_ratio < bubble_threshold_medium
is_medium_vol = vol_ratio >= bubble_threshold_medium and vol_ratio < bubble_threshold_large
is_large_vol = vol_ratio >= bubble_threshold_large
is_buy_bar = close > open
is_sell_bar = close < open
plotshape(show_bubbles and is_small_vol and is_buy_bar, title="Buy Small", style=shape.circle, location=location.absolute, color=color.new(#4caf50, 40), size=size.tiny)
plotshape(show_bubbles and is_medium_vol and is_buy_bar, title="Buy Medium", style=shape.circle, location=location.absolute, color=color.new(#4caf50, 25), size=size.small)
plotshape(show_bubbles and is_large_vol and is_buy_bar, title="Buy Large", style=shape.circle, location=location.absolute, color=color.new(#00e676, 10), size=size.normal)
plotshape(show_bubbles and is_small_vol and is_sell_bar, title="Sell Small", style=shape.circle, location=location.absolute, color=color.new(#f44336, 40), size=size.tiny)
plotshape(show_bubbles and is_medium_vol and is_sell_bar, title="Sell Medium", style=shape.circle, location=location.absolute, color=color.new(#f44336, 25), size=size.small)
plotshape(show_bubbles and is_large_vol and is_sell_bar, title="Sell Large", style=shape.circle, location=location.absolute, color=color.new(#ff1744, 10), size=size.normal)
// ══════════════════════════════════════════════════════════════════════════════
// DELTA HINTERGRUND
// ══════════════════════════════════════════════════════════════════════════════
delta_intensity = math.min(math.abs(delta_percent) / 100, 0.2)
delta_bg_color = delta > 0 ? color.new(#4caf50, 92 - math.round(delta_intensity * 20)) : color.new(#f44336, 92 - math.round(delta_intensity * 20))
bgcolor(show_delta_bg ? delta_bg_color : na, title="Delta Background")
// ══════════════════════════════════════════════════════════════════════════════
// IMBALANCE DETECTION
// ══════════════════════════════════════════════════════════════════════════════
buy_sell_ratio = est_sell_vol > 0 ? est_buy_vol / est_sell_vol : 999
strong_buy_imbalance = buy_sell_ratio > imbalance_threshold and vol_ratio > bubble_threshold_small
strong_sell_imbalance = buy_sell_ratio < (1 / imbalance_threshold) and vol_ratio > bubble_threshold_small
plotshape(show_imbalance and strong_buy_imbalance, title="Buy Imbalance", style=shape.triangleup, location=location.belowbar, color=color.new(#00e676, 0), size=size.tiny)
plotshape(show_imbalance and strong_sell_imbalance, title="Sell Imbalance", style=shape.triangledown, location=location.abovebar, color=color.new(#ff5252, 0), size=size.tiny)
// ══════════════════════════════════════════════════════════════════════════════
// STACKED IMBALANCES
// ══════════════════════════════════════════════════════════════════════════════
var int consec_buy_imb = 0
var int consec_sell_imb = 0
if strong_buy_imbalance
consec_buy_imb += 1
consec_sell_imb := 0
else if strong_sell_imbalance
consec_sell_imb += 1
consec_buy_imb := 0
else
consec_buy_imb := 0
consec_sell_imb := 0
stacked_buy = consec_buy_imb >= stack_count
stacked_sell = consec_sell_imb >= stack_count
plotshape(show_stacked and stacked_buy and consec_buy_imb == stack_count, title="Stacked Buy", style=shape.diamond, location=location.belowbar, color=color.new(#00e676, 0), size=size.small)
plotshape(show_stacked and stacked_sell and consec_sell_imb == stack_count, title="Stacked Sell", style=shape.diamond, location=location.abovebar, color=color.new(#ff5252, 0), size=size.small)
// ══════════════════════════════════════════════════════════════════════════════
// CVD VISUALISIERUNG
// ══════════════════════════════════════════════════════════════════════════════
cvd_max = ta.highest(math.abs(cvd), lookback)
cvd_norm = cvd_max > 0 ? (cvd / cvd_max) * (price_range * 0.08) : 0
cvd_plot_price = lowest_price + cvd_norm + (price_range * 0.04)
cvd_color = cvd > 0 ? color.new(#4caf50, 60) : color.new(#f44336, 60)
plot(show_cvd ? cvd_plot_price : na, "CVD", color=cvd_color, linewidth=2, style=plot.style_area)
// ══════════════════════════════════════════════════════════════════════════════
// INFO DASHBOARD
// ══════════════════════════════════════════════════════════════════════════════
var table dash = table.new(position.top_right, 2, 12, bgcolor=color.new(#0a1628, 5), border_width=1, border_color=color.new(#00bcd4, 50))
if barstate.islast
table.cell(dash, 0, 0, "📊 ORDER FLOW", text_color=#00e5ff, text_size=size.small, bgcolor=color.new(#0d47a1, 40))
table.cell(dash, 1, 0, "v2.2", text_color=#00e5ff, text_size=size.small, bgcolor=color.new(#0d47a1, 40))
table.cell(dash, 0, 1, "POC", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 1, str.tostring(poc_price, "#.##"), text_color=#f44336, text_size=size.tiny)
table.cell(dash, 0, 2, "VAH", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 2, str.tostring(vah_price, "#.##"), text_color=#2196f3, text_size=size.tiny)
table.cell(dash, 0, 3, "VAL", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 3, str.tostring(val_price, "#.##"), text_color=#2196f3, text_size=size.tiny)
table.cell(dash, 0, 4, "VWAP", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 4, str.tostring(vwap_calc, "#.##"), text_color=#ff9800, text_size=size.tiny)
delta_col = delta > 0 ? #4caf50 : #f44336
delta_str = (delta > 0 ? "+" : "") + str.tostring(delta / 1000, "#.#") + "K"
table.cell(dash, 0, 5, "Delta", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 5, delta_str, text_color=delta_col, text_size=size.tiny)
cvd_col = cvd > 0 ? #4caf50 : #f44336
cvd_str = (cvd > 0 ? "+" : "") + str.tostring(cvd / 1000000, "#.##") + "M"
table.cell(dash, 0, 6, "CVD", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 6, cvd_str, text_color=cvd_col, text_size=size.tiny)
vol_col = vol_ratio > bubble_threshold_large ? #ff9800 : vol_ratio > bubble_threshold_small ? #ffeb3b : color.gray
table.cell(dash, 0, 7, "Vol Ratio", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 7, str.tostring(vol_ratio, "#.##") + "x", text_color=vol_col, text_size=size.tiny)
imb_text = strong_buy_imbalance ? "🟢 BUY" : strong_sell_imbalance ? "🔴 SELL" : "⚪ Neutral"
imb_col = strong_buy_imbalance ? #4caf50 : strong_sell_imbalance ? #f44336 : color.gray
table.cell(dash, 0, 8, "Imbalance", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 8, imb_text, text_color=imb_col, text_size=size.tiny)
stack_text = stacked_buy ? "⬆️ " + str.tostring(consec_buy_imb) + "x" : stacked_sell ? "⬇️ " + str.tostring(consec_sell_imb) + "x" : "—"
stack_col = stacked_buy ? #00e676 : stacked_sell ? #ff5252 : color.gray
table.cell(dash, 0, 9, "Stacked", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 9, stack_text, text_color=stack_col, text_size=size.tiny)
pos_poc = close > poc_price ? "↑ Über" : close < poc_price ? "↓ Unter" : "="
pos_col = close > poc_price ? #4caf50 : close < poc_price ? #f44336 : color.gray
table.cell(dash, 0, 10, "vs POC", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 10, pos_poc, text_color=pos_col, text_size=size.tiny)
in_va = close >= val_price and close <= vah_price
va_text = in_va ? "✓ In VA" : "✗ Out"
table.cell(dash, 0, 11, "Value Area", text_color=color.silver, text_size=size.tiny)
table.cell(dash, 1, 11, va_text, text_color=in_va ? #4caf50 : #ff9800, text_size=size.tiny)
// ══════════════════════════════════════════════════════════════════════════════
// ALERTS
// ══════════════════════════════════════════════════════════════════════════════
alertcondition(ta.cross(close, poc_price), title="POC Touch", message="📍 Preis berührt POC!")
alertcondition(strong_buy_imbalance, title="Buy Imbalance", message="🟢 Kauf-Imbalance!")
alertcondition(strong_sell_imbalance, title="Sell Imbalance", message="🔴 Verkauf-Imbalance!")
alertcondition(stacked_buy and consec_buy_imb == stack_count, title="Stacked Buy", message="⬆️⬆️ STACKED BUY!")
alertcondition(stacked_sell and consec_sell_imb == stack_count, title="Stacked Sell", message="⬇️⬇️ STACKED SELL!")
alertcondition(ta.crossover(close, vah_price), title="VAH Breakout", message="↑ VAH Breakout!")
alertcondition(ta.crossunder(close, val_price), title="VAL Breakdown", message="↓ VAL Breakdown!")
alertcondition(is_large_vol, title="High Volume", message="🔥 High Volume!")
// ══════════════════════════════════════════════════════════════════════════════
Show all 648 lines