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

sell order stop must be below price

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

    sell order stop must be below price

    Hi,

    I am working on a very simple strategy that operates on Calculate = Calculate.OnEachTick. Sometimes, when there is a lot of volatility, I encounter the following error: "sell order stop must ..." which disables my strategy:


    Click image for larger version

Name:	image.png
Views:	46
Size:	25.2 KB
ID:	1307723​What solutions can I implement to ensure the orders are executed correctly? I have tried adding a DataSeries of 1 tick, hoping it might help.

    I am using Set commands:
    ​​Click image for larger version

Name:	image.png
Views:	42
Size:	57.6 KB
ID:	1307724

    #2
    Hello Caspersky_,

    This error may appear when submitting a stop order if the stop price is ahead of the market.

    For a buy stop order, such as when exiting a short position or entering a long position, the stop price must be above the current ask price.
    For a sell stop order, such as when exiting a long position or entering a short position, the stop price must be below the current bid price.

    Order methods that submit / change stop orders where the stop price must be on the correct side of the ask or bid:Resolving the error


    There are different approaches to avoiding the invalid order price.

    For the examples below, consider a variable holding your calculated stop price. This could be a price from a custom calculation, or one obtained from an indicator. In these examples 100 will be used as a place holder.
    Code:
    stopPrice = 100; // ← price you have calculated to use as the stop price
    Using Math.Max() / Math.Min() to ensure the calculated stopPrice is above/below the ask/bid:
    Code:
    // ensure sell stop order is below the bid
    stopPrice = Math.Min(stopPrice, GetCurrentBid() - 1 * TickSize);
    ExitLongStopMarket(stopPrice);

    Code:
    // ensure buy stop order is above the ask
    stopPrice = Math.Max(stopPrice, GetCurrentAsk() + 1 * TickSize);
    ExitShortStopMarket(stopPrice);
    Using a condition to submit a market order to exit immediately, instead of a stop order, if the stopPrice is ahead of the market:
    Code:
    // if calculated exit sell stopPrice is less than the bid use stopPrice for stop
    // otherwise exit long position immediately with a market order
    if (Position.MarketPosition == MarketPosition.Long)
    {
    // if the stopPrice value is a valid price, use the stopPrice
    if (stopPrice < GetCurrentBid())
    {
    ExitLongStopMarket(stopPrice);
    }
    // otherwise exit immediately with a market order
    else
    {
    ExitLong();
    }
    }
    
    // if calculated exit buy stopPrice is greater than the ask use stopPrice
    // other wise exit short position immediately with a market order
    if (Position.MarketPosition == MarketPosition.Short)
    {
    if (stopPrice > GetCurrentAsk())
    {
    ExitShortStopMarket(stopPrice);
    }
    else
    {
    ExitShort();
    }
    }​
    Set method considerations


    In addition, Set methods cannot be unset and will continue to hold their values for new entry orders.

    This means it is important to reset Set methods using a number of Ticks, Percent, or Currency before placing a new entry (or using a unique signalName for each new entry). (Setting to a specific price may be an invalid price when the entry order fills, especially for entry limit and stop orders)

    The help guide notes:

    “Notes:
    As Set method orders are submitted upon receiving an entry execution, the Set method should be called prior to submitting the associated entry order to ensure an initial level is set.“

    “Tips:
    You may call this method from within the strategy OnBarUpdate() method should you wish to dynamically change the stop loss price while in an open position
    Should you call this method to dynamically change the stop loss price in the strategy OnBarUpdate() method, you should always reset the stop loss price / offset value when your strategy is flat otherwise, the last price/offset value set will be used to generate your stop loss order on your next open position”

    NinjaScript > Language Reference > Strategy > Order Methods > Managed Approach > SetStopLoss()

    Before calling a new entry call the Set methods first, one line above the entry method:
    Code:
    if (Position.MarketPosition == MarketPosition.Flat)
    {
    // call SetStopLoss() with CalculationMode.Ticks one line above calling EnterLong() to reset
    // this ensures the set method is not holding a price value from a previous order which may be invalid when the new entry fills
    SetStopLoss(CalculationMode.Ticks, 20)
    EnterLong();
    }
    
    // after the entry fills, the stop loss can be moved to any desired valid price with CalculationMode.Price
    if (Position.MarketPosition == MarketPosition.Long && Close[0] > Position.AveragePrice + 10 * TickSize)
    {
    // after 10 ticks of profit, set the stop loss to the maximum valid price
    SetStopLoss(CalculationMode.Price, GetCurrentBid() - TickSize);
    }
    Chelsea B.NinjaTrader Customer Service

    Comment


      #3
      Thanks for the quick response. From my understanding, the issue is happening during the execution of the SetProfitTarget command (I went Long on this specific trade) and not during an entry attempt. Could you please explain how your response addresses this issue?

      Comment


        #4
        Hello Caspersky_,

        Was the call to SetProfitTarget() using CalculationMode.Price?

        Was this reset using CalculationMode.Ticks before placing a new entry?

        Was the call to SetProfitTarget() using CalculationMode.Price called after the position was MarketPosition.Long?
        Chelsea B.NinjaTrader Customer Service

        Comment


          #5
          As you can see in the picture I attached:
          1. No, It uses CalculationMode.Ticks.
          2. No, it after the entered all of it contracts for Long.
          3. The call was using CalculationMode.Ticks and was taken after MarketPosition.Long.

          What do you think? (Thanks in advance).

          Comment


            #6
            Hello Caspersky_,

            The screenshot you have provided does not show any logic in OnBarUpdate(). From this screenshot there would not be a way to know what is being called in the script.

            What do you have showing shows the Set methods using a variables name Ticks which is by default set to 61, though this can be changed in the parameters when running the script.
            Should this be the actual value the Set methods called are not likely to be causing this error.

            Printing GetCurrentAsk() and GetCurrentBid() in OnExecutionUpdate() along with the TraceOrders information and the order.ToString() in OnOrderUpdate() would give a better picture of what the market price is and the order submission price.

            Below is a link to a support article on adding debugging prints and enabling TraceOrders to understand behavior.
            Chelsea B.NinjaTrader Customer Service

            Comment


              #7
              Understood Chelsea, I'm quit new to this so I'm sorry for my misunderstanding.
              I've tried to use your suggestion but instead of taking a market order like in the following:
              else
              {
              ExitLong();​

              I want to wait until the first condition is filled, namely:
              if (stopPrice < GetCurrentBid())
              {
              ExitLongStopMarket(stopPrice);
              }​

              the following is my implementation of OnBarUpdate(), can you tell me if there might be faults here with the use of just "return"?

              protected override void OnBarUpdate()
              {
              if (BarsInProgress != 0)
              return;

              if (CurrentBars[0] < 1)
              return;

              DateTime currentTime = Times[0][0];

              if (currentTime.TimeOfDay == tradeTime.TimeOfDay)
              {
              if (Go_Long && !Go_Short)
              {
              EnterLong(Convert.ToInt32(Contacts), "Long");
              BackBrush = Brushes.Green;
              Print(currentTime.ToString("HH:mm:ss") + " Long " + Convert.ToString(Ticks) + " Ticks.");
              }
              else if (!Go_Long && Go_Short)
              {
              EnterShort(Convert.ToInt32(Contacts), "Short");
              BackBrush = Brushes.Tomato;
              Print(currentTime.ToString("HH:mm:ss") + " Short " + Convert.ToString(Ticks) + " Ticks.");
              }
              }

              // ensure correct stop prices
              double stopPriceLong = GetCurrentBid() - 1* TickSize;
              double stopPriceShort = GetCurrentAsk() + 1* TickSize;

              // exit logic
              if (Position.MarketPosition == MarketPosition.Long)
              {
              if (stopPriceLong < GetCurrentBid())
              {
              ExitLongStopMarket(stopPriceLong);
              }
              else
              {
              // Check the condition in the next tick
              if (Position.Quantity > 0)
              {
              return; // Wait for the condition to be true in the next tick
              }
              }
              }

              if (Position.MarketPosition == MarketPosition.Short)
              {
              if (stopPriceShort > GetCurrentAsk())
              {
              ExitShortStopMarket(stopPriceShort);
              }
              else
              {
              // Check the condition in the next tick
              if (Position.Quantity > 0)
              {
              return; // Wait for the condition to be true in the next tick
              }
              }
              }


              Comment


                #8
                Hello Caspersky_,

                The return would stop processing OnBarUpdate() for that update. This is fine if this is what you want the logic to do.

                To confirm, this is the specific code causing the error?

                If so, with the ExitLongStopMarket() calls, a fast moving market may still be playing a role. It's possible the price is changing by more than 1 tick before the order is received.
                Try setting the price 2 ticks behind the bid or ask.
                Chelsea B.NinjaTrader Customer Service

                Comment


                  #9
                  Hi again Chelsea,

                  The code I provided didn't cause the error. The provided code is updated with your proposal.

                  From what I understand, even with the ExitLongStopMarket() calls using the logic of double stopPriceLong = GetCurrentBid() - 2 * TickSize;, there might be potential issues.

                  Perhaps a better solution is to use just market orders (ExitLong) and take 2 additional spare ticks?

                  Comment


                    #10
                    Hello Caspersky_,

                    It's possible if the market price jumps down by more than a few ticks from one tick to the next right when the price is at the stop price.

                    Using a market order submitted when the market price reaches the desired price is your choice, and wouldn't be affected by the error.

                    If you want to use a stop order, ensuring the stop price is behind the market is necessary. Sometimes in a fast moving market, it may necessary to place the order further from the trading action to ensure the stop price is valid when the order is received by the brokerage. But typically, just checking the order is at least 1 tick below the bid or above the ask is enough.

                    If the code you've suggested is not causing an error, may I have you clarify what the current issue is?
                    Chelsea B.NinjaTrader Customer Service

                    Comment


                      #11
                      I've tried to use your suggested code yesterday with the following logic:

                      Click image for larger version

Name:	image.png
Views:	24
Size:	244.7 KB
ID:	1308154
                      And I got another error (Rejected at RMS - ...):
                      Click image for larger version

Name:	image.png
Views:	21
Size:	239.7 KB
ID:	1308156
                      Here is the Orders Log:
                      Click image for larger version

Name:	image.png
Views:	21
Size:	69.4 KB
ID:	1308155​As you can see, I entered a short position with 10 contracts. I'm not sure why, after hitting 2 out of 10 profit targets, the strategy bought 10 long with market orders. I assume this is related to the stop price not being valid, causing ExitLong() to be called to exit the position with a market order. However, instead of exiting the remaining position, it entered a long trade with an unnecessary 10 contracts.​

                      Thanks for everything, your customer support is 10/10 .

                      Comment


                        #12
                        Hello Caspersky_,

                        So this would be a new issue not related to the invalid stop price issue.

                        It looks like the profit target part filled which attempted to change the quantity of the stop, submit a market order to exit the position, and cancel the stop at the same time, possibly because the stop order could not be resubmitted since it was now ahead of the market price.

                        To avoid this specific scenario, it may be necessary to submit stop orders with isLiveUntilCancelled as true once, and not resubmitting these on each bar to keep them alive, and if deciding to use a market order to exit the position canceling the stop order first, detecting it is cancelled, and then exiting with a market position. As long as the stop can be successfully cancelled the market order would not cause an undesirable position quantity.
                        Chelsea B.NinjaTrader Customer Service

                        Comment


                          #13
                          Great, last question, I have removed the exit logic with Market orders, and added a boolean to make prevent the exit logic from submitting multiple exit orders in quick succession, here is the code:
                          Click image for larger version

Name:	image.png
Views:	21
Size:	35.8 KB
ID:	1308166
                          Seems legit ?

                          Comment

                          Latest Posts

                          Collapse

                          Topics Statistics Last Post
                          Started by mbafelfel, 05-05-2017, 06:12 AM
                          5 responses
                          1,367 views
                          0 likes
                          Last Post Rancher
                          by Rancher
                           
                          Started by Blaze212, 07-07-2024, 08:58 PM
                          3 responses
                          23 views
                          0 likes
                          Last Post Blaze212  
                          Started by yertle, Today, 12:24 PM
                          0 responses
                          4 views
                          0 likes
                          Last Post yertle
                          by yertle
                           
                          Started by reekotubbs, Yesterday, 01:09 PM
                          3 responses
                          28 views
                          0 likes
                          Last Post reekotubbs  
                          Started by medicmiked, Today, 11:56 AM
                          0 responses
                          9 views
                          0 likes
                          Last Post medicmiked  
                          Working...
                          X