Managed NinjaScript MACD Crossover Strategy
A complete single-file NinjaTrader 8 Strategy featuring MACD signal line crossover detection, optional positive zero-line trend filtering, and managed tick brackets.
using System;
using System.ComponentModel.DataAnnotations;
using NinjaTrader.Cbi;
using NinjaTrader.NinjaScript;
using NinjaTrader.NinjaScript.Indicators;
namespace NinjaTrader.NinjaScript.Strategies
{
public class MacdCrossoverStrategy : Strategy
{
[NinjaScriptProperty]
[Range(1, 100)]
[Display(Name = "Fast Period", GroupName = "Parameters", Order = 0)]
public int FastPeriod { get; set; }
[NinjaScriptProperty]
[Range(2, 200)]
[Display(Name = "Slow Period", GroupName = "Parameters", Order = 1)]
public int SlowPeriod { get; set; }
[NinjaScriptProperty]
[Range(1, 100)]
[Display(Name = "Smooth Period", GroupName = "Parameters", Order = 2)]
public int SmoothPeriod { get; set; }
[NinjaScriptProperty]
[Display(Name = "Require Positive MACD for Longs", GroupName = "Filters", Order = 3)]
public bool RequirePositiveMacd { get; set; }
[NinjaScriptProperty]
[Range(1, 200)]
[Display(Name = "Profit Target (Ticks)", GroupName = "Risk", Order = 4)]
public int TargetTicks { get; set; }
[NinjaScriptProperty]
[Range(1, 200)]
[Display(Name = "Stop Loss (Ticks)", GroupName = "Risk", Order = 5)]
public int StopLossTicks { get; set; }
private MACD macd;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Name = "MacdCrossoverStrategy";
Description = "MACD signal line crossover strategy with optional zero-line filter.";
Calculate = Calculate.OnBarClose;
EntriesPerDirection = 1;
EntryHandling = EntryHandling.AllEntries;
IsExitOnSessionCloseStrategy = true;
ExitOnSessionCloseSeconds = 30;
FastPeriod = 12;
SlowPeriod = 26;
SmoothPeriod = 9;
RequirePositiveMacd = false;
TargetTicks = 20;
StopLossTicks = 15;
}
else if (State == State.DataLoaded)
{
macd = MACD(FastPeriod, SlowPeriod, SmoothPeriod);
SetProfitTarget("MacdLong", CalculationMode.Ticks, TargetTicks);
SetStopLoss("MacdLong", CalculationMode.Ticks, StopLossTicks, false);
SetProfitTarget("MacdShort", CalculationMode.Ticks, TargetTicks);
SetStopLoss("MacdShort", CalculationMode.Ticks, StopLossTicks, false);
}
}
protected override void OnBarUpdate()
{
if (CurrentBar < Math.Max(FastPeriod, SlowPeriod) + SmoothPeriod)
return;
bool macdCrossAbove = CrossAbove(macd.Default, macd.Avg, 1);
bool macdCrossBelow = CrossBelow(macd.Default, macd.Avg, 1);
if (Position.MarketPosition == MarketPosition.Flat)
{
if (macdCrossAbove && (!RequirePositiveMacd || macd.Default[0] > 0))
{
EnterLong("MacdLong");
}
else if (macdCrossBelow && (!RequirePositiveMacd || macd.Default[0] < 0))
{
EnterShort("MacdShort");
}
}
}
}
}