Given the ADX’s multi-stage math (see the explainer),
NinjaTrader’s built-in ADX and DM indicators are the sensible building blocks
— we compose them into a single directional-system indicator with a regime read.
What you’ll need
- NinjaTrader 8
- New → NinjaScript Editor → Indicators → New Indicator, name it
AlgoGenADX
The source
#region Using declarations
using System;
using System.Windows.Media;
using NinjaTrader.NinjaScript;
using NinjaTrader.NinjaScript.Indicators;
#endregion
namespace NinjaTrader.NinjaScript.Indicators
{
public class AlgoGenADX : Indicator
{
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "AlgoGen ADX";
Description = "ADX with +DI / -DI (directional system)";
Period = 14;
TrendLevel = 25;
IsOverlay = false;
AddPlot(new Stroke(Brushes.DodgerBlue, 2), PlotStyle.Line, "AdxLine");
AddPlot(new Stroke(Brushes.MediumSeaGreen, 2), PlotStyle.Line, "PlusDI");
AddPlot(new Stroke(Brushes.IndianRed, 2), PlotStyle.Line, "MinusDI");
AddLine(Brushes.Gray, 25, "Trend");
}
}
protected override void OnBarUpdate()
{
// DM(Period) exposes +DI and -DI; ADX(Period) exposes the strength line.
AdxLine[0] = ADX(Period)[0];
PlusDI[0] = DM(Period).DiPlus[0];
MinusDI[0] = DM(Period).DiMinus[0];
}
#region Properties
[NinjaScriptProperty][System.ComponentModel.DataAnnotations.Range(1, int.MaxValue)]
[System.ComponentModel.Display(Name = "Period", GroupName = "Parameters", Order = 0)]
public int Period { get; set; }
[NinjaScriptProperty]
[System.ComponentModel.Display(Name = "TrendLevel", GroupName = "Parameters", Order = 1)]
public double TrendLevel { get; set; }
[Gui.Browsable(false)][System.Xml.Serialization.XmlIgnore] public Series<double> AdxLine => Values[0];
[Gui.Browsable(false)][System.Xml.Serialization.XmlIgnore] public Series<double> PlusDI => Values[1];
[Gui.Browsable(false)][System.Xml.Serialization.XmlIgnore] public Series<double> MinusDI => Values[2];
#endregion
}
}
Using it as a regime filter
In a strategy, the ADX earns its keep by gating trend signals:
bool strongUp = ADX(14)[0] > 25 && DM(14).DiPlus[0] > DM(14).DiMinus[0];
if (strongUp && /* your entry trigger */)
EnterLong();
The math, if you build from scratch
The full chain (identical to the Python post): +DM/−DM keep
only the larger positive directional move; Wilder-smooth them and the ATR; form +DI
and −DI as 100 × smoothed(DM) / ATR; compute DX = 100 × |+DI−−DI| / (+DI+−DI);
Wilder-smooth DX into ADX. NinjaTrader’s ADX/DM implement this, so reusing them
guarantees your values match the platform.
Gotchas
DM(Period).DiPlus/.DiMinus. The direction lines live on theDMindicator;ADXgives only the strength line. You need both.- Lag. Double smoothing makes ADX slow; treat it as a filter.
- Warm-up. Built-ins handle their own warm-up, but early bars are still unreliable until the smoothing settles (~2×Period).
That’s the five-language set: Python, MQL5, Pine Script, EasyLanguage, and this one. Now test an ADX regime filter in AlgoGen.
This post is educational, not financial advice. Indicators describe the past; they don’t predict the future. Backtest anything before you risk real money on it.
Sources and further reading
- NinjaScript system indicator methods (NinjaTrader)
