Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Order executing faster than code can update

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

    Order executing faster than code can update

    Code:
    protected override void OnExecutionUpdate(Cbi.Execution execution, string executionId, double price, int quantity, Cbi.MarketPosition marketPosition, string orderId, DateTime time)
    {
        if (entryLong != null && entryLong == execution.Order)
        {
            if (entryLong.OrderState == OrderState.Filled || entryLong.OrderState == OrderState.PartFilled)
            {
                if (stopLong == null)
                {
    
                    PrintLine(Name + ", " + Bars.ToChartString() + ", Stop1 Long: OnExecutionUpdate(), Line 2319: " + CurrentBar + ", Time: " + Time[0] + ", entryLongBar: " + entryLongBar + ", entryLong.OrderState: " + entryLong.OrderState, "StopPrint");​
    
                    if (StopLongType == OrderType.StopLimit)
                        SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopLimit, Position.Quantity, stopLongLimitPrice, stopLongPriceWithOffset, "", stopLongName);​
    
                }
            }
        }
    }​
    The Print Output is as follows:

    Code:
    Strategy, KTTA (10 Second), Stop1 Long: OnExecutionUpdate(), Line 2319: 735, Time: 26/9/2024 7:08:00 PM, entryLongBar: 735, entryLong.OrderState: PartFilled
    Strategy, KTTA (10 Second), Stop1 Long: OnExecutionUpdate(), Line 2319: 735, Time: 26/9/2024 7:08:00 PM, entryLongBar: 735, entryLong.OrderState: Filled
    Strategy, KTTA (10 Second), Stop1 Long: OnExecutionUpdate(), Line 2319: 735, Time: 26/9/2024 7:08:00 PM, entryLongBar: 735, entryLong.OrderState: Filled
    Strategy, KTTA (10 Second), Stop1 Long: OnExecutionUpdate(), Line 2319: 735, Time: 26/9/2024 7:08:00 PM, entryLongBar: 735, entryLong.OrderState: Filled

    So, what's happening is that the entryLong buy order was split into multiple executions that was firing so quickly that the stopLong never gets a chance to be placed before the next execution happens (hence the stopLong == null check always passes, when by right it should only be for the first execution)​. I ended up with 4 separate stop orders instead of one.

    Also very odd that out of the 4 executions, 1 was marked as OrderState.PartFilled, and the other 3 as OrderState.Filled (for entryLong) when I would've assumed it to be the other way around (3 PartFilled and the final one as Filled)

    Click image for larger version  Name:	image.png Views:	0 Size:	46.0 KB ID:	1319356


    I understand that this may very well be the limitations of the engine, I thought I'd ask here to see if anyone has figured out a workaround for this. I'm using Interactive Brokers, if that matters.

    Thanks in advance!

    -Nick
    Last edited by nicbizz; 09-26-2024, 09:12 AM.

    #2
    Hello Nick,

    Thank you for your post.

    If you mean prevent partial fills, unfortunately, no there is no way to prevent partial fills.

    I recommend reviewing the sample script - it demonstrates checking that the order has fully filled.



    Please let us know if you have any further questions.

    Comment


      #3
      Originally posted by NinjaTrader_Gaby View Post
      Hello Nick,

      Thank you for your post.

      If you mean prevent partial fills, unfortunately, no there is no way to prevent partial fills.

      I recommend reviewing the sample script - it demonstrates checking that the order has fully filled.



      Please let us know if you have any further questions.
      No, not to prevent partial fills, that's impossible in trading.

      In fact, I coded the placement of stop orders to specifically account for partial fills.

      Summarize from above, coded under OnExecutionUpdate():

      Code:
      if (entryLong.OrderState == OrderState.Filled || entryLong.OrderState == OrderState.PartFilled)
      {
          if (stopLong == null)
          {
               SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopLimit, Position.Quantity, stopLongLimitPrice, stopLongPriceWithOffset, "", stopLongName);​
      
          }
          else
          {
              ChangeOrder(stopLong, Position.Quantity, stopLongLimitPrice, stopLongPriceWithOffset);
          }​
      }
      On the first fill (partial), a StopLimit order is submitted because (stopLong == null).

      By right, on subsequent fills, it should change the StopLimit order (using ChangeOrder) because stopLong != null, instead of submitting another StopLimit order.

      However, what's happening is that the executions are fill-ing consecutively, and so quickly that the first StopLimit order doesnt get submitted in time before the next partial fill.

      Hence (stopLong == null) is true for each fill, and I end up with 4 separate StopLimit orders (one for each partial fill) instead of just 1 (see screenshot above).

      I guess what I'm asking is if anybody has experience with this, or what would you recommend I use instead of the "if (stopLong == null)" check to submit the first StopLimit order.

      Thanks!

      Comment


        #4
        Hello,

        I see, thank you for clarifying.

        Where and when is stopLong being assigned a value in the code?

        Comment


          #5
          Originally posted by NinjaTrader_Gaby View Post
          Hello,

          I see, thank you for clarifying.

          Where and when is stopLong being assigned a value in the code?

          Under OnOrderUpdate()

          Code:
          if (order != null && order.Name==stopLongName)
          {
              stopLong = order;
          }
          After doing a bit more research, could this issue stem from the fact that I'm using IBKR, and OnOrderUpdate() is not running in time before the next partial fill comes in?



          Comment


            #6
            Hello nicbizz,

            Thanks for that extra bit of info - yes, when using IB special considerations need to be made for strategies to work correctly due to how the provider sends order events. There is a small note about this in the following page;

            •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. For an example on protecting positions with this approach, see OnExecutionUpdate()



            You can find samples that apply specifically to Interactive Brokers in the following forum post:



            Unfortunately there isn't one that uses the Unmanaged Approach, however I would still recommend taking a look to get an idea of why you should monitor from OnExecutionUpdate in code.

            Please let me know if you have any further questions.

            Comment


              #7
              Originally posted by NinjaTrader_Gaby View Post
              Hello nicbizz,

              Thanks for that extra bit of info - yes, when using IB special considerations need to be made for strategies to work correctly due to how the provider sends order events. There is a small note about this in the following page;

              •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. For an example on protecting positions with this approach, see OnExecutionUpdate()



              You can find samples that apply specifically to Interactive Brokers in the following forum post:



              Unfortunately there isn't one that uses the Unmanaged Approach, however I would still recommend taking a look to get an idea of why you should monitor from OnExecutionUpdate in code.

              Please let me know if you have any further questions.
              Thanks for the tip, Gaby. I went through some of your links and managed to find a solution.

              For anyone else struggling with this, I fixed the issue by directly assigning the order object during order submission in OnExecutionUpdate(), instead of waiting to assign it under OnOrderUpdate()

              Code:
              stopLong = SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopLimit, Position.Quantity, stopLongLimitPrice, stopLongPriceWithOffset, "", stopLongName);​
              Just out of curiosity, is there any drawback to doing it this way? If there isn't, wouldn't it be a good idea to update the HelpGuide so that this is the recommended way to assign order objects instead of OnOrderUpdate(), as it is right now.



              Comment

              Latest Posts

              Collapse

              Topics Statistics Last Post
              Started by argusthome, 03-08-2026, 10:06 AM
              0 responses
              110 views
              0 likes
              Last Post argusthome  
              Started by NabilKhattabi, 03-06-2026, 11:18 AM
              0 responses
              59 views
              0 likes
              Last Post NabilKhattabi  
              Started by Deep42, 03-06-2026, 12:28 AM
              0 responses
              37 views
              0 likes
              Last Post Deep42
              by Deep42
               
              Started by TheRealMorford, 03-05-2026, 06:15 PM
              0 responses
              41 views
              0 likes
              Last Post TheRealMorford  
              Started by Mindset, 02-28-2026, 06:16 AM
              0 responses
              78 views
              0 likes
              Last Post Mindset
              by Mindset
               
              Working...
              X