Pine Script ES Futures Strategy for Prop Firms
ES and MES are among the most liquid futures contracts anywhere — tighter spreads, more predictable intraday behavior, and less gap risk than NQ. A well-tuned Pine Script strategy can clear evaluations at a lower failure rate, provided it respects how ES actually trades.
ES vs. MES: which to trade on an evaluation
| Contract | Tick Value | Point Value | Typical Daily Range |
|---|---|---|---|
| ES | $12.50 | $50 | ~40–80 pts ($2,000–$4,000) |
| MES | $1.25 | $5 | ~40–80 pts ($200–$400) |
MES is 1/10th the size of ES. On a prop firm evaluation, where every dollar of drawdown counts, MES is the correct starting vehicle — a 30-point adverse move costs about $150 on one MES contract versus roughly $1,500 on one ES contract, which can consume a trailing drawdown in a single bad trade.
How ES behaves differently than NQ
ES moves more slowly and predictably than NQ, with specific implications for a Pine Script strategy:
- Smaller typical range per bar — a stop width appropriate for NQ is often far too wide for ES on the same timeframe.
- Better session consistency — ES tends to trend more smoothly, and its afternoon session is generally more tradeable than NQ's midday chop window.
- Cleaner VWAP respect — ES price action tends to respect VWAP levels more consistently, so reversion setups see fewer false breaks.
- Lower single-name news sensitivity — spread across 500 constituents, a single earnings print or tech-sector selloff moves ES less than it moves NQ's more concentrated composition.
Best session windows for ES strategies
Unlike NQ, where the safest approach restricts trading to the first 90 minutes of RTH, ES is tradeable across a broader window:
- 9:30–11:30 AM ET — the primary window, with direction established and momentum trades in play.
- 11:30 AM–1:00 PM ET — typically the day's chop window; reduce size or stand aside, since volume thins and false signals become more common.
- 1:00–3:15 PM ET — an afternoon trend window that often produces some of the day's cleanest ES setups.
- 3:15–4:00 PM ET — market-on-close order flow drives volatility here; manageable with tight stops, but not recommended for an algo strategy without a specific closing-auction filter.
Pine Script rules for ES prop firm evals
1. Proportional ATR stops
Use an ATR baseline rather than a fixed-tick stop. On a 5-minute ES chart, a modest ATR multiple is usually appropriate — never use a stop that doesn't adjust to the day's actual range.
2. Time-based session gating
The script should carry a session variable blocking new entries outside the intended window, with the afternoon window toggleable off for a more conservative configuration.
3. Daily loss kill switch
Same requirement as NQ — once daily realized plus unrealized losses reach a defined share of the account's trailing drawdown, halt new entries. On a 50k account with a $2,500 trail, capping the internal daily loss around 40% of that figure means a bad morning on ES can absorb a handful of stop-outs before the script pulls back for the rest of the session — well before the trail itself is at risk.
4. Breakeven stop management
ES's smoother price action makes breakeven-stop management more reliable than on NQ. Once a position moves 1R in its favor, moving the stop to entry lets a winner run from a protected position without getting stopped out by whipsaw as often as an equivalent NQ trade would.
Top ES setups for prop firm conditions
Opening range breakout
Define the first 15–30 minutes of RTH as the opening range. A confirmed close above the range high signals long, below the low signals short. Stop inside the range, target roughly 2× the range width. ORB setups on ES tend to show among the best backtested win rates for morning sessions.
VWAP reclaim
ES respects VWAP better than almost any other index future. A close below VWAP followed by a close back above it is a setup that works through the morning and often into early afternoon. See our VWAP Pine Script strategy guide for full implementation details.
Failed breakdown reversal
ES frequently fakes below a key level — the prior day's low, VWAP, a pivot — before reversing back above it within a bar or two. That failed breakdown is a high-probability long entry, with a stop below the breakdown candle's low.
Complete MES opening range breakout — Pine Script v5
Captures the first directional move of the RTH session. Configured for a 50k evaluation — adjust the daily loss limit and range window to match your account and preferred setup.
// ── MES ORB — prop firm evaluation ─────────────────────────────────
strategy("MES ORB — Prop Firm", overlay = true,
default_qty_type = strategy.fixed, default_qty_value = 1)
// ── inputs ───────────────────────────────────────────────────────
orbMinutes = input.int(30, "Opening Range (minutes, from 9:30 ET)")
dailyLossLimit = input.float(1000.0, "Daily Loss Cap ($)")
rrRatio = input.float(2.0, "Reward:Risk Ratio")
// ── opening range construction ──────────────────────────────────
rangeEndMin = 930 + orbMinutes
inRangeWin = not na(time("1", "0930-" + str.tostring(rangeEndMin) + ":23456", "America/New_York"))
afterRange = not na(time("1", str.tostring(rangeEndMin) + "-1200:23456", "America/New_York"))
isRTHOpen = not na(time("1", "0930-0931:23456", "America/New_York"))
var float rangeHigh = na
var float rangeLow = na
var bool rangeSet = false
if isRTHOpen and not rangeSet
rangeHigh := high
rangeLow := low
rangeSet := true
if inRangeWin and rangeSet
rangeHigh := math.max(rangeHigh, high)
rangeLow := math.min(rangeLow, low)
// ── daily loss cap ───────────────────────────────────────────────
newDay = ta.change(time("D")) != 0
var float dayStartEquity = 0.0
dayStartEquity := newDay ? strategy.equity : dayStartEquity
if newDay
rangeSet := false
haltedForDay = (strategy.equity - dayStartEquity) <= -dailyLossLimit
// ── breakout entries ─────────────────────────────────────────────
rangeWidth = rangeHigh - rangeLow
breakLong = close > rangeHigh and close[1] <= rangeHigh[1] and barstate.isconfirmed
breakShort = close < rangeLow and close[1] >= rangeLow[1] and barstate.isconfirmed
flat = strategy.position_size == 0
if breakLong and afterRange and not haltedForDay and flat
strategy.entry("ORB-L", strategy.long)
strategy.exit("L-x", "ORB-L", profit = rangeWidth * rrRatio / syminfo.mintick,
loss = rangeWidth / syminfo.mintick)
if breakShort and afterRange and not haltedForDay and flat
strategy.entry("ORB-S", strategy.short)
strategy.exit("S-x", "ORB-S", profit = rangeWidth * rrRatio / syminfo.mintick,
loss = rangeWidth / syminfo.mintick)
// ── EOD flatten ────────────────────────────────────────────────────
eodFlatten = not na(time("1", "1529-1531:23456", "America/New_York")) or
(dayofweek == dayofweek.friday and not na(time("1", "1459-1501:6", "America/New_York")))
if eodFlatten and strategy.position_size != 0
strategy.close_all("EOD flatten") MES sizing for different eval sizes
| Account Size | Typical Trail | Conservative MES Count | Notes |
|---|---|---|---|
| 25k | $1,500 | 1–2 | Scale only after proving the setup |
| 50k | $2,500 | 2–4 | Scale up after several profitable days |
| 100k | $3,000–$4,500 | 4–8 | Gradual scaling, don't jump to max |
| 150k | $5,000 | 6–12 | Prove the edge before scaling further |