//@version=6
strategy(title = 'UT Bot Alerts with Risk Management', overlay = true, pyramiding =
0, default_qty_type = strategy.percent_of_equity, default_qty_value = 100)
// --- Input Parameters ---
// Sensitivity for the ATR Trailing Stop.
float key_value = input.float(1.0, title = 'Key Value (Sensitivity)')
// Period for the Average True Range calculation.
int atr_period = input.int(10, title = 'ATR Period')
// Toggle between regular and Heikin Ashi candles for calculations.
bool use_heikin_ashi = input.bool(false, title = 'Signals from Heikin Ashi
Candles')
// --- Risk Management Parameters ---
// Stop Loss percentage from entry price.
float stop_loss_percent = input.float(2.0, title = 'Stop Loss % (from Entry
Price)', minval = 0.1, step = 0.1)
// Take Profit percentage from entry price.
float take_profit_percent = input.float(4.0, title = 'Take Profit % (from Entry
Price)', minval = 0.1, step = 0.1)
// Risk per trade as a percentage of equity.
float risk_per_trade_percent = input.float(1.0, title = 'Risk Per Trade % of
Equity', minval = 0.1, step = 0.1)
// Value of one point for the futures contract (e.g., 50 for ES, 10 for NQ). YOU
MUST SET THIS!
float contract_point_value = input.float(50.0, title = 'Futures Contract Point
Value (e.g., 50 for ES)', minval = 0.1)
// --- Optional Volume Filter ---
// Enable/disable volume filter.
bool enable_volume_filter = input.bool(false, title = 'Enable Volume Filter')
// Period for Volume Simple Moving Average.
int volume_sma_period = input.int(20, title = 'Volume SMA Period', minval = 1)
// --- ATR Calculation ---
float atr_value = ta.atr(atr_period)
float loss_threshold = key_value * atr_value
// --- Source Price Selection ---
float src = use_heikin_ashi ? request.security(ticker.heikinashi(syminfo.tickerid),
timeframe.period, close, lookahead = barmerge.lookahead_off) : close
// --- ATR Trailing Stop Calculation ---
var float xATRTrailingStop = 0.0
if src > nz(xATRTrailingStop[1], 0) and src[1] > nz(xATRTrailingStop[1], 0)
xATRTrailingStop := math.max(nz(xATRTrailingStop[1]), src - loss_threshold)
else if src < nz(xATRTrailingStop[1], 0) and src[1] < nz(xATRTrailingStop[1], 0)
xATRTrailingStop := math.min(nz(xATRTrailingStop[1]), src + loss_threshold)
else if src > nz(xATRTrailingStop[1], 0)
xATRTrailingStop := src - loss_threshold
else
xATRTrailingStop := src + loss_threshold
// --- Position Determination ---
var int pos = 0
if src[1] > nz(xATRTrailingStop[1], 0) and src < nz(xATRTrailingStop[1], 0)
pos := -1
else if src[1] < nz(xATRTrailingStop[1], 0) and src > nz(xATRTrailingStop[1], 0)
pos := 1
else
pos := nz(pos[1], 0)
// --- Color for Trailing Stop Line ---
color xcolor = pos == -1 ? color.red : pos == 1 ? color.green : color.blue
// --- Crossover Signals ---
float ema_src = ta.ema(src, 1)
bool crossover_above = ta.crossover(ema_src, xATRTrailingStop)
bool crossover_below = ta.crossover(xATRTrailingStop, ema_src)
// --- Volume Filter Logic ---
float avg_volume = ta.sma(volume, volume_sma_period)
bool volume_confirm = not enable_volume_filter or (enable_volume_filter and volume
> avg_volume)
// --- Buy/Sell Signals for Strategy Entries ---
bool buy_signal = src > xATRTrailingStop and crossover_above and volume_confirm
bool sell_signal = src < xATRTrailingStop and crossover_below and volume_confirm
// --- Bar Color Conditions ---
bool bar_buy_condition = src > xATRTrailingStop
bool bar_sell_condition = src < xATRTrailingStop
// --- Calculate Position Size ---
float account_equity = strategy.initial_capital + strategy.netprofit // Current
account equity
float risk_amount = account_equity * (risk_per_trade_percent / 100)
float calculated_qty = 1 // Default to 1 contract if calculations are problematic
if strategy.opentrades == 0 // Only calculate new quantity if no open trades
if buy_signal or sell_signal // Calculate for potential entry
float entry_price = src
float stop_loss_price_long = entry_price * (1 - stop_loss_percent / 100)
float stop_loss_price_short = entry_price * (1 + stop_loss_percent / 100)
float points_at_risk_long = math.abs(entry_price - stop_loss_price_long)
float points_at_risk_short = math.abs(entry_price - stop_loss_price_short)
float risk_per_contract_long = points_at_risk_long * contract_point_value
float risk_per_contract_short = points_at_risk_short * contract_point_value
if buy_signal and risk_per_contract_long > 0
calculated_qty := math.floor(risk_amount / risk_per_contract_long)
else if sell_signal and risk_per_contract_short > 0
calculated_qty := math.floor(risk_amount / risk_per_contract_short)
calculated_qty := math.max(1, calculated_qty) // Ensure at least 1 contract
// --- Strategy Entries with Stop Loss and Take Profit ---
if buy_signal
long_stop_price = src * (1 - stop_loss_percent / 100)
long_take_profit_price = src * (1 + take_profit_percent / 100)
strategy.entry("Buy", direction = strategy.long, qty = calculated_qty)
strategy.exit("Exit Long", from_entry = "Buy", stop = long_stop_price, limit =
long_take_profit_price)
if sell_signal
short_stop_price = src * (1 + stop_loss_percent / 100)
short_take_profit_price = src * (1 - take_profit_percent / 100)
strategy.entry("Sell", direction = strategy.short, qty = calculated_qty)
strategy.exit("Exit Short", from_entry = "Sell", stop = short_stop_price, limit
= short_take_profit_price)
// --- Plotting ---
plot(xATRTrailingStop, title = 'ATR Trailing Stop', color = xcolor, linewidth = 2)
plotshape(buy_signal, title = 'Buy Label', text = 'Buy', style = shape.labelup,
location = location.belowbar, color = color.new(color.green, 0), textcolor =
color.new(color.white, 0), size = size.tiny)
plotshape(sell_signal, title = 'Sell Label', text = 'Sell', style =
shape.labeldown, location = location.abovebar, color = color.new(color.red, 0),
textcolor = color.new(color.white, 0), size = size.tiny)
barcolor(bar_buy_condition ? color.green : na)
barcolor(bar_sell_condition ? color.red : na)
// --- Alert Conditions ---
alertcondition(buy_signal, title = 'UT Long Alert', message = 'UT Long Signal
Detected!')
alertcondition(sell_signal, title = 'UT Short Alert', message = 'UT Short Signal
Detected!')