Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

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 rbeckmann05, Yesterday, 06:48 PM
      1 response
      12 views
      0 likes
      Last Post bltdavid  
      Started by llanqui, Today, 03:53 AM
      0 responses
      6 views
      0 likes
      Last Post llanqui
      by llanqui
       
      Started by burtoninlondon, Today, 12:38 AM
      0 responses
      10 views
      0 likes
      Last Post burtoninlondon  
      Started by AaronKoRn, Yesterday, 09:49 PM
      0 responses
      15 views
      0 likes
      Last Post AaronKoRn  
      Started by carnitron, Yesterday, 08:42 PM
      0 responses
      11 views
      0 likes
      Last Post carnitron  
      Working...
      X