Code: Select all
//@version=5
strategy("Pro News Pullback Scalper", overlay=true, initial_capital=10000, default_qty_type=strategy.cash, commission_type=strategy.commission.cash_per_order, commission_value=1)
// =========================================================================
// 1. TIME & REACTION SETTINGS
// =========================================================================
grp_time = "1. Session & Reaction"
news_session = input.session("14:00-14:15", title="News Chaos Window", group=grp_time, tooltip="Exchange time. The 'sit on your hands' window.")
box_color_bull = input.color(color.new(color.teal, 85), title="Bullish Reaction Color", group=grp_time)
box_color_bear = input.color(color.new(color.maroon, 85), title="Bearish Reaction Color", group=grp_time)
// =========================================================================
// 2. TRIGGER & EXPIRATION SETTINGS
// =========================================================================
grp_trig = "2. Trigger & Filters"
ema_len = input.int(9, title="Pullback EMA", group=grp_trig)
max_wait_bars = input.int(30, title="Max Bars to Wait for Pullback", group=grp_trig, tooltip="If the pullback doesn't happen within this many bars, cancel the setup.")
max_sl_pips = input.float(30.0, title="Max Allowed SL (Pips/Points)", group=grp_trig, tooltip="Prevents taking trades in insane, untradable volatility.")
// =========================================================================
// 3. RISK MANAGEMENT
// =========================================================================
grp_risk = "3. Risk Management"
risk_pct = input.float(1.0, title="Risk Per Trade (%)", step=0.1, group=grp_risk)
rr_ratio = input.float(2.0, title="Risk/Reward Ratio", step=0.1, group=grp_risk)
// =========================================================================
// STATE VARIABLES & TYPES
// =========================================================================
var float init_open = na
var float init_close = na
var float init_high = na
var float init_low = na
var int trend_dir = 0
var bool pullback_valid = false
var float pivot_extreme = na
var int bars_since_news = 0
var box session_box = na
// Trade state trackers for plotting
var float active_sl = na
var float active_tp = na
// =========================================================================
// SESSION LOGIC (The "Before" & "First Reaction" Phase)
// =========================================================================
in_news = not na(time(timeframe.period, news_session))
news_start = in_news and not in_news[1]
news_end = not in_news and in_news[1]
// Open the session
if news_start
init_open := open
init_high := high
init_low := low
trend_dir := 0
pullback_valid := false
pivot_extreme := na
bars_since_news := 0
// Create visual box
session_box := box.new(bar_index, high, bar_index, low, border_color=color.new(color.gray, 50), border_style=line.style_dashed, bgcolor=color.new(color.gray, 90))
// Update high/low of the news session for the box
if in_news
init_high := math.max(init_high, high)
init_low := math.min(init_low, low)
box.set_top(session_box, init_high)
box.set_bottom(session_box, init_low)
box.set_right(session_box, bar_index)
// Close the session and determine direction
if news_end
init_close := close[1]
trend_dir := init_close > init_open ? 1 : (init_close < init_open ? -1 : 0)
pivot_extreme := trend_dir == 1 ? low : high
// Color the box based on the reaction direction
box.set_bgcolor(session_box, trend_dir == 1 ? box_color_bull : (trend_dir == -1 ? box_color_bear : color.new(color.gray, 90)))
// =========================================================================
// PULLBACK & ENTRY LOGIC
// =========================================================================
ema = ta.ema(close, ema_len)
plot(ema, color=color.new(color.blue, 30), title="Pullback EMA", linewidth=2)
// Reset setup if trade is active or max bars exceeded
if strategy.position_size != 0
trend_dir := 0
active_sl := na
active_tp := na
valid_window = not in_news and trend_dir != 0
if valid_window
bars_since_news += 1
// Expiration Filter: Cancel setup if it takes too long
if bars_since_news > max_wait_bars
trend_dir := 0
pullback_valid := false
// Track the extreme of the pullback for SL placement
if trend_dir == 1
pivot_extreme := math.min(pivot_extreme, low)
else if trend_dir == -1
pivot_extreme := math.max(pivot_extreme, high)
// Calculate PIP conversion (works for Forex, Crypto, Indices)
pip_size = syminfo.mintick * (syminfo.type == "forex" ? 10 : 1)
// LONG SETUP
if trend_dir == 1
if close < ema // Validates the pullback
pullback_valid := true
if pullback_valid and close > ema // Trigger
float sl = pivot_extreme
float risk_pips = (close - sl) / pip_size
// Volatility Filter
if risk_pips <= max_sl_pips and risk_pips > 0
float risk_usd = strategy.equity * (risk_pct / 100)
float qty = risk_usd / (close - sl)
float tp = close + ((close - sl) * rr_ratio)
strategy.entry("News Long", strategy.long, qty=qty)
strategy.exit("Exit Long", "News Long", stop=sl, limit=tp)
active_sl := sl
active_tp := tp
trend_dir := 0 // Setup used
// SHORT SETUP
if trend_dir == -1
if close > ema // Validates the pullback
pullback_valid := true
if pullback_valid and close < ema // Trigger
float sl = pivot_extreme
float risk_pips = (sl - close) / pip_size
// Volatility Filter
if risk_pips <= max_sl_pips and risk_pips > 0
float risk_usd = strategy.equity * (risk_pct / 100)
float qty = risk_usd / (sl - close)
float tp = close - ((sl - close) * rr_ratio)
strategy.entry("News Short", strategy.short, qty=qty)
strategy.exit("Exit Short", "News Short", stop=sl, limit=tp)
active_sl := sl
active_tp := tp
trend_dir := 0 // Setup used
// =========================================================================
// VISUAL TRADE MAPPING
// =========================================================================
// Draw SL and TP lines only when a trade is active
plot(strategy.position_size != 0 ? active_sl : na, color=color.new(color.red, 20), style=plot.style_linebr, linewidth=2, title="Stop Loss")
plot(strategy.position_size != 0 ? active_tp : na, color=color.new(color.green, 20), style=plot.style_linebr, linewidth=2, title="Take Profit")