Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

Intrabar error when changing stop order during OnExecution

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

    Intrabar error when changing stop order during OnExecution

    I am working to upgrade my strategy to ride wins, so I changed the SetStopLoss and SetProfitTarget to ExitLongStop and ExitLongLimit or ExitShortStop and ExitShortLimit. I used the example on SampleOnOrderUpdate, as my guideline.

    So I set the Stop and Target orders when the original order is filled (using OnExecution). The Target qty is 1/3 of the qty. When the target order is filled, I would like to change the stop, to be over the entry price, to reduce the risk, and I would like to move it, and I am riding the wins.

    So on OnExecution of the target order, when I reset the stop order, I may get this message:
    HTML Code:
    **NT** A Sell stop order placed at '11/1/2013 7:05:00 AM' has been ignored since the stop price is greater than or equal to close price of the current bar. This is an invalid order and subsequent orders may also be ignored. Please fix your strategy.
    This happens when the last bar is lower than the entry point. Since the OnExecution event can happen intrabar, and technically, NT considers it as previous bar (since the current bar is not closed), this error is real when backtest, and causes my strategy to bleed.

    You can see the example at 07:10. My guess is the error happening intrabar, and considered as 7:05, closes at 4290.0, which happen to be below the entry price 4291.0.

    How can you deal with it?

    Here is my OnExecution:
    Code:
            
    protected override void OnExecution(IExecution execution)
            {
    			int eStopQty, eTargetQty;
    			double eOrderStopPrice;
    			string eOrderName;
    			// once the order is filled, set the stop and the target
    			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))
    				{
    					eStopQty = execution.Order.Filled;
    					eTargetQty = eStopQty < 3 ? 1 : (int)Math.Round((double)eStopQty / 3,0);
    					eOrderName = execution.Order.Name;
    					if (execution.MarketPosition == MarketPosition.Long)
    					{
    						// Stop Order
    						stopOrder 	= ExitLongStop(0, true, eStopQty, orderStopPrice 
    											- (stopPassThrough ? priceTouch : 0), eOrderName+".Loss", eOrderName);
    						
    						// Target Order
    						targetOrder = ExitLongLimit(0, true, eTargetQty, orderTargetPrice 
    											+ (targetPassThrough ? priceTouch : 0), eOrderName+".Profit", eOrderName);
    					}
    					else 
    					{
    						// Stop Order
    						stopOrder 	= ExitShortStop(0, true, eStopQty, orderStopPrice 
    											+ (stopPassThrough ? priceTouch : 0), orderName+".Loss", orderName);
    						
    						// Target Order
    						targetOrder = ExitShortLimit(0, true, eTargetQty, orderTargetPrice 
    											- (targetPassThrough ? priceTouch : 0), orderName+".Profit", orderName);
    					}
    #if (DEBUG)			
    this.Debug("eOrderName="+eOrderName+", Stop:[Price="+orderStopPrice+", Qty="+eStopQty+"], Target:[Price="+orderTargetPrice+", Qty="+eTargetQty+"]");
    #endif
    					// Resets the entryOrder object to null after the order has been filled
    					if (execution.Order.OrderState != OrderState.PartFilled)
    					{
    						entryOrder 	= null;
    					}
    				}
    			}
    			
    			// set new stop for the rest of the qty, when target reached 
    			if (targetOrder != null && targetOrder == execution.Order
    				&& (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled))
    			{
    				setWinStop(Position.AvgPrice, execution.Price, trialingStopTicks);
    				eStopQty = Position.Quantity;
    				eOrderStopPrice = getWinStop();
    				eOrderName = execution.Order.FromEntrySignal;
    #if (DEBUG)			
    this.Debug("Target filled="+eOrderName+", FilledPrice="+targetOrder.AvgFillPrice
    					+", Price="+eOrderStopPrice+", Qty="+eStopQty
    					+", Dir="+execution.Order.OrderAction
    					+", Filled="+execution.Order.OrderState+"]"+execution);
    #endif
    				if (execution.Order.OrderAction == OrderAction.Sell || execution.Order.OrderAction == OrderAction.SellShort) // its the opposit dir					
    				{
    					stopOrder 	= ExitLongStop(0, true, eStopQty, eOrderStopPrice
    										- (stopPassThrough ? priceTouch : 0), eOrderName+".Stop", eOrderName);
    #if (DEBUG)			
    this.Debug("ExitLongStop="+stopOrder);
    #endif
    				}
    				else
    				{
    					stopOrder 	= ExitShortStop(0, true, eStopQty, eOrderStopPrice
    										+ (stopPassThrough ? priceTouch : 0), eOrderName+".Stop", eOrderName);
    #if (DEBUG)			
    this.Debug("ExitShortStop="+stopOrder);
    #endif
    				}
    				targetOrder = null;
    				orderTimeBaseCounter = Off;				
    			}
    
    			// Reset our stop order and target orders' IOrder objects after our position is closed.
    			if (stopOrder != null && stopOrder == execution.Order
    				&& (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled))
    			{
    				stopOrder = null;
    				targetOrder = null;
    				orderTimeBaseCounter = Off;
    			}
    		}
    Attached Files
    Last edited by Shai Samuel; 11-26-2013, 12:05 AM.

    #2
    Hi Shai, that would be correct you would submit the orders for the next bar, however the last series reference price checked is the last bar completed close here for order validity. You could for example bring in a finer series and submit explicitly to this series in backtesting. For realtime checks the OnMarketData() would be ideal to compare to the current inside market for example.
    BertrandNinjaTrader Customer Service

    Comment


      #3
      Originally posted by NinjaTrader_Bertrand View Post
      Hi Shai, that would be correct you would submit the orders for the next bar, however the last series reference price checked is the last bar completed close here for order validity. You could for example bring in a finer series and submit explicitly to this series in backtesting. For realtime checks the OnMarketData() would be ideal to compare to the current inside market for example.
      Dear Bertrand, thank you for your kind reply.

      To make sure I understand, you are saying two things:
      1. On backtest (or realtime as well), if I would like to submit this, I need for execution purposes, to go into finer series such as 1 minute or 1 tick. Do you have an example of doing so?
      2. On realtime, alternatively, I can use OnMarketData. Do you have an example of using OnMarketData?

      Comment


        #4
        Originally posted by Shai Samuel View Post
        Dear Bertrand, thank you for your kind reply.

        To make sure I understand, you are saying two things:
        1. On backtest (or realtime as well), if I would like to submit this, I need for execution purposes, to go into finer series such as 1 minute or 1 tick. Do you have an example of doing so?
        2. On realtime, alternatively, I can use OnMarketData. Do you have an example of using OnMarketData?
        1. For an example of adding intrabar granularity for backtesting purposes, please see the following:

        You can submit orders to different Bars objects. This allows you the flexibility of submitting orders to different timeframes. Like in live trading, taking entry conditions from a 5min chart means executing your order as soon as possible instead of waiting until the next 5min bar starts building. You can achieve this by


        2. The following strategy sample contains use of OnMarketData:



        Documentation on OnMarketData is available below:

        MatthewNinjaTrader Product Management

        Comment


          #5
          Thanks Matthew for your reply. It actually looks easy...

          I have 2 questions regarding using secondary intrabar series:
          1. If the primary series is 5 min, can the secondary series be 1 tick?
          2. If I use 1 tick as a second series, is there a downside of such a details series, performance & memory wise?

          Comment


            #6
            Before receiving your reply to my 2 questions, I implemented the intrabar example into my strategy. The way it works, the OnBarUpdate() is managed by BarsInProgress == 0, but the rest of the strategy (OnOrderUpdate, OnExecution, OnPositionUpdate...) is based on the orders, which all are executed on BarsInProgress = 1 (orderBIP).

            What happens is the first order is placed and get cancelled for some reason at the same bar. I can't understand why?

            It might be since my secondary series is 10 ticks, the order gets expired?

            Attached is the code.

            $ES@10/31/13-16:45:00 <OnStartUp> $Dir=0, $Enter=0, $Target=0, $Stop=0, $TimeBase=0
            10/31/2013 7:00:00 PM Entered internal PlaceOrder() method at 10/31/2013 7:00:00 PM: BarsInProgress=1 Action=SellShort OrderType=Limit Quantity=1 LimitPrice=1753.75 StopPrice=0 SignalName='$ES.Sell' FromEntrySignal=''
            $ES@10/31/13-19:00:00 <++ Enter Order=$ES.Sell, Qty=1> $Dir=-1, $Enter=1753.75, $Target=1751.25, $Stop=1756.25, $TimeBase=-99
            10/31/2013 7:00:00 PM Cancelled expired order: BarsInProgress=0: Order='NT-00000/Backtest' Name='$ES.Sell' State=Working Instrument='ES 12-13' Action=SellShort Limit price=1753.7475 Stop price=0 Quantity=1 Strategy='bdtStrategy' Type=Limit Tif=Gtc Oco='' Filled=0 Fill price=0 Token='7e1bdca27c02482c856f2f7524d0e6b6' Gtd='12/1/2099 12:00:00 AM'
            11/1/2013 12:14:52 AM Entered internal PlaceOrder() method at 11/1/2013 12:14:52 AM: BarsInProgress=1 Action=Buy OrderType=Limit Quantity=1 LimitPrice=1753.75 StopPrice=0 SignalName='$ES.Buy' FromEntrySignal=''
            $ES@11/01/13-00:15:00 <++ Enter Order=$ES.Buy, Qty=1> $Dir=1, $Enter=1753.75, $Target=1756.25, $Stop=1751.25, $TimeBase=-99
            11/1/2013 12:15:00 AM Cancelled expired order: BarsInProgress=0: Order='NT-00001/Backtest' Name='$ES.Buy' State=Working Instrument='ES 12-13' Action=Buy Limit price=1753.7525 Stop price=0 Quantity=1 Strategy='bdtStrategy' Type=Limit Tif=Gtc Oco='' Filled=0 Fill price=0 Token='afc55e6253ec4f0986ee5b766a8fcc41' Gtd='12/1/2099 12:00:00 AM'
            Attached Files

            Comment


              #7
              Ok, I found my problem, and solve it. It seems that few of my order entry had "false" for liveUntilCancelled. I fixed it and now it work fine. So please just comment to my original 1 questions on post #5/

              Comment


                #8
                Originally posted by Shai Samuel View Post
                Thanks Matthew for your reply. It actually looks easy...

                I have 2 questions regarding using secondary intrabar series:
                1. If the primary series is 5 min, can the secondary series be 1 tick?
                2. If I use 1 tick as a second series, is there a downside of such a details series, performance & memory wise?
                Glad to hear you could resolve Shai. Yes it could be certainly 1 tick added in. However processing tick by tick would have a performance impact for sure and would limit would range you could backtest likely.
                BertrandNinjaTrader Customer Service

                Comment


                  #9
                  Thanks Bertrand,

                  Just to make it clear. I am using 5 min to initiate my signal. I am using 1 tick to create the orders (with SetProfitTraget and SetStopLoss). I am using the OnExcuation of target1 Filled, to move my stops closer to target2 and target3 (so its called once).

                  I don't see where I would pay with performance. Does NT do anything in the background to slow performace, if you filter out the 1 tick calls?

                  Comment


                    #10
                    Even in this case the 1tick series would have to be loaded / maintained by NT, which would mean a performance impact over working just with minute base data for example. One word of caution though, in this setup the Sets would still work off the primary series here, they would not benefit from the added series as they would be tied to primary. To submit to the 1 tick for exits, you would need to work with the more advanced Exit method that would offer a BIP input to submit against.
                    BertrandNinjaTrader Customer Service

                    Comment


                      #11
                      The reason why I wanted to use 1 tick as secondary series, is catch the exit point of the first target set, so I can adjust the stops of the 2nd and the 3rd target stops, without the delay of the completion of the bar. I could do with 1 min, but I thought 1 tick is the most exact and will always be relevant.

                      From what you say, it is costly, but I don't fully understand the cost. What you said, it slows down the entire process, so backtesting and optimization are slower?

                      Comment


                        #12
                        Yes 1 tick will be more exact to the point you try to hit, as it's the finest resolution possible. It will be having an impact on the entire process if you're having to deal with 1 tick data base. Plus most providers don't offer that much to backtest on compared to minute for example. So my suggestion would be testing with 1min first. Changing over 1 tick later on once the code is done is likely not that big of a deal.
                        BertrandNinjaTrader Customer Service

                        Comment


                          #13
                          To avoid errors, such as a rejection of the stop, when it was created on OnExecution, I switched back to SetStopLoss and SetProfitTraget. The LimitOrder is executed on BIP=1, but I have the feeling that the Stop and Target orders are set on BIP=0. Is this correct? Can I do anything to change it?

                          Comment


                            #14
                            That is correct and expected here Shai, the Sets would only be tied to the primary series.
                            BertrandNinjaTrader Customer Service

                            Comment


                              #15
                              Thanks.

                              I am back to just one, and using OnExcution.

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by PaulMohn, Today, 03:49 AM
                              0 responses
                              7 views
                              0 likes
                              Last Post PaulMohn  
                              Started by inanazsocial, Today, 01:15 AM
                              1 response
                              9 views
                              0 likes
                              Last Post NinjaTrader_Jason  
                              Started by rocketman7, Today, 02:12 AM
                              0 responses
                              10 views
                              0 likes
                              Last Post rocketman7  
                              Started by dustydbayer, Today, 01:59 AM
                              0 responses
                              4 views
                              0 likes
                              Last Post dustydbayer  
                              Started by trilliantrader, 04-18-2024, 08:16 AM
                              5 responses
                              23 views
                              0 likes
                              Last Post trilliantrader  
                              Working...
                              X