//@version=6
// Author: MEOW PURR
// Author Telegram: @MeowForex1
indicator('Drone Arrows with Supply & Demand', 'Drone Arrows S&D', overlay = true)

// Settings
sensitivity = input.float(1.0, 'Sensitivity', 0.1, 5.0, 0.1, group = 'Signal Settings')
atr_length = input.int(10, 'ATR Length', 1, 50, group = 'Signal Settings')
atr_multiplier = input.float(7.0, 'ATR Multiplier', 1.0, 20.0, 0.5, group = 'Signal Settings')

// Filters
use_trend_filter = input.bool(true, 'Use Trend Filter', group = 'Filters')
ma_length = input.int(20, 'Moving Average Length', 5, 100, group = 'Filters')
use_volume_filter = input.bool(false, 'Use Volume Filter', group = 'Filters')
volume_threshold = input.float(1.1, 'Volume Threshold', 1.0, 3.0, 0.1, group = 'Filters')

show_signals = input.bool(true, 'Show Signals', group = 'Display')

// Risk Management
levels2 = input.bool(true, 'Show TP/SL Levels', group = 'Risk Management', inline = 'MMDB2')
lvlLines = input.bool(true, 'Show Lines ', inline = 'levels2', group = 'Risk Management')
linesStyle = input.string('SOLID', '', ['SOLID', 'DASHED', 'DOTTED'], inline = 'levels2', group = 'Risk Management')
lvlDistance = input.int(40, 'Distance', 1, inline = 'levels2', group = 'Risk Management')
lvlDecimals = input.int(4, '   Decimals', 1, 8, inline = 'levels2', group = 'Risk Management')
atrRisk = input.int(3, 'Risk Multiplier ', 1, group = 'Risk Management', inline = 'levels3')
atrLen = input.int(14, '  ATR Length', 1, group = 'Risk Management', inline = 'levels3')
percentStop = input.float(1, 'Stop Loss % (0 to Disable)', 0, group = 'Risk Management')

// Dashboard Settings
show_dashboard = input.bool(true, 'Show MTF Dashboard', group = 'Dashboard')

// Supply & Demand Settings
show_zones = input.bool(true, 'Show Supply & Demand Zones', group = 'Supply & Demand')
zone_strength = input.int(2, 'Minimum Zone Strength', 1, 5, group = 'Supply & Demand', tooltip = 'Minimum number of touches required')
zone_lookback = input.int(20, 'Zone Detection Length', 5, 50, group = 'Supply & Demand')
max_zones = input.int(5, 'Maximum Zones to Show', 1, 10, group = 'Supply & Demand')
supply_color = input.color(color.new(color.red, 80), 'Supply Zone Color', group = 'Supply & Demand')
demand_color = input.color(color.new(color.green, 80), 'Demand Zone Color', group = 'Supply & Demand')

// SuperTrend Calculation (hidden)
supertrend(src, factor, atrLen) =>
    atr = ta.atr(atrLen)
    upperBand = src + factor * atr
    lowerBand = src - factor * atr
    prevLowerBand = nz(lowerBand[1])
    prevUpperBand = nz(upperBand[1])
    lowerBand := lowerBand > prevLowerBand or close[1] < prevLowerBand ? lowerBand : prevLowerBand
    upperBand := upperBand < prevUpperBand or close[1] > prevUpperBand ? upperBand : prevUpperBand
    var int direction = na
    var float superTrend = na
    prevSuperTrend = nz(superTrend[1])

    if na(atr[1])
        direction := 1
        direction
    else if prevSuperTrend == prevUpperBand
        direction := close > upperBand ? -1 : 1
        direction
    else
        direction := close < lowerBand ? 1 : -1
        direction

    superTrend := direction == -1 ? lowerBand : upperBand
    [superTrend, direction]

// Calculate SuperTrend (for signal generation only)
[supertrend_line, direction] = supertrend(close, sensitivity * atr_multiplier, atr_length)

// Raw Signals
raw_buy = ta.crossover(close, supertrend_line)
raw_sell = ta.crossunder(close, supertrend_line)

// Filters
// 1. Trend Filter
ma = ta.sma(close, ma_length)
trend_up = close > ma
trend_down = close < ma
trend_filter_buy = not use_trend_filter or trend_up
trend_filter_sell = not use_trend_filter or trend_down

// 2. Volume Filter
volume_ma = ta.sma(volume, 20)
volume_ok = not use_volume_filter or volume > volume_ma * volume_threshold

