Map each plot to one series
I write the AddPlot order beside each Values index during review. That catches mismatches when a second output is added later.
NinjaScript Indicator builder
Define the calculation, plot, parameters, and bar timing in plain English. Pineify can turn that specification into one editable NT8 Indicator file with static diagnostics.
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.NinjaScript;
namespace NinjaTrader.NinjaScript.Indicators
{
public class RsiLineExample : Indicator
{
private RSI rsi;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "RsiLineExample";
Calculate = Calculate.OnBarClose;
IsOverlay = false;
Period = 14;
AddPlot(Brushes.DodgerBlue, "RsiValue");
AddLine(Brushes.Gray, 70, "Upper");
AddLine(Brushes.Gray, 30, "Lower");
}
else if (State == State.DataLoaded)
{
rsi = RSI(Period, 3);
}
}
protected override void OnBarUpdate()
{
if (CurrentBar < Period - 1)
return;
Value[0] = rsi[0];
}
[NinjaScriptProperty]
[Range(1, 200)]
[Display(Name = "Period", GroupName = "Parameters", Order = 0)]
public int Period { get; set; }
[Browsable(false)]
[XmlIgnore]
public Series<double> RsiValue => Values[0];
}
}This RSI example is a structural starting point. Compile it in NinjaScript Editor and check the chart output before using it in another script.
A NinjaScript Indicator is a C# class that inherits Indicator, declares display outputs with AddPlot, and assigns bar values through Value or Values in OnBarUpdate. Put stable UI defaults and plots in State.SetDefaults, initialize data-dependent indicator objects in State.DataLoaded, and guard each historical series access before calculation.
A custom NinjaTrader 8 Indicator needs the Indicators namespace, a public class derived from Indicator, and the OnStateChange and OnBarUpdate overrides. State.SetDefaults holds the name, Calculate mode, panel choice, parameter defaults, and ordinary plot declarations.
OnBarUpdate receives bar-processing events. It should return before a required lookback is ready, calculate the current value, and assign that result to the intended plot series. Keep the first version small enough that every state transition and output has an obvious purpose.
AddPlot(Brushes.DodgerBlue, "RsiValue") creates one display plot and one matching series. Value[0] writes the current bar of the first plot. The same assignment can be written as Values[0][0]. If the Indicator has two plots, Values[1][0] writes the second one.
Declaration order is a contract. Renaming a plot does not change its numeric index, but inserting a plot earlier in the list does. Review every Values index after changing plot order. Expose a named Series property when other scripts need to read a particular output.
The example creates the RSI object in State.DataLoaded. At that point configured data is available, so the object can be retained and reused by OnBarUpdate. Recreating the same indicator on every bar makes the code harder to inspect and can add unnecessary work.
State.SetDefaults should remain light because NinjaTrader can create temporary instances while opening lists or compiling. Do not read Bars or Instrument data, open external resources, or create data-dependent objects there.
If code reads Close[5], it needs at least five prior bars. If a 50-period calculation is used, guard for the longer dependency. In a single-series script, CurrentBar is enough. In a multi-series script, check CurrentBars for every series that the calculation reads.
BarsRequiredToPlot controls when plots appear. It does not make an unsafe Close[n] or secondary series access safe. The guard belongs in the code path before the read.
A useful generation prompt names the formula, source series, period limits, Calculate mode, panel, plot names, colors, and any fixed lines. Ask for one complete Indicator source file. Review the class name, property ranges, AddPlot order, lookback guards, and output assignments before checking it.
Pineify can report static C# and supported API diagnostics for that file. Then compile it in NinjaScript Editor, apply it to a chart, compare several known bars, and inspect behavior across reloads and realtime updates. Each stage can reveal a different problem.
I write the AddPlot order beside each Values index during review. That catches mismatches when a second output is added later.
I base the CurrentBar check on the longest series access or calculation, not on the number that happens to look tidy in the UI.
After compilation, I inspect a few chart bars where the expected value can be calculated independently. A smooth plot is not proof that the formula is right.
Create one editable NT8 Indicator or Strategy file with a bounded diagnostic loop.
Build a small script while learning states, series, guards, and platform testing.
Move a generated source file through editor compilation and focused Print output.
Use a Strategy when the script needs managed orders instead of display-only output.
This page explains NinjaScript development and Pineify code generation. It is not investment advice. Generated code can be wrong, a static check does not replace NinjaScript Editor compilation, and no example promises future results.
Generate one editable NinjaTrader 8 Indicator or Strategy source file and review static C# and supported API diagnostics.
Learn NinjaScript lifecycle, series indexing, plots, guards, compilation, and chart testing from one small Indicator.
Move a NinjaScript file through static preflight, NinjaScript Editor compilation, source-located repairs, and focused Print output.
Review a complete managed Strategy using SetTrailStop, stable entry signals, position checks, and explicit risk units.
State the inputs, calculation, plots, and bar timing. Inspect the generated file and static diagnostics before compiling it in NinjaTrader 8.
Build a NinjaScript Indicator