Open any NinjaTrader 8 strategy's properties and you will find a setting called Calculate with three choices: On bar close, On each tick, and On price change. Most people leave it on the default and never think about it again. That is a mistake, because this one dropdown decides when your code runs, which bar your code is looking at, and how far apart your backtest and your live results can drift.
We have spent a lot of hours chasing "why did the bot do that" questions in NinjaScript, and a surprising number of them trace back to Calculate. This guide explains each mode using NinjaTrader's own documentation, shows the trap that catches almost everyone who switches off the default, and gives you a practical way to pick the right setting for an automated futures strategy.
What the Calculate Setting Actually Controls
Every NinjaScript strategy and indicator does its core work inside a method called OnBarUpdate(). NinjaTrader's help guide describes it as "an event driven method which is called whenever a bar is updated," and says the frequency of those calls "will be determined by the 'Calculate' property."
So Calculate is not a performance knob or a display option. It is the heartbeat of your strategy. The official definition is short:
"OnBarClose means once at the close of the bar. OnEachTick means on every single tick. OnPriceChange means once for each price change." (NinjaTrader 8 Help Guide, Calculate)
The default is Calculate.OnBarClose. NinjaTrader also notes the property should only be set inside OnStateChange() during State.SetDefaults or State.Configure. Set it anywhere else and you are asking for behavior you did not plan.
The Three Modes, One at a Time
OnBarClose: one decision per bar
Your logic runs once, when a bar finishes. On a 5-minute NQ chart, that is one evaluation every five minutes. Nothing that happens inside the bar reaches your code until the bar is complete.
This is the calmest way to run a strategy. Signals are based on finished bars, so a crossover that appears and disappears mid-bar never triggers a trade. It is also the mode that behaves most like a backtest, for reasons we will get to in a moment. The cost is speed. If price blows through your level right after a bar opens, you will not know about it until that bar closes.
OnEachTick: every trade that prints
Your logic runs on every incoming tick. On a busy NQ open that can mean a very large number of calls per second. This mode gives you the fastest possible reaction, and it is the only one that sees every volume update.
The price is CPU and complexity. Code that was fine at one call per bar can become heavy when it runs thousands of times inside a single bar, especially if it loops through history or rebuilds drawing objects. On a VPS with limited cores this adds up quickly. We covered hardware tradeoffs in do you need a VPS to run a NinjaTrader 8 algo.
OnPriceChange: a lighter real-time mode
Your logic runs when the price changes. If two ticks print back to back at the same price, the second one does not trigger OnBarUpdate(). For most price-based rules, such as "has the last price crossed my stop level," you lose nothing and save a lot of redundant calls.
There is one firm limit, and NinjaTrader states it directly: "If your script relies on volume updates OnPriceChange should NOT be used since it can potentially miss volume updates if they occur at the same price." If your strategy uses cumulative delta, volume at price, or anything that counts contracts, use OnEachTick.
| Question | OnBarClose | OnEachTick | OnPriceChange |
|---|---|---|---|
| When does OnBarUpdate run in real time? | Once, when the bar closes | Every tick | Each time price changes |
| Reaction speed | Slowest (up to one full bar) | Fastest | Near tick speed |
| CPU load | Lowest | Highest | Middle |
| Safe for volume-based logic? | Yes, on completed bars | Yes | No, can miss same-price volume |
| IsFirstTickOfBar useful? | No | Yes | Yes |
| How it runs on historical data | Bar close | Bar close (unless Tick Replay) | Bar close (unless Tick Replay) |
| Default? | Yes | No | No |
The Trap: Historical Bars Ignore Your Setting
Look at the last-but-one row of that table again. This is the part that trips people up, and it explains a lot of "my backtest looked nothing like live" complaints.
NinjaTrader's documentation is explicit. On a historical data set, "only the OHLCVT of the bar is known and not each tick that made up the bar. As a result, State.Historical data processes OnBarUpdate() only on the close of each historical bar even if this property is set to OnEachTick or OnPriceChange."
Read that as a strategy builder. You can set a strategy to OnEachTick, write logic that depends on intrabar movement, run it in the Strategy Analyzer, and get a clean result. That result was produced by bar-close processing. Then you enable it live, it starts running on every tick, and it is effectively a different strategy.
A quick example of the drift
Suppose your rule is "go long when price trades above the prior bar's high." On historical bars your code only sees each bar once, at its close, so it can only act after the bar that broke the high has finished. Live on OnEachTick, the same rule fires the moment the high is taken out, often at a very different price, and sometimes on bars that reversed and closed back below. Same code, two sets of trades.
It also affects what you see when a strategy is first enabled. The historical portion of the chart is processed bar by bar, then the strategy switches to real-time calls. Positions it "took" historically were calculated with bar-close logic, even though everything after the transition runs tick by tick. If you have ever enabled a strategy and found it already sitting in a position you did not expect, this transition is one of the first places to look. Our guide on why your NinjaTrader 8 backtest doesn't match live trading goes deeper into the other causes.
Bar Indexing Changes Too
There is a second, quieter difference. Under OnBarClose, your code runs after a bar finishes, so the most recent bar you are working with is that completed bar. Under OnEachTick or OnPriceChange in real time, your code runs while a bar is still forming, so index [0] is that developing bar and [1] is the last completed one.
That means a line like Close[0] > Open[0] means "the last finished bar was green" in one mode and "price is currently above this bar's open" in the other. Switch the Calculate setting without revisiting your indexes and you have silently changed your strategy's rules.
NinjaTrader's own example for IsFirstTickOfBar shows the adjustment. It checks CCI(20)[1] for the entry, because on the first tick of a new bar the bar that just closed sits at index 1.
The Hybrid Pattern: Enter on the Close, Manage on the Tick
For a lot of automated futures strategies, the best answer is not choosing one mode. It is using a tick-level mode and splitting your logic into two parts: entries that should only be evaluated on completed bars, and risk management that should react immediately.
NinjaTrader provides IsFirstTickOfBar for exactly this. The help guide describes it as indicating "if the incoming tick is the first tick of a new bar," and notes it "is only of value in scripts that run tick by tick," meaning OnEachTick or OnPriceChange. Their example looks like this:
if (IsFirstTickOfBar) { if (CCI(20)[1] < -250) EnterLong(); return; }if (CCI(20)[0] > 250) ExitLong();
The entry check runs once per bar, using the bar that just completed, which gives you bar-close style signals. The exit check runs on every call, so the strategy can get out as soon as the condition is met instead of waiting for the bar to finish. Two cautions from the documentation: IsFirstTickOfBar "should NOT be accessed outside of the OnBarUpdate() method," and on historical data, remember that everything still runs once per bar anyway.
This pattern is also why many NQ strategies that look "slow" on paper hold up better live. Entries stay disciplined and unaffected by mid-bar noise, while daily loss limits, trailing logic, and flatten rules respond in real time. That split matters a lot on prop firm accounts, where one late exit can breach a drawdown line. See prop firm trailing drawdown explained for algo traders for why seconds count there.
Getting Intrabar Detail Into a Backtest
If historical bars always process on the close, how do you test a strategy that genuinely depends on intrabar behavior? NinjaTrader gives you three tools, each with its own limits.
Tick Replay
The Calculate documentation points to "TickReplay or a Multi-time frame script" for accessing intrabar data historically. Tick Replay loads the bid, ask and last data that built each bar "in the exact sequence of market data events." To see the option you enable Show Tick Replay under Control Center, Tools, Options, Market data.
The catch for strategy builders is significant. NinjaTrader states that "Tick Replay is not intended to function in NinjaScript strategy backtests, and will not provide the same results as running a strategy on live data with Tick Replay enabled." It also uses more PC resources and cannot be used with Renko or Line Break bars. Tick Replay helps indicators and helps a live strategy build accurate history on a chart. It is not your backtesting fix.
Order Fill Resolution: High
In a Strategy Analyzer backtest, the default order fill resolution is "Standard (Fastest)," which uses the same bar series you are testing on to fill orders. Setting it to High lets you "set a secondary bar series to be used as the price data to fill your orders," such as 1-tick or 1-second data under a 5-minute strategy.
This improves where your orders fill, which fixes a big share of backtest optimism around stops and targets. It does not make your signal logic run intrabar. NinjaTrader also notes it "cannot be used with Multi Time Frame/Multi Instrument strategies, or when Tick Replay is used," and very granular series will slow the test down.
A secondary 1-tick series
The most flexible route is adding a finer data series to the strategy itself and running your intrabar logic against it. NinjaTrader's multi-time frame documentation includes a warning worth copying into your notes: orders submitted on the primary series in a backtest are filled "by looking ahead to the next bar of the current series," before the finer series has a chance to run. Their guidance is to "submit orders in all cases to the highest granularity series" if that is where your order logic lives. This takes more code, and you also have to filter BarsInProgress correctly, but it is the closest you will get to live tick behavior in a historical test.
Skip the months of NinjaScript debugging
NQ Ultra is a ready-to-run NinjaTrader 8 strategy built and tested for prop firm accounts, with the execution details already worked out.
Get NQ Ultra on WhopSo Which Setting Should You Use?
Here is the decision process we use when building or reviewing a strategy.
- Are entries and exits both based on completed bars? Use OnBarClose. It is the default, the lightest on CPU, and the closest match between backtest and live. Most crossover and breakout-confirmation systems belong here.
- Do you need to react inside the bar, but only to price? Use OnPriceChange with the
IsFirstTickOfBarsplit. Entries on the close, stops and flatten rules in real time. - Does any logic count volume or order flow? Use OnEachTick. OnPriceChange can miss same-price volume updates, and NinjaTrader says not to use it for that.
- Did you change the setting on an existing strategy? Recheck every
[0]and[1]reference, then retest in Market Replay before going live. A normal backtest will not show you the difference. Our walkthrough on testing a NinjaTrader 8 strategy with Market Replay shows how.
Whatever you choose, measure it on real-time or replayed data, not just the Strategy Analyzer. A tick-driven strategy validated only on historical bars has been validated as a bar-close strategy.
Common Calculate Mistakes We See
- Switching to OnEachTick "to be faster" without changing any logic. Your indexes now point at a developing bar, and signals can fire and vanish inside the same bar.
- Trusting an OnEachTick backtest. It ran on bar closes. The live strategy will not.
- Using OnPriceChange for delta or volume filters. Same-price volume can be skipped.
- Setting Calculate outside OnStateChange. NinjaTrader limits it to SetDefaults or Configure for a reason.
- Running heavy loops on every tick. Move expensive work inside an
IsFirstTickOfBarblock so it runs once per bar. - Expecting Tick Replay to fix strategy backtests. NinjaTrader says it is not intended to work that way.
Calculate looks like a minor setting, but it quietly decides whether your strategy is the one you tested. Pick it on purpose, write your bar references to match it, and test it on the kind of data it will actually run on. That alone will remove a whole category of surprises from your live trading.