// 3. Basic momentum check
momentum_ok = math.abs(close - close[1]) > ta.atr(14) * 0.1

// Final Signals
buy_signal = raw_buy and trend_filter_buy and volume_ok and momentum_ok
sell_signal = raw_sell and trend_filter_sell and volume_ok and momentum_ok

// Track signals to avoid rapid fire
var int last_signal_bar = 0
var string last_signal_type = ''

signal_cooldown = 2 // minimum bars between signals
bars_since_last = bar_index - last_signal_bar
cooldown_ok = bars_since_last >= signal_cooldown

// Final filtered signals with cooldown
final_buy = buy_signal and cooldown_ok and last_signal_type != 'BUY'
final_sell = sell_signal and cooldown_ok and last_signal_type != 'SELL'

// Update tracking
if final_buy
    last_signal_bar := bar_index
    last_signal_type := 'BUY'
    last_signal_type

if final_sell
    last_signal_bar := bar_index
    last_signal_type := 'SELL'
    last_signal_type

// Multi-Timeframe Trend Analysis using EMA 50
getTrend(tf) =>
    ema50 = request.security(syminfo.tickerid, tf, ta.ema(close, 50))
    current_close = request.security(syminfo.tickerid, tf, close)
    current_close > ema50 ? 1 : current_close < ema50 ? -1 : 0

// Get trends for different timeframes
trend_m1 = getTrend('1')
trend_m5 = getTrend('5')
trend_m15 = getTrend('15')
trend_m30 = getTrend('30')
trend_h1 = getTrend('60')
trend_h4 = getTrend('240')
trend_daily = getTrend('1D')

// Count bullish and bearish trends
bullish_count = (trend_m1 == 1 ? 1 : 0) + (trend_m5 == 1 ? 1 : 0) + (trend_m15 == 1 ? 1 : 0) + (trend_m30 == 1 ? 1 : 0) + (trend_h1 == 1 ? 1 : 0) + (trend_h4 == 1 ? 1 : 0) + (trend_daily == 1 ? 1 : 0)
bearish_count = (trend_m1 == -1 ? 1 : 0) + (trend_m5 == -1 ? 1 : 0) + (trend_m15 == -1 ? 1 : 0) + (trend_m30 == -1 ? 1 : 0) + (trend_h1 == -1 ? 1 : 0) + (trend_h4 == -1 ? 1 : 0) + (trend_daily == -1 ? 1 : 0)

// Determine overall market condition
overall_trend = bullish_count >= 4 ? 'STRONG BUY' : bearish_count >= 4 ? 'STRONG SELL' : 'FLAT MARKET'

// Supply & Demand Zone Detection
type Zone
float top
float bottom
int left_bar
int touches
bool is_supply
bool is_valid

var array<Zone> zones = array.new<Zone>()

// Function to detect swing highs and lows
isSwingHigh(len) =>
    ta.pivothigh(high, len, len)

isSwingLow(len) =>
    ta.pivotlow(low, len, len)

// Function to count touches in a zone
countTouches(zone_top, zone_bottom, lookback) =>
    touches = 0
    for i = 1 to lookback by 1
        if high[i] <= zone_top and high[i] >= zone_bottom
            touches := touches + 1
            touches
        if low[i] <= zone_top and low[i] >= zone_bottom
            touches := touches + 1
            touches
    touches

// Function to detect swing highs and lows (returns pivot price or na)
getSwingHigh(len) =>
    ta.pivothigh(high, len, len)

getSwingLow(len) =>
    ta.pivotlow(low, len, len)

// --- Always compute pivots on every bar (consistency) ---
pivotHigh = getSwingHigh(zone_lookback)   // series float (price) or na
pivotLow  = getSwingLow(zone_lookback)    // series float (price) or na

swing_high = not na(pivotHigh)            // series bool
swing_low  = not na(pivotLow)             // series bool

