Now that we've covered the basics of C# and NinjaScript, let's put that knowledge into practice by building our first custom indicator: a Simple Moving Average (SMA).
Simple Moving Average (SMA)
Traders use SMA to smooth out price fluctuations and identify trends.
SMA formula
SMA is a classic moving average indicator calculated by adding recent prices. Then dividing that figure by the number of time periods in the calculation average.
The formula of SMA is simple as its name:
SMA = (A1 + A2 + A3 + ... + An) / n
Where:
- A(n): the price of an asset at period n
- n: number of total periods
For example, we can calculate the SMA of a security with the following closing prices over a 15-day period.
- Week One (5 days): 20, 22, 24, 25, 23
- Week Two (5 days): 26, 28, 26, 29, 27
- Week Three (5 days): 28, 30, 27, 29, 28
- Total sum = 20 + 22 + 24 + 25 + 23 + 26 + 28 + 26 + 29 + 27 + 28 + 30 + 27 + 29 + 28 = 392
- Average: 392 / 15 = 26.13
The 15-day simple moving average for this security would be $26.13.
Convert formula to code
First, we need to define 2 variables: one for the period and one for the average value.
// This variable will store the number of bars used to calculate the SMA.
int period = 14;
// This variable will accumulate the sum of the closing prices.
double sumPrice = 0.0;
Note that the sumPrice
is in double datatype. Therefore, its value always has a dot even with zero. It’s not mandatory but a good practice to keep.
In the formula above, we need to analyze the price within a period. In this situation, the period is 14. It means we need the price of 14 continuous bars. However, at the beginning we did not have enough bars. Therefore, we must wait until there’re at least 14 bars on the chart to do the calculation. In the OnBarUpdate()
function, add this condition:
if (CurrentBar < period)
{
return; // Not enough bars to calculate SMA
}
The condition checks if the current bar number (CurrentBar
) is less than the period (14). The CurrentBar
counts from zero, left to right. It started at 0 so the condition is “less than (<)” and does not have equal (=). The numbers from 0 to 13 represent 14 distinct values.
Note: In programming, we usually started from zero (0), not one (1).
If the CurrentBar
is under 14, it means that the chart does not have enough bars for calculation. We use a return statement without a return value to make OnBarUpdate()
skip one iteration.
When the chart has enough bars, the condition fails, meaning no return and no skip. The code will continue. We will add a loop to calculate the sum of price within 14 bars:
// Loop through the last 'period' bars
for (int bar = 0; bar < period; bar++) {
// Add the closing price of each bar to the sum
sumPrice = sumPrice + Close[bar];
}
In the code above, we use a common for
loop. It has 3 parts:
- First: declare one temporary variable
int bar = 0
. This variable will be used only within this loop.
- Second: comparison with period
bar < period
. If it’s true, meaning the bar is still less than the period (14) → do the logic inside the curly brackets.
- Third: increase bar value by 1 using
bar++
. It’s a shortcut of bar = bar + 1
. Now the temporary variable bar has a value of 1. The loop continues until the condition fails, meaning bar = period = 14
. At that moment, the loop runs 14 times, then ends. Code execution continues to the next line beyond the curly brackets.
The body of the loop uses the Close
price. It’s one of 4 main prices of a bar: Open, High, Low, Close. In NinjaScript, the default variable Close
holds closing prices for each bar on the chart. If you want to get the price of a specific bar, use the square brackets: Close[X bars ago]
.
For example, Close[0]
is the closing price of the current bar, Close[1]
is the closing price of the previous bar. More details here. This is an easy-to-confuse concept. Currently you just need to know that. We can dig deeper later.
Note: programming is different from math at the equal sign (=):
- In math, equal (=) means comparison. You compare the value of 2 number, or 2 variables
- In programming, equal (=) means assignment. You assign the value on the right to the variable on the left:
sumPrice = sumPrice + Close[bar]
. In this situation, you calculate the value of sumPrice + Close[bar]
, then assign the value to the variable sumPrice
.
If you want to do comparison in C# programming, use double equals (==).
This effectively sums up the closing prices for within a period of 14 bars.
double avgValue = sumPrice / period;
Print(avgValue);
// Reset sum for the next bar's calculation
sumPrice = 0.0;
After the loop has finished calculating the sumPrice
, this line calculates the average value with 14 bars. The result is stored in the avgValue
variable. You print the value to the NinjaTrader output window to observe the calculation.
Finally, sumPrice
is reset to zero. As I mentioned in the previous article, the function OnBarUpdate()
runs at every bar on the chart. If I did not reset the value of sumPrice
, it will keep the same value calculated in this bar into the next bar and cumulates. This causes a failed result.
After that, press the F5 on your keyboard to compile the code. You will hear a “ding ding” sound upon successful compilation. Open a chart & add the indicator. Then open up NinjaScript Output and press F5, you will see the SMA values printed out.

