Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Issue with setting up Stop loss orders reliably in OnExecutionUpdate for partial fill

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

    Issue with setting up Stop loss orders reliably in OnExecutionUpdate for partial fill

    I developed a breakout strategy and the initial stop loss and take profit order setup is based on SampleOnOrderUpdate.

    I deployed the strategy this morning to two of my Apex eval accounts each with trade size = 2. The entry orders were filled right after cash session opened, but only 1 stop loss/profit target order was setup, so a profitable trade ended to be a loss.

    I just tried replay with Enforce Partial Fills and the behavior is correct, the number of stop loss/take profit orders is the same as then entry order.

    What's the best way to isolate the root cause of this issue if this is not a known issue?

    #2
    Hello FutureDragon,

    If some of the targets are not being submitted you would need to check if the logic is happening correctly when the entry fills. You can use prints in that use case to better understand what your logic was doing at that time to get an idea of there is some kind of an error in the logic.

    Comment


      #3
      Jesse, the logic is the same as what's in the sample, and has been tested in analyzer and replay many weeks, and the issue only happens in live system (Apex eval), and I am not able to reproduce the issue any other way, as things behave correctly on SIM, or replay. In the meantime, I will add prints, but it's not going to help for the issue without a way to reproduce the behavior. I can share the log with you if it helps to rule out the issue is from the system.

      Comment


        #4
        Hello FutureDragon,

        Not all live data providers work the same for OnExecution events so you would still need to debug what you made. Without knowing what the specific problem is in the code we would just be guessing at what may be happening. If the target was not submitted at all that points to the logic in OnExecutionUpdate which is observing the entry fill.

        Comment


          #5
          Jesse, the stop loss/target was only submitted for one out of two contracts and the log showed a partial fill, so I concluded that partial fill has something to do with this issue.

          Good point about data provider. I am reviewing posts on Rithimic and OnExecutionUpdate right now.

          Reviewing the code, if the data provider (Rithimic) doesn't always provide the expected execution.Order.Filled field, then this could happen.

          Below is my version of OnExecutionUpdate based on the SampleOnOrderUpdate.

          protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)
          {
          /* 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))
          {
          // We sum the quantities of each execution making up the entry order
          sumFilled += execution.Quantity;

          if (marketPosition == MarketPosition.Long)
          {
          // Submit exit orders for partial fills
          if (execution.Order.OrderState == OrderState.PartFilled)
          {
          //if (UseStopLoss)
          // stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, execution.Order.AverageFillPrice - TickSize * StopLossTicks, stopSignal, entrySignal);
          ExitLongStopMarketWithRetry(execution);

          targetOrder = ExitLongLimit(1, true, execution.Order.Filled, execution.Order.AverageFillPrice + ProfitTargetTicks * TickSize, targetSignal, entrySignal);
          }
          // Update our exit order quantities once orderstate turns to filled and we have seen execution quantities match order quantities
          else if (execution.Order.OrderState == OrderState.Filled && sumFilled == execution.Order.Filled)
          {
          // Stop-Loss order for OrderState.Filled
          ExitLongStopMarketWithRetry(execution);

          targetOrder = ExitLongLimit(1, true, execution.Order.Filled, execution.Order.AverageFillPrice + ProfitTargetTicks * TickSize, targetSignal, entrySignal);
          }
          }
          else if (marketPosition == MarketPosition.Short)
          {
          // Submit exit orders for partial fills
          if (execution.Order.OrderState == OrderState.PartFilled)
          {
          ExitShortStopMarketWithRetry(execution);

          targetOrder = ExitShortLimit(1, true, execution.Order.Filled, execution.Order.AverageFillPrice - ProfitTargetTicks * TickSize, targetSignal, entrySignal);
          }
          // Update our exit order quantities once orderstate turns to filled and we have seen execution quantities match order quantities
          else if (execution.Order.OrderState == OrderState.Filled && sumFilled == execution.Order.Filled)
          {
          // Stop-Loss order for OrderState.Filled
          ExitShortStopMarketWithRetry(execution);

          targetOrder = ExitShortLimit(1, true, execution.Order.Filled, execution.Order.AverageFillPrice - ProfitTargetTicks * TickSize, targetSignal, entrySignal);
          }


          }

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

          // Reset our stop order and target orders' Order objects after our position is closed. (1st Entry)
          if ((stopOrder != null && stopOrder == execution.Order) || (targetOrder != null && targetOrder == execution.Order))
          {
          if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled)
          {
          stopOrder = null;
          targetOrder = null;
          }
          }
          }​

          Comment


            #6
            Hello FutureDragon,

            If a partial fill happens you would have to account for that. I wouldn't be able to say what may have happened based on seeing the code. You would need to know how the code executed in that use case to understand why the order was not submitted. I would suggest adding prints and then check how the logic you have is working when a partial fill happens.

            Comment


              #7
              I think I found the root cause, and it's documented here: https://ninjatrader.com/support/help...rderupdate.htm

              "•Rithmic and Interactive Brokers Users: When using a NinjaScript strategy it is best practice to only work with passed by value data from OnExecution. Instances of multiple fills at the same time for the same instrument might result in an incorrect OnPositionUpdate, as sequence of events are not guaranteed due to provider API design."

              I suggest someone update the SampleOnOrderUpdate to avoid other people running into the same issue on live system.
              Last edited by FutureDragon; 12-08-2022, 05:23 PM.

              Comment


                #8
                Hello FutureDragon,

                As mentioned in post 4 not all brokers work the same for those events, to find out the problem you need to debug your individual script to see where its having an issue. If you see that there is a discrepancy in the events for the broker you are using then you would have to make modifications to account for that. The SampleOnOrderUpdate is a generic sample that applies to most brokers, if you use a broker which does not get the same events that the majority of other brokers support then that sample may work differently in your use case. You can find a different sample that was posted on the forum here: https://ninjatrader.com/support/foru...98#post1125798

                Comment


                  #9
                  Thanks Jesse. I will update my strategy based on the UnmanagedOnOrderUpdate. The difficulty of debugging issues like this is the issue only happens for real account, so I have to loss money to debug the issue. Would the events behave the same for SIM accounts?

                  Comment


                    #10
                    Hello FutureDragon,

                    For some brokers no they will not behave the same as the sim account, that is what the note in the help guide is relaying. Some brokers produce events that are not in the order that other brokers use so they would not work with existing OnOrderUpdate/OnExecutionUpdate examples. The sim account and samples that we provide apply to the majority of brokers excluding the ones mentioned in the help guide. For your script you would have to debug it to see if you are running into an issue surrounding the order of events or some other part of your logic because apex is not directly mentioned in the help guide.

                    Comment


                      #11
                      Originally posted by NinjaTrader_Jesse View Post
                      Hello FutureDragon,

                      For some brokers no they will not behave the same as the sim account, that is what the note in the help guide is relaying. Some brokers produce events that are not in the order that other brokers use so they would not work with existing OnOrderUpdate/OnExecutionUpdate examples. The sim account and samples that we provide apply to the majority of brokers excluding the ones mentioned in the help guide. For your script you would have to debug it to see if you are running into an issue surrounding the order of events or some other part of your logic because apex is not directly mentioned in the help guide.
                      I'm currently testing a strategy in simulation with one contract on ES. Would running the strategy with 100 contracts (in simulation) give me some indication of what might happen in live with 100 contracts (using a CQG demo feed currently)? Where are the code samples for handling partial order fills/checking order fill status?

                      Comment


                        #12
                        Hello mballagan,

                        The simulation engine does allow for part fills so you can get an idea of what would happen in realtime. It seems this question is only loosely related to this thread, if you have follow up questions please start a new thread so we can assist in more detail.

                        There is a sample in the following link that shows how you can use OnExecutionUpdate to check for different order states. The partial fill state is checked for in that sample however because it uses 1 quantity the targets are not updated. If you wanted to support part fills you would need to use the execution object to get the Order object, inside the Order object you can find the quantity and the filled amount. You can use the filled amount as the quantity for the target in part filled situations to match the partial amount.

                        https://ninjatrader.com/support/help...ub=CancelOrder

                        https://ninjatrader.com/support/help.../execution.htm
                        https://ninjatrader.com/support/help.../nt8/order.htm

                        Comment

                        Latest Posts

                        Collapse

                        Topics Statistics Last Post
                        Started by NullPointStrategies, Yesterday, 05:17 AM
                        0 responses
                        62 views
                        0 likes
                        Last Post NullPointStrategies  
                        Started by argusthome, 03-08-2026, 10:06 AM
                        0 responses
                        134 views
                        0 likes
                        Last Post argusthome  
                        Started by NabilKhattabi, 03-06-2026, 11:18 AM
                        0 responses
                        75 views
                        0 likes
                        Last Post NabilKhattabi  
                        Started by Deep42, 03-06-2026, 12:28 AM
                        0 responses
                        45 views
                        0 likes
                        Last Post Deep42
                        by Deep42
                         
                        Started by TheRealMorford, 03-05-2026, 06:15 PM
                        0 responses
                        50 views
                        0 likes
                        Last Post TheRealMorford  
                        Working...
                        X