Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Sell Stop Market Order seling below Stop Price in Backtest

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

    Sell Stop Market Order seling below Stop Price in Backtest

    Hi!

    I have a sell stop market order which is filled below the stop price although there is no gap going above the stop price between submission and fill.

    I have a Sell Stop Market order upon Entry Submission in OnOrderUpdate (with OrderState filled) at the entryprice - 8$. In OnBarUpdate I check if the High is 2$ above the entry price and if yes the order is changed to the entry price as stop price.

    Here you can see the stop price is 1097.8 and the fill is at 1097.6:

    Click image for larger version  Name:	image.png Views:	0 Size:	7.2 KB ID:	1235051
    The close where the order stop price is changed to breakeven is 1097.5. The sell stop market order is changed to 1097.8 stop price. The order is filled at the next open at 1097.6 (so below the stop​ of 1097.8).

    Click image for larger version  Name:	image.png Views:	0 Size:	19.5 KB ID:	1235052

    Click image for larger version  Name:	image.png Views:	0 Size:	18.5 KB ID:	1235053

    I am using the unmanaged approach. How is it possible that the order is filled even though the stop price of 1097.8 is not crossed after submission of the sell stop order? What am I missing?

    Thanks in advance!​​​
    Attached Files
    Last edited by KirkHammett; 02-12-2023, 01:45 AM.

    #2
    Hello KirkHammett,

    Not enough information has been provided to know how this order filled.

    We can assume this is historical or Calculate OnBarClose and that 1-tick intar-bar granularity has not been implemented for accurate order fills, if the order is filling at the open of the next bar.


    If the order is between the high and low, that order will be considered filled.




    For accurate fill prices in historical, implement 1-tick intra-bar granularity.
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Hi Chelsea,

      I still don't get it. Yes it is OnBarClose without intrabar granularity.

      Here is the code:

      Code:
      //
      // Copyright (C) 2015, 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
      using System.IO;
      //using System.Timers;
      
      // This namespace holds all strategies and is required. Do not change it.
      namespace NinjaTrader.NinjaScript.Strategies
      {    
          public class MyTEST : Strategy
          {        
              Order longEntry = null;
              Order stopLossLong = null;
              bool breakeven = false;
      
      
              protected override void OnStateChange()
              {
                  if(State == State.SetDefaults)
                  {
                      Description                            = @"Sample monitoring for and trading a breakout";
                      Name                                = "MyTEST";
                      Calculate                           = Calculate.OnBarClose;
      //                Calculate                           = Calculate.OnBarClose;
                      EntriesPerDirection                 = 1;
                      EntryHandling                       = EntryHandling.UniqueEntries;
                      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;
                      IsUnmanaged                         = true;
                      IsAdoptAccountPositionAware         = true;
                      IsInstantiatedOnEachOptimizationIteration = false;
      //                PrintTo = PrintTo.OutputTab2;
                  }
      
                  else if (State == State.Configure)
                  {                    
                      AddDataSeries(new BarsPeriod { BarsPeriodType = BarsPeriodType.Minute, Value = 1440 });    
                  }
              }        
      
              protected override void OnBarUpdate()
              {
                  if (CurrentBars[0] < 20 || CurrentBars[1] < 20)
                      return;
      
                  if (BarsInProgress == 0)
                  {
                      if (Bars.IsLastBarOfSession)
                          CancelOrder(longEntry);
      
                      if (IsFlat || IsShort)
                      breakeven = false;
      
                      if (breakeven == false)
                          if (stopLossLong != null && stopLossLong.StopPrice < Position.AveragePrice && High[0] >= Position.AveragePrice + 2.0)
                          {
                              ChangeOrder(stopLossLong, 1, 0, Position.AveragePrice);
                              breakeven = true;
                          }
      
      
                      if (Bars.IsFirstBarOfSession)
                          if (IsFlat)
                              SubmitOrderUnmanaged(0, OrderAction.Buy, OrderType.Market, 1, 0, 0, "MyLE"+CurrentBar.ToString(), "MyLE");
      
                      if (Bars.IsLastBarOfSession)
                      {                    
                          if (IsLong)
                          {
                              SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.Market, 1, 0, 0, "MyLX"+CurrentBar.ToString(), "MyLX");
                          }
                          CancelOrder(longEntry);
                          CancelOrder(stopLossLong);
                      }
      
                  }
      
      
      
              }
      
      
              protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
              {
                  if (order.Name == "MyLE")
                      longEntry = order;
      
                  if (order.Name == "MySLL")
                      stopLossLong = order;
      
                  if (order.Name == "MyLE" && order.OrderState == OrderState.Filled)
                  {
                      longEntry = null;
                      SubmitOrderUnmanaged(0, OrderAction.SellShort, OrderType.StopMarket, Position.Quantity, 0, order.AverageFillPrice - 8.0, "MySLL"+CurrentBar.ToString(), "MySLL");
                  }
                  if (order.Name == "MyLE" && order.OrderState == OrderState.Cancelled)
                      CancelOrder(stopLossLong);
      
                  if (order.Name == "MySLL" && order.OrderState == OrderState.Filled)
                      stopLossLong = null;
      
                  if (order.Name == "MyLX" && order.OrderState == OrderState.Filled)
                      stopLossLong = null;
      
      
              }
      
              #region Helpers
              bool IsFlat { get { return base.Position.MarketPosition == MarketPosition.Flat; }}
              bool IsLong { get { return base.Position.MarketPosition == MarketPosition.Long; }}
              bool IsShort { get { return base.Position.MarketPosition == MarketPosition.Short; }}
              bool TradingStocks { get { return base.Instrument.MasterInstrument.InstrumentType == InstrumentType.Stock; }}
              bool TradingFutures { get { return base.Instrument.MasterInstrument.InstrumentType == InstrumentType.Future; }}
              bool TradingForex { get { return base.Instrument.MasterInstrument.InstrumentType == InstrumentType.Forex; }}
              bool TradingIndex { get { return base.Instrument.MasterInstrument.InstrumentType == InstrumentType.Index; }}
              bool TradingCFD { get { return base.Instrument.MasterInstrument.InstrumentType == InstrumentType.Cfd; }}
              #endregion
      
      
          }
      
      }
      ​
      The trade I was referring to in my first post is on GC future on 15 December 2008. As I said: The Close is 1097.5. At this close the Sell Stop Order is changed to 1097.8. The Open afterwards is 1097.6 and the sell Stop Order is filled at the Open (1097.6) although below 1097.8. How is this possible?

      Thanks in advance!

      Comment


        #4
        Hello KirkHammett,

        The order is filled on the next bar as it is submitted after the submission bar is closed (OnBarClose). It is between the high and low of that bar so it is filled.

        If you want the order filled at an accurate price and time you would need the 1-tick intra-bar granularity implemented.
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          Hi Chelsea,

          I figured it out: Since the Sell Stop Order is changed to a price above the Close at the Bar where the Calculation takes place the position is closed at the next open even though it is below the stop price. The weird thing is: This behavior only occurs if the I use ChangeOrder. If I use a SubmitOrderUnmanaged the Order is simply ignored because it is above the Close. Is this difference in the behavior between Changeorder and SubmitOrderUnmanaged expected?

          If you want to try it I made a more simplified code for the ChangeOrder example (see below). After you tried this code just comment the Sell Stop Order at the first bar of session (Line 84) and Change order (Line 92) and instead uncomment the Sell Stop Market Order at barnumber 2 (Line 92) and you will see the difference.

          I use the GC Future on 60 Minutes.

          Is this difference between Changing an Order and Submitting an Order expected?

          Code:
          //
          // Copyright (C) 2015, 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
          using System.IO;
          
          // This namespace holds all strategies and is required. Do not change it.
          namespace NinjaTrader.NinjaScript.Strategies
          {    
              public class MyTEST : Strategy
              {        
                  double barnumber = 0;
                  Order SLL = null;
          
                  protected override void OnStateChange()
                  {
                      if(State == State.SetDefaults)
                      {
                          Description                            = @"Sample monitoring for and trading a breakout";
                          Name                                = "MyTEST";
                          Calculate                           = Calculate.OnBarClose;
          //                Calculate                           = Calculate.OnBarClose;
                          EntriesPerDirection                 = 1;
                          EntryHandling                       = EntryHandling.UniqueEntries;
                          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;
                          IsUnmanaged                         = true;
                          IsAdoptAccountPositionAware         = true;
                          IsInstantiatedOnEachOptimizationIteration = false;
          //                PrintTo = PrintTo.OutputTab2;
                      }
          
                      else if (State == State.Configure)
                      {                    
                          AddDataSeries(new BarsPeriod { BarsPeriodType = BarsPeriodType.Minute, Value = 1440 });    
                      }
                  }        
          
                  protected override void OnBarUpdate()
                  {
                      if (CurrentBars[0] < 20 || CurrentBars[1] < 20)
                          return;
          
                      if (BarsInProgress == 0 && ToDay(Time[0]) == 20081215)
                      {
                          if (Bars.IsFirstBarOfSession)
                          {
                              barnumber = 0;
          
                              SubmitOrderUnmanaged(0, OrderAction.Buy, OrderType.Market, 1, 0, 0, "MyLE"+CurrentBar.ToString(), "MyLE");
                              SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, 1, 0, Close[0]-10, "MySLL"+CurrentBar.ToString(), "MySLL");
                          }
          
                          barnumber++;
          
                          if (barnumber == 2)
                          {
          //                    SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, Position.Quantity, 0, Position.AveragePrice, "MySLL"+CurrentBar.ToString(), "MySLL");
                              ChangeOrder(SLL, 1, 0, Position.AveragePrice);
                          }
          
                          if (Bars.IsLastBarOfSession)
                              if (Position.MarketPosition == MarketPosition.Long)
                                  SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.Market, 1, 0, 0, "MyLX"+CurrentBar.ToString(), "MyLX");
                      }
                  }
          
                  protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
                  {
                      if (order.Name == "MySLL")
                          SLL = order;
                  }
              }
          
          }
          ​
          ​
          Last edited by KirkHammett; 02-14-2023, 07:08 AM.

          Comment


            #6
            Hello KirkHammett,

            A sell stop order must have the stop price below the bid. A sell stop with a stop price above the bid will be rejected by every brokerage. No brokerage is going to accept that order.

            To confirm, you are stating that ChangeOrder() will allow a change to a historical order to an invalid order price?
            Chelsea B.NinjaTrader Customer Service

            Comment


              #7
              Hi Chelsea,

              yes that is correct. ChangeOrder lets me change it to an invalid price in a backtest.

              Comment


                #8
                Hello KirkHammett,

                Thanks for confirming. I will do some testing and let you know what I find.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  Hello KirkHammett,

                  I was able to reproduce the ChangeOrder() allowing an invalid order price and have reported the behavior to our development.

                  This issue is being tracked with ID # NTEIGHT-15703.

                  As new releases of NinjaTrader become available, please check the release notes for the number 15703.


                  Once listed, please update to the latest release and confirm the issue is resolved.
                  Chelsea B.NinjaTrader Customer Service

                  Comment


                    #10
                    Thanks for clarification!

                    Comment

                    Latest Posts

                    Collapse

                    Topics Statistics Last Post
                    Started by johnMoss, Yesterday, 08:56 PM
                    2 responses
                    19 views
                    0 likes
                    Last Post johnMoss  
                    Started by michelz, Yesterday, 08:30 AM
                    6 responses
                    36 views
                    0 likes
                    Last Post MiCe1999  
                    Started by ntbone, Yesterday, 01:50 AM
                    13 responses
                    54 views
                    0 likes
                    Last Post MiCe1999  
                    Started by gyilaoliver, Today, 10:30 AM
                    1 response
                    6 views
                    0 likes
                    Last Post NinjaTrader_Gaby  
                    Started by Irukandji, Yesterday, 04:24 PM
                    2 responses
                    27 views
                    0 likes
                    Last Post NinjaTrader_LuisH  
                    Working...
                    X