//@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!')