NinjaTrader 8 Order-Flow Imbalance Scalper
Unmanaged NinjaScript strategy that classifies every trade print, scores order-flow imbalance with rolling Z-scores and scalps with layered protection logic.
The problem
The spec called for a scalper that reacts to order-flow imbalance as it happens, not at bar close. It also had to be safe enough to leave running: every fill protected, hard daily limits, and no surprises on restart.
What I built
- Tick-level signal:
OnMarketData()caches the best bid and ask and processes every last-trade print. Signals are evaluated intrabar on each trade. - Aggressor classification: prints at or above the ask count as buys and at or below the bid as sells. The fallback is the uptick/downtick rule, then the last known direction.
- OFI statistics: delta, imbalance percent, and a rolling mean, standard deviation and Z-score. The lookback is either per bar or a rolling tick window.
- Entry filters: Z-score and imbalance thresholds per side, minimum volume, maximum spread and an optional fast/slow trend filter.
- Unmanaged orders: market or limit entries with an entry timeout. A stop is submitted on every fill, and an optional target is OCO-linked to it.
- Trade management: breakeven, an optional trailing stop, optional reversal, one trade at a time and cooldown bars.
- Risk limits: an HHmmss trading window that can cross midnight, exit on session close, max trades, max consecutive losses, daily loss and profit locks, max hold time and max bars in trade.
- Operating modes: log-only mode (signals without orders), wait-until-flat on start, and strategy-only or account-wide flatten on shutdown. A small OFI status block and signal markers are drawn on the chart.
Details
- Missing-protection watchdog: after a short grace period, if a position has no working stop (or a required target is missing), the strategy locks trading and flattens.
- Stops only tighten: stop moves are tracked as pending changes, so a stop is never loosened or modified twice in flight.
- Backtest parity: the logic lives in
OnMarketData(), so historical tests run with Tick Replay. The recommended flow is tick charts, then Sim or Market Replay, then live.