Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Trouble Using ExitShortLimit and ExitLongLimit in a Managed Strategy

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    Trouble Using ExitShortLimit and ExitLongLimit in a Managed Strategy

    Hi,

    I'm trying to write a Strategy using Managed entries and exist. I'm able to successfully enter the market, set an initial stop, and then modify the stop when a certain number of ticks is hit. However, when I try to establish three discrete limit orders as profit targets for the various contracts in the entry order, NinjaTrader ignores them. In the Strategy Performance window, there is no record of any of these limit orders being established. I didn't think I needed to create a discrete entry for each quantity of contracts I'm managing. Is that correct? Below, please find the offending code.

    Thanks!

    protected override void OnBarUpdate()
    {
    // We don't want to trade on the supporting Instrument. Only the main Instrument on the chart.
    if( BarsInProgress == 0 )
    {

    // A sell is indicated
    if( IsFirstTickOfBar &&
    Position.MarketPosition == MarketPosition.Flat &&
    ind.JamboIndicatorDown.IsValidDataPoint(0) )
    {
    // Entry
    EnterShort( 0, 5, "JamboStrategy Short Entry");
    SetStopLoss( "JamboStrategy Short Entry", CalculationMode.Ticks, 100, false);
    }

    if( IsFirstTickOfBar &&
    Position.MarketPosition == MarketPosition.Flat &&
    ind.JamboIndicatorUp.IsValidDataPoint(0) )
    {
    // Entry
    EnterLong( 0, 5, "JamboStrategy Long Entry");

    SetStopLoss( "JamboStrategy Long Entry", CalculationMode.Ticks, 100, false);

    }

    // When in a position, establish
    if( Position.MarketPosition == MarketPosition.Short )
    {
    ExitShortLimit( 3, Position.AveragePrice - 7*TickSize, "JamboStrategy Short Exit 1", "JamboStrategy Short Entry");
    ExitShortLimit( 1, Position.AveragePrice - 10*TickSize, "JamboStrategy Short Exit 2", "JamboStrategy Short Entry");
    ExitShortLimit( 1, Position.AveragePrice - 15*TickSize, "JamboStrategy Short Exit 3", "JamboStrategy Short Entry");
    }

    if( Position.MarketPosition == MarketPosition.Long )
    {
    ExitLongLimit( 3, Position.AveragePrice + 7*TickSize, "JamboStrategy Long Exit 1", "JamboStrategy Long Entry");
    ExitLongLimit( 1, Position.AveragePrice + 10*TickSize, "JamboStrategy Long Exit 2", "JamboStrategy Long Entry");
    ExitLongLimit( 1, Position.AveragePrice + 15*TickSize, "JamboStrategy Long Exit 3", "JamboStrategy Long Entry");
    }

    // Once we've entered a position, adjust stops when the first target is touched.

    if( Position.MarketPosition == MarketPosition.Short &&
    (Position.AveragePrice - 7*TickSize).ApproxCompare( Close[0] ) >= 0)
    {
    SetStopLoss( "JamboStrategy Short Entry", CalculationMode.Price, Position.AveragePrice -1*TickSize, false );
    }

    if( Position.MarketPosition == MarketPosition.Long &&
    (Position.AveragePrice + 7*TickSize).ApproxCompare( Close[0] ) <= 0)
    {
    SetStopLoss( "JamboStrategy Long Entry", CalculationMode.Price, Position.AveragePrice +1*TickSize, false );
    }


    }

    }​

    #2
    Hello Jambo,

    Thanks for your post.

    I see you are using Set methods (SetStopLoss()) and you are using Exit methods (ExitShortLimit() and ExitLongLimit()) in your script. This would go against the Managed Approach Internal Order Handling Rules noted in the help guide documentation below.

    Managed Approach Internal Order Handling Rules: https://ninjatrader.com/support/help...rnalOrderHandl ingRulesThatReduceUnwantedPositions

    You must use only Set methods such as SetStopLoss() or only Exit methods such as ExitLongLimit() in the script, not both.

    Please modify your strategy to use either Set methods or Exit methods in the script so it does not go against the Managed Approach Internal Order Handling Rules linked above.

    Further, this sample can assist further with managing multiple exit/entry signals:
    https://ninjatrader.com/support/helpGuides/nt8/en-us/using_multiple_entry_exit_sign.htm

    ​This reference sample can help with scaling in and out of a strategy.
    https://ninjatrader.com/suppport/helpGuides/nt8/en-us/scaling_out_of_a_position.htm

    Also, if you choose to use Set methods, the initial Set method should be called before your Entry order method as noted on the SetStopLoss() help guide page.

    For example:

    SetStopLoss();
    EnterLong();

    From the help guide: "Since they are submitted upon receiving an execution, the Set method should be called prior to submitting the associated entry order to ensure an initial level is set."

    SetStopLoss(): https://ninjatrader.com/support/help...etstoploss.htm
    Last edited by NinjaTrader_BrandonH; 10-08-2023, 05:21 PM.
    <span class="name">Brandon H.</span><span class="title">NinjaTrader Customer Service</span><iframe name="sig" id="sigFrame" src="/support/forum/core/clientscript/Signature/signature.php" frameborder="0" border="0" cellspacing="0" style="border-style: none;width: 100%; height: 120px;"></iframe>

    Comment


      #3
      Thanks, Brandon, for your helpful reply. I've taken a different stab at my entries and exits, avoiding the "Set" methods. Please find below a snippet of my code. When debugging, the Only order that gets created is the first, either "JamboStrategy Short Entry A" or "JamboStrategy Long Entry A." All other Entry, Stop, or Exit orders return null, though all are reached in the code, and are ignored (when tested in Visual Studio). I'm sure I'm overlooking something in the documentation about Managed Approach Strategies, but can you help?

      Thanks!

      Jambo

      namespace NinjaTrader.NinjaScript.Strategies
      {
      public class JimsRbEmaRbLinearRegStrategy : Strategy
      {
      JamboIndicator ind = null;
      bool initialStopSet = false;

      Order stopOrderA, stopOrderB, stopOrderC, entryOrderA, entryOrderB, entryOrderC, exitOrderA, exitOrderB, exitOrderC;

      protected override void OnStateChange()
      {
      if (State == State.SetDefaults)
      {
      Description = @"Uses JamboIndicator to enter and a 7-10-15 Tick Target strategy. Stops move to BE+1 when 7 ticks is reached.";
      Name = "JimsRbEmaRbLinearRegStrategy";
      Calculate = Calculate.OnEachTick;
      EntriesPerDirection = 1;
      EntryHandling = EntryHandling.UniqueEntries;
      IsExitOnSessionCloseStrategy = true;
      ExitOnSessionCloseSeconds = 30;
      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;

      AddPlot(new Stroke(Brushes.Red, 2), PlotStyle.TriangleDown, "JamboIndicatorSell");
      AddPlot(new Stroke(Brushes.Lime, 2), PlotStyle.TriangleUp, "JamboIndicatorBuy");
      }
      else if (State == State.Configure)
      {

      AddDataSeries(Data.BarsPeriodType.Range, RBBarSize);
      }
      else if(State == State.DataLoaded)
      {
      ind = JamboIndicator( );
      }
      }




      protected override void OnBarUpdate()
      {
      // We don't want to trade on the supporting Instrument. Only the main Instrument on the chart.
      if( BarsInProgress == 0 )
      {
      // A sell is indicated
      if( IsFirstTickOfBar &&
      Position.MarketPosition == MarketPosition.Flat &&
      ind.RbEmaRbLinRegSell.IsValidDataPoint(0) )
      {

      initialStopSet = false;

      entryOrderA = EnterShort( 0, 3, "JamboStrategy Short Entry A");
      entryOrderB = EnterShort( 0, 1, "JamboStrategy Short Entry B");
      entryOrderC = EnterShort( 0, 1, "JamboStrategy Short Entry C");

      }

      if( IsFirstTickOfBar &&
      Position.MarketPosition == MarketPosition.Flat &&
      ind.RbEmaRbLinRegBuy.IsValidDataPoint(0) )
      {
      // Entry

      initialStopSet = false;

      entryOrderA = EnterLong( 0, 3, "JamboStrategy Long Entry A");
      entryOrderB = EnterLong( 0, 1, "JamboStrategy Long Entry B");
      entryOrderC = EnterLong( 0, 1, "JamboStrategy Long Entry C");
      }


      if( Position.MarketPosition == MarketPosition.Short )
      {
      // Initial Stop
      if( !initialStopSet ) {
      // Three Stop Orders
      stopOrderA = ExitShortStopMarket( Position.AveragePrice +100*TickSize, "JamboStrategy Short Entry A");
      stopOrderB = ExitShortStopMarket( Position.AveragePrice +100*TickSize, "JamboStrategy Short Entry B");
      stopOrderC = ExitShortStopMarket( Position.AveragePrice +100*TickSize, "JamboStrategy Short Entry C");

      // Three Taget Orders
      exitOrderA = ExitShortLimit( 3, Position.AveragePrice - 7*TickSize, "JamboStrategy Short Exit 1", "JamboStrategy Short Entry A");
      exitOrderB = ExitShortLimit( 1, Position.AveragePrice - 10*TickSize, "JamboStrategy Short Exit 2", "JamboStrategy Short Entry B");
      exitOrderC = ExitShortLimit( 1, Position.AveragePrice - 15*TickSize, "JamboStrategy Short Exit 3", "JamboStrategy Short Entry C");

      initialStopSet = true;
      }
      else if( (Position.AveragePrice - 7*TickSize).ApproxCompare( Close[0] ) >= 0 )
      {
      // Once 7 ticks has been hit, move the stop to BE for all positions
      if( stopOrderA.OrderState == OrderState.Working ) {
      ChangeOrder( stopOrderA, stopOrderA.Quantity, 0, Position.AveragePrice -1*TickSize );
      ChangeOrder( stopOrderB, stopOrderB.Quantity, 0, Position.AveragePrice -1*TickSize );
      ChangeOrder( stopOrderC, stopOrderC.Quantity, 0, Position.AveragePrice -1*TickSize );}
      }

      }

      if( Position.MarketPosition == MarketPosition.Long )
      {

      // Initial Stop
      if( !initialStopSet ) {

      // Three Stop Orders all at 100 ticks initially
      stopOrderA = ExitLongStopMarket( Position.AveragePrice -100*TickSize, "JamboStrategy Long Entry A");
      stopOrderB = ExitLongStopMarket( Position.AveragePrice -100*TickSize, "JamboStrategy Long Entry B");
      stopOrderC = ExitLongStopMarket( Position.AveragePrice -100*TickSize, "JamboStrategy Long Entry C");

      // Three Taget Orders at 7 ticks, 10 ticks, and 15 ticks, respectively
      exitOrderA = ExitLongLimit( 3, Position.AveragePrice + 7*TickSize, "JamboStrategy Long Exit 1", "JamboStrategy Long Entry A");
      exitOrderB = ExitLongLimit( 1, Position.AveragePrice + 10*TickSize, "JamboStrategy Long Exit 2", "JamboStrategy Long Entry B");
      exitOrderC = ExitLongLimit( 1, Position.AveragePrice + 15*TickSize, "JamboStrategy Long Exit 3", "JamboStrategy Long Entry C");
      initialStopSet = true;
      }
      else if( (Position.AveragePrice + 7*TickSize).ApproxCompare( Close[0] ) <= 0 )
      {
      // Once 7 ticks has been hit, move the stop to BE for all positions
      if( stopOrderA.OrderState == OrderState.Working ) {
      ChangeOrder( stopOrderA, stopOrderA.Quantity, 0, Position.AveragePrice +1*TickSize );
      ChangeOrder( stopOrderB, stopOrderB.Quantity, 0, Position.AveragePrice +1*TickSize );
      ChangeOrder( stopOrderC, stopOrderC.Quantity, 0, Position.AveragePrice +1*TickSize );
      }
      }


      }




      }

      }

      Comment


        #4
        Hello Jambo,

        Thanks for your notes.

        I see in the code you shared that the EntriesPerDirection property is set to 1 and the EntryHandling property is set to UniqueEntries but your entryOrderA order has a quantity of 3

        This means that if you set EntryHandling to EntryHandling.UniqueEntries, NinjaScript will process order entry methods up to the maximum allowable entries set by the EntriesPerDirection property for each uniquely named entry.

        For example, if you have two entry order methods using unique signal names ("entry1" and "entry2"), set EntriesPerDirection to 1, and use EntryHandling.UniqueEntries, a maximum number of 1 entry orders will be processed for each uniquely named entry order (1 order for "entry1" and 1 order for "entry2").

        See the help guide documentation below for more information.

        EntriesPerDirection: https://ninjatrader.com/support/help...rdirection.htm
        EntryHandling: https://ninjatrader.com/support/help...ing.htm​

        "...and are ignored (when tested in Visual Studio)"

        You would need to test the strategy by running it on a Demo account, on the Sim101 account that comes default with NinjaTrader, or using the Playback connection in NinjaTrader. By running the strategy this way you would be able to see exactly how the strategy is behaving.

        To debug the strategy to understand why the script is behaving as it is, such as placing orders or not placing orders when expected, it is necessary to add prints to the script that print the values used for the logic of the script to understand how the script is evaluating.

        You should add debugging prints throughout the script and run the script in the Strategies tab of the Control Center or on a Chart window. Then, you could review the print Output in the New > NinjaScript Output window to see how your logic is evaluating.

        Below is a link to a forum post that demonstrates how to use prints to understand behavior.
        https://ninjatrader.com/support/foru...121#post791121

        ​Enabling a Strategy from the Control Center — https://ninjatrader.com/support/helpGuides/nt8/index.html?strategies_tab2.htm#UnderstandingTheStr ategiesTab

        Enabling a Strategy in a Chart window — https://ninjatrader.com/support/help...rategyInAChart

        Further, you could consider using OnExecutionUpdate() and OnOrderUpdate() to submit/manage your stop/targets being placed by the script.

        Here is a reference sample demonstrating the use of OnExecutionUpdate() and OnOrderUpdate() to submit protective orders: https://ninjatrader.com/support/help...xec.htm​
        <span class="name">Brandon H.</span><span class="title">NinjaTrader Customer Service</span><iframe name="sig" id="sigFrame" src="/support/forum/core/clientscript/Signature/signature.php" frameborder="0" border="0" cellspacing="0" style="border-style: none;width: 100%; height: 120px;"></iframe>

        Comment


          #5
          Thanks, Brandon. Unfortunately, when I change EntriesPerDirection to "5", instead of "1," it makes no difference. Only the first entry order of the day, in back-testing, is established and filled. Every subsequent order, be it a target order or or a stop order is ignored (each value returned by the additional target orders or stop orders is null). Either I must be doing something wrong other than the designation of the EntriesPerDirection variable, or there some problem with the Managed Approach documentation, since it seems I am using the entry and exit methods as specified.

          Comment


            #6
            Hello Jambo,

            Thanks for your notes.

            If the expected trade(s) are not appearing, this would indicate that the condition to place the order is not evaluating as true or the order is being ignored for other reasons.

            To debug the strategy to understand why the script is behaving as it is, such as placing orders or not placing orders when expected, it is necessary to add prints to the script that print the values used for the logic of the script to understand how the script is evaluating.

            You should add debugging prints throughout the script and run the script in the Strategies tab of the Control Center or on a Chart window. Then, you could review the print Output in the New > NinjaScript Output window to see how your logic is evaluating.

            Also, enable TraceOrders which will let us know if any orders are being ignored and not being submitted when the condition to place the orders is evaluating as true.

            Below is a link to a forum post that demonstrates how to use prints to understand behavior.
            https://ninjatrader.com/support/foru...121#post791121

            Further, you may consider using OnExecutionUpdate() and OnOrderUpdate() for submitting/managing protective orders. Below is a reference sample demonstrating the use of OnExecutionUpdate() and OnOrderUpdate() for placing protective orders.

            SampleOnOrderUpdate: https://ninjatrader.com/support/help...xec.htm​

            Note that when backtesting on historical data, only the Open, High, Low, and Close will be available and there will be no intra-bar data. This means actions cannot happen intra-bar, fills cannot happen intra-bar. All prices and actions come from and occur when the bar closes as this is all the information that is known.

            Because of this, OnBarUpdate will only update 'On bar close' as it does not have the intra-bar information necessary for 'On price change' or 'On each tick' and the script will not have the intra-bar information to accurately fill an order at the exact price and time.

            Below is a link to the help guide on Calculate.
            https://ninjatrader.com/support/help.../calculate.htm

            This means by default when backtesting no intra-bar granularity is added. Intrabar granularity could be added to the script by enabling Tick Replay, adding a 1-Tick secondary series to the script, and submitting orders to that 1-Tick series.

            Here is a forum thread detailing intrabar granularity: https://forum.ninjatrader.com/forum/...t773377​
            Last edited by NinjaTrader_BrandonH; 10-10-2023, 11:42 AM.
            <span class="name">Brandon H.</span><span class="title">NinjaTrader Customer Service</span><iframe name="sig" id="sigFrame" src="/support/forum/core/clientscript/Signature/signature.php" frameborder="0" border="0" cellspacing="0" style="border-style: none;width: 100%; height: 120px;"></iframe>

            Comment


              #7
              Hi Brandon, Thanks for the extensive information. Adding Prints and turning TraceOrders on has added valuable information. It allowed me to discover that the the Global EntriesPerDirection value on the NinjaTrader UI apparently takes precedence over any attempt to set this value within the OnStateChange block in the Strategy code. I'm now able to create three distinct Entry trades. Now, on to determining why my Exits don't seem to be firing. TraceOrders is very helpful. Thanks again for your help. I'll let you know if I run into any additional, intractable problems.

              Comment

              Latest Posts

              Collapse

              Topics Statistics Last Post
              Started by NullPointStrategies, Today, 05:17 AM
              0 responses
              50 views
              0 likes
              Last Post NullPointStrategies  
              Started by argusthome, 03-08-2026, 10:06 AM
              0 responses
              126 views
              0 likes
              Last Post argusthome  
              Started by NabilKhattabi, 03-06-2026, 11:18 AM
              0 responses
              69 views
              0 likes
              Last Post NabilKhattabi  
              Started by Deep42, 03-06-2026, 12:28 AM
              0 responses
              42 views
              0 likes
              Last Post Deep42
              by Deep42
               
              Started by TheRealMorford, 03-05-2026, 06:15 PM
              0 responses
              46 views
              0 likes
              Last Post TheRealMorford  
              Working...
              X