Indicator Template for NinjaTrader 8 (NinjaScript)
This article is Part 1 of a series covering how to build a custom indicator for NinjaTrader 8 (NT8) using NinjaScript and Visual Studio.
This article will be the first in a series of articles covering the creation of indicators in NinjaTrader 8 (NT8). As mentioned in the title, we will be using NinjaScript to build our indicators. If you have not read the following two articles already, please do so before continuing.
For paid subscribers, source code for the tutorials can be found on the HGT GitHub.
There is an option to build indicators directly in the NinjaScript Editor within NinjaTrader8 (NT8). There is also a wizard to help build the script for you. This series does not cover this. While I am by no means a developer, I do believe that learning how to use the NinjaScript language, and how the underlying functions work, will help build more stable parameters and indicators for use in trading.
Disclaimer: the following post is an organized representation of my research and project notes. It doesn't represent any type of advice, financial or otherwise. Its purpose is to be informative and educational.
Creating the Indicator Template
Open Visual Studio and open the NinjaTrader.Custom.sln
file.
Open the Indicators folder and then open a new class within the folder. Alternatively, you can create folders for your indicators but understand that if you make a folder inside the solution, it doesn't mean that it will show up within NinjaTrader or in the NinjaScript Editor.
The first thing we add is the appropriate namespace, then we set the class to public and inherit the indicator class. Then we define two string variables to set the naming convention. I am going to define a name and version. This will be the name of the indicator within NT8.
We will need two overrides: OnStateChange()
and OnStateChange()
.1
Note: it seems the standard (at least within NinjaScript) that variables are declared just under the public class and before defining overrides. NinjaScript Best Practices recommends that only constants should be set at the class level. Variables can be declared but should wait until the state has reached State.Configure
. 2
Perhaps more to come on the NinjaScript Lifecycle. 3
namespace NinjaTrader.NinjaScript.Indicators
{
public class Template: Indicator
{
private const string IndName = "Template";
private const string IndVersion = " v1";
protected override void OnStateChange()
{
/* Called whenever script enters a new "state". */
}
protected override void OnBarUpdate()
{
/* Where core logic is contained */
}
}
}
Within OnStateChange()
we are going to type out a few state setting that we may use often, so we can go ahead and create them now.
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
}
else if (State == State.Configure)
{
}
else if (State == State.DataLoaded)
{
}
else if (State == State.Terminated)
{
}
Inside of State.SetDefaults
we are going to add/create two methods: SetDefaultSettings()
and SetParameters()
. We will define these methods below but leave them empty for now. We will also go ahead and add ClearOutputWindow()
to the State.Configure
. This part of the state is only entered once, each time that it loads/reloads. This will help to keep the NinjaScript Output window in NT8 clean as you tinker with your indicators.
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
SetDefaultSettings();
SetParameters();
}
else if (State == State.Configure)
{
ClearOutputWindow();
}
else if (State == State.DataLoaded)
{
}
else if (State == State.Terminated)
{
}
Note: you can create folders for your custom indicators from within the solution file or from within the editor in NT8.
Next, we build out the SetDefaultsSettings()
function and put a place holder for SetParameters()
:
private void SetDefaultSettings()
{
Name = IndName+IndVersion;
IsOverlay = true;
Calculate = Calculate.OnBarClose;
DisplayInDataBox = true;
ShowTransparentPlotsInDataBox = true
BarsRequiredToPlot = 0;
ArePlotsConfigurable = true;
}
private void SetParameters()
{
}
Name sets the name of the indicator within NT8.
IsOverlay false creates a separate panel for the indicator.
Calculate has three settings: OnBarClose
, OnEachTick
, & OnPriceChange
. 4
DisplayInDataBox whether or not to display the indicator value in the data box.
ShowTransparentPlotsInDataBox defaults to false. This controls whether or not the information from your indicator will be visible in the data box if you set the indicator plot to transparent.
BarsRequiredToPlot is not the same as minimum number of bars needed to calculate the script values. It just defines how many bars are needed to actually plot the indicator. 5
ArePlotsConfigurable actually defaults to true. I leave the setting here in the template for ease of change if I wish to set it to false for some reason.
We will add in a Parameters region directly in the class and help to set the template up for adding in Parameters that will be user changeable in the GUI once the template is complete.
#region Parameters
// NinjaScript Properties will go here.
#endregion
And lastly, we add in some simple logic for avoiding errors with calculating data on previous bars that don't exist on the chart. Like the bar that comes before the first bar in the chart...
protected override void OnBarUpdate()
{
if (CurrentBar < 1)
return;
}
The completed template looks like:
namespace NinjaTrader.NinjaScript.Indicators
{
public class Template: Indicator
{
private const string IndName = "Template";
private const string IndVersion = " v1";
#region Parameters
// NinjaScript Properties will go here.
#endregion
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
SetDefaultSettings();
SetParameters();
}
else if (State == State.Configure)
{
ClearOutputWindow();
}
else if (State == State.DataLoaded)
{
}
else if (State == State.Terminated)
{
}
private void SetDefaultSettings()
{
Name = IndName+IndVersion;
IsOverlay = true;
Calculate = Calculate.OnBarClose;
DisplayInDataBox = true;
ShowTransparentPlotsInDataBox = true
BarsRequiredToPlot = 0;
ArePlotsConfigurable = true;
}
private void SetParameters()
{
}
protected override void OnBarUpdate()
{
/* Where core logic is contained */
if (CurrentBar < 1)
return;
}
}
}
A Note on NinjaScript Attributes
This section is going to introduce NinjaScript Properties (an attribute) and how to use them to define your parameter variables as NinjaScript Properties and set default values in the SetParameters()
function. We will add a couple of parameters to the indicator template for reference and future use.
NinjaScript Property Attribute
The NinjaScript Property Attribute is used to declare a variable as a parameter in NinjaScript. They are useful for making indicators optimizable in the Strategy Analyzer and are helpful when a custom indicator is being called within a strategy. 6
There are several different types of attributes that are useful when developing in NT8 and NinjaScript. This is section is just a simple introduction to the concept. These attributes will be explored in more depth as the articles progress in complexity. Any discoveries that change how I setup my template will be noted here as well.
We will use the [NinjaScriptProperty] and [Display] attributes. All of the code goes within the parameters region (#region Parameters).
#region Parameters
private int _period;
[NinjaScriptProperty]
[Display(Name = "Period", GroupName = "Parameters", Order = 1)]
public int Period
{
get { return _period; }
set { _period = value; }
}
#endregion
Conclusion
This is a basic template for building indicators in NinjaTrader 8 with NinjaScript. It is just the starting point for creating custom indicators and there will be more tutorials in the future to expand on this topic. Look for the next tutorial in the coming weeks that covers how to create two variations of a net profit indicator.
Feel free to comment below or e-mail me if you need any help with anything, wish to criticize, or have thoughts on improvements. Paid subscribers will have access to this code and more at the private HGT GitHub repo. As always, this newsletter just represents refined versions of my own research notes. That means these notes are plastic. There could be mistakes or better ways to accomplish what I am trying to do. Nothing is set in stone and I am always looking for ways to improve.