// Detect new zones (only on realtime bars)
if barstate.isrealtime
    if swing_high and show_zones
        zone_top = high[zone_lookback]
        zone_bottom = low[zone_lookback]
        zone_touches = countTouches(zone_top, zone_bottom, zone_lookback * 2)

        if zone_touches >= zone_strength
            new_zone = Zone.new(
                 top = zone_top,
                 bottom = zone_bottom,
                 left_bar = bar_index - zone_lookback,
                 touches = zone_touches,
                 is_supply = true,
                 is_valid = true)
            array.unshift(zones, new_zone)

    if swing_low and show_zones
        zone_top = high[zone_lookback]
        zone_bottom = low[zone_lookback]
        zone_touches = countTouches(zone_top, zone_bottom, zone_lookback * 2)

        if zone_touches >= zone_strength
            new_zone = Zone.new(
                 top = zone_top,
                 bottom = zone_bottom,
                 left_bar = bar_index - zone_lookback,
                 touches = zone_touches,
                 is_supply = false,
                 is_valid = true)
            array.unshift(zones, new_zone)

// Function to check if zone is broken
isZoneBroken(zone, is_supply) =>
    is_supply ? close > zone.top : close < zone.bottom

// Clean up invalid zones and limit max zones (on last bar)
if barstate.islast
    if array.size(zones) > 0
        for i = array.size(zones) - 1 to 0 by 1
            zone = array.get(zones, i)
            if isZoneBroken(zone, zone.is_supply)
                array.remove(zones, i)
            else if array.size(zones) > max_zones
                array.remove(zones, i)

// Draw zones (only on last bar)
var array<box> zone_boxes = array.new<box>()

if barstate.islast
    // Clear old boxes
    if array.size(zone_boxes) > 0
        for box_element in zone_boxes
            box.delete(box_element)
        array.clear(zone_boxes)

    // Draw new boxes
    if show_zones and array.size(zones) > 0
        for zone in zones
            if zone.is_valid
                zone_color = zone.is_supply ? supply_color : demand_color
                zone_box = box.new(left = zone.left_bar, top = zone.top, right = bar_index + 10, bottom = zone.bottom, bgcolor = zone_color, border_color = color.new(zone.is_supply ? color.red : color.green, 0), border_width = 1, extend = extend.right)
                array.push(zone_boxes, zone_box)

// TP/SL Calculation System
countBull = ta.barssince(final_buy)
countBear = ta.barssince(final_sell)
trigger = nz(countBull, bar_index) < nz(countBear, bar_index) ? 1 : 0

atrBand = ta.atr(atrLen) * atrRisk
atrStop = trigger == 1 ? low - atrBand : high + atrBand

srcStop = close

lastTrade(src) =>
    ta.valuewhen(final_buy or final_sell, src, 0)
entry_y = lastTrade(srcStop)
stop_y = lastTrade(atrStop)
tp1_y = (entry_y - lastTrade(atrStop)) * 1 + entry_y
tp2_y = (entry_y - lastTrade(atrStop)) * 2 + entry_y
tp3_y = (entry_y - lastTrade(atrStop)) * 3 + entry_y
tp4_y = (entry_y - lastTrade(atrStop)) * 4 + entry_y
tp5_y = (entry_y - lastTrade(atrStop)) * 5 + entry_y

// Decimal formatting
decimals = lvlDecimals == 1 ? '#.#' : lvlDecimals == 2 ? '#.##' : lvlDecimals == 3 ? '#.###' : lvlDecimals == 4 ? '#.####' : lvlDecimals == 5 ? '#.#####' : lvlDecimals == 6 ? '#.######' : lvlDecimals == 7 ? '#.#######' : '#.########'

