Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Two separate OCOs for a given entry

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

    Two separate OCOs for a given entry

    Hi,

    I have written a strategy that enters say a 2 lot with a near and wide profit target for each individual 1 lot. Both 1 lots have a trailing stop loss as well.

    Problem: I currently only have one IOrder entryOrder which both OCOs are related to. If I get a nearProfitTarget fill for 1 lot and the price then retraces, my nearStopLoss triggers rather than my wideStopLoss. So, is it more efficient/elegant/correct to code up the strategy with

    [A] two separate entry orders: nearEntryOrder and wideEntryOrder, or
    [B] to set the nearStopLoss to null if the nearProfitTarget gets hit and vice-versa, and in doing so leaving just the wideProfitTarget and wideStopLoss to act as required?

    Thanks,
    darmbk.

    #2
    Hello,

    I would recommend option B, where you're setting the stop loss to null after the profit target has been hit, etc.

    Please let me know if you have any questions on how to accomplish this.
    MatthewNinjaTrader Product Management

    Comment


      #3
      Hi Matthew,

      The following code snippet was intended to nullify a partner stop or profit order if the other was employed. However I am still getting the stopOrderNear being actioned after the profitTargetNear has been hit so something is not correct? Otherwise, can you suggest how to accomplish this please?

      Thanks,
      Dar.


      protected override void OnExecution(IExecution execution)
      {
      .....
      if ((stopOrderNear != null && stopOrderNear == execution.Order) || (targetOrderNear != null && targetOrderNear == execution.Order))
      {
      if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled)
      {
      stopOrderNear = null;
      targetOrderNear = null;
      }
      }

      if ((stopOrderWide != null && stopOrderWide == execution.Order) || (targetOrderWide != null && targetOrderWide == execution.Order))
      {
      if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled)
      {
      stopOrderWide = null;
      targetOrderWide = null;
      }
      }
      }

      Comment


        #4
        Are you actually canceling the order somewhere? Or just setting it to null in OnExecution?

        As a refresher, please take a look at the Using CancelOrder() method:

        When using NinjaTrader's Enter() and Exit() methods, the default behavior is to automatically expire them at the end of a bar unless they are resubmitted to keep them alive. Sometimes you may want more flexibility in this behavior and wish to submit orders as live-until-cancelled. When orders are submitted as live-until
        MatthewNinjaTrader Product Management

        Comment


          #5
          This is the complete listing of OnExecution. I am setting the entry order to null upon execution.

          protected override void OnExecution(IExecution execution)
          {
          /* We advise monitoring OnExecution to trigger submission of stop/target orders instead of OnOrderUpdate() since OnExecution() is called after OnOrderUpdate()
          which ensures your strategy has received the execution which is used for internal signal tracking. */
          if (entryOrder != null && entryOrder == execution.Order)
          {
          if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
          {
          mostProfitablePriceSinceFillPrice = execution.Order.AvgFillPrice;

          if (execution.MarketPosition == MarketPosition.Long)
          {
          // Stop-Loss order below our entry price
          stopOrderNear = ExitLongStop(0, true, 1, execution.Order.AvgFillPrice - stopTargetNear * TickSize, "MyNearStop", "MyEntry");
          stopOrderWide = ExitLongStop(0, true, 1, execution.Order.AvgFillPrice - stopTargetWide * TickSize, "MyWideStop", "MyEntry");

          // Target order above our entry price
          targetOrderNear = ExitLongLimit(0, true, 1, execution.Order.AvgFillPrice + profitTargetNear * TickSize, "MyNearTarget", "MyEntry");
          targetOrderWide = ExitLongLimit(0, true, 1, execution.Order.AvgFillPrice + profitTargetWide * TickSize, "MyWideTarget", "MyEntry");
          }
          else if (execution.MarketPosition == MarketPosition.Short)
          {
          // Stop-Loss order below our entry price
          stopOrderNear = ExitShortStop(0, true, 1, execution.Order.AvgFillPrice + stopTargetNear * TickSize, "MyNearStop", "MyEntry");
          stopOrderWide = ExitShortStop(0, true, 1, execution.Order.AvgFillPrice + stopTargetWide * TickSize, "MyWideStop", "MyEntry");

          // Target order above our entry price
          targetOrderNear = ExitShortLimit(0, true, 1, execution.Order.AvgFillPrice - profitTargetNear * TickSize, "MyNearTarget", "MyEntry");
          targetOrderWide = ExitShortLimit(0, true, 1, execution.Order.AvgFillPrice - profitTargetWide * TickSize, "MyWideTarget", "MyEntry");
          }

          // Resets the entryOrder object to null after the order has been filled
          if (execution.Order.OrderState != OrderState.PartFilled)
          {
          entryOrder = null;
          }
          }
          }

          // Reset our stop order and target orders' IOrder objects after our position is closed.
          if ((stopOrderNear != null && stopOrderNear == execution.Order) || (targetOrderNear != null && targetOrderNear == execution.Order))
          {
          if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled)
          {
          stopOrderNear = null;
          targetOrderNear = null;
          }
          }

          if ((stopOrderWide != null && stopOrderWide == execution.Order) || (targetOrderWide != null && targetOrderWide == execution.Order))
          {
          if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled)
          {
          stopOrderWide = null;
          targetOrderWide = null;
          }
          }
          }

          Comment


            #6
            Thanks for the clarification - see what you mean now.

            In this case, it'd be easier to have a separate entry order for each stop and target and set those per the entrySignal name.

            Please see the attached and let me know if you have any questions
            Attached Files
            MatthewNinjaTrader Product Management

            Comment


              #7
              Hi Matthew,

              I have made these edits but am only getting one entry order occurring and not the two we are looking for. Any thoughts as to why this would happen? My two entry orders are actioned together in the code so there should be no reason that any conditions are to blame.

              entryOrderNear = EnterLong(1, "MyNearEntry");
              entryOrderWide = EnterLong(1, "MyWideEntry");

              I attach the test code I have so far.

              Thanks,
              darmbk.
              Attached Files

              Comment


                #8
                You will want to make sure you have changed the "entries per direction" to at least 2 to process additional signals.

                You could also set the Entry Handling to "Unique Entries" and leave the entries per direction to 1.

                This si configured from the Order Handling section of the strategy parameters before you backtest or start live.
                MatthewNinjaTrader Product Management

                Comment


                  #9
                  Hi Matthew,

                  Thanks for solving my problem. Just to add to what you have told me based on my review of the EntryHandling entry in the Language Reference (example shown below). I believe that if I specified AllEntries and EntriesPerDirection = 2 it is possible that I could get two SMA crossover entries and no RSI cross entries if the conditions were right for the former and not the latter over two or more consecutive bar updates. Correct?

                  // Example #2
                  // EnterLong() will be processed once for each uniquely named entry.
                  protected override void Initialize()
                  {
                  EntriesPerDirection = 1;
                  EntryHandling = EntryHandling.UniqueEntries;
                  }

                  protected override void OnBarUpdate()
                  {
                  if (CrossAbove(SMA(10), SMA(20), 1)
                  EnterLong("SMA Cross Entry");

                  if (CrossAbove(RSI(14, 3), 30, 1)
                  EnterLong("RSI Cross Entry);

                  Comment


                    #10
                    If you set AllEntires and Entries Per Direction to 2, the strategy was no longer process any entry signals once there are a total 2 entries, regardless of the signal name.

                    This means if you had 2 SMA Cross Entries, all RSI Cross Entry would be ignored and vice versa

                    Since you're using AllEntires, you could end up with 1 Entry on SMA and another on RSI, and it would no longer take any entries since the total will now be 2.

                    Switching to Unique entries would allow up to 2 entries per each entry name. This means you could have 2 entries on SMA and 2 on the RSI at the same time.
                    MatthewNinjaTrader Product Management

                    Comment

                    Latest Posts

                    Collapse

                    Topics Statistics Last Post
                    Started by Geovanny Suaza, 02-11-2026, 06:32 PM
                    0 responses
                    648 views
                    0 likes
                    Last Post Geovanny Suaza  
                    Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                    0 responses
                    369 views
                    1 like
                    Last Post Geovanny Suaza  
                    Started by Mindset, 02-09-2026, 11:44 AM
                    0 responses
                    108 views
                    0 likes
                    Last Post Mindset
                    by Mindset
                     
                    Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                    0 responses
                    572 views
                    1 like
                    Last Post Geovanny Suaza  
                    Started by RFrosty, 01-28-2026, 06:49 PM
                    0 responses
                    574 views
                    1 like
                    Last Post RFrosty
                    by RFrosty
                     
                    Working...
                    X