I have a strategy where I want to take two positions when price crosses a trailing dot indicator.
- Entries are Entry1 and Entry2.
- Entry1 has a fixed target value which may or may not get hit before going the other direction.
- Entry2 is to be held until price crosses the trail dots in the opposite direction at which point it should reverse and Entry1 enters a new position (looking again for its fixed target value) in the same direction as the now reversed Entry2.
- If for some reason both positions are flat, then if it crosses above or below the nearest swing level it is to take Entry1 & Entry2 in that direction.
Looking at this post, https://forum.ninjatrader.com/forum/ninjatrader-8/strategy-development/105571-reversing-position-command-in-strategy-builder, it says that using EnterLong() and EnterShort() , they reverse open positions. I.e, if you’re currently long qty (1) and you EnterShort() qty (1) it will actually enter Short qty (1) to close the long position and then Enter Short a second qty (1) to net the desired EnterShort() command.
So theoretically there should at all times be no more than two open positions… The Entry1 Fixed Target position, and the Entry2 Runner position. I’m finding myself with more open positions than 2 and can’t figure out why.
Any thoughts would be appreciated.
Thanks!
Here’s the code from Strategy Builder…
namespace NinjaTrader.NinjaScript.Strategies
{
public class sjrTrailBreak : Strategy
{
private WTTrailTicks WTTrailTicks1;
private Swing Swing1;
protected override void OnStateChange()
{
if (State == State.SetDefaults)
{
Description = @"Enter the description for your new custom Strategy here.";
Name = "sjrTrailBreak";
Calculate = Calculate.OnEachTick;
EntriesPerDirection = 2;
EntryHandling = EntryHandling.AllEntries;
IsExitOnSessionCloseStrategy = true;
ExitOnSessionCloseSeconds = 600;
IsFillLimitOnTouch = false;
MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
OrderFillResolution = OrderFillResolution.Standard;
Slippage = 0;
StartBehavior = StartBehavior.WaitUntilFlat;
TimeInForce = TimeInForce.Gtc;
TraceOrders = false;
RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
StopTargetHandling = StopTargetHandling.PerEntryExecution;
BarsRequiredToTrade = 20;
// Disable this property for performance gains in Strategy Analyzer optimizations
// See the Help Guide for additional information
IsInstantiatedOnEachOptimizationIteration = true;
QTY1 = 1;
QTY2 = 1;
ProfitTarget1 = 10;
ProfitTarget2 = 100;
StopLoss = 40;
}
else if (State == State.Configure)
{
}
else if (State == State.DataLoaded)
{
WTTrailTicks1 = WTTrailTicks(Close, Convert.ToInt32(StopLoss));
Swing1 = Swing(Close, 5);
WTTrailTicks1.Plots[0].Brush = Brushes.Bisque;
Swing1.Plots[0].Brush = Brushes.DarkCyan;
Swing1.Plots[1].Brush = Brushes.Goldenrod;
AddChartIndicator(WTTrailTicks1);
AddChartIndicator(Swing1);
SetProfitTarget(@"Entry1", CalculationMode.Ticks, ProfitTarget1);
SetTrailStop(@"Entry1", CalculationMode.Ticks, StopLoss, false);
SetTrailStop(@"Entry2", CalculationMode.Ticks, StopLoss, false);
}
}
protected override void OnBarUpdate()
{
if (BarsInProgress != 0)
return;
if (CurrentBars[0] < 1)
return;
// Set 1
if (CrossAbove(Close, WTTrailTicks1, 1))
{
EnterLong(Convert.ToInt32(QTY1), @"Entry1");
EnterLong(Convert.ToInt32(QTY2), @"Entry2");
}
// Set 2
if (CrossBelow(Close, WTTrailTicks1, 1))
{
EnterShort(Convert.ToInt32(QTY1), @"Entry1");
EnterShort(Convert.ToInt32(QTY2), @"Entry2");
}
// Set 3
if ((CrossAbove(Close, Swing1.SwingHigh, 1))
&& (Position.MarketPosition == MarketPosition.Flat))
{
EnterLong(Convert.ToInt32(QTY1), @"Entry1");
EnterLong(Convert.ToInt32(QTY2), @"Entry2");
}
// Set 4
if ((CrossBelow(Close, Swing1.SwingLow, 1))
&& (Position.MarketPosition == MarketPosition.Flat))
{
EnterShort(Convert.ToInt32(QTY1), @"Entry1");
EnterShort(Convert.ToInt32(QTY2), @"Entry2");
}
}
#region Properties
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="QTY1", Description="Number of contracts for Entry 1", Order=1, GroupName="Parameters")]
public int QTY1
{ get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="QTY2", Description="Number of contracts for Entry 2", Order=2, GroupName="Parameters")]
public int QTY2
{ get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="ProfitTarget1", Description="Number of ticks for Target 1", Order=3, GroupName="Parameters")]
public int ProfitTarget1
{ get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="ProfitTarget2", Description="Number of ticks for Target 2", Order=4, GroupName="Parameters")]
public int ProfitTarget2
{ get; set; }
[NinjaScriptProperty]
[Range(1, int.MaxValue)]
[Display(Name="StopLoss", Description="Number of ticks for Stop Loss", Order=5, GroupName="Parameters")]
public int StopLoss
{ get; set; }
#endregion
}
}