Back to Blog

Taming the Beast: The Zero Lag Williams Alligator for NinjaTrader 8

If you’ve been trading for more than a week, you’re likely familiar with the "Alligator" — Bill Williams’ classic trend-following powerhouse. It’s reliable, visual, and a staple on many charts. But let’s be honest: the original version can feel like a sleepy reptile that takes way too long to wake up.

By the time the Jaw, Teeth, and Lips finally align, half the move is already in the rearview mirror. To fix this, we have ported the popular Near Zero Lag Williams Alligator (originally seen on ThinkScript) over to NinjaTrader 8.

Why Port This to NinjaTrader?

NinjaTrader 8 is a powerhouse for precision execution and backtesting. By using a Zero Lag version of the Alligator, you’re essentially giving the reptile a shot of espresso.

The "Zero Lag" Advantage

Standard moving averages are inherently lagging because they rely on past data. The "Zero Lag" version replaces traditional smoothing with a calculation that weights recent price action more heavily, allowing the lines to pivot significantly faster.

Trading Techniques

1. The Sleeping Alligator (Range)

When the Jaw, Teeth, and Lips are tangled or moving horizontally, the Alligator is sleeping. This is your cue to sit on your hands.

Pro Tip: The longer the Alligator sleeps, the hungrier it will be when it wakes up. Expect a massive breakout after long periods of consolidation.

2. The Awakening (The Entry)

3. The Sated Alligator (The Exit)

In the Zero Lag version, the Green line (Lips) is your primary exit trigger. When the Lips cross back over the Red line, the "meal" is over. Because this version has near-zero lag, this crossover happens much closer to the actual price peak than the standard version.

The NinjaTrader 8 Code

Below is the C# code for the Zero Lag Williams Alligator. Save this as a .cs file in your NinjaTrader's Indicators folder and compile it through the NinjaScript editor.

// Zero Lag Williams Alligator for NinjaTrader 8
// Adapted from the Near Zero Lag ThinkScript community version

#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.DrawingTools;
#endregion

namespace NinjaTrader.NinjaScript.Indicators.OranselIndustries
{
    public class NearZeroLagWilliamsAlligator : Indicator
    {
        private Series<double> iTrendJaw;
        private Series<double> iTrendTeeth;
        private Series<double> iTrendLips;
        
        protected override void OnStateChange()
        {
            if (State == State.SetDefaults)
            {
                Description = @"Near Zero-Lag Williams Alligator Using the Dr Ehlers ITrend";
                Name = "NearZeroLagWilliamsAlligator";
                Calculate = Calculate.OnBarClose;
                IsOverlay = true;
                DisplayInDataBox = true;
                DrawOnPricePanel = true;
                PaintPriceMarkers = true;
                ScaleJustification = NinjaTrader.Gui.Chart.ScaleJustification.Right;
                IsSuspendedWhileInactive = true;
                
                Jaw = 13;
                Teeth = 8;
                Lips = 5;
                
                AddPlot(Brushes.Blue, "JAW");
                AddPlot(Brushes.Red, "TEETH");
                AddPlot(Brushes.Cyan, "LIPS");
            }
            else if (State == State.DataLoaded)
            {
                iTrendJaw = new Series<double>(this);
                iTrendTeeth = new Series<double>(this);
                iTrendLips = new Series<double>(this);
            }
        }

        protected override void OnBarUpdate()
        {
            if (CurrentBar < 10)
                return;
                
            // Calculate ITrend for JAW (with 8 bar offset)
            double priceJaw = CurrentBar >= 8 ? (High[8] + Low[8]) / 2.0 : (High[0] + Low[0]) / 2.0;
            iTrendJaw[0] = GetITrend(priceJaw, Jaw, iTrendJaw);
            
            // Calculate ITrend for TEETH (with 5 bar offset)
            double priceTeeth = CurrentBar >= 5 ? (High[5] + Low[5]) / 2.0 : (High[0] + Low[0]) / 2.0;
            iTrendTeeth[0] = GetITrend(priceTeeth, Teeth, iTrendTeeth);
            
            // Calculate ITrend for LIPS (with 3 bar offset)
            double priceLips = CurrentBar >= 3 ? (High[3] + Low[3]) / 2.0 : (High[0] + Low[0]) / 2.0;
            iTrendLips[0] = GetITrend(priceLips, Lips, iTrendLips);
            
            // Set plot values
            Values[0][0] = iTrendJaw[0];
            Values[1][0] = iTrendTeeth[0];
            Values[2][0] = iTrendLips[0];
        }
        
        private double GetITrend(double price, int length, Series<double> iTrendSeries)
        {
            double alpha = 2.0 / (length + 1);
            
            if (CurrentBar < 6)
            {
                // Initialization period
                double price0 = price;
                double price1 = CurrentBar >= 1 ? ((High[1] + Low[1]) / 2.0) : price;
                double price2 = CurrentBar >= 2 ? ((High[2] + Low[2]) / 2.0) : price;
                
                return (price0 + 2 * price1 + price2) / 4.0;
            }
            else
            {
                // Get previous prices (adjusting for the offset already applied)
                double price0 = price;
                double price1 = (High[1] + Low[1]) / 2.0;
                double price2 = (High[2] + Low[2]) / 2.0;
                
                double iTrend1 = iTrendSeries[1];
                double iTrend2 = iTrendSeries[2];
                
                return (alpha - alpha * alpha / 4.0) * price0 +
                       0.5 * alpha * alpha * price1 -
                       (alpha - 0.75 * alpha * alpha) * price2 +
                       2.0 * (1.0 - alpha) * iTrend1 -
                       (1.0 - alpha) * (1.0 - alpha) * iTrend2;
            }
        }

        #region Properties
        [NinjaScriptProperty]
        [Range(1, int.MaxValue)]
        [Display(Name="Jaw", Description="Jaw Period", Order=1, GroupName="Parameters")]
        public int Jaw { get; set; }

        [NinjaScriptProperty]
        [Range(1, int.MaxValue)]
        [Display(Name="Teeth", Description="Teeth Period", Order=2, GroupName="Parameters")]
        public int Teeth { get; set; }

        [NinjaScriptProperty]
        [Range(1, int.MaxValue)]
        [Display(Name="Lips", Description="Lips Period", Order=3, GroupName="Parameters")]
        public int Lips { get; set; }

        [Browsable(false)]
        [XmlIgnore]
        public Series<double> JAW
        {
            get { return Values[0]; }
        }

        [Browsable(false)]
        [XmlIgnore]
        public Series<double> TEETH
        {
            get { return Values[1]; }
        }

        [Browsable(false)]
        [XmlIgnore]
        public Series<double> LIPS
        {
            get { return Values[2]; }
        }
        #endregion
    }
}

Comparison Table

ComponentPeriodClassic OffsetZero Lag Benefit
Lips (Green)53 BarsInstant reaction to momentum shifts
Teeth (Red)85 BarsCatches the "meat" of the move earlier
Jaw (Blue)138 BarsProvides a faster trend baseline

Final Thoughts

The Zero Lag Williams Alligator is like upgrading from a standard telescope to a high-definition radar. It doesn't change the underlying physics of the market, but it certainly makes the picture clearer and faster to react to.

Remember, the Alligator is a trend-follower. It thrives in trending markets but can get "choppy" in tight ranges. Always use it alongside volume or a momentum oscillator like the Awesome Oscillator for the best results.

NinjaTraderNinjaScriptC#Volume AnalysisBacktesting
Back to Blog