NinjaTrader.
The retail futures workhorse. NinjaScript is C# inside the platform — close to native speed, full access to the order management system, and a brutally honest tick-replay backtester.
The honest pitch.
NinjaTrader 8 is what most retail futures automators graduate to once Pine Script feels too constrained. NinjaScript is real C# — you get OnBarUpdate / OnOrderUpdate / OnExecutionUpdate event handlers, a strongly typed order ticket API, and a tick-by-tick replay mode that matches live execution closely. Real costs are the data feed (Rithmic, Kinetick, CQG, or your broker's own) and the live license; expect $150-$250/mo all-in for serious futures work. Linux is not supported.
Auth, orders, limits.
| Auth | Local install; data feed credentials configured in Tools → Options. |
|---|---|
| Order API | Native NinjaScript (C#) — Strategy / AddOn / Indicator classes. |
| Data feed | Sold separately: Kinetick (free EOD / paid live), Rithmic, CQG, Continuum, broker-provided. |
| Sandbox | Sim101 paper account; Strategy Analyzer for historical; Playback for tick-level replay. |
| Latency | Native C#, microseconds on-machine. Network latency depends on data feed POP location. |
| Platform | Windows only. Use Parallels / Boot Camp on Mac. |
Hello-world, but real.
A simple SMA-cross strategy that submits market orders with attached stop and target. Note OnStateChange for setup and EnterLong/EnterShort, which automatically reverse position when called against an existing one.
| 1 | using NinjaTrader.Cbi; |
| 2 | using NinjaTrader.NinjaScript.Strategies; |
| 3 | |
| 4 | public class SmaCrossStrategy : Strategy |
| 5 | { |
| 6 | private SMA smaFast; |
| 7 | private SMA smaSlow; |
| 8 | |
| 9 | protected override void OnStateChange() |
| 10 | { |
| 11 | if (State == State.SetDefaults) |
| 12 | { |
| 13 | Name = "SmaCrossStrategy"; |
| 14 | Calculate = Calculate.OnBarClose; |
| 15 | IsExitOnSessionCloseStrategy = true; |
| 16 | ExitOnSessionCloseSeconds = 30; |
| 17 | } |
| 18 | else if (State == State.DataLoaded) |
| 19 | { |
| 20 | smaFast = SMA(9); |
| 21 | smaSlow = SMA(21); |
| 22 | AddChartIndicator(smaFast); |
| 23 | AddChartIndicator(smaSlow); |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | protected override void OnBarUpdate() |
| 28 | { |
| 29 | if (CurrentBar < smaSlow.Period) return; |
| 30 | |
| 31 | SetStopLoss(CalculationMode.Ticks, 80); // 80 ticks |
| 32 | SetProfitTarget(CalculationMode.Ticks, 160); // 160 ticks (2R) |
| 33 | |
| 34 | if (CrossAbove(smaFast, smaSlow, 1)) EnterLong(1, "L"); |
| 35 | else if (CrossBelow(smaFast, smaSlow, 1)) EnterShort(1, "S"); |
| 36 | } |
| 37 | } |
The traps everyone hits.
Real production failure modes. Sev1 = capital loss risk. Sev2 = data integrity / silent wrongness. Sev3 = developer ergonomics that bite later.
Sim101 ≠ live fills
Sev1What happens. The simulator assumes you get the bid/ask without slippage on small size. Live, especially on illiquid contracts, slippage can be multiple ticks per fill.
Fix. Use the Playback connection with real tick data and a fill-resolution of 'Last' or 'Bid/Ask' before going live. Add a slippage assumption of 1-3 ticks in your strategy's R-multiple math.
OnBarUpdate fires on partial bars
Sev2What happens. When Calculate is set to OnEachTick, OnBarUpdate runs many times per bar. Indicators based on Close will look correct on chart but be partial during the bar.
Fix. Default to Calculate=OnBarClose for systematic strategies. Only switch to OnEachTick for intra-bar exit logic that needs it (stops/targets work without this).
Strategy restarts ≠ resumed positions
Sev1What happens. If NT8 restarts mid-trade, the strategy's internal position state may be empty even though the broker still shows the position. Subsequent EnterLong calls double up.
Fix. Use 'StartBehavior=ImmediatelySubmit', enable 'SetOrderQuantity=Strategy', and reconcile against broker positions on State.Realtime entry. Add a Sync-On-Connect check.
Data feed disconnect
Sev2What happens. A 30-second data feed gap during a fast move can cause your strategy to miss the entry bar and trigger one bar later — at a much worse price.
Fix. Subscribe to Connection.StatusChange events and set strategy state to 'Halt' on disconnect. Re-enable manually after reviewing the gap.
Windows-only deployment
Sev3What happens. You cannot ship NT8 to a Linux VPS. Many low-cost VPS providers don't offer Windows VMs, raising your hosting cost.
Fix. Use Contabo / Hetzner / TradingFX VPS with Windows Server. Budget $20-$60/mo for a dedicated VPS in your broker's region.
What to pair it with.
No platform stands alone. These are the layers that — paired with NinjaTrader — produce production-grade automation.
| Layer | Recommended | Why |
|---|---|---|
| Data feed | Rithmic (low-latency) or Kinetick (cheaper, broker-provided) | Order-routing latency is dominated by the data POP, not the platform. |
| Broker | NinjaTrader Brokerage, Tradovate (via 8.x connector), or your existing FCM | NT8 is broker-agnostic; pick the lowest commission for your contract mix. |
| VPS | Contabo / Hetzner / TradingFX with Windows Server 2022 | Co-locate near the exchange / data POP. NT8 cannot run on Linux. |
| Backtest research | Strategy Analyzer + a separate Python research notebook | Use NT8 for tick-accurate backtests; use pandas for parameter studies and statistics. |