Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Preventing second target order

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

    Preventing second target order

    Hi
    Niggly issue.
    I use an unmanaged approach and every now and again my target order throws up the wrong quantity.
    It is usually when the order happens on the first tick of the bar - my code automatically adjusts position size and it seems to send out this erroneous second target order. I traced the orders and they are literally milliseconds apart.
    Is there anyway to prevent this that someone can share?
    Edit I think it may be because of a part fill issue. The unmanaged template puts a target order in there and I wonder if the sum quantity is somehow getting confused.
    I reproduce the template code below.

    Code:
            #region ON Execution update
            protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)
            {
                if (longEntry != null && longEntry == 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
                        sumFilledLong += execution.Quantity;
    
                        if (State == State.Historical)
                            oco = DateTime.Now.ToString() + CurrentBar + "LongExits";
                        else
                            oco = GetAtmStrategyUniqueId() + "LongExits";
    
                        if (stopLossLong == null && targetLong == null)
                        {
                            SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, execution.Order.Filled, 0, execution.Order.AverageFillPrice - StopDistance * TickSize, oco, "StopLossLong");
                            SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.Limit, execution.Order.Filled, execution.Order.AverageFillPrice + ProfitDistance * TickSize, 0, oco, "TargetLong");
                        }
                        else
                        {
                            // Submit exit orders for partial fills
                            if (execution.Order.OrderState == OrderState.PartFilled)
                            {
                                ChangeOrder(stopLossLong, execution.Order.Filled, 0, execution.Order.AverageFillPrice - StopDistance * TickSize);
                                ChangeOrder(targetLong, execution.Order.Filled, execution.Order.AverageFillPrice + ProfitDistance * TickSize, 0);
                            }
                            // 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 && sumFilledLong == execution.Order.Filled)
                            {
                                // Stop-Loss order for OrderState.Filled
                                ChangeOrder(stopLossLong, execution.Order.Filled, 0, execution.Order.AverageFillPrice - StopDistance * TickSize);
                                ChangeOrder(targetLong, execution.Order.Filled, execution.Order.AverageFillPrice + ProfitDistance * TickSize, 0);
                            }
    
                        }
    
                        // Resets the entryOrder object and the sumFilled counter to null / 0 after the order has been filled
                        if (execution.Order.OrderState != OrderState.PartFilled && sumFilledLong == execution.Order.Filled)
                        {
                            longEntry = null;
                            sumFilledLong = 0;
                        }
                    }
                }          
                if (shortEntry != null && shortEntry == 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
                        sumFilledShort += execution.Quantity;
    
                        if (State == State.Historical)
                            oco = DateTime.Now.ToString() + CurrentBar + "ShortExits";
                        else
                            oco = GetAtmStrategyUniqueId() + "ShortExits";
    
                        if (stopLossShort == null && targetShort == null)
                        {
                            SubmitOrderUnmanaged(0, OrderAction.BuyToCover, OrderType.StopMarket, execution.Order.Filled, 0, execution.Order.AverageFillPrice + StopDistance * TickSize, oco, "StopLossShort");
                            SubmitOrderUnmanaged(0, OrderAction.BuyToCover, OrderType.Limit, execution.Order.Filled, execution.Order.AverageFillPrice - ProfitDistance * TickSize, 0, oco, "TargetShort");
                        }
                        else
                        {
                            // Submit exit orders for partial fills
                            if (execution.Order.OrderState == OrderState.PartFilled)
                            {
                                ChangeOrder(stopLossShort, execution.Order.Filled, 0, execution.Order.AverageFillPrice + StopDistance * TickSize);
                                ChangeOrder(targetShort, execution.Order.Filled, execution.Order.AverageFillPrice - ProfitDistance * TickSize, 0);
                            }
                            // 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 && sumFilledShort == execution.Order.Filled)
                            {
                                // Stop-Loss order for OrderState.Filled
                                ChangeOrder(stopLossShort, execution.Order.Filled, 0, execution.Order.AverageFillPrice + StopDistance * TickSize);
                                ChangeOrder(targetShort, execution.Order.Filled, execution.Order.AverageFillPrice - ProfitDistance * TickSize, 0);
                            }
                        }
    
                        // Resets the entryOrder object and the sumFilled counter to null / 0 after the order has been filled
                        if (execution.Order.OrderState != OrderState.PartFilled && sumFilledShort == execution.Order.Filled)
                        {
                            shortEntry  = null;
                            sumFilledShort = 0;
                        }
                    }
                }
                
                // Reset our stop order and target orders' Order objects after our position is closed.
                if ((stopLossLong != null && stopLossLong == execution.Order) || (targetLong != null && targetLong == execution.Order))
                {
                    if (execution.Order.OrderState == OrderState.Filled
                        || execution.Order.OrderState == OrderState.PartFilled)
                    {
                        stopLossLong = null;
                        targetLong = null;
                    }
                }
                if ((stopLossShort != null && stopLossShort == execution.Order) || (targetShort != null && targetShort == execution.Order))
                {
                    if (execution.Order.OrderState == OrderState.Filled
                        || execution.Order.OrderState == OrderState.PartFilled)
                    {
                        stopLossShort = null;
                        targetShort = null;
                    }
                }
            }
            
            #endregion
    ​
    Last edited by Mindset; 02-02-2024, 12:56 AM. Reason: added partial fill theory

    #2
    Hello Mindset,

    Use prints to debug and understand the behavior.


    Print the execution object above and outside of all conditions.

    Is the entry being part filled?

    Is the condition to send the limit order evaluating as true multiple times?
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Yes it's definitely the partial fill issue. So I just removed the partial fill code and wait for it to be completely filled.
      I can manually adjust my strategy for the odd partial fill rather than spending hours trying to work out what it is.
      As I trade quite small currently it's not an issue and is something I will have to come back to when I feel strong enough to debug it!!

      Comment

      Latest Posts

      Collapse

      Topics Statistics Last Post
      Started by NullPointStrategies, Yesterday, 05:17 AM
      0 responses
      56 views
      0 likes
      Last Post NullPointStrategies  
      Started by argusthome, 03-08-2026, 10:06 AM
      0 responses
      133 views
      0 likes
      Last Post argusthome  
      Started by NabilKhattabi, 03-06-2026, 11:18 AM
      0 responses
      73 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
      49 views
      0 likes
      Last Post TheRealMorford  
      Working...
      X