My strategies use the SetStopLoss() method in OnExcecution() with a dynamic SL-offset in Ticks that is calculated in OnBarUpdate(). I have noticed that SetStopLoss() doesn't trigger an exit order when price "jumps" above/ below the SL-level. When I say that price "jumps" I mean that the dynamic SL-level passes 0 ticks and gets negative without touching the zero-level . To avoid this problem I have added an extra "JumpStopLoss" exit in the OnBarUpdate() that catches this situations. But this extra "Jump Stop" executes one bar later and some ticks below/ above the true StopLoss compared to if SetStopLoss() would trigger also when price jumps above/below 0. How can I make the SetStopLoss() trigger also when price jumps above/ below 0?
I'v attached two screenshots and a simple as possible example code that uses your MACrossOver strategy and the OnExceution sample code. The first screen shot shows the strategy with the extra "Jumpstop" and the seccond screen shot shows the same image without the "JumpStop".
namespace NinjaTrader.Strategy
{
/// <summary>
/// Simple moving average cross over strategy.
/// </summary>
[Description("Simple moving average cross over strategy.")]
public class SL_Example_MACrossOver : Strategy
{
#region Variables
private int fast = 10;
private int slow = 25;
private double stopLoss; // StoppLoss offset in SetStopLoss()
private IOrder long1 = null; // This variable holds an object representing our entry order
private IOrder short1 = null; // This variable holds an object representing our entry order
#endregion
/// <summary>
/// This method is used to configure the strategy and is called once before any strategy method is called.
/// </summary>
protected override void Initialize()
{
SMA(Fast).Plots[0].Pen.Color = Color.Orange;
SMA(Slow).Plots[0].Pen.Color = Color.Green;
Add(SMA(Fast));
Add(SMA(Slow));
// Entry handling
EntriesPerDirection = 1;
EntryHandling = EntryHandling.UniqueEntries;
CalculateOnBarClose = true;
}
/// <summary>
/// Called on each bar update event (incoming tick).
/// </summary>
protected override void OnBarUpdate()
{ if(Position.MarketPosition == MarketPosition.Flat)
{
if (CrossAbove(SMA(Fast), SMA(Slow), 1))
{
long1 = EnterLong("Long");
}
else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
{
short1 = EnterShort("Short");
}
}
#region 1 Tick SL-strategy
// Calculate stopLoss in ticks.
// Recalculate StopLoss before position
if (Position.MarketPosition == MarketPosition.Flat)
{
stopLoss = (High[0]-Low[0])/TickSize +1;
}
// Set SL 1 tick below highest low since entry
if (Position.MarketPosition == MarketPosition.Long)
{
stopLoss = (Position.AvgPrice - MAX(Low, BarsSinceEntry() +1 )[0])/ TickSize + 1;
}
// Set SL 1 tick above lowest high since entry
else if (Position.MarketPosition == MarketPosition.Short)
{
stopLoss = (MIN(High, BarsSinceEntry() +1 )[0] - Position.AvgPrice)/ TickSize + 1;
}
/*
Print("");
Print(Time[0]);
Print("Position.AvgPrice: " + Position.AvgPrice);
Print("MIN(High, BarsSinceEntry() +1 )[0]: " + MIN(High, BarsSinceEntry() +1 )[0]);
Print("MAX(Low, BarsSinceEntry() +1 )[0]: " + MAX(Low, BarsSinceEntry() +1 )[0]);
Print("stopLoss: " + stopLoss);
Print("");
*/
[COLOR=Red]/*
//[B]EXTRA JUMP STOP[/B] - Check if the StopLoss level is hit. If price jumps above the StopLoss level , exit position since StopLoss is hit
if (Position.MarketPosition == MarketPosition.Long && Low[0] <= Position.AvgPrice - stopLoss*TickSize )
{
ExitLong("JumpStopLoss", "Long" );
}
//If price jumps below the StopLoss level , exit position since StopLoss is hit
else if (Position.MarketPosition == MarketPosition.Short && High[0] >= Position.AvgPrice + stopLoss*TickSize )
{
ExitShort("JumpStopLoss", "Short" );
}
*/[/COLOR]
#endregion
}
#region OnExecution
protected override void OnExecution(IExecution execution)
{
if (long1 != null && long1.Token == execution.Order.Token)
{
if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
{
SetStopLoss("Long", CalculationMode.Ticks, stopLoss, false);
// Resets the entryOrder object to null after the order has been partially filled
if (execution.Order.OrderState != OrderState.PartFilled)
{
long1 = null;
}
}
}
if (short1 != null && short1.Token == execution.Order.Token)
{
if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
{
SetStopLoss("Short", CalculationMode.Ticks, stopLoss, false);
// Resets the entryOrder object to null after the order has been partially filled
if (execution.Order.OrderState != OrderState.PartFilled)
{
short1 = null;
}
}
}
}
#endregion
#region Properties
/// <summary>
/// </summary>
[Description("Period for fast MA")]
[GridCategory("Parameters")]
public int Fast
{
get { return fast; }
set { fast = Math.Max(1, value); }
}
/// <summary>
/// </summary>
[Description("Period for slow MA")]
[GridCategory("Parameters")]
public int Slow
{
get { return slow; }
set { slow = Math.Max(1, value); }
}
#endregion
}
}

Comment