Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Sell stop or sell stop limit orders can't be placed above the market

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

    Sell stop or sell stop limit orders can't be placed above the market

    Hi, I'm having trouble with an EnterLongStopMarket:

    2020-12-14 15:13:54:327 (Conexión de reproducción) Cbi.Account.OrderUpdateCallback: realOrderState=Rejected orderId='xxxx' account='Playback101' name='SE' orderState=Rejected instrument='NQ 12-20' orderAction=SellShort limitPrice=0 stopPrice=11949.5 quantity=1 orderType='Stop Market' filled=0 averageFillPrice=0 time='2020-11-23 00:31:23' statementDate='2020-11-23' error=OrderRejected comment='Sell stop or sell stop limit orders can't be placed above the market.' nr=2

    OnBarUpdate:

    if ( (CrossBelow(x, a, 1))
    && (z< y && Position.Quantity == 0)
    {
    SetStopLoss(CalculationMode.Price, (buyEntryprice+20));
    EnterShortStopMarket(0, true, Convert.ToInt32(DefaultQuantity),sellEntryprice, "SE");
    }

    the strange thing is that the error happens when the replay is at 1000x and not when it is done at 1x. What am I missing here?

    #2
    Hello rocker84,

    Thanks for your post.

    There was an issue with inconsistent Playback behavior that was addressed in Release 23.2. Could you update to this version of the platform and repeat your test?

    If the issue is still apparent, could you prepare a barebones strategy that demonstrates the issue so we can reproduce on our end?

    Exporting as Source Code - https://ninjatrader.com/support/help...tAsSourceFiles

    Update - https://ninjatrader.com/PlatformDirect

    We look forward to asissting.
    JimNinjaTrader Customer Service

    Comment


      #3
      Originally posted by NinjaTrader_Jim View Post
      Hello rocker84,

      Thanks for your post.

      There was an issue with inconsistent Playback behavior that was addressed in Release 23.2. Could you update to this version of the platform and repeat your test?

      If the issue is still apparent, could you prepare a barebones strategy that demonstrates the issue so we can reproduce on our end?

      Exporting as Source Code - https://ninjatrader.com/support/help...tAsSourceFiles

      Update - https://ninjatrader.com/PlatformDirect

      We look forward to asissting.
      I still have the same error that I have to solve with the code, but it seems that now it works the same with 1000x or 1x, many errors that appeared before now do not appear. Thanks a lot.

      Comment


        #4
        Hello rocker84,

        Thanks for updating and replying back.

        The reject noted in post #1 is for a Short Entry where the stop price is placed above the market. In other words, the price in sellEntryprice is not at a valid level when the order is submitted.

        You are using buyEntryprice as an offset for the stop loss but sellEntryprice is used for the entry order. This may be an oversight where the rejection occurs.

        Ultimately, addressing the issue from here involves reproducing the issue with debugging prints added so you can observe the price that is being submitted, and how that price got calculated so you can make adjustments.

        Debugging Tips - https://ninjatrader.com/support/help...script_cod.htm

        As a tip, you could consider offsetting your orders with GetCurrentBid + GetCurrentAsk to ensure they are submitted to valid levels.

        GetCurrentBid - https://ninjatrader.com/support/help...currentbid.htm

        GetCurrrentAsk - https://ninjatrader.com/support/help...currentask.htm

        We look forward to assisting.
        JimNinjaTrader Customer Service

        Comment


          #5
          Originally posted by NinjaTrader_Jim View Post
          Hello rocker84,

          Thanks for updating and replying back.

          The reject noted in post #1 is for a Short Entry where the stop price is placed above the market. In other words, the price in sellEntryprice is not at a valid level when the order is submitted.

          You are using buyEntryprice as an offset for the stop loss but sellEntryprice is used for the entry order. This may be an oversight where the rejection occurs.

          Ultimately, addressing the issue from here involves reproducing the issue with debugging prints added so you can observe the price that is being submitted, and how that price got calculated so you can make adjustments.

          Debugging Tips - https://ninjatrader.com/support/help...script_cod.htm

          As a tip, you could consider offsetting your orders with GetCurrentBid + GetCurrentAsk to ensure they are submitted to valid levels.

          GetCurrentBid - https://ninjatrader.com/support/help...currentbid.htm

          GetCurrrentAsk - https://ninjatrader.com/support/help...currentask.htm

          We look forward to assisting.
          I practically fixed all the errors, but some that appear from time to time and stop the strategy. Is there any example code that takes into account all the details for limit orders and stop orders? Even if an error appears, do not stop the strategy. Thanks in advance

          Comment


            #6
            Hello rocker84,

            I can't suggest a strategy example that handles all cases of order errors, but it is possible to write a strategy that uses RealtimeErrorHandling to keep the strategy running in the event of an order error or rejection.

            RealtimeErrorHandling

            To prevent the strategy from being deactivated when an order error occurs, you can set the strategy's RealtimeErrorHandling property to IgnoreAllErrors. StopCancelCloseIgnoreRejects will keep the strategy running for rejections but not for other order errors like a failure to change an order. With this property set, you can then trap order errors in OnOrderUpdate if you would like to have the strategy attempt a different action.

            Please note that this is reserved for advanced uses that want to implement their own order error handling. Neglecting to handle an order error when having RealtimeErrorHandling set to IgnoreAllErrors or StopCancelCloseIgnoreRejects can result in catastrophic damages to your account. ALWAYS monitor your automated trading strategies.

            RealtimeErrorHandling - https://ninjatrader.com/support/help...orhandling.htm

            OnOrderUpdate() - https://ninjatrader.com/support/help...rderupdate.htm
            JimNinjaTrader Customer Service

            Comment


              #7
              Originally posted by NinjaTrader_Jim View Post
              Hello rocker84,

              I can't suggest a strategy example that handles all cases of order errors, but it is possible to write a strategy that uses RealtimeErrorHandling to keep the strategy running in the event of an order error or rejection.

              RealtimeErrorHandling

              To prevent the strategy from being deactivated when an order error occurs, you can set the strategy's RealtimeErrorHandling property to IgnoreAllErrors. StopCancelCloseIgnoreRejects will keep the strategy running for rejections but not for other order errors like a failure to change an order. With this property set, you can then trap order errors in OnOrderUpdate if you would like to have the strategy attempt a different action.

              Please note that this is reserved for advanced uses that want to implement their own order error handling. Neglecting to handle an order error when having RealtimeErrorHandling set to IgnoreAllErrors or StopCancelCloseIgnoreRejects can result in catastrophic damages to your account. ALWAYS monitor your automated trading strategies.

              RealtimeErrorHandling - https://ninjatrader.com/support/help...orhandling.htm

              OnOrderUpdate() - https://ninjatrader.com/support/help...rderupdate.htm
              Ok, I think the error that I could not solve is that my strategy checks the bid / ask, set the stop correctly on that, but once the order is sent the price moves quickly and then the order would be rejected. How should this situation be considered with the code?

              Comment


                #8
                Hello rocker84,

                Submitting a stop market order directly on the bid/ask could carry significant risk of rejection as the price would only have to slip 1 tick before that order would become invalid.

                You can check if the order's OrderState is OrderState.Rejected in OnOrderUpdate to attempt a different action when using IgnoreAllErrors or StopCancelCloseIgnoreRejects. Please see the example snippet in the RealtimeErrorHandling documentation to see how this can be set up. That action could be to submit a market order to exit, or to place another stop market order at a different level.

                I do have an example that can demonstrate handling a rejected order and I have attached it here.

                Please let us know if you have any additional questions.



                Attached Files
                JimNinjaTrader Customer Service

                Comment


                  #9
                  Originally posted by NinjaTrader_Jim View Post
                  Hello rocker84,

                  Submitting a stop market order directly on the bid/ask could carry significant risk of rejection as the price would only have to slip 1 tick before that order would become invalid.

                  You can check if the order's OrderState is OrderState.Rejected in OnOrderUpdate to attempt a different action when using IgnoreAllErrors or StopCancelCloseIgnoreRejects. Please see the example snippet in the RealtimeErrorHandling documentation to see how this can be set up. That action could be to submit a market order to exit, or to place another stop market order at a different level.

                  I do have an example that can demonstrate handling a rejected order and I have attached it here.

                  Please let us know if you have any additional questions.


                  Thanks a lot! To cancel the operation completely it is working fine, however if I send it to market with "EnterLong ()" it takes the stoploss of the previous operation. I think Onbarupdate is mixed with OnOrderUpdate. Is there a way to reset the stop and add it in OnOrderUpdate? Here's what those parts of the code look like (had to hide a lot):

                  protected override void OnBarUpdate()

                  ///...///

                  if ( (something)
                  && something
                  && something
                  && something
                  && something
                  && something
                  )

                  {



                  SetStopLoss(@"MyEntryLong",CalculationMode.Percent , 0.01,false);

                  if (Position.MarketPosition == MarketPosition.Flat)
                  {
                  if (GetCurrentBid(0) >= (buyEntryprice-TickSize)) EnterLongLimit(0, true, Convert.ToInt32(DefaultQuantity),buyEntryprice, "MyEntryLong");
                  else EnterLongStopMarket(0, true, Convert.ToInt32(DefaultQuantity),buyEntryprice, "MyEntryLong");
                  }
                  }

                  if(Position.MarketPosition == MarketPosition.Long)

                  {

                  if(GetCurrentBid(0) > stopLossBuy) //&& (Low[0] < stopLossBuy))
                  {


                  SetStopLoss(@"MyEntryLong",CalculationMode.Price, (Math.Floor( stopLossBuy / TickSize) * TickSize),false);
                  ///added to rejected order
                  SetStopLoss(@"MyEntryLong2",CalculationMode.Price, (Math.Floor( stopLossBuy / TickSize) * TickSize),false);
                  }}

                  if((upBarCounter >= (maxBarsAfter-1)) && (entryOrderLong != null))

                  {
                  upBarCounter = 0;
                  CancelOrder(entryOrderLong);
                  }


                  ///same for short






                  protected override void OnExecutionUpdate(Execution execution, string executionId, double price, int quantity, MarketPosition marketPosition, string orderId, DateTime time)
                  {
                  Share("StockTwits", "Order Filled");
                  }




                  protected override void OnPositionUpdate(Position position, double averagePrice, int quantity, MarketPosition marketPosition)
                  {

                  if (Position.MarketPosition == MarketPosition.Flat && SystemPerformance.AllTrades.Count > 0)
                  {
                  currentPnL += SystemPerformance.AllTrades[SystemPerformance.AllTrades.Count - 1].ProfitCurrency;

                  }

                  }

                  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 order in OnOrderUpdate() to ensure the assignment occurs when expected.
                  // This is more reliable than assigning Order objects in OnBarUpdate,
                  // as the assignment is not guaranteed to be complete if it is referenced immediately after submitting
                  if (order.Name == "MyEntryLong")
                  {
                  entryOrderLong = order;
                  // Reset the entryOrder object to null if order was cancelled without any fill
                  if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                  entryOrderLong = null;
                  }

                  if (order.Name == "MyEntryLong2")
                  {
                  entryOrderLong2 = order;
                  // Reset the entryOrder2 object to null if order was cancelled without any fill
                  if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                  entryOrderLong2 = null;
                  }

                  if (entryOrderLong != null && entryOrderLong == order)
                  {
                  // Rejection handling
                  if (order.OrderState == OrderState.Rejected)
                  {
                  // Order was rejected !!!!
                  // Do something about it here
                  entryOrderLong = null;

                  SetStopLoss(@"MyEntryLong2", CalculationMode.Percent, 0.01,false);
                  ///SetStopLoss(@"MyEntryLong2",CalculationMode.Price, (Math.Floor( stopLossBuy / TickSize) * TickSize),false);
                  EnterLong(Convert.ToInt32(ContratosporTrade), @"MyEntryLong2");

                  }
                  }

                  // Assign order in OnOrderUpdate() to ensure the assignment occurs when expected.
                  // This is more reliable than assigning Order objects in OnBarUpdate,
                  // as the assignment is not guaranteed to be complete if it is referenced immediately after submitting
                  if (order.Name == "MyEntryShort")
                  {
                  entryOrderShort = order;
                  // Reset the entryOrder object to null if order was cancelled without any fill
                  if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                  entryOrderShort = null;
                  }

                  if (order.Name == "MyEntryShort2")
                  {
                  entryOrderShort2 = order;
                  // Reset the entryOrder2 object to null if order was cancelled without any fill
                  if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                  entryOrderShort2 = null;
                  }

                  if (entryOrderShort != null && entryOrderShort == order)
                  {
                  // Rejection handling
                  if (order.OrderState == OrderState.Rejected)
                  {
                  // Order was rejected !!!!
                  // Do something about it here
                  entryOrderShort = null;

                  SetStopLoss(@"MyEntryShort2", CalculationMode.Percent, 0.01,false);
                  ///SetStopLoss(@"MyEntryShort2",CalculationMode.Price , (Math.Ceiling( stopLossSell / TickSize) * TickSize),false);
                  EnterShort(Convert.ToInt32(ContratosporTrade), @"MyEntryShort2");

                  }
                  }


                  }

                  Comment


                    #10
                    Hello rocker84,

                    Thanks for your question.

                    So I understand correctly, the first entry gets rejected and when you submit the second entry, it is using the stop loss of the first entry as opposed to the stop loss for the second entry?

                    I see that you are using signal names to tie the entries to their own stop losses. This is important to do. We should also keep in mind that Set methods should be called before that associated entry method gets called so the stop loss is properly reset and prepped for when that entry order executes. If a Set method not given an fromEntrySignal name, it will apply to all entries. If the Set method is called again, it will update the stop loss.

                    We should also note that OnOrderUpdate and OnBarUpdate are asynchronous to eachother. It is possible that the Set method gets called elsewhere after the order is submitted, but before it executes, which would adjust the initial stop loss before the entry order is executed and the associated stop loss is submitted. Narrowing that down will require debugging steps. I.E. to reproduce the occurrence with Playback, and place prints beside your Set methods to see which is firing and adjusting the stop.

                    I have also tested a modification of the RejectionTest example to demonstrate:

                    1. SetStopLoss is called before the Enter method of the first order with a stop loss of 10 ticks
                    2. SetStopLoss is called in OnOrderUpdate before the 2nd Enter method is called with a stop loss of 20 ticks.
                    3. When the 1st order gets rejected, the second stop loss is placed 20 ticks away from the current market price.

                    You may wish to comment out custom stop loss handling until you get behavior matching the test script, and then to add the stop loss moving behaviors back to identify which parts are adjusting your stop loss unexpectedly.

                    We look forward to assisting.

                    Attached Files
                    JimNinjaTrader Customer Service

                    Comment


                      #11
                      Originally posted by NinjaTrader_Jim View Post
                      Hello rocker84,

                      Thanks for your question.

                      So I understand correctly, the first entry gets rejected and when you submit the second entry, it is using the stop loss of the first entry as opposed to the stop loss for the second entry?

                      I see that you are using signal names to tie the entries to their own stop losses. This is important to do. We should also keep in mind that Set methods should be called before that associated entry method gets called so the stop loss is properly reset and prepped for when that entry order executes. If a Set method not given an fromEntrySignal name, it will apply to all entries. If the Set method is called again, it will update the stop loss.

                      We should also note that OnOrderUpdate and OnBarUpdate are asynchronous to eachother. It is possible that the Set method gets called elsewhere after the order is submitted, but before it executes, which would adjust the initial stop loss before the entry order is executed and the associated stop loss is submitted. Narrowing that down will require debugging steps. I.E. to reproduce the occurrence with Playback, and place prints beside your Set methods to see which is firing and adjusting the stop.

                      I have also tested a modification of the RejectionTest example to demonstrate:

                      1. SetStopLoss is called before the Enter method of the first order with a stop loss of 10 ticks
                      2. SetStopLoss is called in OnOrderUpdate before the 2nd Enter method is called with a stop loss of 20 ticks.
                      3. When the 1st order gets rejected, the second stop loss is placed 20 ticks away from the current market price.

                      You may wish to comment out custom stop loss handling until you get behavior matching the test script, and then to add the stop loss moving behaviors back to identify which parts are adjusting your stop loss unexpectedly.

                      We look forward to assisting.
                      You are the best, that did the job. Thanks a lot.

                      Testing it on tickreplay it occurred to me that maybe a stoploss could be rejected as well. What happens in that case? Do it leave the stop that was previously active in the broker or cancel it?

                      I am thinking of adding something like:

                      if (order.OrderState == OrderState.Rejected)
                      {
                      if (Position.MarketPosition == MarketPosition.Long) ExitLong ();
                      if (Position.MarketPosition == MarketPosition.Short) ExitShort ();
                      }


                      Where in the code should I add it? Currently the code looks like this:


                      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 order in OnOrderUpdate() to ensure the assignment occurs when expected.
                      // This is more reliable than assigning Order objects in OnBarUpdate,
                      // as the assignment is not guaranteed to be complete if it is referenced immediately after submitting
                      if (order.Name == "entryOrderLong")
                      {
                      entryOrderLong = order;
                      // Reset the entryOrder object to null if order was cancelled without any fill
                      if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                      entryOrderLong = null;
                      }

                      if (order.Name == "entryOrderLong2")
                      {
                      entryOrderLong2 = order;
                      // Reset the entryOrder2 object to null if order was cancelled without any fill
                      if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                      entryOrderLong2 = null;
                      }

                      if (entryOrderLong != null && entryOrderLong == order)
                      {
                      // Rejection handling
                      if (order.OrderState == OrderState.Rejected)
                      {
                      // Order was rejected !!!!
                      // Do something about it here
                      entryOrderLong = null;
                      SetStopLoss(@"entryOrderLong2",CalculationMode.Per cent, 0.01,false);
                      EnterLong(Convert.ToInt32(ContratosporTrade), @"entryOrderLong2");

                      }
                      }

                      // This is more reliable than assigning Order objects in OnBarUpdate,
                      // as the assignment is not guaranteed to be complete if it is referenced immediately after submitting
                      if (order.Name == "entryOrderShort")
                      {
                      entryOrderShort = order;
                      // Reset the entryOrder object to null if order was cancelled without any fill
                      if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                      entryOrderShort = null;
                      }

                      if (order.Name == "entryOrderShort2")
                      {
                      entryOrderShort2 = order;
                      // Reset the entryOrder2 object to null if order was cancelled without any fill
                      if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                      entryOrderShort2 = null;
                      }

                      if (entryOrderShort != null && entryOrderShort == order)
                      {
                      // Rejection handling
                      if (order.OrderState == OrderState.Rejected)
                      {
                      // Order was rejected !!!!
                      // Do something about it here
                      entryOrderShort = null;
                      SetStopLoss(@"entryOrderShort2",CalculationMode.Pe rcent, 0.01,false);
                      EnterShort(Convert.ToInt32(ContratosporTrade), @"entryOrderShort2");

                      }
                      }
                      }

                      Comment


                        #12
                        Hello rocker84,

                        Thanks for your question.

                        When processing historical data, if an order is summitted to the wrong side of the market, or moved to the wrong side of the market, the order submission or change would be ignored and the backtest will continue. This would not be handled as a rejection or with RealtimeErrorHandling.

                        If you take a more advanced approach and submit orders to a single tick data series with the prices offset in the proper direction, you can avoid cases where a historical order would be ignored where "virtual bars" would estimate price movement hat would deem the submission/change invalid.

                        With historical processing, the OHLC of a bar is used to estimate price movement and "virtual bars" are created to guess how the market moved during that bar. If you submit an order and the next bar in the data series has a High closer to the Open, and a Buy Stop Market order is submitted closer to the Low or Close of that bar, the virtual bars will first move up, which may result in the order not being filled since that price movement would result in that order being invalid.

                        Understanding Historical Fill Processing - https://ninjatrader.com/support/help...lFillAlgorithm

                        Submitting orders to a single tick data series would have the orders filled with the actual intrabar granularity, and if prices are properly offset, the orders will be valid. Please see the example below for how you can submit orders to a single tick data series.

                        Backtesting with Intrabar Granularity - https://ninjatrader.com/support/help...ipt_strate.htm

                        Please note that we cannot specify a fill series with the Set methods, so instead of using Set methods, you could consider using Exit methods in OnExecutionUpdate so you can direct the target and stop orders to the single tick data series.

                        SampleOnOrderUpdate - https://ninjatrader.com/support/help...and_onexec.htm

                        Past this, TraceOrders and debugging prints can be used to see if an order was ignored with historical processing, and to see what the price level of that order was when it was submitted.

                        TraceOrders - https://ninjatrader.com/support/help...aceorders2.htm

                        We look forward to assisting.
                        JimNinjaTrader Customer Service

                        Comment

                        Latest Posts

                        Collapse

                        Topics Statistics Last Post
                        Started by Waxavi, Today, 02:10 AM
                        0 responses
                        3 views
                        0 likes
                        Last Post Waxavi
                        by Waxavi
                         
                        Started by TradeForge, Today, 02:09 AM
                        0 responses
                        9 views
                        0 likes
                        Last Post TradeForge  
                        Started by Waxavi, Today, 02:00 AM
                        0 responses
                        2 views
                        0 likes
                        Last Post Waxavi
                        by Waxavi
                         
                        Started by elirion, Today, 01:36 AM
                        0 responses
                        4 views
                        0 likes
                        Last Post elirion
                        by elirion
                         
                        Started by gentlebenthebear, Today, 01:30 AM
                        0 responses
                        4 views
                        0 likes
                        Last Post gentlebenthebear  
                        Working...
                        X