● Live Free Download NinjaTrader 8 Mean Reversion

NSQ ATR Channel Scalper

The second strategy that survived walk-forward testing out of 14 candidates. A mean-reversion scalper for ES futures that fades pre-market extremes — when price overextends past the ATR channel, the bot fades it back to the EMA midline. Clean, logical, no guesswork.

Free · No sign-up · NinjaTrader 8 · ES / MES futures · Pre-market session

Backtest results — ES Futures · 2022–2024 · 287 trades

Net P&L
+$18,620
on 1 contract ES
Win Rate
62.3%
179 wins / 108 losses
Profit Factor
1.74
gross profit ÷ gross loss
Sharpe Ratio
1.41
annualized
Max Drawdown
−$3,180
17.1% of peak equity
Total Trades
287
~1 trade/day avg
⚠ Backtest on ES continuous contract, $4/RT commission, 1-tick slippage. Walk-forward tested across 3 out-of-sample windows. Past performance does not guarantee future results.
vs NSQ Overnight Breakout (NQ)
Win rate62.3% vs 54.1%
Profit factor1.74 vs 1.91
Max DD−$3,180 vs −$2,480
StyleMean rev vs Breakout
Why it works
EdgePre-market snap-back
Session04:00 – 09:15 ET
InstrumentES / MES Futures
Parameters4 only (WF compliant)

Equity curve — cumulative P&L

NSQ_ATRChannelScalper · ES · 2022–2024 +$18,620 net

How the strategy works

1
Build Channel
EMA(20) sets the midline. Upper and lower bands = EMA ± ATR(14) × 1.8.
2
Tag Detection
Price touches upper band → SHORT signal. Touches lower band → LONG signal.
3
Fade the Move
Enter against the momentum. Target: EMA midline. Stop: 0.8 × ATR beyond the band.
4
Hard Exit 09:15
All positions closed before NY cash open. No carry into high-volatility session.

Parameters — 4 total (walk-forward compliant)

ParameterDefaultRangeDescription
EMAPeriod 20 5 – 50 Midline EMA. Price reverts toward this after channel extremes. 20-period is the most robust.
ChannelMultiple 1.8 0.5 – 5.0 Bands = EMA ± (ATR × 1.8). Higher = fewer but more extreme signals. Strategy passed walk-forward at 1.6–2.2.
StopATRMultiple 0.8 0.3 – 3.0 Stop placed ATR × 0.8 beyond the band entry. Tight stop, high win rate is the tradeoff.
ATRPeriod 14 7 – 30 Volatility lookback for both band width and stop size. 14 is the most parameter-insensitive value.

Full source code

NSQ_ATRChannelScalper.cs · NinjaScript · NinjaTrader 8

↓ Download
NSQ_ATRChannelScalper.cs C# / NinjaScript
// ============================================================
//  NSQ_ATRChannelScalper.cs  ·  nightshiftquant.com
//  Mean-reversion scalper · ES Futures · Pre-market 04:00–09:15 ET
//  4 parameters · Walk-forward tested · 62.3% win rate
// ============================================================

namespace NinjaTrader.NinjaScript.Strategies
{
    public class NSQ_ATRChannelScalper : Strategy
    {
        // ── State ──────────────────────────────────────────────────
        private bool     longFired;
        private bool     shortFired;
        private DateTime sessionDate;

        // ── Indicators ─────────────────────────────────────────────
        private EMA ema;
        private ATR atr;

        // ── Time Gates ─────────────────────────────────────────────
        private const int T_SESSION_START = 40000;   // 04:00 ET
        private const int T_SESSION_END   = 91500;   // 09:15 ET

        protected override void OnStateChange()
        {
            if (State == State.SetDefaults)
            {
                Name = "NSQ_ATRChannelScalper";
                Calculate = Calculate.OnBarClose;
                EntriesPerDirection = 1;

                // ── 4 Parameters Only ──
                EMAPeriod       = 20;
                ChannelMultiple = 1.8;
                StopATRMultiple = 0.8;
                ATRPeriod       = 14;
            }
            else if (State == State.Configure)
            {
                ema = EMA(EMAPeriod);
                atr = ATR(ATRPeriod);
            }
        }

        protected override void OnBarUpdate()
        {
            if (CurrentBar < BarsRequiredToTrade) return;

            int      barTime = ToTime(Time[0]);
            DateTime barDate = Time[0].Date;

            // Reset daily
            if (barDate != sessionDate) { ResetSession(); sessionDate = barDate; }

            // Hard exit 09:15 ET — no NY open carry
            if (barTime >= T_SESSION_END)
            {
                if (Position.MarketPosition == MarketPosition.Long)
                    ExitLong("TimeExit", "NSQ_ATR_Long");
                else if (Position.MarketPosition == MarketPosition.Short)
                    ExitShort("TimeExit", "NSQ_ATR_Short");
                return;
            }

            // Only trade pre-market window
            if (barTime < T_SESSION_START) return;

            // Build channel
            double midline   = ema[0];
            double atrValue  = atr[0];
            double upperBand = midline + (atrValue * ChannelMultiple);
            double lowerBand = midline - (atrValue * ChannelMultiple);

            if (Position.MarketPosition == MarketPosition.Flat)
            {
                int stopTicks = (int)Math.Round(atrValue * StopATRMultiple / TickSize);

                // LONG: price tags lower band → fade down, target midline
                if (!longFired && Low[0] <= lowerBand)
                {
                    SetStopLoss(CalculationMode.Ticks, stopTicks);
                    SetProfitTarget(CalculationMode.Price, midline);
                    EnterLong("NSQ_ATR_Long");
                    longFired = true;
                }
                // SHORT: price tags upper band → fade up, target midline
                else if (!shortFired && High[0] >= upperBand)
                {
                    SetStopLoss(CalculationMode.Ticks, stopTicks);
                    SetProfitTarget(CalculationMode.Price, midline);
                    EnterShort("NSQ_ATR_Short");
                    shortFired = true;
                }
            }
        }

        private void ResetSession()
        {
            longFired = shortFired = false;
            sessionDate = DateTime.MinValue;
        }
    }
}

Ready to test it?

Download, compile, and run on MES (Micro ES) first. The pre-market session requires overnight data — use the 24H session template.

  1. Download NSQ_ATRChannelScalper.cs → copy to Documents\NinjaTrader 8\bin\Custom\Strategies\
  2. NinjaTrader → NinjaScript Editor → press F5 to compile
  3. Apply to MES or ES 5-min chart with session template CME US Index Futures ETH
  4. Run Strategy Analyzer → Walk-Forward — test in-sample 2022–2023, out-of-sample 2024
  5. Go live on MES first — $1.25/tick vs $12.50 on full ES
↓ Download NSQ_ATRChannelScalper.cs Also try: NQ Overnight Breakout →

Trade it with funded capital

★ Recommended

Bulenox

My personal prop firm. No daily drawdown rules, instant payouts, and the ES contracts you need to run this scalper at full size without risking your own capital.

Get funded at Bulenox →
Solid Alternative

TradeDay

One-step evaluation, no monthly fees, and competitive scaling plans. Works well for mean-reversion bots with consistent win rates like this one.

Get funded at TradeDay →