// Label creation function
labelTpSl(y, txt, color) =>
    label labelTpSl = percentStop != 0 ? label.new(bar_index + 1, y, txt, xloc.bar_index, yloc.price, color, label.style_label_left, #000000, size.normal) : na
    label.delete(labelTpSl[1])

// Line style
style2 = linesStyle == 'SOLID' ? line.style_solid : linesStyle == 'DASHED' ? line.style_dashed : line.style_dotted

// Line creation function
lineTpSl(y, color) =>
    line lineTpSl = percentStop != 0 ? line.new(bar_index - (trigger ? countBull : countBear) + 4, y, bar_index + 1, y, xloc.bar_index, extend.none, color, style2) : na
    line.delete(lineTpSl[1])

// Display TP/SL (only on last bar and when there's a signal)
var label entry_lbl = na
var label stop_lbl = na
var label tp1_lbl = na
var label tp2_lbl = na
var label tp3_lbl = na
var label tp4_lbl = na
var label tp5_lbl = na

var line entry_line = na
var line stop_line = na
var line tp1_line = na
var line tp2_line = na
var line tp3_line = na
var line tp4_line = na
var line tp5_line = na

if barstate.islast
    // Delete old labels and lines
    label.delete(entry_lbl[1])
    label.delete(stop_lbl[1])
    label.delete(tp1_lbl[1])
    label.delete(tp2_lbl[1])
    label.delete(tp3_lbl[1])
    label.delete(tp4_lbl[1])
    label.delete(tp5_lbl[1])

    line.delete(entry_line[1])
    line.delete(stop_line[1])
    line.delete(tp1_line[1])
    line.delete(tp2_line[1])
    line.delete(tp3_line[1])
    line.delete(tp4_line[1])
    line.delete(tp5_line[1])

    if levels2 and percentStop != 0
        entry_lbl := label.new(bar_index + 1, entry_y, 'ENTRY: ' + str.tostring(entry_y, decimals), xloc.bar_index, yloc.price, color.rgb(242, 244, 252), label.style_label_left, #000000, size.normal)
        stop_lbl := label.new(bar_index + 1, stop_y, 'STOP LOSS: ' + str.tostring(stop_y, decimals), xloc.bar_index, yloc.price, #f90808, label.style_label_left, #000000, size.normal)
        tp1_lbl := label.new(bar_index + 1, tp1_y, 'TP 1: ' + str.tostring(tp1_y, decimals), xloc.bar_index, yloc.price, #00ff08, label.style_label_left, #000000, size.normal)
        tp2_lbl := label.new(bar_index + 1, tp2_y, 'TP 2: ' + str.tostring(tp2_y, decimals), xloc.bar_index, yloc.price, #00ff08, label.style_label_left, #000000, size.normal)
        tp3_lbl := label.new(bar_index + 1, tp3_y, 'TP 3: ' + str.tostring(tp3_y, decimals), xloc.bar_index, yloc.price, #00ff08, label.style_label_left, #000000, size.normal)
        tp4_lbl := label.new(bar_index + 1, tp4_y, 'TP 4: ' + str.tostring(tp4_y, decimals), xloc.bar_index, yloc.price, #00ff08, label.style_label_left, #000000, size.normal)
        tp5_lbl := label.new(bar_index + 1, tp5_y, 'TP 5: ' + str.tostring(tp5_y, decimals), xloc.bar_index, yloc.price, #00ff08, label.style_label_left, #000000, size.normal)
        tp5_lbl

    if lvlLines and percentStop != 0
        left_bar = bar_index - ((trigger == 1) ? countBull : countBear) + 4
        right_bar = bar_index + 1

        entry_line := line.new(left_bar, entry_y, right_bar, entry_y, xloc.bar_index, extend.none, color.white, style2)
        stop_line  := line.new(left_bar, stop_y,  right_bar, stop_y,  xloc.bar_index, extend.none, color.red,   style2)
        tp1_line   := line.new(left_bar, tp1_y,   right_bar, tp1_y,   xloc.bar_index, extend.none, color.green, style2)
        tp2_line   := line.new(left_bar, tp2_y,   right_bar, tp2_y,   xloc.bar_index, extend.none, color.green, style2)
        tp3_line   := line.new(left_bar, tp3_y,   right_bar, tp3_y,   xloc.bar_index, extend.none, color.green, style2)
        tp4_line   := line.new(left_bar, tp4_y,   right_bar, tp4_y,   xloc.bar_index, extend.none, color.green, style2)
        tp5_line   := line.new(left_bar, tp5_y,   right_bar, tp5_y,   xloc.bar_index, extend.none, color.green, style2)

// ONLY PLOT ARROWS - NO LINES OR BAR COLORS
plotshape(final_buy and show_signals, title = 'Buy Signal', text = 'BUY', location = location.belowbar, style = shape.labelup, size = size.normal, color = color.green, textcolor = color.white)

plotshape(final_sell and show_signals, title = 'Sell Signal', text = 'SELL', location = location.abovebar, style = shape.labeldown, size = size.normal, color = color.red, textcolor = color.white)

// Simple Two-Column Dashboard
var table dashboard = table.new(position.top_right, 2, 10, bgcolor = color.rgb(20, 20, 30), border_width = 1, border_color = color.rgb(80, 80, 100))

if barstate.islast and show_dashboard
    // Header
    table.cell(dashboard, 0, 0, 'Timeframe', bgcolor = color.rgb(40, 40, 60), text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 0, 'Trend', bgcolor = color.rgb(40, 40, 60), text_color = color.white, text_size = size.small)

    // Timeframe trends
    table.cell(dashboard, 0, 1, 'M1', bgcolor = color.rgb(30, 30, 40), text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 1, trend_m1 == 1 ? 'UP' : trend_m1 == -1 ? 'DOWN' : 'FLAT', bgcolor = color.rgb(30, 30, 40), text_color = trend_m1 == 1 ? color.green : trend_m1 == -1 ? color.red : color.yellow, text_size = size.small)

    table.cell(dashboard, 0, 2, 'M5', bgcolor = color.rgb(25, 25, 35), text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 2, trend_m5 == 1 ? 'UP' : trend_m5 == -1 ? 'DOWN' : 'FLAT', bgcolor = color.rgb(25, 25, 35), text_color = trend_m5 == 1 ? color.green : trend_m5 == -1 ? color.red : color.yellow, text_size = size.small)

    table.cell(dashboard, 0, 3, 'M15', bgcolor = color.rgb(30, 30, 40), text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 3, trend_m15 == 1 ? 'UP' : trend_m15 == -1 ? 'DOWN' : 'FLAT', bgcolor = color.rgb(30, 30, 40), text_color = trend_m15 == 1 ? color.green : trend_m15 == -1 ? color.red : color.yellow, text_size = size.small)

    table.cell(dashboard, 0, 4, 'M30', bgcolor = color.rgb(25, 25, 35), text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 4, trend_m30 == 1 ? 'UP' : trend_m30 == -1 ? 'DOWN' : 'FLAT', bgcolor = color.rgb(25, 25, 35), text_color = trend_m30 == 1 ? color.green : trend_m30 == -1 ? color.red : color.yellow, text_size = size.small)

    table.cell(dashboard, 0, 5, 'H1', bgcolor = color.rgb(30, 30, 40), text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 5, trend_h1 == 1 ? 'UP' : trend_h1 == -1 ? 'DOWN' : 'FLAT', bgcolor = color.rgb(30, 30, 40), text_color = trend_h1 == 1 ? color.green : trend_h1 == -1 ? color.red : color.yellow, text_size = size.small)

    table.cell(dashboard, 0, 6, 'H4', bgcolor = color.rgb(25, 25, 35), text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 6, trend_h4 == 1 ? 'UP' : trend_h4 == -1 ? 'DOWN' : 'FLAT', bgcolor = color.rgb(25, 25, 35), text_color = trend_h4 == 1 ? color.green : trend_h4 == -1 ? color.red : color.yellow, text_size = size.small)

    table.cell(dashboard, 0, 7, 'DAILY', bgcolor = color.rgb(30, 30, 40), text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 7, trend_daily == 1 ? 'UP' : trend_daily == -1 ? 'DOWN' : 'FLAT', bgcolor = color.rgb(30, 30, 40), text_color = trend_daily == 1 ? color.green : trend_daily == -1 ? color.red : color.yellow, text_size = size.small)

    // Overall market condition
    overall_color = overall_trend == 'STRONG BUY' ? color.green : overall_trend == 'STRONG SELL' ? color.red : color.yellow
    overall_bg = overall_trend == 'STRONG BUY' ? color.rgb(0, 80, 0) : overall_trend == 'STRONG SELL' ? color.rgb(80, 0, 0) : color.rgb(80, 80, 0)

    table.cell(dashboard, 0, 8, 'OVERALL', bgcolor = overall_bg, text_color = color.white, text_size = size.small)
    table.cell(dashboard, 1, 8, overall_trend, bgcolor = overall_bg, text_color = overall_color, text_size = size.small)

    // Author information
    table.cell(dashboard, 0, 9, 'Author: MEOW PURR\nTelegram: @MeowForex1', bgcolor = color.rgb(20, 20, 30), text_color = color.rgb(200, 200, 255), text_size = size.tiny)
    table.cell(dashboard, 1, 9, '', bgcolor = color.rgb(20, 20, 30), text_color = color.white, text_size = size.tiny)

// Alerts
alertcondition(final_buy, title = 'Buy Signal', message = 'BUY Signal Generated!')
alertcondition(final_sell, title = 'Sell Signal', message = 'SELL Signal Generated!')
alertcondition(overall_trend == 'STRONG BUY', title = 'Strong Buy Market', message = 'Strong Buy Market Condition!')
alertcondition(overall_trend == 'STRONG SELL', title = 'Strong Sell Market', message = 'Strong Sell Market Condition!')