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

Breakeven stop moves at close of bar and not when condition is met

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

    Breakeven stop moves at close of bar and not when condition is met

    Click image for larger version

Name:	PlayBackOutcome.png
Views:	231
Size:	65.0 KB
ID:	1217706Click image for larger version  Name:	BEreached.png Views:	0 Size:	62.7 KB ID:	1217702Click image for larger version  Name:	ReplayMode.png Views:	0 Size:	68.6 KB ID:	1217703Click image for larger version  Name:	ScriptReload.png Views:	0 Size:	75.5 KB ID:	1217704
    NOTE: If you can't see the enlarged images, please right-click on each image and open in a new window tab​


    Hi, I haven't been able to get my strategy to move the BreakEven stop to order.AverageFillPrice +/- 7 ticks when the condition is met. In Replay Mode the stop moves to BE when the bar closes. When I reload the script Strategy in Replay the historical result differs completely from the one obtained in Replay. See attached screenshots.

    I've tried everything that is suggested in the forum:
    1. Added 1 tick secondary chart series
    2. Tried TickRepay, High Fill Resolution, all the Calculation options, Prints all over the code
    3. Downloaded all the Samples provided by Ninja and Chelsea.
    4. Changed my code from basic entries and exits to the approach using OnOrderUpdate() and OnExecutionUpdate() methods
    5. Inserted the Breakeven handling code in the OEU and in the OBU methods

    I know this issue is widely experienced and the documentation provided in the forum is ample. But I'm stuck with this mind-boggling issue. Can you please help me find a solution?

    Code:
      
                            // This code is inserted in the OEU method.
                            if(enShort)
                            {
                                stopOrder = ExitShortStopMarket(2, true, execution.Order.Filled, execution.Order.AverageFillPrice+ (Stop*TickSize), "MyStop", "MyEntry");
                                targetOrder = ExitShortLimit(2, true, execution.Order.Filled, execution.Order.AverageFillPrice - (Target * TickSize), "MyTarget", "MyEntry");
                                // This code for TriggerSate = 1 works fine here.
                                if(TriggerState == 1   && stopOrder != null && stopOrder.StopPrice > Position.AveragePrice) //&& (Close[0] >= currentPtPrice)
                                {      
                                    Print("Trigger1 "+Time[0]);
                                    currentSlPrice = order.AverageFillPrice + (Stop * TickSize);
                                    currentPtPrice =  order.AverageFillPrice - (BreakEvenTicks *TickSize);
                                    Print("currentSlPrice "+Time[0]+ "  "+currentSlPrice);
                                    Print("currentPtPrice "+ Time[0]+ "  "+currentPtPrice);
                                    TriggerState = 2;
                                     BackBrush = Brushes.DarkKhaki;
                                   }
                                #region BE code was removed from here and inserted in the OBU method because it never entered here                          /*
                                if (TriggerState == 2 && (Closes[2][0] <= currentPtPrice))
                               {
                                    TriggerState = 3;
    
                                       stopOrder = ExitShortStopMarket(0, true, stopOrder.Quantity, order.AverageFillPrice, "MyStop", "MyEntry");
                                       //ChangeOrder(stopOrder, DefaultQuantity,0,PriceEntered);  Tried both approaches.... same result                    
    ​
                                       BackBrush = Brushes.LightGreen;
    
                                       currentSlPrice = Position.AveragePrice;
                                    currentPtPrice -= trailFrequency * (TickSize / 2);
    
                               }​
    Code:
                        //This is the code I moved up the the OBU method. It works partially. The stop moves when the primary series bar closes.
                        if ((TriggerState == 2)
                         && (Closes[2][0] <= currentPtPrice)
                         && stopOrder != null && stopOrder.StopPrice > Position.AveragePrice    )
                        {
                            //Print("TriggerState 2 " +Time[0] );
                            TriggerState = 3;
                            currentSlPrice = PriceEntered; //Position.AveragePrice;
                            currentPtPrice -= trailFrequency * (TickSize / 2);
    
                            Print("currentSlPrice " +Time[0] + "   "+currentSlPrice);
                            Draw.Diamond(this, @"BreakEvenBuilderExample Diamond_1", true, 0, (High[0] + (2 * TickSize)) , Brushes.DarkCyan);
                            //SetStopLoss(CalculationMode.Price,currentSlPrice);
                            //stopOrder = ExitShortStopMarket(2, true, stopOrder.Quantity, Position.AveragePrice, "MyStop", "MyEntry");
                            ChangeOrder(stopOrder, DefaultQuantity,0,PriceEntered);                      
    
                           BackBrush = Brushes.LightGreen;
                        }
    ​
    Code:
    else if (State == State.Configure)
                {
                    //BarArray Series 1
                    AddDataSeries("ES 12-22", Data.BarsPeriodType.Minute, 5, Data.MarketDataType.Last);
                    // BarArray series 2
                    AddDataSeries(Data.BarsPeriodType.Tick, 1);
    All my coding is taken from the examples provided by Ninja.

    I appreciate your support. Thanks.
    Last edited by bobperez; 10-01-2022, 10:18 PM.

    #2
    Hello bobperez,

    To trigger actions before the bar closes, set Calculate to OnPriceChange.

    In historical, this would also require enabling TickReplay, (and 1-tick intra-bar granularity which appears to be implemented).
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      https://clipchamp.com/watch/SycaOVZd...183.1664762514Hi Chelsea,

      Thank you for your kind reply,

      I've already implemented your suggestion, but the BreakEven does not trigger at 7 ticks. It does after the primary bar closes.

      BobPerez
      Last edited by bobperez; 10-02-2022, 08:34 PM.

      Comment


        #4
        Hello BobPerez,

        Are you printing on every bar update to confirm the prints are appearing intra-bar? Are you seeing multiple prints with the same timestamp?


        Are the orders being submitted to a 1-tick series? Have you enabled TraceOrders and looked at the output to show the order is being submitted before the bar closes?
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5


          Hi again Chelsea,

          Here is a screenshot of my output window for the trade considered. Apparently, the answer to all your questions is Yes. This is the code that generated the output window and the breakeven handling.

          Code:
            
                              if (TriggerState == 2 && Closes[2][0] >= currentPtPrice) //TriggerState == 2 && Close[0] >= currentPtPrice
                                     {
                                         Print("TRIGGER 2");    
                                         Print("High[0] >= currentPtPrice "+Convert.ToString(High[0] >= currentPtPrice));    
                                         Print("currentPtPrice "+ currentPtPrice.ToString());    
          
                                         Print("TRIGGER 3");    
                                            TriggerState = 3;
                                          //stopOrder = ExitLongStopMarket(2, true, stopOrder.Quantity, Position.AveragePrice , "MyStop", "MyEntry");
                                          ChangeOrder(stopOrder, DefaultQuantity,0,PriceEntered);                      
          
                                             BackBrush = Brushes.LightGreen;
          
                                             currentSlPrice = PriceEntered;
                                          currentPtPrice += trailFrequency * (TickSize / 2);
                                     }​
          
                              if(TriggerState > 2)
                                     {
                                             Print("TRIGGER > 2");    
          
                                         if(UsarTrailStop )
                                          {  
                                          // Checks to see if our Stop Order has been submitted already
                                              if(Lows[2][0]> Lows[2][1]  && Closes[2][0] >= currentPtPrice && stopOrder != null && stopOrder.StopPrice < currentSlPrice)  
                                              {
                                                      currentSlPrice = Low[1]-(TickSize/2) > currentSlPrice ? Low[1]-(TickSize/2) : currentSlPrice ;
                                                  currentPtPrice +=  (trailFrequency *(TickSize/2));
                                              }
                                          }
                                          //stopOrder = ExitLongStopMarket(2, true, stopOrder.Quantity,currentSlPrice , "MyStop", "MyEntry");
                                          ChangeOrder(stopOrder, DefaultQuantity,0,currentSlPrice);                      
          
                                             BackBrush = Brushes.PaleGreen;
                                     }
                                      if (Close[0] >= currentPtPrice && stopOrder != null)
                                      {
                                          // Checks to see if our Stop Order has been submitted already
                                          if (stopOrder != null && stopOrder.StopPrice < currentSlPrice)
                                          {
          
                                              currentPtPrice +=  trailFrequency * (TickSize / 2);
                                              currentSlPrice +=  trailDistance * (TickSize / 2);
          
                                              // Modifies stop-loss to breakeven
                                             // stopOrder = ExitLongStopMarket(2, true, stopOrder.Quantity,currentSlPrice , "MyStop", "MyEntry");
                                              ChangeOrder(stopOrder, DefaultQuantity,0,currentSlPrice);                      
          
                                             BackBrush = Brushes.Green;
          
                                          }
                                      }​



          Thans again, BobPerezClick image for larger version  Name:	TraceOrder.png Views:	0 Size:	100.9 KB ID:	1217753
          Last edited by bobperez; 10-02-2022, 08:58 PM.

          Comment


            #6
            Hello BobPerez,

            To save the output from the output window to a text file so this can be shared, right-click the output window and select Save As.

            Looking at the screenshot, I am not seeing multiple updates for the same bar. This would imply that the script is not updating intra-bar and since it is not updating intra-bar orders and other actions will only be triggered when the bar closes.

            Use Calculate.OnEachTick/.OnPriceChange with TickReplay to trigger intra-bar actions, implement 1-tick intra-bar granularity for accurate order fills.
            Chelsea B.NinjaTrader Customer Service

            Comment


              #7
              Hi Chelsea, Sorry for my late reply. I had a busy day.

              With TickReplay and OnPriceChange the breakeven stoploss triggered correctly when the condition was met, and the position was closed at Breakeven.

              Now I see a difference between the Playback which got stopped at Breakeven as expected, and the Historic result after reloading the script.
              Click image for larger version

Name:	DifferencePlayback-Historic.png
Views:	212
Size:	23.1 KB
ID:	1217890
              How can I fix this?

              Thanks,

              BobPerez

              Comment


                #8
                Hello bobperez,

                Are you implementing 1-tick intra-bar granularity?
                Please answer this before continuing.

                Are you using a bar type that does not work with TickReplay like renko?

                To understand what is causing differences, write the information to file and attach the output files with your reply.

                Follow the directions in this forum thread:
                Citizens of the NinjaTrader Community, A common question we hear from clients is 'why are results from backtest different from real-time or from market replay?'. Live orders are filled on an exchange with a trading partner on an agreed upon price based on market dynamics. Backtest orders are not using these market dynamics.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  Hi Chelsea,

                  Yes, I am implementing 1-Tick granularity.
                  I am using 1 minute bars.
                  TickReplay is turned on.

                  The structure of the strategy is the following:

                  protected override void OnStateChange()
                  region State.SetDefaults
                  region State.Configure
                  if (State == State.Configure)
                  {
                  AddDataSeries("ES 12-22", Data.BarsPeriodType.Minute, 5, Data.MarketDataType.Last);
                  AddDataSeries(Data.BarsPeriodType.Tick, 1);
                  }​
                  protected override void OnBarUpdate()
                  if (BarsInProgress != 0)
                  return;​
                  If( BarsInProgress == 0)
                  {
                  // Full coding goes here
                  }
                  protected override void OnOrderUpdate
                  protected override void OnExecutionUpdate

                  Thanks again.

                  BobPerez
                  Attached Files
                  Last edited by bobperez; 10-04-2022, 09:12 PM.

                  Comment


                    #10
                    Hello bobperez,

                    First, I am seeing your logic is allowing for some invalid orders.
                    28/09/2022 9:51:00 a. m. Strategy 'RobertAnderson1Min/272814399': Ignored SubmitOrderManaged() method at 28/09/2022 9:51:00 a. m.: BarsInProgress=0 Action=BuyToCover OrderType=Market Quantity=0 LimitPrice=0 StopPrice=0 SignalName='' FromEntrySignal='' Reason='This was an exit order but no position exists to exit'
                    May I also have you output the order object in OnOrderUpdate() so that we can see all orders as they change states?
                    28/09/2022 9:51:00 a. m. Strategy 'RobertAnderson1Min/272814399: Cancelled pending exit order, since associated position is closed, orderId='NT-00021-623' account='Playback101' name='MyTarget' orderState=Working instrument='ES 12-22' orderAction=Sell orderType='Limit' limitPrice=3677 stopPrice=0 quantity=1 tif=Gtc oco='' filled=0 averageFillPrice=0 onBehalfOf='' id=-1 time='2022-09-28 09:50:52' gtd='2099-12-01' statementDate='2022-10-04'
                    In playback, this order was cancelled, was there another order that filled and closed the position? The output from the order object in OnOrderUpdate() would let us know what orders are filling.

                    The output isn't really showing what's happening as there are no comparison labels..

                    I am happy to assist with making a more informative output.

                    The specific condition in question is:
                    Code:
                    if (TriggerState == 2 && Closes[2][0] >= currentPtPrice)
                    Is this correct?

                    If so, the output I would write would be:
                    Code:
                    message = string.Format("{0:dd/MM/yyyy H:mm:ss.ffff} | BIP: {1} | TriggerState: {2} == 2 && Closes[2][0]: {3} >= currentPtPrice: {4}", Time[0], BarsInProgress, TriggerState, Closes[2][0], currentPtPrice);

                    Do you have any check to make sure the stopOrder is in a working state before attempting to modify the order?
                    Chelsea B.NinjaTrader Customer Service

                    Comment


                      #11
                      Click image for larger version  Name:	AutoTrade.png Views:	4 Size:	42.8 KB ID:	1218246Click image for larger version  Name:	HistoricTrade.png Views:	5 Size:	70.9 KB ID:	1218248 ​​​​​

                      Hi Chelsea,

                      Thank you for your sustained support. I hope the files I'm attaching comply with your request.​

                      For the historic trade, I placed a starting time after the trade was made.
                      For the auto trade, I placed a starting time before the trade occurred.

                      Code:
                            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;
                                      PriceEntered = order.AverageFillPrice;
                      
                      
                                      // 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)
                                          {
                                              if(enShort)
                                                  stopOrder = ExitShortStopMarket(2, true, execution.Order.Filled, execution.Order.AverageFillPrice+ (Stop*TickSize), "MyStop", "MyEntry");
                                              else if (enLong)
                                                  stopOrder = ExitLongStopMarket(2, true, execution.Order.Filled, execution.Order.AverageFillPrice - (Target * TickSize), "MyStop", "MyEntry");
                      
                                                      Print(" INSIDE SECTION: execution.Order.OrderState == OrderState.PartFilled");
                      
                                                     message = string.Format("{0:dd/MM/yyyy H:mm:ss.ffff} |  stopOrder: {1} | execution.Order.OrderState == OrderState.PartFilled", Time[0], stopOrder);                    
                                                      Print(message);
                      
                                                      Print("-------------- LEAVING  SECTION: execution.Order.OrderState == OrderState.PartFilled------------------");
                      
                                              //targetOrder = ExitLongLimit(0, true, execution.Order.Filled, execution.Order.AverageFillPrice + 12 * TickSize, "MyTarget", "MyEntry");
                                          }
                      
                      
                                          // Update our exit order quantities once orderstate turns to filled and we have seen execution quantities match order quantities
                                          if (execution.Order.OrderState == OrderState.Filled && sumFilled == execution.Order.Filled)
                                          {
                      
                                              tradeCounter++;
                      
                                              #region isShort
                                              if(Position.MarketPosition == MarketPosition.Short && (execution.Order.OrderState != OrderState.Cancelled ))
                                              {
                                                  stopOrder = ExitShortStopMarket(2, true, execution.Order.Filled, execution.Order.AverageFillPrice+ (Stop*TickSize), "MyStop", "MyEntry");
                                                  targetOrder = ExitShortLimit(2, true, execution.Order.Filled, execution.Order.AverageFillPrice - (Target * TickSize), "MyTarget", "MyEntry");
                      
                                                  Print("FROM INSIDE SHORT execution.Order.OrderState == OrderState.Filled && sumFilled == execution.Order.Filled");
                                                  message = string.Format("{0:dd/MM/yyyy H:mm:ss.ffff} |  stopOrder: {1} ", Time[0], stopOrder);                    
                                                  Print(message);
                                                  Print("------------------");
                                                  message = string.Format("{0:dd/MM/yyyy H:mm:ss.ffff} |  targetOrder: {1} ", Time[0], targetOrder);                    
                                                  Print(message);
                      
                      
                      
                                                  if(TriggerState == 1   && stopOrder != null && stopOrder.StopPrice > Position.AveragePrice) //&& (Close[0] >= currentPtPrice)
                                                  {      
                                                      Print("Trigger1 "+Time[0]);
                                                      //currentSlPrice = Position.AveragePrice + (Stop * TickSize);
                                                      //currentPtPrice =  Position.AveragePrice - (BreakEvenTicks *TickSize);
                                                      currentSlPrice = PriceEntered+ (Stop * TickSize);
                                                      currentPtPrice =  PriceEntered - (BreakEvenTicks *TickSize);
                      
                                                      Print("currentSlPrice "+Time[0]+ "  "+currentSlPrice);
                                                      Print("currentPtPrice "+ Time[0]+ "  "+currentPtPrice);
                                                      TriggerState = 2;
                                                       BackBrush = Brushes.DarkKhaki;
                                                     }
                                              }    
                      
                                              #region enlong
                                              if (Position.MarketPosition == MarketPosition.Long)  //else
                                              {
                                                  Print("isLong");
                                                  stopOrder = ExitLongStopMarket(2, true, execution.Order.Filled, execution.Order.AverageFillPrice-Stop*TickSize, "MyStop", "MyEntry");
                                                     targetOrder = ExitLongLimit(2, true, execution.Order.Filled, execution.Order.AverageFillPrice + Target * TickSize, "MyTarget", "MyEntry");
                      
                                                  Print("FROM INSIDE LONG execution.Order.OrderState == OrderState.Filled && sumFilled == execution.Order.Filled");
                                                  message = string.Format("{0:dd/MM/yyyy H:mm:ss.ffff} |  stopOrder: {1} ", Time[0], stopOrder);                    
                                                  Print(message);
                                                  Print("------------------");
                                                  message = string.Format("{0:dd/MM/yyyy H:mm:ss.ffff} |  targetOrder: {1} ", Time[0], targetOrder);                    
                                                  Print(message);
                      
                      
                                                  if(TriggerState == 1   && stopOrder != null && stopOrder.StopPrice < Position.AveragePrice) //&& (Close[0] >= currentPtPrice)
                                                  {      
                                                     Print("TRIGGER 1");    
                      
                                                      currentSlPrice = execution.Order.AverageFillPrice - (Stop * TickSize);
                                                      currentPtPrice =  execution.Order.AverageFillPrice + (BreakEvenTicks *TickSize);
                      
                                                      Print("currentSlPrice "+Time[0]+ "  "+currentSlPrice);
                                                      Print("currentPtPrice "+ Time[0]+ "  "+currentPtPrice);
                      
                                                      TriggerState = 2;
                                                       BackBrush = Brushes.DarkKhaki;
                                                     }
                                              }    
                                              #endregion islong
                      
                      
                                          }
                      
                      
                                          // Resets the entryOrder object and the sumFilled counter to null / 0 after the order has been filled
                                          //message = string.Format("{0:dd/MM/yyyy H:mm:ss.ffff} |  execution.Order.OrderState != OrderState.PartFilled: {1} && sumFilled == execution.Order.Filled {2}", Time[0], execution.Order.OrderState != OrderState.PartFilled,sumFilled == execution.Order.Filled);                    
                      
                                          if (execution.Order.OrderState != OrderState.PartFilled && sumFilled == execution.Order.Filled)
                                          {
                                              entryOrder = null;
                                              sumFilled = 0;
                                              //Print(message);
                                         }
                                      }
                                  }
                      
                                  // 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;
                                      }
                                  }
                              }​


                      Thanks,

                      BobPerez
                      Last edited by bobperez; 10-05-2022, 09:18 PM.

                      Comment


                        #12
                        Hello bobperez,

                        It appears different orders are being submitted at different times.

                        The first line in what I am assuming is real-time

                        28/09/2022 9:50:53 a. m. Strategy 'RobertAnderson1Min/272814421': Entered internal SubmitOrderManaged() method at 28/09/2022 9:50:53 a. m.: BarsInProgress=2 Action=Buy OrderType=StopMarket Quantity=1 LimitPrice=0 StopPrice=3673,50 SignalName='MyEntry' FromEntrySignal=''

                        VS historical

                        28/09/2022 9:50:52 a. m. Strategy 'RobertAnderson1Min/272814421': Entered internal SubmitOrderManaged() method at 28/09/2022 9:50:52 a. m.: BarsInProgress=2 Action=Sell OrderType=StopMarket Quantity=1 LimitPrice=0 StopPrice=3671,50 SignalName='MyStop' FromEntrySignal='MyEntry'

                        Use prints to understand why.

                        Find the condition placing these orders. Print the time of the bar and all values used in the condition. Include labels and comparison labels in the output.
                        Chelsea B.NinjaTrader Customer Service

                        Comment


                          #13
                          Thanks Chelsea, As soon as I have any finding I'll write back.

                          BobPerez

                          Comment

                          Latest Posts

                          Collapse

                          Topics Statistics Last Post
                          Started by Gerik, Today, 09:40 AM
                          1 response
                          6 views
                          0 likes
                          Last Post NinjaTrader_Gaby  
                          Started by RookieTrader, Today, 09:37 AM
                          1 response
                          10 views
                          0 likes
                          Last Post NinjaTrader_ChelseaB  
                          Started by alifarahani, Today, 09:40 AM
                          0 responses
                          5 views
                          0 likes
                          Last Post alifarahani  
                          Started by KennyK, 05-29-2017, 02:02 AM
                          3 responses
                          1,284 views
                          0 likes
                          Last Post NinjaTrader_Clayton  
                          Started by AttiM, 02-14-2024, 05:20 PM
                          11 responses
                          185 views
                          0 likes
                          Last Post NinjaTrader_ChelseaB  
                          Working...
                          X