IsFirstTickOfBar is a NinjaScript property that is true only on the first tick of each new bar under Calculate.OnEachTick. Gating entries with it makes an OnEachTick strategy decide once per closed bar — using the settled Close[1] — which removes intrabar repaint while keeping tick-level updates for everything else. This article is educational only and is not trading advice; it implies nothing about profitability.
IsFirstTickOfBar is a boolean that NinjaTrader sets true only on the first OnBarUpdate() call of each newly opened bar, and false on every subsequent tick of that bar. It is meaningful under Calculate.OnEachTick (and OnPriceChange), where OnBarUpdate() runs many times per bar. It lets you run one specific block of logic exactly once per bar while everything else keeps updating tick by tick.
The crucial detail is what data is available on that first tick. When the first tick of a new bar arrives, the previous bar has just closed and its values are final. So inside an IsFirstTickOfBar block, Close[1], High[1], and Low[1] refer to the settled, committed prior bar — data that will never change again. That is precisely the property that eliminates repaint.
if (IsFirstTickOfBar)
{
// runs once per bar; Close[1] is the just-closed, final bar
double lastClose = Close[1];
}This is the standard idiom for getting closed-bar decisions out of a tick-driven strategy without giving up the responsiveness that OnEachTick provides for stops and displays. You can confirm the fix worked with the free [/ninjascript](/ninjascript) validator.
Repaint happens when your entry reads the developing Close[0], which moves on every tick until the bar closes. IsFirstTickOfBar breaks that dependency two ways: it fires your entry logic only once per bar, and it steers that logic to read Close[1] — the bar that already closed — instead of the moving current bar.
Contrast the two versions. The repainting one:
// WRONG: reads developing Close[0] every tick under OnEachTick
protected override void OnBarUpdate()
{
if (CurrentBar < 20) return;
if (Close[0] > SMA(20)[0]) // Close[0] still moving
EnterLong();
}The fixed one:
protected override void OnBarUpdate()
{
if (CurrentBar < 20) return;
if (IsFirstTickOfBar)
{
// Close[1] and SMA(20)[1] are settled: no repaint
if (Close[1] > SMA(20)[1])
EnterLong();
}
}In the fixed version the condition is evaluated against data that cannot change, so the signal cannot un-fire. It commits once, on settled values. This is the same closed-bar guarantee that Calculate.OnBarClose gives, but achieved while staying in OnEachTick. For why the un-gated version misleads a backtest, see [/learn/repainting](/learn/repainting) and [/learn/look-ahead-bias](/learn/look-ahead-bias).
If gating with IsFirstTickOfBar reproduces the closed-bar decision, why not simply use Calculate.OnBarClose? Because the two are not equivalent for the rest of your code. OnBarClose runs OnBarUpdate() only when a bar closes, so anything that needs to react between bars — trailing stops, breakeven moves, intrabar exits, live plots — cannot run until the next close.
Calculate.OnEachTick with IsFirstTickOfBar gating gives you both: the entry decision is committed once per closed bar on settled data, while stop management and displays continue to update every tick.
protected override void OnBarUpdate()
{
if (CurrentBar < 20) return;
if (IsFirstTickOfBar)
{
// entry: settled data, once per bar, no repaint
if (Close[1] > SMA(20)[1] && Position.MarketPosition == MarketPosition.Flat)
EnterLong();
}
// runs every tick: react to price continuously
if (Position.MarketPosition == MarketPosition.Long)
SetStopLoss(CalculationMode.Price, Low[1] - TickSize);
}This is the pattern to reach for when a strategy needs intrabar risk management but bar-committed entries. If your logic has no intrabar needs at all, OnBarClose is simpler and just as safe — see the companion article on the three Calculate modes.
The first mistake is reading Close[0] inside the gate and assuming it is settled. On the first tick of a new bar, Close[0] is the opening tick of the bar that is only now beginning — it is not settled and will move all bar. The settled data is Close[1]. Always index back one when you want the just-closed bar.
The second mistake is guarding against CurrentBar. On startup IsFirstTickOfBar can be true while you still lack the history your indicator needs, so keep the if (CurrentBar < N) return; guard so you never index past the start of the series.
The third concerns multi-series strategies. If you call AddDataSeries(...), OnBarUpdate() runs for each series, distinguished by BarsInProgress. IsFirstTickOfBar refers to the series currently being processed, so gate on both:
if (BarsInProgress == 0 && IsFirstTickOfBar)
{
// first tick of the primary series only
}The fourth: IsFirstTickOfBar is a live/real-time concept. In the Strategy Analyzer on bar data there is only one call per bar, so the gate is effectively always satisfied — which is exactly why the gated strategy behaves consistently between backtest and live. Validate that consistency at [/ninjascript](/ninjascript). This is educational material only, not trading advice, and asserts nothing about profitability.
Educational only — not financial advice. Trading involves substantial risk of loss.