FVG Midpoint Strategy (Pine Script)
//@version=5
strategy("FVG Midpoint RR 1:3 (Prev Candle Wick SL, 1-2% Risk, Daily Loss Limit)",
overlay=true, initial_capital=1000,
calc_on_order_fills=true, calc_on_every_tick=true,
pyramiding=0, commission_type=strategy.commission.percent, commission_value=0.0)
// =================== Inputs ===================
useStrict1H = input.bool(true, "Enforce 1H timeframe (show warning if not)")
minGap = input.float(250.0, "Min FVG Gap (USD)", step=1)
riskPercent = input.float(0.02, "Max Risk per Trade (% of Capital)", step=0.01)
dailyLossLimit = input.float(0.03, "Max Daily Loss Limit (% of Capital)", step=0.01)
cancelAfterHrs = input.int(24, "Cancel unfilled limit after (hours)", minval=1)
timeoutAfterHrs = input.int(24, "Force close trade after (hours)", minval=1)
// =================== Utilities ===================
ms_1h = 60 * 60 * 1000
f_inRange(x, a, b) => math.min(a,b) <= x and x <= math.max(a,b)
// =================== Check 1H ===================
is1H = timeframe.isintraday and timeframe.multiplier == 60
if useStrict1H and not is1H
label.new(bar_index, high, "■■ Use on 1H for intended rules",
style=label.style_label_down, textcolor=color.white, color=color.orange)
// =================== Daily Loss Tracker ===================
var float dailyLoss = 0.0
var int lastDay = dayofmonth(time)
if dayofmonth(time) != lastDay
dailyLoss := 0.0
lastDay := dayofmonth(time)
// =================== Three-candle FVG detection ===================
bullCandle = close[1] > open[1]
bearCandle = close[1] < open[1]
bullFVG_now = low[0] > high[2] and bullCandle
bearFVG_now = high[0] < low[2] and bearCandle
bullLower = high[2]
bullUpper = low[0]
bearUpper = low[2]
bearLower = high[0]
bullSize = bullUpper - bullLower
bearSize = bearLower - bearUpper
// =================== State ===================
var bool fvgActive = false
var bool fvgIsBull = na
var float fvgLower = na
var float fvgUpper = na
var float fvgMid = na
var float fvgSL = na
var int fvgCreatedAt = na
var bool orderPlaced = false
newFvgFound = (bullFVG_now and bullSize >= minGap) or (bearFVG_now and bearSize >= minGap)
if newFvgFound and dailyLoss < dailyLossLimit * strategy.initial_capital
fvgIsBull := bullFVG_now
fvgLower := bullFVG_now ? bullLower : bearLower
fvgUpper := bullFVG_now ? bullUpper : bearUpper
fvgMid := (fvgLower + fvgUpper) / 2.0
fvgSL := bullFVG_now ? low[3] : high[3]
fvgCreatedAt := time
fvgActive := true
orderPlaced := false
if fvgActive and not orderPlaced
if time - fvgCreatedAt > cancelAfterHrs * ms_1h
fvgActive := false
longID = "Long@FVGmid"
shortID = "Short@FVGmid"
if fvgActive and not orderPlaced and strategy.position_size == 0 and dailyLoss < dailyLossLimit * str
if fvgIsBull
strategy.entry(longID, strategy.long, limit=fvgMid)
orderPlaced := true
else
strategy.entry(shortID, strategy.short, limit=fvgMid)
orderPlaced := true
if orderPlaced and strategy.position_size == 0 and time - fvgCreatedAt > cancelAfterHrs * ms_1h
strategy.cancel(fvgIsBull ? longID : shortID)
fvgActive := false
orderPlaced := false
if strategy.position_size != 0
isLong = strategy.position_size > 0
entryPx = strategy.position_avg_price
slPrice = fvgSL
slDist = math.abs(entryPx - slPrice)
tpPrice = isLong ? (entryPx + 3.0 * slDist) : (entryPx - 3.0 * slDist)
entryTime = strategy.opentrades > 0 ? strategy.opentrades.entry_time(0) : na
timedOut = not na(entryTime) and (time - entryTime > timeoutAfterHrs * ms_1h)
strategy.exit("Exit", from_entry=isLong ? longID : shortID, stop=slPrice, limit=tpPrice)
if timedOut
strategy.close(isLong ? longID : shortID, comment="Timed out 24h")
fvgActive := false
orderPlaced := false
canSize(entryPrice, sl) =>
dist = math.abs(entryPrice - sl)
dist > 0 ? ((riskPercent * strategy.initial_capital) / dist) : 0.0
if fvgActive and orderPlaced and strategy.position_size == 0
wouldFill = f_inRange(fvgMid, low, high)
if wouldFill
qty = canSize(fvgMid, fvgSL)
if fvgIsBull
strategy.entry(longID, strategy.long, limit=fvgMid, qty=qty)
else
strategy.entry(shortID, strategy.short, limit=fvgMid, qty=qty)
plot(fvgActive ? fvgLower : na, "FVG Lower", style=plot.style_linebr, linewidth=2, color=color.new(co
plot(fvgActive ? fvgUpper : na, "FVG Upper", style=plot.style_linebr, linewidth=2, color=color.new(co
plot(fvgActive ? fvgMid : na, "FVG Mid", style=plot.style_linebr, linewidth=1, color=color.gray)
plot(fvgActive ? fvgSL : na, "StopLoss (prev wick)", style=plot.style_linebr, linewidth=1, color=c
bgcolor(fvgActive ? color.new(fvgIsBull ? color.green : color.red, 90) : na)