I'm encountering an issue with my custom NinjaTrader strategy with ninjascript (originially with strategy builder, then I unlocked the code), and I'm hoping someone here might be able to shed some light on it. The strategy is designed to calculate and track the high and low of a specific time zone (a 30m zone from 9:30 AM EST to 9:59 AM EST and then use those values during a breakout strategy that must have a breakout within the next 10 minutes of the zone (10:00am - 10:10am).
The problem arises right at the end of the zone timeframe (9:59 AM). For some reason, towards the very last bar of the zone, the ZoneHigh and ZoneLow values seem to revert to the Close of the same bar instead of remaining consistent. Here’s a snippet of the ninjascript output (ZoneHigh should be 5941.75, and ZoneLow should be 5924.5 as seen on some of the lines in output):
ZoneHigh is 5926.25at 11/15/2024 6:58:59 AM ZoneLow is 5926.25at 11/15/2024 6:58:59 AM ZoneHigh is 5926.25at 11/15/2024 6:58:59 AM ZoneLow is 5926.25at 11/15/2024 6:58:59 AM ZoneHigh is 5941.75at 11/15/2024 6:59:00 AM ZoneLow is 5924.5at 11/15/2024 6:59:00 AM ZoneHigh is 5941.75at 11/15/2024 6:59:00 AM ZoneLow is 5924.5at 11/15/2024 6:59:00 AM ZoneHigh is 5941.75at 11/15/2024 6:59:00 AM ZoneLow is 5924.5at 11/15/2024 6:59:00 AM ZoneHigh is 5941.75at 11/15/2024 6:59:00 AM ZoneLow is 5924.5at 11/15/2024 6:59:00 AM ZoneHigh is 5926.25at 11/15/2024 6:58:59 AM ZoneLow is 5926.25at 11/15/2024 6:58:59 AM
I’ve been trying to debug this for many hours but can’t seem to figure out why the ZoneHigh and ZoneLow are not consistent at the end of the period. Here is my code:
namespace NinjaTrader.NinjaScript.Strategies
{
public class Dero30mStrat : Strategy
{
private double ZoneHigh;
private double ZoneLow;
private bool ZoneComplete;
private bool TradeEntered;
private int Period;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = @"Enter the description for your new custom Strategy here.";
Name = "Dero30mStrat";
Calculate = Calculate.OnEachTick;
EntriesPerDirection = 1;
EntryHandling = EntryHandling.AllEntries;
IsExitOnSessionCloseStrategy = true;
ExitOnSessionCloseSeconds = 30;
IsFillLimitOnTouch = false;
MaximumBarsLookBack = MaximumBarsLookBack.Infinite;
OrderFillResolution = OrderFillResolution.Standard;
Slippage = 0;
StartBehavior = StartBehavior.WaitUntilFlat;
TimeInForce = TimeInForce.Gtc;
TraceOrders = false;
RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
StopTargetHandling = StopTargetHandling.ByStrategyPosition;
BarsRequiredToTrade = 20;
// Disable this property for performance gains in Strategy Analyzer optimizations
// See the Help Guide for additional information
IsInstantiatedOnEachOptimizationIteration = true;
ZoneStartTime = DateTime.Parse("06:30", System.Globalization.CultureInfo.InvariantCulture);
ZoneEndTime = DateTime.Parse("6:59", System.Globalization.CultureInfo.InvariantCulture);
BreakoutStartTime = DateTime.Parse("7:00", System.Globalization.CultureInfo.InvariantCulture);
BreakoutEndTime = DateTime.Parse("7:10", System.Globalization.CultureInfo.InvariantCulture);
TicksAboveHigh = 1;
TicksBelowLow = 1;
ProfitTargetTicks = 14;
StopLossTicks = 14;
ZoneHigh = 0;
ZoneLow = 0;
ZoneComplete = false;
TradeEntered = false;
Period = 30;
}
else if (State == State.Configure)
{
AddDataSeries("ES 12-24", Data.BarsPeriodType.Minute, 1, Data.MarketDataType.Last);
AddDataSeries("ES 12-24", Data.BarsPeriodType.Tick, 1, Data.MarketDataType.Last);
SetProfitTarget("", CalculationMode.Ticks, ProfitTargetTicks);
SetStopLoss("", CalculationMode.Ticks, StopLossTicks, false);
}
}
protected override void OnBarUpdate()
{
if (CurrentBar < Period)
return;
if (Bars.IsFirstBarOfSession)
{
ZoneHigh = High[0];
ZoneLow = Low[0];
// ZoneComplete = false;
Print("ZoneHigh At Start is " + ZoneHigh + "at " + Time[0]);
Print("ZoneHigh At Start is " + ZoneLow + "at " + Time[0]);
Print("Bar number " + CurrentBar + " was the first bar processed of the session at " + Time[0]);
}
// Set 1
// Set Zone High and Low within the specified time range
if ((Times[0][0].TimeOfDay >= ZoneStartTime.TimeOfDay)
&& (Times[0][0].TimeOfDay <= ZoneEndTime.TimeOfDay))
{
ZoneHigh = High[HighestBar(High, Period)];
ZoneLow = Low[LowestBar(Low, Period)];
Print("ZoneHigh is " + ZoneHigh + " at " + Time[0]);
Print("ZoneLow is " + ZoneLow + " at " + Time[0]);
}
// Set 2
// Mark the zone as complete after ZoneEndTime
// if (Times[0][0].TimeOfDay >= ZoneEndTime.TimeOfDay)
// {
// ZoneComplete = true;
// }
// Set 3
// Entry Conditions
if (
// Time is between breakoutstart and end time
((Times[0][0].TimeOfDay >= BreakoutStartTime.TimeOfDay)
&& (Times[0][0].TimeOfDay <= BreakoutEndTime.TimeOfDay))
// price goes above zone
&& (CrossAbove(Close, ZoneHigh, 1))
// && (ZoneComplete == true)
&& (TradeEntered == false)
&& (BarsInProgress == 1))
{
EnterLong(1, Convert.ToInt32(DefaultQuantity), @"Long");
TradeEntered = true;
}
// Set 4
else if (
// Time is between breakoutstart and end time
((Times[0][0].TimeOfDay >= BreakoutStartTime.TimeOfDay)
&& (Times[0][0].TimeOfDay <= BreakoutEndTime.TimeOfDay))
// price goes below zone
&& (CrossBelow(Close, ZoneLow, 1))
// && (ZoneComplete == true)
&& (TradeEntered == false)
&& (BarsInProgress == 1))
{
EnterShort(1, Convert.ToInt32(DefaultQuantity), @"Short");
TradeEntered = true;
}
// Set 5
// Reset trade entry flag after BreakoutEndTime to allow trades on next day
if (Times[0][0].TimeOfDay > BreakoutEndTime.TimeOfDay)
{
TradeEntered = false;
}
}
#region Properties
[NinjaScriptProperty]
[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
[Display(Name="ZoneStartTime", Order=1, GroupName="Parameters")]
public DateTime ZoneStartTime
{ get; set; }
[NinjaScriptProperty]
[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
[Display(Name="ZoneEndTime", Order=2, GroupName="Parameters")]
public DateTime ZoneEndTime
{ get; set; }
[NinjaScriptProperty]
[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
[Display(Name="BreakoutStartTime", Order=3, GroupName="Parameters")]
public DateTime BreakoutStartTime
{ get; set; }
[NinjaScriptProperty]
[PropertyEditor("NinjaTrader.Gui.Tools.TimeEditorKey")]
[Display(Name="BreakoutEndTime", Order=4, GroupName="Parameters")]
public DateTime BreakoutEndTime
{ get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="TicksAboveHigh", Order=5, GroupName="Parameters")]
public int TicksAboveHigh
{ get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="TicksBelowLow", Order=6, GroupName="Parameters")]
public int TicksBelowLow
{ get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="ProfitTargetTicks", Order=7, GroupName="Parameters")]
public int ProfitTargetTicks
{ get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="StopLossTicks", Order=8, GroupName="Parameters")]
public int StopLossTicks
{ get; set; }
#endregion
}
}
Has anyone run into a similar issue, or could someone suggest what might be causing this behavior? Any help would be greatly appreciated!

Comment