Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

runner with onexecution update

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

    runner with onexecution update

    hi I wanted to add an additional trade for a runner, so one entry is normal and another one is for larger take profit. I used an example from NT. I was wondering is this the appropriate way to add runner? WIth current code I have an issue that, it submits 2 entry orders but places take profit and stop loss only for one.


    https://ninjatrader.com/support/help...onorderupdate_ and_onexec.htm


    Code:
    //
    // Copyright (C) 2019, NinjaTrader LLC <www.ninjatrader.com>.
    // NinjaTrader reserves the right to modify or overwrite this NinjaScript component with each release.
    //
    #region Using declarations
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Xml.Serialization;
    using NinjaTrader.Cbi;
    using NinjaTrader.Gui;
    using NinjaTrader.Gui.Chart;
    using NinjaTrader.Gui.SuperDom;
    using NinjaTrader.Data;
    using NinjaTrader.NinjaScript;
    using NinjaTrader.Core.FloatingPoint;
    using NinjaTrader.NinjaScript.Indicators;
    using NinjaTrader.NinjaScript.DrawingTools;
    #endregion
    
    // This namespace holds all strategies and is required. Do not change it.
    namespace NinjaTrader.NinjaScript.Strategies
    {
        public class SampleOnOrderUpdate : Strategy
        {
            private Order entryOrder = null; // This variable holds an object representing our entry order
            private Order stopOrder = null; // This variable holds an object representing our stop loss order
            private Order targetOrder = null; // This variable holds an object representing our profit target order
            private int sumFilled = 0; // This variable tracks the quantities of each execution making up the entry order
    
            protected override void OnStateChange()
            {
                if (State == State.SetDefaults)
                {
                    Description = @"Sample Using OnOrderUpdate() and OnExecution() methods to submit protective orders";
                    Name = "SampleOnOrderUpdate";
                    Calculate = Calculate.OnBarClose;
                    EntriesPerDirection = 1;
                    EntryHandling = EntryHandling.AllEntries;
                    IsExitOnSessionCloseStrategy = true;
                    ExitOnSessionCloseSeconds = 30;
                    IsFillLimitOnTouch = false;
                    MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
                    OrderFillResolution = OrderFillResolution.Standard;
                    Slippage = 0;
                    StartBehavior = StartBehavior.WaitUntilFlat;
                    TimeInForce = TimeInForce.Gtc;
                    TraceOrders = false;
                    RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
                    StopTargetHandling = StopTargetHandling.ByStrategyPosition;
                    BarsRequiredToTrade = 20;
                }
                else if (State == State.Realtime)
                {
                    // one time only, as we transition from historical
                    // convert any old historical order object references
                    // to the new live order submitted to the real-time account
                    if (entryOrder != null)
                        entryOrder = GetRealtimeOrder(entryOrder);
                    if (stopOrder != null)
                        stopOrder = GetRealtimeOrder(stopOrder);
                    if (targetOrder != null)
                        targetOrder = GetRealtimeOrder(targetOrder);
                }
            }
    
            protected override void OnBarUpdate()
            {
                // Submit an entry market order if we currently don't have an entry order open and are past the BarsRequiredToTrade bars amount
                if ( Position.MarketPosition == MarketPosition.Flat && CurrentBar > BarsRequiredToTrade)
                {
                    /* Enter Long. We will assign the resulting Order object to entryOrder1 in OnOrderUpdate() */
                    EnterLongStopMarket(0,true, PositionSize, longPrice, "MyEntry");
                    EnterLongStopMarket(0,true, PositionSizeRunner, longPrice, "MyEntryRunner");​
                  
                }
    
                /* If we have a long position and the current price is 4 ticks in profit, raise the stop-loss order to breakeven.
                We use (7 * (TickSize / 2)) to denote 4 ticks because of potential precision issues with doubles. Under certain
                conditions (4 * TickSize) could end up being 3.9999 instead of 4 if the TickSize was 1. Using our method of determining
                4 ticks helps cope with the precision issue if it does arise. */
                if (Position.MarketPosition == MarketPosition.Long && Close[0] >= Position.AveragePrice + (7 * (TickSize / 2)))
                {
                    // Checks to see if our Stop Order has been submitted already
                    if (stopOrder != null && stopOrder.StopPrice < Position.AveragePrice)
                    {
                        // Modifies stop-loss to breakeven
                        stopOrder = ExitLongStopMarket(0, true, stopOrder.Quantity, Position.AveragePrice, "MyStop", "MyEntry");
                       [B]stopOrder = ExitLongStopMarket(0, true, stopOrder.Quantity, Position.AveragePrice, "MyStop", "MyEntryRunner");[/B]
                    }
                }
            }
    
            protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
            {
                // Handle entry orders here. The entryOrder object allows us to identify that the order that is calling the OnOrderUpdate() method is the entry order.
                // Assign entryOrder in OnOrderUpdate() to ensure the assignment occurs when expected.
                // This is more reliable than assigning Order objects in OnBarUpdate, as the assignment is not gauranteed to be complete if it is referenced immediately after submitting
                if (order.Name == "MyEntry" || order.Name == "MyEntryRunner" || )
                {)
                {
                    entryOrder = order;
    
                    // Reset the entryOrder object to null if order was cancelled without any fill
                    if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                    {
                        entryOrder = null;
                        sumFilled = 0;
                    }
                }
            }
    
            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;
    
                        // Submit exit orders for partial fills
                        if (execution.Order.OrderState == OrderState.PartFilled)
                        {
                            stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, execution.Order.AverageFillPrice - 4 * TickSize, "MyStop", "MyEntry");
                            targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + 8 * TickSize, "MyTarget", "MyEntry");
                            [B]stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, execution.Order.AverageFillPrice - 4 * TickSize, "MyStop", "MyEntryRunner");
                            targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + 20 * TickSize, "MyTarget", "MyEntryRunner");[/B]
                        }
                        // 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
                            stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, execution.Order.AverageFillPrice - 4 * TickSize, "MyStop", "MyEntry");
                            targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + 8 * TickSize, "MyTarget", "MyEntry");
                            [B]stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, execution.Order.AverageFillPrice - 4 * TickSize, "MyStop", "MyEntryRunner");
                            targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + 20 * TickSize, "MyTarget", "MyEntryRunner");[/B]
                        }
    
                        // 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;
                    }
                }
            }
        }
    }​

    #2
    Hello tkaboris,

    When you say runner what specifically are you asking for? A trailing stop? Leave the order active?

    We would need specific details on what you wanted the order to do, the term runner does not tell me what you want to do with the order.

    With the code provided you have conflicts and are using/resetting the same variables for all of the targets so that specifically is not valid. I would suggest to reduce what you have to remove all code associated with your second order and target so you have it working for a single entry order and its targets. At that point post what code you have left and define what you mean by runner so we know how to assist.

    Comment


      #3
      HI well this code works for one entry. When i want a runner, I mean I open two seperate trades in the same direction, stop loss the same, take profit is different.
      So how can I modify this script to allow for runner as well?
      I have set EntriesPerDirection = 2;

      private Order entryOrder = null; // This variable holds an object representing our entry order
      private Order stopOrder = null; // This variable holds an object representing our stop loss order
      private Order targetOrder = null; // This variable holds an object representing our profit target order
      private int sumFilled = 0; // This variable tracks the quantities of each execution making up the entry order​

      if (Position.MarketPosition == MarketPosition.Flat && CurrentBar > BarsRequiredToTrade)
      {
      /* Enter Long. We will assign the resulting Order object to entryOrder1 in OnOrderUpdate() */
      EnterLongStopMarket(0,true, PositionSize, longPrice, "MyEntry");

      }​

      Code:
      protected override void OnBarUpdate()
              {
                  // Submit an entry market order if we currently don't have an entry order open and are past the BarsRequiredToTrade bars amount
                  if (entryOrder == null && Position.MarketPosition == MarketPosition.Flat && CurrentBar > BarsRequiredToTrade)
                  {
                      /* Enter Long. We will assign the resulting Order object to entryOrder1 in OnOrderUpdate() */
                      EnterLongStopMarket(0,true, PositionSize, longPrice, "MyEntry");
                      
                  }
      
                  /* If we have a long position and the current price is 4 ticks in profit, raise the stop-loss order to breakeven.
                  We use (7 * (TickSize / 2)) to denote 4 ticks because of potential precision issues with doubles. Under certain
                  conditions (4 * TickSize) could end up being 3.9999 instead of 4 if the TickSize was 1. Using our method of determining
                  4 ticks helps cope with the precision issue if it does arise. */
                  if (Position.MarketPosition == MarketPosition.Long && Close[0] >= Position.AveragePrice + (7 * (TickSize / 2)))
                  {
                      // Checks to see if our Stop Order has been submitted already
                      if (stopOrder != null && stopOrder.StopPrice < Position.AveragePrice)
                      {
                          // Modifies stop-loss to breakeven
                          stopOrder = ExitLongStopMarket(0, true, stopOrder.Quantity, Position.AveragePrice, "MyStop", "MyEntry");
                      }
                  }
              }
      
              protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
              {
                  // Handle entry orders here. The entryOrder object allows us to identify that the order that is calling the OnOrderUpdate() method is the entry order.
                  // Assign entryOrder in OnOrderUpdate() to ensure the assignment occurs when expected.
                  // This is more reliable than assigning Order objects in OnBarUpdate, as the assignment is not gauranteed to be complete if it is referenced immediately after submitting
                  if (order.Name == "MyEntry" )
                  {
                  {
                      entryOrder = order;
      
                      // Reset the entryOrder object to null if order was cancelled without any fill
                      if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                      {
                          entryOrder = null;
                          sumFilled = 0;
                      }
                  }
              }
      
              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;
      
                          // Submit exit orders for partial fills
                          if (execution.Order.OrderState == OrderState.PartFilled)
                          {
                              stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, execution.Order.AverageFillPrice - 4 * TickSize, "MyStop", "MyEntry");
                              targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + 8 * TickSize, "MyTarget", "MyEntry");
                            
                          }
                          // 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
                              stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, execution.Order.AverageFillPrice - 4 * TickSize, "MyStop", "MyEntry");
                              targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + 8 * TickSize, "MyTarget", "MyEntry");
                              
                          }
      
                          // 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


        #4
        Hello tkaboris,

        I would suggest to avoid using the term runner for this use case, what you are asking for is just two entry orders that have associated targets for each entry.

        The code you have that works for 1 single order and its targets is essentially what is required if you want to add a second order, you need to make new variables for that second order and its targets so you can correctly locate them in OnOrderUpdate and OnExecutionUpdate. The reason the other sample was not valid is that you used the same variables for both sets of orders and targets, the logic was not correct and will be reset incorrectly.

        When using OnOrderUpdate and OnExecutionUpdate the standard flow would go like the following:
        1. Place an entry order from OnBarUpdate.
        2. Look for the entry order by its name in OnOrderUpdate and assign it to a unique variable.
        3. Wait for the fill and look for the fill in OnExecutionUpdate, the previously saved variable is then used to compare if the execution matches the saved order.
        4. If the saved order matches the execution submit targets and reset the entry order variable back to null.
        5. Look for the target orders in OnOrderUpdate by their names and save each to a unique variable.
        6. Wait for the fill of one of the targets and then reset both target variables back to null.
        7. If you used a start behavior that lets historical orders transition into realtime you also need to use GetRealtimeOrder on the order variables.

        When adding a second set of orders you repeat every one of these steps for that second entry and its targets. You need to add completely new variables for each of those orders so they do not conflict with the existing logic for the first set of orders. The entry and targets can have completely different prices, that is up to your goal. The entries signal name and the targets names also need to be different from the first set of orders to be seperate.

        Comment


          #5
          Thank you, does this look they way it suppose to be for entry order, stoploss and take profit? I want to make sure I find order for take profit and stoploss correctly

          Code:
          private Order entryOrder = null; // This variable holds an object representing our entry order
          private Order stopOrder = null; // This variable holds an object representing our stop loss order
          private Order targetOrder = null; // This variable holds an object representing our profit target order
          
          protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled,
                    double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
                  {
                    // Assign entryOrder in OnOrderUpdate() to ensure the assignment occurs when expected.
                    // This is more reliable than assigning Order objects in OnBarUpdate, as the assignment is not gauranteed to be complete if it is referenced immediately after submitting
                    if (            
                         order.Name == "MyEntryLong" || order.Name == "MyEntryShort"    
                        )
                       entryOrder = order;
                   }
          
           if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                          {
                              entryOrder = null;
                              sumFilled = 0;
                              
                          }
          
          OnBarUpdate
          EnterLongStopMarket(0,true, PositionSize, longPrice, "MyEntryLong");
          EnterShortStopMarket(0,true, PositionSize, shortPrice,"MyEntryShort");
          
          protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)
                  {
                      
                      
                        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;
                              
                              // ============ Longs with MyEntryLong
                              if (execution.Order.OrderState == OrderState.PartFilled)
                              {
                                  if(execution.Name == "MyEntryLong"  && longStop <= bid){
                                  stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, longStop, "MyStopLong", "MyEntryLong");                      
                                  }
                                  if(execution.Name == "MyEntryLong" && longTarget >= bid){
                                  targetOrder = ExitLongLimit(0, true, execution.Order.Filled, longTarget, "MyTargetLong", "MyEntryLong");                      
                                  }
                              }
                            
                              else if (execution.Order.OrderState == OrderState.Filled && sumFilled == execution.Order.Filled)
                              {                        
                                
                                  if(execution.Name == "MyEntryLong"  && longStop <= bid){                        
                                  stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, longStop, "MyStopLong", "MyEntryLong");                                                  
                                  }
                                  if(execution.Name == "MyEntryLong"  && longTarget >= bid){
                                  targetOrder = ExitLongLimit(0, true, execution.Order.Filled, longTarget, "MyTargetLong", "MyEntryLong");                        
                                  }
                              }
                              
                              //============ Shorts with MyEntrySHorts
                              if (execution.Order.OrderState == OrderState.PartFilled)
                              {
                                  if(execution.Name == "MyEntryShort"  && shortStop >= ask){
                                  stopOrder = ExitShortStopMarket(0, true, execution.Order.Filled, shortStop, "MyStopShort", "MyEntryShort");                      
                                  }
                                  if(execution.Name == "MyEntryShort" && shortTarget<= ask){
                                  targetOrder = ExitShortLimit(0, true, execution.Order.Filled, shortTarget, "MyTargetShort", "MyEntryShort");                      
                                  }
                              }
                              // 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)
                              {                        
                                  if(execution.Name == "MyEntryShort"  && shortStop >= ask){
                                  stopOrder = ExitShortStopMarket(0, true, execution.Order.Filled, shortStop, "MyStopShort", "MyEntryShort");                      
                                  }
                                  if(execution.Name == "MyEntryShort" && shortTarget<= ask){
                                  targetOrder = ExitShortLimit(0, true, execution.Order.Filled, shortTarget, "MyTargetShort", "MyEntryShort");                      
                                  }
                              }
                              
          
                              // 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 tkaboris,

            That is possibly correct, you would need to try it and make sure that your conditions are working. If you are unsure if your conditions are working right you would need to add prints into the script so you can trace how the logic was executed when you ran the strategy.

            In regard to the variables you can interchangeably use variables for long and short because you won't be long and short at the same time.

            To follow up with your previous inquiry once you confirm this logic is working as you intended you could add the second entry order and its targets. Just make sure to keep in mind the second entry and targets require new separate variables and need to have unique signal names so they are not associated with the first entry.

            Comment


              #7
              hi
              I managed to have one order to work properly.
              However when I add second order (runner), which is basically second same order that shares same entry, stoploss, takeprofit, I get cancelling one of the other going on as seen in this GIF

              I made this logic to cancel order if risk is more then needed. It works perfectly with one EntriesPerDirection = 1, but not with 2.

              if(riskShortOver && Position.MarketPosition == MarketPosition.Flat && legDown==2 && isUpLeg )
              {
              CancelOrder(entryOrder);
              if(TradeRunner)
              {
              CancelOrder(entryOrderRunner);
              }
              }​

              OnOrderUpdate
              if (
              order.Name == "MyEntryLong" || order.Name == "MyEntryShort"
              )
              entryOrder = order;
              if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
              {
              entryOrder = null;
              sumFilled = 0;
              }​

              if (order.Name == "MyEntryLongRunner" || order.Name == "MyEntryShortRunner")
              entryOrderRunner = order;
              if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
              {
              entryOrderRunner = null;
              sumFilledRunner = 0;
              }​

              Update:
              when I print from Onorderupdate I see that it generates new runner id everytick
              Time: 7/17/2024 12:20:00 PM
              entryOrder OnOrderUpdate
              entryOrderRunner OnOrderUpdateorderId='2d79d5c33dc34892a95b05a1c9d4 e613' account='Sim101' name='MyEntryLongRunner' orderState=CancelSubmitted instrument='NQ 09-24' orderAction=Buy orderType='Stop Market' limitPrice=0 stopPrice=20052.5 quantity=1 tif=Gtc oco='' filled=0 averageFillPrice=0 onBehalfOf='' id=181640 time='2024-07-17 12:19:12' gtd='2099-12-01' statementDate='2024-07-17'​



              Last edited by tkaboris; 07-17-2024, 10:20 AM.

              Comment


                #8
                Hello tkaboris,

                Your second order cannot share with the first entry at all if you want it to not affect the original entry and targets, it needs to be a unique new entry with unique new targets to be unassociated from the original entry.

                Remember to have a second set of orders that are not associated with the original entry or targets those new orders need new unique variables and logic to control them and you also need to use unique signal names. In your original script where you added the second set of orders you had shared variables and also used non unique signal names so they were all linked together.

                Comment


                  #9

                  I tried to make sure all ordres are unique. Below is the current script that i use for longs. I would appricate if you can take a look. I didnt include logic to cancel order because even without it has issues when running with EntriesPerDirection=2. Strategy on is pricechange

                  Something is wrong with the script it constanly generates new runnerorderrid and alternating between 1and2.

                  Code:
                  private Order entryOrder = null; // This variable holds an object representing our entry order
                  private Order stopOrder = null; // This variable holds an object representing our stop loss order
                  private Order targetOrder = null; // This variable holds an object representing our profit target order
                  private int sumFilled = 0; // This variable tracks the quantities of each execution making up the entry order
                  
                  private Order entryOrderRunner = null; // This variable holds an object representing our entry order
                  private Order stopOrderRunner = null; // This variable holds an object representing our stop loss order
                  private Order targetOrderRunner = null; // This variable holds an object representing our profit target order
                  private int sumFilledRunner = 0; // This variable tracks the quantities of each execution making up the entry order
                  
                  
                  protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled,
                                    double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
                          {
                            // Assign entryOrder in OnOrderUpdate() to ensure the assignment occurs when expected.
                            // This is more reliable than assigning Order objects in OnBarUpdate, as the assignment is not gauranteed to be complete if it is referenced immediately after submitting
                            if (                  
                                     order.Name == "MyEntryLong" || order.Name == "MyEntryShort"  
                                    )
                               entryOrder = order;
                            if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                          {
                              entryOrder = null;
                              sumFilled = 0;
                                          }
                                          
                            if (order.Name == "MyEntryLongTrap" || order.Name == "MyEntryShortTrap")
                               entryOrderTrap = order;              
                            if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                          {
                              entryOrderTrap = null;
                              sumFilledTrap = 0;
                                          }
                                  
                            if (order.Name == "MyEntryLongRunner" || order.Name == "MyEntryShortRunner")              
                                   entryOrderRunner = order;
                            if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                          {
                              entryOrderRunner = null;
                              sumFilledRunner = 0;
                                          }
                          }
                  
                          // OnBarUpdate
                          // Condition
                          riskLongOver = false;
                          if(longRisk > tradeRiskTicks)
                          {
                                  riskLongOver = true;
                          }
                          if(
                                  legUp == 2 && isDownLeg              
                                  && !riskLongOver
                                  )
                          {
                                  secEntryLong = true;
                   
                          }
                          else
                          {
                                  secEntryLong = false;
                          }
                          if(isLongEntry)
                          {                              
                                  trapLongLevel = Low[1]-(TickSize*EntryPlacement);
                                  Draw.Diamond(this, "longTrap", false, -1, trapLongLevel, Brushes.Magenta);      
                          }
                  
                          // Entry
                  
                          if(secEntryLong      
                          && (BarsSinceExitExecution("MyStopLong") > 1 || BarsSinceExitExecution("MyStopLong") == -1)
                          && (BarsSinceExitExecution("MyTargetLong") > 1 || BarsSinceExitExecution("MyTargetLong") == -1)
                          && (Position.MarketPosition == MarketPosition.Flat)
                          && ((Time[1].TimeOfDay >= Start.TimeOfDay) && (Time[1].TimeOfDay <= End.TimeOfDay))
                          )
                          {
                          if(longPrice >= GetCurrentAsk() ){
                          EnterLongStopMarket(0,true, PositionSize, longPrice, "MyEntryLong");
                                  
                                  if(TradeRunner)
                                  {
                                          EnterLongStopMarket(0,true, PositionSizeRunner, longPrice, "MyEntryLongRunner");
                                  }
                                  }
                                          myFreeTradeLong = true;
                          }
                  
                          // Take profits and stop losses
                  
                          protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)
                                  {
                                        
                                        
                                    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;
                                                          
                                                          // ============ Longs with MyEntryLong
                                      if (execution.Order.OrderState == OrderState.PartFilled)
                                      {
                                          if(execution.Name == "MyEntryLong"  && longStop <= bid){
                                          stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, longStop, "MyStopLong", "MyEntryLong");                      
                                                                  }
                                          if(execution.Name == "MyEntryLong" && longTarget >= bid){
                                          targetOrder = ExitLongLimit(0, true, execution.Order.Filled, longTarget, "MyTargetLong", "MyEntryLong");                      
                                                                  }
                                      }
                                    
                                      else if (execution.Order.OrderState == OrderState.Filled && sumFilled == execution.Order.Filled)
                                      {                                          
                                        
                                          if(execution.Name == "MyEntryLong"  && longStop <= bid){                                                
                                          stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, longStop, "MyStopLong", "MyEntryLong");                                                                        
                                                                  }
                                          if(execution.Name == "MyEntryLong"  && longTarget >= bid){
                                          targetOrder = ExitLongLimit(0, true, execution.Order.Filled, longTarget, "MyTargetLong", "MyEntryLong");                        
                                                                  }
                                      }
                                                          
                                                        
                                                          
                  
                                      // 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;
                                  }
                              }
                                          #endregion
                                          #region MyEntryRunner
                                          
                                           if ((entryOrderRunner != null) && (entryOrderRunner == 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
                                      sumFilledRunner += execution.Quantity;
                                          
                                                          //=================== Longs with MyEntryLongRunner
                                                          
                                          if (execution.Order.OrderState == OrderState.PartFilled)
                                                                  
                                      {                                  
                                          if(execution.Name == "MyEntryLongRunner"  && longStop <= bid){
                                          stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, longStop, "MyStopLong", "MyEntryLongRunner");                      
                                                                  }
                                          if(execution.Name == "MyEntryLongRunner" && execution.Order.AverageFillPrice + (TickSize * ProfitTargetTicks) >= bid){
                                          targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + (TickSize * ProfitTargetTicks), "MyTargetLong", "MyEntryLongRunner");                      
                                                                  }
                                      }
                                      // 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 && sumFilledRunner == execution.Order.Filled)
                                      {
                                                                  
                                          // Stop-Loss order for OrderState.Filledfor Shorts
                                          if(execution.Name == "MyEntryLongRunner"  && longStop <= bid){
                                          stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, longStop, "MyStopLong", "MyEntryLongRunner");                      
                                                                  }
                                          if(execution.Name == "MyEntryLongRunner" && execution.Order.AverageFillPrice + (TickSize * ProfitTargetTicks) >= bid){
                                          targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + (TickSize * ProfitTargetTicks), "MyTargetLong", "MyEntryLongRunner");                      
                                                                  }
                                      }
                                                          
                                      
                                      }
                                                          // Resets the entryOrder object and the sumFilled counter to null / 0 after the order has been filled
                                      if (execution.Order.OrderState != OrderState.PartFilled && sumFilledRunner == execution.Order.Filled)
                                      {
                                          entryOrderRunner = null;
                                          sumFilledRunner = 0;
                                      }
                                  }
                              }
                  
                              
                                          // Reset our stop order and target orders' Order objects after our position is closed. (1st Entry)
                              if ((stopOrderRunner != null && stopOrderRunner == execution.Order) || (targetOrderRunner != null && targetOrderRunner == execution.Order))
                              {
                                  if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled)
                                  {
                                      stopOrderRunner = null;
                                      targetOrderRunner = null;
                                  }
                              }​

                  Comment


                    #10
                    Hello tkaboris,

                    I am not sure I understand what this code is trying to do, it looks like you have a lot of extra added logic in OnOrderUpdate. I can't debug your custom code for you but I can suggest using prints if that is not working in some way.

                    I would suggest to start again from this sample: https://ninjatrader.com/support/help...and_onexec.htm

                    Before you can move onto more complex tasks it would be best to make sure you fully understand how the first set of orders works in relation to the code that is present. Once you are certain that you understand how the logic is flowing when the script is used you can begin to add the second set of orders. At this point do not add any extra custom logic before adding the second set of orders. You want to make sure that you have the second set of orders working before you do anything more complex.

                    If we are looking at that sample the parts you would duplicate to make a second order would be the following items:
                    Line 93, a second entry order with a new unique signal name
                    Line 103-113, finding the new entry order and assigning it to a variable separate from the existing condition in this area
                    Line 120-158, A second block of code just like this would need to be created to check if the execution was the entry order, if so submit targets and assign them to a new unique variable and use new unique signal names.

                    At this point everything should look identical to the original code besides having unique variable and signal names. You should have a test script that produces two entries with targets that are associated with each entry and do not conflict with each other. If you are adding any other logic like the time conditions or BarsSinceExitExecution logic that you have in the above sample you are likely going to have a much more difficult time debugging the script. Starting with the most basic proof of concept test is the best way to begin adding features to a script.

                    Comment


                      #11
                      Hi that is the exact sample i was following. that example is only for one entry though.

                      for your first remark
                      I have both on line 95 and 147
                      if ((entryOrder != null ) && (entryOrder == execution.Order ))
                      if ((entryOrderRunner != null) && (entryOrderRunner == execution.Order ))

                      for third point, If I added this logic it doesnt execute stop loss or take profits. Is it wrong?

                      else if (execution.Order.OrderState == OrderState.Filled && sumFilled == execution.Order.Filled && execution.Order.OrderId == entryOrder.ToString())
                      {

                      if(execution.Name == "MyEntryLong" && longStop <= bid){
                      stopOrder = ExitLongStopMarket(0, true, execution.Order.Filled, longStop, "MyStopLong", "MyEntryLong");
                      }
                      if(execution.Name == "MyEntryLong" && longTarget >= bid){
                      targetOrder = ExitLongLimit(0, true, execution.Order.Filled, longTarget, "MyTargetLong", "MyEntryLong");
                      }
                      }​

                      my prints fron execution update show same orderid
                      entryOrder ExecutionrderId='c3d53bf309964120ac5bb4f192754f00' account='Playback101' name='MyEntryLong' orderState=Filled instrument='NQ 09-24' orderAction=Buy orderType='Stop Market' limitPrice=0 stopPrice=20884.5 quantity=1 tif=Gtc oco='' filled=1 averageFillPrice=20884.5 onBehalfOf='' id=182562 time='2024-07-11 07:54:36' gtd='2099-12-01' statementDate='2024-07-11'

                      Execution.Order.OrderIdc3d53bf309964120ac5bb4f1927 54f00​
                      Last edited by tkaboris; 07-17-2024, 12:24 PM.

                      Comment


                        #12
                        Hello tkaboris,

                        Yes I know that is for a single entry, that is why I provided a explanation of how to add a second entry while using that sample.

                        Regarding the code you posted, that is not like the original sample so I would suggest to refer back to the original sample and make sure you used exactly that code with zero changes.

                        Your second orders code will be identical to the first orders code in the way that it is structured. The only changes would be the variables being used and the names for the order being used.

                        Please make sure you review the original sample and ensure that you completely understand what that is doing before trying to make any changes, any changes to that logic will result in different results than what that sample originally shows.

                        Comment


                          #13
                          I have a question regarding the original sample

                          in on barupdate before we enter a position there is a condition
                          entryOrder == null

                          I currently dont have that, because if i place it my entry price doesnt trail and stays only in original place.
                          Should this condition be in my strategy? My entries for long are always above the current price

                          Comment


                            #14
                            Hello tkaboris,

                            That part is required for that logic to work correctly, that makes sure that no entry has been placed so far. Your copy of this sample should exactly reflect the sample, do not make any changes to the samples logic before trying to add the second order. The first and second orders logic would look nearly identical to the original samples code besides the second set of orders having their own variables and unique signal names.

                            You should not be concerned with trailing or doing any other tasks at this point until you fully grasp how the original code is working. Because you want to add a second order you need to work on that part first, if you start making other changes before that it will greatly increase how difficult it is to debug and I can only refer back to using prints to confirm what you are doing is working.

                            Comment


                              #15
                              hi

                              I believe I understand haow relationsiop between onexecution onbarupdate and onorder update works. I took example from sample and applied it my strategy. I followed same process adding a second order. The result its doing its submitting new orders integrenchably. Its working with one order fine, but when two orders per entry is mess.

                              I know you suggest me to copy exact copy from sample and I am sure sample will work. But sample is not a strategy because it only contains entry order, and not stop or take profit or second order.

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by abelsheila, 05-14-2025, 07:38 PM
                              2 responses
                              29 views
                              0 likes
                              Last Post hglover945  
                              Started by nailz420, 05-14-2025, 09:14 AM
                              1 response
                              57 views
                              0 likes
                              Last Post NinjaTrader_ChristopherJ  
                              Started by NinjaTrader_Brett, 05-12-2025, 03:19 PM
                              0 responses
                              326 views
                              1 like
                              Last Post NinjaTrader_Brett  
                              Started by domjabs, 05-12-2025, 01:55 PM
                              2 responses
                              62 views
                              0 likes
                              Last Post domjabs
                              by domjabs
                               
                              Started by Morning Cup Of Trades, 05-12-2025, 11:50 AM
                              1 response
                              81 views
                              0 likes
                              Last Post NinjaTrader_ChristopherJ  
                              Working...
                              X