The whole code will look like this:

Plot the SMA values
Currently, it works. However, you don’t know whether it’s correct or not. Also, you will not want to look at those raw values all the time. You need to turn them into a plot line for better visuals. If we can’t visualize the numbers, what’s the point of using programming, right?
First, you need to define a new variable to hold the plot line. Insert this code snippet right below the sumPrice
variable:
// Declare a Series to hold SMA values
public Series<double> HelloWorldSMA {
get { return Values[0]; }
}
Here’s a breakdown:
public Series<double>
: This means the property is publicly accessible (seen from UI) and holds a series of double
values.
get { return Values[0]; }
: This is the getter, which returns the first Values
array element.
- In NinjaTrader's NinjaScript,
Values[0]
typically represents the primary data series used for calculations. More about it can be found here.
Then, in the function OnStateChange()
, add this line to the default condition state:
AddPlot(Brushes.Chocolate, "Hello World SMA");
The AddPlot()
function adds a plot to the chart. We'll use it to display our SMA. The first argument is the color, and the second is the name of the plot. When I called Values[0]
in the above declaration, I specifically “mapped” it to this new plot. Therefore, they depended on each other.
In some indicators, you have multiple plot lines, you may need to add more plots. Each of them is added to the Values
array and accessible by their definition order:
AddPlot(Brushes.Red, "Plot #1"); // Values[0]
AddPlot(Brushes.Green, "Plot #2"); // Values[1]
AddPlot(Brushes.Blue, "Plot #3"); // Values[2]
Back to our code, after declaring the SMA plot line, we need to append the raw SMA value of each bar to it by replacing the Print()
with this code:
// Assign the calculated SMA value to the current bar's plot
HelloWorldSMA[0] = avgValue;
The HelloWorldSMA
is a series of double
that hold multiple values. When I write zero in the square bracket, I want to set the value for the current bar being evaluated by choosing a barsAgo
value of 0.
More details about the Series can be found here.
After that, compile the code (F5) and go back to your chart to see the result.

Bingo! You can see there’s a new chocolate plot line showing in the bottom panel. This confirms that your SMA indicator is displaying correctly.
Verify the indicator
When creating a new indicator, you will not know whether it runs correctly without doing tests. However, for the classic indicator like SMA, we have a simple trick: Open up the Indicators manager. Find and add the default SMA indicator by NinjaTrader to the chart (you can config it to have a different style (See figure below).

Click on our custom SMA plot line. Drag the line to the price panel. Please make sure the default NinjaTrader SMA period is the same as your indicator period. You will see that they’re identical to each other. Meaning you have built yourself a correct SMA indicator.


This ensures that our custom SMA is calculating the same values as the built-in SMA, confirming its accuracy.
Next
Excellent work! You have successfully created your first NinjaScript indicator.
In the next article, I will demonstrate how to customize the indicator's properties via the user interface and also make some improvements to the SMA algorithm.
Appendix
NinjaScript for Beginner