//@version=5
strategy("Candle Range Theory (CRT) Strategy",
overlay=true,
margin_long=100,
margin_short=100,
default_qty_type=strategy.percent_of_equity,
default_qty_value=10)
// ─────────────────────────────────────────
// INPUTS
// ─────────────────────────────────────────
grp1 = "CRT Settings"
refCandle = input.int(1, "Reference Candle Lookback", minval=1, maxval=5, group=grp1)
fvgMultiplier = input.float(0.5, "FVG Min Size (% of candle)", minval=0.1, maxval=2.0, step=0.1, group=grp1)
sweepBuffer = input.float(0.1, "Sweep Buffer (ticks)", minval=0.0, maxval=5.0, step=0.1, group=grp1)
grp2 = "Trade Management"
slMultiplier = input.float(1.5, "Stop Loss Multiplier (ATR)", minval=0.5, maxval=5.0, step=0.1, group=grp2)
tpRatio = input.float(2.0, "Take Profit RR Ratio", minval=1.0, maxval=10.0, step=0.5, group=grp2)
useTrailStop = input.bool(false, "Use Trailing Stop", group=grp2)
trailPercent = input.float(1.0, "Trail Stop %", minval=0.1, maxval=5.0, step=0.1, group=grp2)
grp3 = "Filters"
useEMA = input.bool(true, "Use EMA Trend Filter", group=grp3)
emaLen = input.int(200, "EMA Length", minval=10, maxval=500, group=grp3)
useSession = input.bool(false, "Use Session Filter", group=grp3)
sessionTime = input.session("0700-1600", "Allowed Session (Exchange Time)", group=grp3)
grp4 = "Display"
showRefBox = input.bool(true, "Show Reference Candle Box", group=grp4)
showFVG = input.bool(true, "Show Fair Value Gaps", group=grp4)
showLabels = input.bool(true, "Show Entry Labels", group=grp4)
// ─────────────────────────────────────────
// CALCULATIONS
// ─────────────────────────────────────────
atr = ta.atr(14)
ema200 = ta.ema(close, emaLen)
trendUp = close > ema200
trendDown = close < ema200
// Session filter
inSession = useSession ? not na(time(timeframe.period, sessionTime)) : true
// Reference candle range (N bars ago)
refHigh = high
refLow = low
refBody = math.abs(close - open )
// Sweep detection (manipulation candle = current bar)
bufTicks = sweepBuffer * syminfo.mintick
bullishSweep = low < refLow - bufTicks // Swept below reference low → bullish reversal
bearishSweep = high > refHigh + bufTicks // Swept above reference high → bearish reversal
// Reversal confirmation: price closes BACK inside reference range
bullishConf = bullishSweep and close > refLow and close < refHigh
bearishConf = bearishSweep and close < refHigh and close > refLow
// ─────────────────────────────────────────
// FAIR VALUE GAP DETECTION
// ─────────────────────────────────────────
// Bullish FVG: gap between high and low (current)
fvgBullHigh = high
fvgBullLow = low
bullFVG = low > high and (low - high ) > (atr * fvgMultiplier * 0.1)
// Bearish FVG: gap between low and high
fvgBearLow = low
fvgBearHigh = high
bearFVG = high < low and (low - high) > (atr * fvgMultiplier * 0.1)
// ─────────────────────────────────────────
// ENTRY CONDITIONS
// ─────────────────────────────────────────
longCondition = bullishConf
and (not useEMA or trendUp)
and inSession
and strategy.position_size == 0
shortCondition = bearishConf
and (not useEMA or trendDown)
and inSession
and strategy.position_size == 0
// ─────────────────────────────────────────
// STOP LOSS & TAKE PROFIT
// ─────────────────────────────────────────
longSL = low - (atr * slMultiplier)
longTP = close + ((close - longSL) * tpRatio)
shortSL = high + (atr * slMultiplier)
shortTP = close - ((shortSL - close) * tpRatio)
// ─────────────────────────────────────────
// STRATEGY EXECUTION
// ─────────────────────────────────────────
if longCondition
strategy.entry("Long", strategy.long)
strategy.exit("Long Exit", "Long",
stop = longSL,
limit = longTP,
trail_percent = useTrailStop ? trailPercent : na)
if shortCondition
strategy.entry("Short", strategy.short)
strategy.exit("Short Exit", "Short",
stop = shortSL,
limit = shortTP,
trail_percent = useTrailStop ? trailPercent : na)
// ─────────────────────────────────────────
// VISUALS — Reference Candle Box
// ─────────────────────────────────────────
var box refBox = na
if showRefBox and barstate.islast
box.delete(refBox)
refBox := box.new(
bar_index , refHigh, bar_index, refLow,
border_color=color.new(color.gray, 30),
bgcolor=color.new(color.gray, 85),
border_width=1)
// ─────────────────────────────────────────
// VISUALS — EMA
// ─────────────────────────────────────────
plot(useEMA ? ema200 : na, "EMA Filter", color=color.new(color.orange, 0), linewidth=2)
// ─────────────────────────────────────────
// VISUALS — Sweep Wicks
// ─────────────────────────────────────────
plotshape(bullishSweep and not bullishConf,
title="Bullish Sweep", style=shape.triangledown,
location=location.belowbar, color=color.new(color.red, 40), size=size.tiny)
plotshape(bearishSweep and not bearishConf,
title="Bearish Sweep", style=shape.triangleup,
location=location.abovebar, color=color.new(color.red, 40), size=size.tiny)
// ─────────────────────────────────────────
// VISUALS — Entry Signals
// ─────────────────────────────────────────
plotshape(longCondition and showLabels,
title="Long Entry", style=shape.labelup,
location=location.belowbar, color=color.new(color.teal, 0),
textcolor=color.white, text="CRT\nLong", size=size.small)
plotshape(shortCondition and showLabels,
title="Short Entry", style=shape.labeldown,
location=location.abovebar, color=color.new(color.red, 0),
textcolor=color.white, text="CRT\nShort", size=size.small)
// ─────────────────────────────────────────
// VISUALS — SL/TP Lines on Entry
// ─────────────────────────────────────────
var line slLine = na
var line tpLine = na
if longCondition
line.delete(slLine)
line.delete(tpLine)
slLine := line.new(bar_index, longSL, bar_index + 10, longSL,
color=color.red, width=1, style=line.style_dashed)
tpLine := line.new(bar_index, longTP, bar_index + 10, longTP,
color=color.green, width=1, style=line.style_dashed)
if shortCondition
line.delete(slLine)
line.delete(tpLine)
slLine := line.new(bar_index, shortSL, bar_index + 10, shortSL,
color=color.red, width=1, style=line.style_dashed)
tpLine := line.new(bar_index, shortTP, bar_index + 10, shortTP,
color=color.green, width=1, style=line.style_dashed)
// ─────────────────────────────────────────
// VISUALS — Fair Value Gaps (background)
// ─────────────────────────────────────────
bgcolor(showFVG and bullFVG ? color.new(color.teal, 90) : na, title="Bullish FVG")
bgcolor(showFVG and bearFVG ? color.new(color.red, 90) : na, title="Bearish FVG")
// ─────────────────────────────────────────
// INFO TABLE
// ─────────────────────────────────────────
var table infoTable = table.new(position.top_right, 2, 6,
border_color=color.gray, border_width=1,
bgcolor=color.new(color.black, 80))
if barstate.islast
table.cell(infoTable, 0, 0, "CRT Strategy", text_color=color.white, text_size=size.small, bgcolor=color.new(color.blue, 60))
table.cell(infoTable, 1, 0, "", text_color=color.white, text_size=size.small, bgcolor=color.new(color.blue, 60))
table.cell(infoTable, 0, 1, "EMA Filter", text_color=color.silver, text_size=size.small)
table.cell(infoTable, 1, 1, useEMA ? str.tostring(emaLen) + " ON" : "OFF",
text_color=useEMA ? color.green : color.gray, text_size=size.small)
table.cell(infoTable, 0, 2, "Trend", text_color=color.silver, text_size=size.small)
table.cell(infoTable, 1, 2, trendUp ? "Bullish ▲" : "Bearish ▼",
text_color=trendUp ? color.teal : color.red, text_size=size.small)
table.cell(infoTable, 0, 3, "ATR(14)", text_color=color.silver, text_size=size.small)
table.cell(infoTable, 1, 3, str.tostring(math.round(atr, 5)),
text_color=color.white, text_size=size.small)
table.cell(infoTable, 0, 4, "TP Ratio", text_color=color.silver, text_size=size.small)
table.cell(infoTable, 1, 4, str.tostring(tpRatio) + "R",
text_color=color.white, text_size=size.small)
table.cell(infoTable, 0, 5, "Session Filter", text_color=color.silver, text_size=size.small)
table.cell(infoTable, 1, 5, useSession ? "ON" : "OFF",
text_color=useSession ? color.green : color.gray, text_size=size.small)