//@version=5
indicator("Phidias Master Engine [v9.5 TITAN]", shorttitle="Phidias_v9.5", overlay=true, max_labels_count=500)
// ═══════════════════════════════════════════════════════════════════════════════
// 1. GLOBAL INPUTS
// ═══════════════════════════════════════════════════════════════════════════════
nq_sym = input.symbol("NQ1!", "NQ Symbol", group="Institutional Sync")
pl_input = input.float(0, "Current P&L ($)", step=50, group="Preservation Gate")
stop_pts = input.float(4.0, "Stop Loss (Pts)", group="Risk Audit")
target_pts = input.float(8.0, "Target (Pts)", group="Risk Audit")
rr_floor = 1.5
// Silent Sweep Detection
grp_sweep = "Sweep Detection (Silent)"
z_threshold = input.float(2.5, "Z-Score Volume Threshold", minval=0.5, step=0.1, group=grp_sweep)
touch_zone_ticks = input.int(2, "Touch Zone (ticks from boundary)", minval=0, maxval=10, group=grp_sweep)
tick_size_input = input.float(0.25, "Tick Size", step=0.25, group=grp_sweep)
max_tracked = input.int(10, "Max Tracked Boxes", minval=5, maxval=20, group=grp_sweep)
sweep_stale_bars = input.int(15, "Sweep Stale After (bars)", minval=5, maxval=60, group=grp_sweep)
sweep_expire_bars = input.int(30, "Sweep Expires After (bars)", minval=10, maxval=120, group=grp_sweep)
// RSI Settings
grp_rsi = "RSI Divergence"
rsi_len = input.int(14, "RSI Length", minval=5, maxval=30, group=grp_rsi)
rsi_ob = input.float(70.0, "Overbought", minval=60, maxval=90, group=grp_rsi)
rsi_os = input.float(30.0, "Oversold", minval=10, maxval=40, group=grp_rsi)
div_lookback = input.int(20, "Divergence Lookback (bars)", minval=5, maxval=30, group=grp_rsi)
div_confirm = input.int(2, "Divergence Confirm (bars)", minval=1, maxval=5, group=grp_rsi)
// ═══════════════════════════════════════════════════════════════════════════════
// 2. CURRENT PRICE DATA
// ═══════════════════════════════════════════════════════════════════════════════
mes_c = close
mes_v = volume
nq_c = request.security(nq_sym, timeframe.period, close)
// ═══════════════════════════════════════════════════════════════════════════════
// 3. LONDON MIDPOINT (08:00 UTC)
// ═══════════════════════════════════════════════════════════════════════════════
var float lon_mid = na
var bool lon_tested = false
is_lon_start = not na(time(timeframe.period, "0800-0805", "UTC"))
if is_lon_start
lon_mid := (high + low) / 2
lon_tested := false
if not na(lon_mid) and not lon_tested
if low <= lon_mid and high >= lon_mid
lon_tested := true
// ═══════════════════════════════════════════════════════════════════════════════
// 4. ZONE MEMORY
// ═══════════════════════════════════════════════════════════════════════════════
vol_ma = ta.sma(mes_v, 20)
atr_val = ta.atr(14)
atr_ma = ta.sma(atr_val, 20)
is_climax = mes_v > vol_ma * 1.8 or atr_val > atr_ma * 1.5
var red_highs = array.new_float(3, na)
var red_lows = array.new_float(3, na)
var grn_highs = array.new_float(3, na)
var grn_lows = array.new_float(3, na)
var int r_ghosts = 0
var int g_ghosts = 0
if is_lon_start
r_ghosts := 0
g_ghosts := 0
if is_climax
if close < open
array.unshift(red_highs, high)
array.unshift(red_lows, low)
array.pop(red_highs)
array.pop(red_lows)
else
array.unshift(grn_highs, high)
array.unshift(grn_lows, low)
array.pop(grn_highs)
array.pop(grn_lows)
// ═══════════════════════════════════════════════════════════════════════════════
// 5. REFINED ZONE ANALYSIS — nearest = immediate structural threat
// ═══════════════════════════════════════════════════════════════════════════════
bool in_red = false
bool in_grn = false
bool box_broken = false
string break_type = ""
float nearest_resistance = na // closest red zone top above price (immediate threat for longs)
float nearest_support = na // closest green zone bottom below price (immediate threat for shorts)
for i = 0 to 2
rh = array.get(red_highs, i)
rl = array.get(red_lows, i)
gh = array.get(grn_highs, i)
gl = array.get(grn_lows, i)
if not na(rh)
if mes_c >= rl and mes_c <= rh
in_red := true
float red_edge = rh
if red_edge > mes_c
if na(nearest_resistance) or (red_edge - mes_c) < (nearest_resistance - mes_c)
nearest_resistance := red_edge
if not na(gh)
if mes_c >= gl and mes_c <= gh
in_grn := true
float grn_edge = gl
if grn_edge < mes_c
if na(nearest_support) or (mes_c - grn_edge) < (mes_c - nearest_support)
nearest_support := grn_edge
if not na(rh) and close < rl
box_broken := true
break_type := "SUPPLY"
if not na(gh) and close > gh
box_broken := true
break_type := "DEMAND"
if not na(rh) and close > rh
array.set(red_highs, i, na)
array.set(red_lows, i, na)
r_ghosts += 1
if not na(gh) and close < gl
array.set(grn_highs, i, na)
array.set(grn_lows, i, na)
g_ghosts += 1
// ═══════════════════════════════════════════════════════════════════════════════
// 6. SILENT SWEEP DETECTION ENGINE
// ═══════════════════════════════════════════════════════════════════════════════
float vol_sma_z = ta.sma(volume, 20)
float vol_std_z = ta.stdev(volume, 20)
float z_vol = vol_std_z != 0 ? (volume - vol_sma_z) / vol_std_z : 0
bool high_vol = z_vol >= z_threshold
bool bullish_candle = close > open
var float[] s_box_tops = array.new_float(0)
var float[] s_box_bottoms = array.new_float(0)
var int[] s_box_dirs = array.new_int(0)
var int[] s_box_births = array.new_int(0)
var int[] s_box_touches = array.new_int(0)
var bool[] s_box_swept = array.new_bool(0)
if high_vol
array.push(s_box_tops, high)
array.push(s_box_bottoms, low)
array.push(s_box_dirs, bullish_candle ? 1 : -1)
array.push(s_box_births, bar_index)
array.push(s_box_touches, 0)
array.push(s_box_swept, false)
if array.size(s_box_tops) > max_tracked
array.shift(s_box_tops)
array.shift(s_box_bottoms)
array.shift(s_box_dirs)
array.shift(s_box_births)
array.shift(s_box_touches)
array.shift(s_box_swept)
var int last_sweep_bar = 0
var int last_sweep_dir = 0
var int last_sweep_touches = 0
var float last_sweep_level = na
float touch_zone = touch_zone_ticks * tick_size_input
int n_sboxes = array.size(s_box_tops)
if n_sboxes > 0
for i = n_sboxes - 1 to 0
float b_top = array.get(s_box_tops, i)
float b_bottom = array.get(s_box_bottoms, i)
int b_dir = array.get(s_box_dirs, i)
int b_birth = array.get(s_box_births, i)
bool b_swept = array.get(s_box_swept, i)
int b_touch = array.get(s_box_touches, i)
if bar_index - b_birth > 200 or b_swept
continue
if b_dir == 1
bool near_bottom = low <= (b_bottom + touch_zone) and low >= (b_bottom - touch_zone)
bool closed_above = close > b_bottom
bool swept_below = low < (b_bottom - touch_zone)
if near_bottom and closed_above and not swept_below
array.set(s_box_touches, i, b_touch + 1)
if swept_below
array.set(s_box_swept, i, true)
last_sweep_bar := bar_index
last_sweep_dir := 1
last_sweep_touches := b_touch
last_sweep_level := b_bottom
if b_dir == -1
bool near_top = high >= (b_top - touch_zone) and high <= (b_top + touch_zone)
bool closed_below = close < b_top
bool swept_above = high > (b_top + touch_zone)
if near_top and closed_below and not swept_above
array.set(s_box_touches, i, b_touch + 1)
if swept_above
array.set(s_box_swept, i, true)
last_sweep_bar := bar_index
last_sweep_dir := -1
last_sweep_touches := b_touch
last_sweep_level := b_top
int sweep_age = bar_index - last_sweep_bar
bool sweep_active = last_sweep_bar > 0 and sweep_age <= sweep_expire_bars
bool sweep_fresh = sweep_active and sweep_age <= sweep_stale_bars
bool sweep_stale = sweep_active and sweep_age > sweep_stale_bars
int pending_touches = 0
int active_boxes = 0
if array.size(s_box_tops) > 0
for i = 0 to array.size(s_box_tops) - 1
if bar_index - array.get(s_box_births, i) <= 200 and not array.get(s_box_swept, i)
active_boxes += 1
pending_touches += array.get(s_box_touches, i)
// ═══════════════════════════════════════════════════════════════════════════════
// 7. RSI DIVERGENCE ENGINE
// ═══════════════════════════════════════════════════════════════════════════════
float rsi_val = ta.rsi(close, rsi_len)
float price_low_1 = ta.lowest(low, div_lookback)
float price_low_2 = ta.lowest(low, div_lookback)[div_lookback]
float price_high_1 = ta.highest(high, div_lookback)
float price_high_2 = ta.highest(high, div_lookback)[div_lookback]
float rsi_low_1 = ta.lowest(rsi_val, div_lookback)
float rsi_low_2 = ta.lowest(rsi_val, div_lookback)[div_lookback]
float rsi_high_1 = ta.highest(rsi_val, div_lookback)
float rsi_high_2 = ta.highest(rsi_val, div_lookback)[div_lookback]
bool raw_bull_div = price_low_1 < price_low_2 and rsi_low_1 > rsi_low_2
bool raw_bear_div = price_high_1 > price_high_2 and rsi_high_1 < rsi_high_2
var int bull_div_count = 0
var int bear_div_count = 0
if raw_bull_div
bull_div_count += 1
else
bull_div_count := 0
if raw_bear_div
bear_div_count += 1
else
bear_div_count := 0
bool bull_div_confirmed = bull_div_count >= div_confirm
bool bear_div_confirmed = bear_div_count >= div_confirm
string rsi_state = ""
color rsi_bg = color.new(#000000, 40)
color rsi_tc = color.gray
if bull_div_confirmed and rsi_val < rsi_os
rsi_state := "OS + BULL DIV"
rsi_bg := color.new(color.green, 10)
rsi_tc := color.white
else if bear_div_confirmed and rsi_val > rsi_ob
rsi_state := "OB + BEAR DIV"
rsi_bg := color.new(color.red, 10)
rsi_tc := color.white
else if bull_div_confirmed
rsi_state := "BULL DIV"
rsi_bg := color.new(color.green, 40)
rsi_tc := color.green
else if bear_div_confirmed
rsi_state := "BEAR DIV"
rsi_bg := color.new(color.red, 40)
rsi_tc := color.red
else if rsi_val > rsi_ob
rsi_state := "OB " + str.tostring(rsi_val, "#.#")
rsi_bg := color.new(color.red, 60)
rsi_tc := color.red
else if rsi_val < rsi_os
rsi_state := "OS " + str.tostring(rsi_val, "#.#")
rsi_bg := color.new(color.green, 60)
rsi_tc := color.green
else
rsi_state := str.tostring(rsi_val, "#.#")
rsi_bg := color.new(#000000, 40)
rsi_tc := color.gray
// ═══════════════════════════════════════════════════════════════════════════════
// 8. TARGET CALCULATIONS
// ═══════════════════════════════════════════════════════════════════════════════
float long_target = mes_c + target_pts
float short_target = mes_c - target_pts
float dyn_rr = target_pts / stop_pts
// ═══════════════════════════════════════════════════════════════════════════════
// 9. DUAL GATE AUDIT ENGINE — refined proximity
// ═══════════════════════════════════════════════════════════════════════════════
bool is_rsw = not na(time(timeframe.period, "1430-1445", "UTC"))
bool rr_fail = dyn_rr < rr_floor
bool loss_limit = pl_input <= -500
bool long_trap = in_red
bool long_nq_fail = nq_c < nq_c[1] and not box_broken
bool long_target_blocked = not na(nearest_resistance) and nearest_resistance < long_target
string long_veto = ""
if loss_limit
long_veto := "LOSS"
else if is_rsw
long_veto := "RSW"
else if rr_fail
long_veto := "R:R"
else if long_trap
long_veto := "ZONE"
else if long_nq_fail
long_veto := "NQ"
else if long_target_blocked
long_veto := "BLOCKED"
bool long_pass = long_veto == ""
bool short_trap = in_grn
bool short_nq_fail = nq_c > nq_c[1] and not box_broken
bool short_target_blocked = not na(nearest_support) and nearest_support > short_target
string short_veto = ""
if loss_limit
short_veto := "LOSS"
else if is_rsw
short_veto := "RSW"
else if rr_fail
short_veto := "R:R"
else if short_trap
short_veto := "ZONE"
else if short_nq_fail
short_veto := "NQ"
else if short_target_blocked
short_veto := "BLOCKED"
bool short_pass = short_veto == ""
// ═══════════════════════════════════════════════════════════════════════════════
// 10. SETUP GRADING ENGINE
// ═══════════════════════════════════════════════════════════════════════════════
bool sweep_long_aligned = sweep_fresh and last_sweep_dir == 1
bool sweep_short_aligned = sweep_fresh and last_sweep_dir == -1
bool rsi_supports_long = bull_div_confirmed or rsi_val < rsi_os
bool rsi_supports_short = bear_div_confirmed or rsi_val > rsi_ob
bool rsi_warns_long = bear_div_confirmed
bool rsi_warns_short = bull_div_confirmed
bool rsi_neutral = not rsi_supports_long and not rsi_supports_short and not rsi_warns_long and not rsi_warns_short
string long_grade = "X"
if not long_pass
long_grade := "X"
else if sweep_long_aligned and (rsi_supports_long or (rsi_neutral and not rsi_warns_long))
long_grade := "A+"
else if rsi_warns_long
long_grade := "C"
else if sweep_long_aligned or rsi_supports_long
long_grade := "B+"
else
long_grade := "B+"
string short_grade = "X"
if not short_pass
short_grade := "X"
else if sweep_short_aligned and (rsi_supports_short or (rsi_neutral and not rsi_warns_short))
short_grade := "A+"
else if rsi_warns_short
short_grade := "C"
else if sweep_short_aligned or rsi_supports_short
short_grade := "B+"
else
short_grade := "B+"
f_grade_bg(string grade) => grade == "A+" ? color.new(#00e676, 15) : grade == "B+" ? color.new(#448aff, 25) : grade == "C" ? color.new(#ffd600, 25) : color.new(#444455, 50)
f_grade_tc(string grade) => grade == "A+" ? color.white : grade == "B+" ? color.white : grade == "C" ? color.black : color.gray
// ═══════════════════════════════════════════════════════════════════════════════
// 11. CANDLE COLOURING
// ═══════════════════════════════════════════════════════════════════════════════
color candle_col = na
if long_pass and not short_pass
candle_col := color.new(color.green, 60)
else if short_pass and not long_pass
candle_col := color.new(color.red, 60)
else if long_pass and short_pass
candle_col := color.new(color.yellow, 60)
else
candle_col := color.new(color.gray, 80)
barcolor(candle_col)
// ═══════════════════════════════════════════════════════════════════════════════
// 12. VISUALS
// ═══════════════════════════════════════════════════════════════════════════════
plot(lon_mid, "London Mid", color=lon_tested ? color.gray : color.aqua, linewidth=2)
plotshape(box_broken, "Box Break", shape.diamond, location.belowbar, color=break_type == "DEMAND" ? color.green : color.red, size=size.small)
plot(long_target, "Long Target", color=color.new(color.green, 70), style=plot.style_linebr, linewidth=1)
plot(short_target, "Short Target", color=color.new(color.red, 70), style=plot.style_linebr, linewidth=1)
// ═══════════════════════════════════════════════════════════════════════════════
// 13. GRADED ALERTS
// ═══════════════════════════════════════════════════════════════════════════════
var string prev_long_grade = "X"
var string prev_short_grade = "X"
bool long_a_plus_new = long_grade == "A+" and prev_long_grade != "A+"
bool long_b_plus_new = long_grade == "B+" and prev_long_grade == "X"
bool long_c_new = long_grade == "C" and prev_long_grade == "X"
bool short_a_plus_new = short_grade == "A+" and prev_short_grade != "A+"
bool short_b_plus_new = short_grade == "B+" and prev_short_grade == "X"
bool short_c_new = short_grade == "C" and prev_short_grade == "X"
bool long_gate_closed = long_grade == "X" and prev_long_grade != "X"
bool short_gate_closed = short_grade == "X" and prev_short_grade != "X"
prev_long_grade := long_grade
prev_short_grade := short_grade
alertcondition(long_a_plus_new, title="⚡ A+ LONG", message="A+ LONG SETUP — Gate open, sweep aligned, RSI supports.")
alertcondition(short_a_plus_new, title="⚡ A+ SHORT", message="A+ SHORT SETUP — Gate open, sweep aligned, RSI supports.")
alertcondition(long_b_plus_new, title="📈 B+ LONG", message="B+ LONG SETUP — Gate open.")
alertcondition(short_b_plus_new, title="📉 B+ SHORT", message="B+ SHORT SETUP — Gate open.")
alertcondition(long_c_new, title="⚠️ C LONG", message="C LONG SETUP — RSI divergence warning.")
alertcondition(short_c_new, title="⚠️ C SHORT", message="C SHORT SETUP — RSI divergence warning.")
// ═══════════════════════════════════════════════════════════════════════════════
// 14. UI TABLE
// ═══════════════════════════════════════════════════════════════════════════════
var table t = table.new(position.bottom_left, 9, 3, bgcolor=color.new(#000000, 80), border_width=1)
if barstate.islast
// Row 0: Headers
table.cell(t, 0, 0, "SYM", text_color=#888888, text_size=size.tiny)
table.cell(t, 1, 0, "R:R", text_color=#888888, text_size=size.tiny)
table.cell(t, 2, 0, "LONG", text_color=#888888, text_size=size.tiny)
table.cell(t, 3, 0, "SHORT", text_color=#888888, text_size=size.tiny)
table.cell(t, 4, 0, "ZONE", text_color=#888888, text_size=size.tiny)
table.cell(t, 5, 0, "GATE", text_color=#888888, text_size=size.tiny)
table.cell(t, 6, 0, "CANDLE", text_color=#888888, text_size=size.tiny)
table.cell(t, 7, 0, "SWEEP", text_color=#888888, text_size=size.tiny)
table.cell(t, 8, 0, "RSI", text_color=#888888, text_size=size.tiny)
// Row 1: Data
string candle_status = long_pass and short_pass ? "BOTH" : long_pass ? "GREEN" : short_pass ? "RED" : "DEAD"
color candle_bg = long_pass and short_pass ? color.yellow : long_pass ? color.green : short_pass ? color.red : color.gray
// Create GATE status text
string gate_status = ""
color gate_bg = color.new(#000000, 40)
if long_pass and short_pass
gate_status := "BOTH OPEN"
gate_bg := color.new(color.yellow, 30)
else if long_pass
gate_status := "LONG OPEN"
gate_bg := color.new(color.green, 30)
else if short_pass
gate_status := "SHORT OPEN"
gate_bg := color.new(color.red, 30)
else
// Gate is closed - show the primary veto reason
if loss_limit
gate_status := "LOSS LIMIT"
else if is_rsw
gate_status := "RSW"
else if rr_fail
gate_status := "R:R FAIL"
else if long_trap or short_trap
gate_status := "ZONE TRAP"
else if long_nq_fail or short_nq_fail
gate_status := "NQ FAIL"
else if long_target_blocked or short_target_blocked
gate_status := "BLOCKED"
else
gate_status := "CLOSED"
gate_bg := color.new(color.gray, 30)
table.cell(t, 0, 1, "MES", text_color=#FF9800, text_size=size.tiny)
table.cell(t, 1, 1, str.tostring(dyn_rr, "#.#") + "R", bgcolor=dyn_rr < rr_floor ? color.red : color.green, text_color=color.black, text_size=size.tiny)
table.cell(t, 2, 1, str.tostring(long_target, "#.##"), text_color=color.green, bgcolor=color.new(#000000, 40), text_size=size.tiny)
table.cell(t, 3, 1, str.tostring(short_target, "#.##"), text_color=color.red, bgcolor=color.new(#000000, 40), text_size=size.tiny)
string zone_text = in_red ? "RED" : in_grn ? "GREEN" : "CLEAN"
zone_text += " | G:" + str.tostring(r_ghosts) + "/" + str.tostring(g_ghosts)
table.cell(t, 4, 1, zone_text, bgcolor=(in_red or in_grn) ? color.new(color.red, 40) : color.new(color.green, 40), text_color=color.white, text_size=size.tiny)
// GATE cell - PROPERLY POPULATED
table.cell(t, 5, 1, gate_status, bgcolor=gate_bg, text_color=color.white, text_size=size.tiny)
// CANDLE cell
table.cell(t, 6, 1, candle_status, bgcolor=candle_bg, text_color=color.black, text_size=size.tiny)
// Sweep cell
string sweep_text = sweep_fresh ? "SWEEP " + (last_sweep_dir == 1 ? "↓ DEMAND" : "↑ SUPPLY") : sweep_stale ? "STALE" : "NO SWEEP"
color sweep_bg = sweep_fresh ? color.new(color.green, 20) : color.new(#000000, 40)
table.cell(t, 7, 1, sweep_text, bgcolor=sweep_bg, text_color=color.white, text_size=size.tiny)
// RSI cell
table.cell(t, 8, 1, rsi_state, bgcolor=rsi_bg, text_color=rsi_tc, text_size=size.tiny)
// Row 2: Grades
table.cell(t, 2, 2, long_grade + " LONG", bgcolor=f_grade_bg(long_grade), text_color=f_grade_tc(long_grade), text_size=size.tiny)
table.cell(t, 3, 2, short_grade + " SHORT", bgcolor=f_grade_bg(short_grade), text_color=f_grade_tc(short_grade), text_size=size.tiny)