NinjaScript managed Strategy

Build a NinjaScript Trailing Stop Strategy

Write the entry, exit, stop unit, distance, signal name, and bar timing as explicit rules. Pineify can turn that specification into one editable NT8 Strategy file for review and static checking.

EmaTrailExample.cs
Complete Strategy
using System.ComponentModel.DataAnnotations;
using NinjaTrader.Cbi;
using NinjaTrader.NinjaScript;

namespace NinjaTrader.NinjaScript.Strategies
{
    public class EmaTrailExample : Strategy
    {
        private const string LongSignal = "LongEntry";

        protected override void OnStateChange()
        {
            if (State == State.SetDefaults)
            {
                Name = "EmaTrailExample";
                Calculate = Calculate.OnBarClose;
                BarsRequiredToTrade = 50;
                TrailTicks = 12;
            }
            else if (State == State.Configure)
            {
                SetTrailStop(
                    LongSignal,
                    CalculationMode.Ticks,
                    TrailTicks,
                    false);
            }
        }

        protected override void OnBarUpdate()
        {
            if (CurrentBar < BarsRequiredToTrade)
                return;

            if (Position.MarketPosition == MarketPosition.Flat
                && CrossAbove(SMA(20), SMA(50), 1))
                EnterLong(1, LongSignal);

            if (Position.MarketPosition == MarketPosition.Long
                && CrossBelow(SMA(20), SMA(50), 1))
                ExitLong("LongExit", LongSignal);
        }

        [NinjaScriptProperty]
        [Range(1, 500)]
        [Display(Name = "Trail ticks", GroupName = "Risk", Order = 0)]
        public int TrailTicks { get; set; }
    }
}

The 20 and 50 EMA crossover and 12-tick trail are illustrative test inputs. They are not a recommendation or expected return.

Direct answer

Use SetTrailStop before the associated entry is submitted. For a fixed managed trailing stop, call it in State.Configure with a stable fromEntrySignal, CalculationMode, and distance. SetTrailStop follows favorable price movement according to the Strategy calculation frequency. Compile and test the Strategy in NinjaTrader because a static check cannot validate fills, stop behavior, or performance.

What to know first

  • SetTrailStop should be active before the matching EnterLong or EnterShort call.
  • The fromEntrySignal must match the entry signal name exactly.
  • For one position, SetStopLoss takes precedence if it is also active for the same signal.
  • Ticks, Pips, and Percent are supported calculation modes for SetTrailStop; Price and Currency are not.

What SetTrailStop controls

SetTrailStop defines a managed stop that can follow a position as price moves in its favor. NinjaTrader updates the stop based on the Strategy Calculate setting. Calculate.OnBarClose means the strategy processes the rule after a bar closes; it does not request intrabar updates.

The distance unit is explicit. With CalculationMode.Ticks, a value of 12 means twelve instrument ticks. Percent and Pips use different units. Do not copy the same numeric value across modes and assume the risk is unchanged.

Associate the stop with the entry signal

The example declares LongEntry once and uses it in both SetTrailStop and EnterLong. That string association tells the managed approach which entry the protective order belongs to. A spelling change in one call can break the intended relationship.

The exit also passes LongEntry as its fromEntrySignal. Stable names make entry, exit, and protection reviewable as one unit. They also matter when a Strategy has more than one entry path.

  • Declare signal names once when they are reused.
  • Gate the entry with Position.MarketPosition when duplicate submissions are not intended.
  • Keep each exit tied to the intended entry signal.

Choose fixed or dynamic trailing logic

A fixed trail can be configured in State.Configure, as shown. A dynamic value can be set from OnBarUpdate before entry, but it must be reset when the Strategy returns to flat or the last value can carry into a later trade. The exact reset rule should be visible in the source.

SetTrailStop should not compete with SetStopLoss or SetParabolicStop for the same position. NinjaTrader documents that SetStopLoss takes precedence when both target the same position. Choose one protection model for that signal unless you have a tested reason to change it.

Separate entry logic from risk behavior

The EMA crossover in the sample makes the order flow easy to see. It does not establish that a 20 and 50 EMA system has an edge. The Strategy still needs commission, slippage, session, instrument, data quality, and order-state assumptions stated before its results can be interpreted.

When reviewing a generated Strategy, check entry frequency, Calculate mode, position gating, signal names, quantity, stop units, and behavior after a rejected or partial order. A clean compile does not answer those questions.

Compile and test the stop in NinjaTrader 8

Pineify can generate one complete Strategy source file and run a static C# and supported API check. Move the resulting file into NinjaScript Editor, compile it, and resolve any installation-specific errors. Then use Strategy Analyzer and simulation to observe the actual order sequence.

Inspect individual trades, not only summary metrics. Confirm the initial stop distance, each favorable update, exit association, flat-state reset, gaps, session transitions, and behavior on the intended Calculate mode. Test unseen data separately from the period used to design the rule.

Practical checks I use

Write the unit beside the number

I record 12 ticks, 1 percent, or another explicit unit in the specification. A bare stop value is not enough to review the risk.

Trace one signal end to end

I compare the string used by SetTrailStop, EnterLong, and ExitLong. One mismatch can detach protection or close a different entry path.

Inspect the actual order sequence

I use Strategy Analyzer and simulation to verify when the stop appears and moves. Static acceptance cannot establish runtime order behavior.

Primary sources

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.

Frequently asked questions

Turn Explicit Stop Rules Into NinjaScript

State the entry, exit, trail unit, distance, and bar timing. Inspect one complete Strategy file before testing it in NinjaTrader 8.

Build a Trailing Stop Strategy