4H Range Scalping Strategy V6
This strategy defines a trading range based on the first 4-hour candle of the day and looks for breakouts followed by re-entries (fakeouts) to scalp the market.
Strategy Logic
The strategy operates on a 5-minute chart but uses the first 4 hours of the day (e.g., NY Midnight to 4 AM) to establish a High and Low range.
- Short Setup: Price breaks ABOVE the range high, then closes back INSIDE the range.
- Long Setup: Price breaks BELOW the range low, then closes back INSIDE the range.
- Risk Management: Uses a fixed Risk/Reward ratio (default 2.0).
Pine Script V6 Code
Copy the code below and paste it into your TradingView Pine Editor.
//@version=6
strategy("4H Range Scalping Strategy", overlay=true, initial_capital=1000, default_qty_type=strategy.percent_of_equity, default_qty_value=2, currency=currency.USD)
// ==========================================
// 1. USER INPUTS
// ==========================================
// Risk Management
input_rr = input.float(2.0, "Risk/Reward Ratio", minval=0.1, step=0.1, tooltip="Target profit relative to Stop Loss size.")
// Session Settings
input_start_hour = input.int(0, "Session Start Hour (NY Time)", minval=0, maxval=23, tooltip="Start hour of the first 4H candle (0 = 00:00).")
input_ny_timezone = input.string("America/New_York", "Timezone", options=["America/New_York", "UTC", "Europe/London"])
// Visuals
input_show_range = input.bool(true, "Show Range Lines")
input_color_high = input.color(color.red, "Range High Color")
input_color_low = input.color(color.green, "Range Low Color")
// ==========================================
// 2. TIME MANAGEMENT & RANGE DEFINITION
// ==========================================
// Get current time components in the target timezone
current_hour = hour(time, input_ny_timezone)
current_minute = minute(time, input_ny_timezone)
// Define the 4-Hour Formation Period
// The strategy relies on the FIRST 4-hour candle of the day.
// If start is 00:00, formation is 00:00 to 03:59.
formation_end_hour = input_start_hour + 4
is_formation_period = (current_hour >= input_start_hour) and (current_hour < formation_end_hour)
// State Variables to store the Range High/Low for the day
var float day_range_high = na
var float day_range_low = na
// Temporary variables to track High/Low DURING the formation period
var float temp_high = na
var float temp_low = na
// Detect start of a new day/session to reset variables
is_new_session = (current_hour == input_start_hour) and (current_minute == 0)
if is_new_session
// Reset everything for the new day
day_range_high := na
day_range_low := na
temp_high := high
temp_low := low
else if is_formation_period
// Continuously update the high/low during the first 4 hours
temp_high := math.max(nz(temp_high, high), high)
temp_low := math.min(nz(temp_low, low), low)
// Lock the Range after the formation period ends
// We check if we have just finished the formation period
if not is_formation_period and na(day_range_high) and not na(temp_high)
day_range_high := temp_high
day_range_low := temp_low
// ==========================================
// 3. STRATEGY LOGIC & EXECUTION
// ==========================================
// Variables to track Breakout State (Fakeout detection)
var bool is_above_range = false
var bool is_below_range = false
var float breakout_extreme_high = na
var float breakout_extreme_low = na
// Reset breakout states on new session
if is_new_session
is_above_range := false
is_below_range := false
breakout_extreme_high := na
breakout_extreme_low := na
// Only trade if the range is defined and we are outside the formation period
can_trade = not na(day_range_high) and not is_formation_period
// --- Short Setup Logic ---
// 1. Price must be ABOVE range (Breakout)
// 2. Then Price must Close INSIDE range (Re-entry)
if can_trade
// Check if price is currently above the range
if close > day_range_high
is_above_range := true
// Track the highest point reached during this breakout
breakout_extreme_high := math.max(nz(breakout_extreme_high, high), high)
// Check for Re-entry (Signal)
else if is_above_range and close < day_range_high
// CONDITION MET: Breakout High -> Closed Back Inside
// Update extreme one last time for the current signal candle
float final_sl_price = math.max(nz(breakout_extreme_high, high), high)
float entry_price = close
float risk = final_sl_price - entry_price
float target_price = entry_price - (risk * input_rr)
// Execute Short
if risk > 0
strategy.entry("Short", strategy.short, comment="Re-entry Short")
strategy.exit("Exit Short", "Short", stop=final_sl_price, limit=target_price)
// Reset state
is_above_range := false
breakout_extreme_high := na
// --- Long Setup Logic ---
// 1. Price must be BELOW range (Breakout)
// 2. Then Price must Close INSIDE range (Re-entry)
if can_trade
// Check if price is currently below the range
if close < day_range_low
is_below_range := true
// Track the lowest point reached during this breakout
breakout_extreme_low := math.min(nz(breakout_extreme_low, low), low)
// Check for Re-entry (Signal)
else if is_below_range and close > day_range_low
// CONDITION MET: Breakout Low -> Closed Back Inside
// Update extreme one last time
float final_sl_price = math.min(nz(breakout_extreme_low, low), low)
float entry_price = close
float risk = entry_price - final_sl_price
float target_price = entry_price + (risk * input_rr)
// Execute Long
if risk > 0
strategy.entry("Long", strategy.long, comment="Re-entry Long")
strategy.exit("Exit Long", "Long", stop=final_sl_price, limit=target_price)
// Reset state
is_below_range := false
breakout_extreme_low := na
// ==========================================
// 4. VISUALIZATION
// ==========================================
// Plot Range Lines
plot(input_show_range and not is_formation_period ? day_range_high : na, "Range High", color=input_color_high, style=plot.style_linebr, linewidth=2)
plot(input_show_range and not is_formation_period ? day_range_low : na, "Range Low", color=input_color_low, style=plot.style_linebr, linewidth=2)
// Highlight Formation Period Background
bgcolor(is_formation_period ? color.new(color.blue, 90) : na, title="Formation Period")
// Plot Signals
plotshape(series=not is_above_range[1] and is_above_range, title="Breakout High Started", location=location.abovebar, color=color.new(color.red, 80), style=shape.triangledown, size=size.tiny)
plotshape(series=not is_below_range[1] and is_below_range, title="Breakout Low Started", location=location.belowbar, color=color.new(color.green, 80), style=shape.triangleup, size=size.tiny)
How to Optimize This Strategy
Raw strategies often fail due to slippage and lack of dynamic risk management. To make this strategy production-ready:
- Add Commission Logic: Most backtests ignore fees.
- Implement Dynamic Stops: Use ATR-based trailing stops.
- Filter Choppy Markets: Add an ADX or Volume filter.
You can do all of this automatically using our AI Co-pilot.