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

Limit Can't Be Greater Than Current Ask - Reloaded

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

    Limit Can't Be Greater Than Current Ask - Reloaded

    Hey guys - I'm getting that dreaded message again. I'm clearing with FXCM which seems to be rather jumpy with rejections.



    Now I did do my homework and have implemented the following:

    Initialize() method:

    RealtimeErrorHandling = RealtimeErrorHandling.TakeNoAction;

    In my OnOrderUpdate method:

    Code:
    if (order.OrderState == OrderState.Filled || order.OrderState == OrderState.PartFilled) {
    	if (enableLog) {
    		Print(instrumentName + "." + BarsPeriod.Value + "." + BarsPeriod.BasePeriodType);
    		Print("Order: " + order.OrderAction + " was filled");
    	}
    	
    	barNumberOfFill = CurrentBars[0] + startIndexSeriesOne;
    	if (enableLog) {
    		Print(instrumentName + "." + BarsPeriod.Value + "." + BarsPeriod.BasePeriodType);
    		Print("EXECUTED at BarNumberOfFill (adjusted): " + barNumberOfFill);
    		Print("CurrentBars: " + PriceToString(CurrentBars[0]));
    		Print("Time on 0 series: " + Times[0][0]);
    	}
    	
    	
    	//Log(order.ToString(), LogLevel.Information);
    	if (entryOrder != null && entryOrder == order) {
    		
    		if (order.OrderState == OrderState.Rejected) 
    		{
    			if (entryOrder.OrderAction == OrderAction.Buy) {
                                 if (Closes[1][0] <= unfilledMaxDistance) {
                                 	String message = "Long Entry REJECTED - attempting again with Limit at ask: " + currentAsk;
                                 	Print(message);
                                 	Log(message, LogLevel.Information);
                                 	entryOrder = EnterLongLimit(1, true, unfilledPositionSize, currentAsk, LONG_POSITION);
                            } else {
                                 	String message = "Long Entry REJECTED and Ask at " + currentAsk + " has moved beyond the entry range terminating at " + unfilledMaxDistance;
                                 	Print(message);
                                 	Log(message, LogLevel.Information);
                            }
    	 	} else if (entryOrder.OrderAction == OrderAction.SellShort) {
                          if (Closes[1][0] >= unfilledMaxDistance) {
    	               	   String message = "Short Entry REJECTED - attempting again with Limit at bid: " + currentBid;
    	               	    Print(message);
    	               	   Log(message, LogLevel.Information);
    			   entryOrder = EnterShortLimit(1, true, unfilledPositionSize, currentBid, SHORT_POSITION);
    		     } else {
    		       	    String message = "Short Entry REJECTED and Bid at " + currentBid + " has moved beyond the entry range terminating at " + unfilledMaxDistance;
    			    Print(message);
    			    Log(message, LogLevel.Information);
    	             }
    	        }
    		}
    However looking at that code I think that the rejection part may never been called in that instance. Doesn't this part:

    if (entryOrder != null && entryOrder == order) {

    have to move outside:

    if (order.OrderState == OrderState.Filled || order.OrderState == OrderState.PartFilled) {

    The reason I have the existing conditional flow stems from an old template I have been using for years now (and has worked fine). Anyway, my inkling here is that the rejection handling is not being called properly due to a problem in my OnOrderUpdate conditional flow. However, still - even in that case it should not have thrown the alert and just failed quietly.

    Any input would be appreciated, as always :-)

    #2
    Hello,

    Thank you for the question.

    I do see that the topmost condition is:

    Code:
    if (order.OrderState == OrderState.Filled || order.OrderState == OrderState.PartFilled) {
    Which would limit the statement to only Filled or Part Filled orders.

    If you need to include all states you could remove this check all together unless your logic relies on it.

    Otherwise, the inner conditions:

    Code:
    if (order.OrderState == OrderState.Rejected) 
    {
    would not be called because a the order type was not allowed based on the first condition.

    If you have some old conditions in there I would recommend just removing all of the code from this section and reworking it to "clean" it up.


    I look forward to being of further assistance.
    JesseNinjaTrader Customer Service

    Comment


      #3
      Originally posted by NinjaTrader_Jesse View Post
      Hello,

      Thank you for the question.

      I do see that the topmost condition is:

      Code:
      if (order.OrderState == OrderState.Filled || order.OrderState == OrderState.PartFilled) {
      Which would limit the statement to only Filled or Part Filled orders.

      If you need to include all states you could remove this check all together unless your logic relies on it.

      Otherwise, the inner conditions:

      Code:
      if (order.OrderState == OrderState.Rejected) 
      {
      would not be called because a the order type was not allowed based on the first condition.

      If you have some old conditions in there I would recommend just removing all of the code from this section and reworking it to "clean" it up.


      I look forward to being of further assistance.
      Yes, that's what I was thinking. I had originally used the following context:

      Code:
      1. if (order.OrderState == OrderState.Filled || order.OrderState == OrderState.PartFilled) { 
        2. if (entryOrder != null && entryOrder == order) {
           3.a.if (entryOrder.OrderAction == OrderAction.SellShort) {
           3.b if (entryOrder.OrderAction == OrderAction.Buy) {
      
      ...
      And that conditional sequence has worked properly for years. Perhaps the second condition was a bit overkill but alas.

      When I saw the example for the rejection handling I foolishly searched for the 2nd condition (entryOrder != null && entryOrder == order) to weave in the rejection handling.

      It seems to me that moving the rejection handling outside all that will be proper approach:

      Code:
      protected override void OnOrderUpdate(IOrder order) 
      {
      	try {
      		
      		if (entryOrder != null && entryOrder == order)
      		{	
      			// Reset the entryOrder object to null if order was cancelled without any fill
      			if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
      			{
      				entryOrder = null;
      			}
      		}
      		
      		if (entryOrder != null && entryOrder == order) {
      			
      			if (order.OrderState == OrderState.Rejected) 
      			{
      				if (entryOrder.OrderAction == OrderAction.Buy) {
      					if (Closes[1][0] <= unfilledMaxDistance) {
      						String message = "Long Entry REJECTED - attempting again with Limit at ask: " + currentAsk;
      						Print(message);
      						Log(message, LogLevel.Information);
      						entryOrder = EnterLongLimit(1, true, unfilledPositionSize, currentAsk, LONG_POSITION);
      					} else {
      						String message = "Long Entry REJECTED and Ask at " + currentAsk + " has moved beyond the entry range terminating at " + unfilledMaxDistance;
      						Print(message);
      						Log(message, LogLevel.Information);
      					}
      				} else if (entryOrder.OrderAction == OrderAction.SellShort) {
      					if (Closes[1][0] >= unfilledMaxDistance) {
      						String message = "Short Entry REJECTED - attempting again with Limit at bid: " + currentBid;
      						Print(message);
      						Log(message, LogLevel.Information);
      						entryOrder = EnterShortLimit(1, true, unfilledPositionSize, currentBid, SHORT_POSITION);
      					} else {
      						String message = "Short Entry REJECTED and Bid at " + currentBid + " has moved beyond the entry range terminating at " + unfilledMaxDistance;
      						Print(message);
      						Log(message, LogLevel.Information);
      					}
      				}
      			} 
      		}
      
      		// now handle the filled order flow...
           
      		if (order.OrderState == OrderState.Filled || order.OrderState == OrderState.PartFilled) {
      Again any input/suggestions are welcome :-)

      Comment


        #4
        Hello,

        That looks more correct for finding the states and ensuring the order is not null when used.

        The scope being outside of the prior condition should now allow the actual rejection handing conditions to be checked.

        After testing this if you find that anything is still not working correctly and need assistance please let me know and we can work though the logic.

        I look forward to being of further assistance.
        JesseNinjaTrader Customer Service

        Comment


          #5
          Originally posted by NinjaTrader_Jesse View Post
          Hello,

          That looks more correct for finding the states and ensuring the order is not null when used.

          The scope being outside of the prior condition should now allow the actual rejection handing conditions to be checked.

          After testing this if you find that anything is still not working correctly and need assistance please let me know and we can work though the logic.

          I look forward to being of further assistance.
          Thanks Jesse - I think that'll do it. But I do have one question I would like to clarify. Remember that the strategy still threw that alert I showed below? Should it not have silently failed to fill? (which would have made it harder to find the issue actually so I'm not complaining). Recall that I set the proper flag in the Initialize method:

          RealtimeErrorHandling = RealtimeErrorHandling.TakeNoAction;

          So why is it still issuing alerts?

          Comment


            #6
            Hello,

            The alert would still be present to inform you of what had occurred.

            This property simply prevents the strategy from disabling and closing all its positions but would still alert you.

            I look forward to being of further assistance.
            JesseNinjaTrader Customer Service

            Comment


              #7
              Originally posted by NinjaTrader_Jesse View Post
              Hello,

              The alert would still be present to inform you of what had occurred.

              This property simply prevents the strategy from disabling and closing all its positions but would still alert you.

              I look forward to being of further assistance.
              Alright, understood. I hope that this alerts don't require anyone being present, meaning the strategy doesn't switch into a wait loop until the alert has been acknowledged. Just making sure... if not that would be a problem.

              Also, is there a way to disable the alerts altogether? I would content with just having log output frankly. Especially since I'm handling rejections internally.

              Comment


                #8
                Hello,

                As far as I can tell nothing is prevented while the alert is open other than clicking on items in the platform. The test I had conducted opened multiple alerts regarding the rejected order I was testing with.

                There is no supported way to completely disable the alerts for this in this case.

                I would recommend testing this scenario to ensure nothing is effected in your specific case, one way to do this would be to purposely submit orders at incorrect prices on the Sim account for any situation you feel may happen.

                I look forward to being of further assistance.
                JesseNinjaTrader Customer Service

                Comment


                  #9
                  Unfortunately in live tape the rejection handling continues to be ignored. I had it run overnight and it popped up the usual alert but without attempting to resubmit. My output only shows the rejection but no traces of resubmission. See my method below - it should have plotted something in the output.

                  Code:
                  protected override void OnOrderUpdate(IOrder order) 
                  		{
                  			try {
                  
                  				//Log("Entering OnOrderUpdate with: " + order.OrderAction + " at " + order.AvgFillPrice, LogLevel.Information);
                  				System.Text.StringBuilder buffer = new System.Text.StringBuilder();
                  				
                  				// Handle entry orders here. The entryOrder object allows us to identify that the order 
                  				// that is calling the OnOrderUpdate() method is the entry order.
                  				if (entryOrder != null && entryOrder == order)
                  				{	
                  					// Reset the entryOrder object to null if order was cancelled without any fill
                  					if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                  					{
                  						//Log("onOrderUpdate: RESETTING ENTRY TO NULL: " + buffer, LogLevel.Warning);
                  						entryOrder = null;
                  					}
                  				}
                  				
                  				if (entryOrder != null && entryOrder == order) {
                  					
                  					if (order.OrderState == OrderState.Rejected) 
                  					{
                  						if (entryOrder.OrderAction == OrderAction.Buy) {
                  							if (Closes[1][0] <= unfilledMaxDistance) {
                  								String message = "Long Entry REJECTED - attempting again with Limit at ask: " + currentAsk;
                  								Print(message);
                  								Log(message, LogLevel.Information);
                  								entryOrder = EnterLongLimit(1, true, unfilledPositionSize, currentAsk, LONG_POSITION);
                  							} else {
                  								String message = "Long Entry REJECTED and Ask at " + currentAsk + " has moved beyond the entry range terminating at " + unfilledMaxDistance;
                  								Print(message);
                  								Log(message, LogLevel.Information);
                  							}
                  						} else if (entryOrder.OrderAction == OrderAction.SellShort) {
                  							if (Closes[1][0] >= unfilledMaxDistance) {
                  								String message = "Short Entry REJECTED - attempting again with Limit at bid: " + currentBid;
                  								Print(message);
                  								Log(message, LogLevel.Information);
                  								entryOrder = EnterShortLimit(1, true, unfilledPositionSize, currentBid, SHORT_POSITION);
                  							} else {
                  								String message = "Short Entry REJECTED and Bid at " + currentBid + " has moved beyond the entry range terminating at " + unfilledMaxDistance;
                  								Print(message);
                  								Log(message, LogLevel.Information);
                  							}
                  						}
                  					} 
                  				}
                  No idea what's going on here. Any ideas?

                  Comment


                    #10
                    Originally posted by molecool View Post
                    Unfortunately in live tape the rejection handling continues to be ignored. I had it run overnight and it popped up the usual alert but without attempting to resubmit. My output only shows the rejection but no traces of resubmission. See my method below - it should have plotted something in the output.

                    Code:
                    protected override void OnOrderUpdate(IOrder order) 
                    		{
                    			try {
                    
                    				//Log("Entering OnOrderUpdate with: " + order.OrderAction + " at " + order.AvgFillPrice, LogLevel.Information);
                    				System.Text.StringBuilder buffer = new System.Text.StringBuilder();
                    				
                    				// Handle entry orders here. The entryOrder object allows us to identify that the order 
                    				// that is calling the OnOrderUpdate() method is the entry order.
                    				if (entryOrder != null && entryOrder == order)
                    				{	
                    					// Reset the entryOrder object to null if order was cancelled without any fill
                    					if (order.OrderState == OrderState.Cancelled && order.Filled == 0)
                    					{
                    						//Log("onOrderUpdate: RESETTING ENTRY TO NULL: " + buffer, LogLevel.Warning);
                    						entryOrder = null;
                    					}
                    				}
                    				
                    				if (entryOrder != null && entryOrder == order) {
                    					
                    					if (order.OrderState == OrderState.Rejected) 
                    					{
                    						if (entryOrder.OrderAction == OrderAction.Buy) {
                    							if (Closes[1][0] <= unfilledMaxDistance) {
                    								String message = "Long Entry REJECTED - attempting again with Limit at ask: " + currentAsk;
                    								Print(message);
                    								Log(message, LogLevel.Information);
                    								entryOrder = EnterLongLimit(1, true, unfilledPositionSize, currentAsk, LONG_POSITION);
                    							} else {
                    								String message = "Long Entry REJECTED and Ask at " + currentAsk + " has moved beyond the entry range terminating at " + unfilledMaxDistance;
                    								Print(message);
                    								Log(message, LogLevel.Information);
                    							}
                    						} else if (entryOrder.OrderAction == OrderAction.SellShort) {
                    							if (Closes[1][0] >= unfilledMaxDistance) {
                    								String message = "Short Entry REJECTED - attempting again with Limit at bid: " + currentBid;
                    								Print(message);
                    								Log(message, LogLevel.Information);
                    								entryOrder = EnterShortLimit(1, true, unfilledPositionSize, currentBid, SHORT_POSITION);
                    							} else {
                    								String message = "Short Entry REJECTED and Bid at " + currentBid + " has moved beyond the entry range terminating at " + unfilledMaxDistance;
                    								Print(message);
                    								Log(message, LogLevel.Information);
                    							}
                    						}
                    					} 
                    				}
                    No idea what's going on here. Any ideas?
                    You might want to turn on TraceOrders. Your code looks correct, on the face of it.

                    Maybe your broker has a time-out within which it will ignore resubmission of a rejected order? Just speculating here. You might want to call and ask.

                    Comment


                      #11
                      Originally posted by koganam View Post
                      You might want to turn on TraceOrders. Your code looks correct, on the face of it.

                      Maybe your broker has a time-out within which it will ignore resubmission of a rejected order? Just speculating here. You might want to call and ask.
                      TraceOrders is turned on by default in all my strategies. Which is why I know the order got rejected but was never re-attempted again:

                      7/24/2015 5:50:17 AM Entered internal PlaceOrder() method at 7/24/2015 5:50:17 AM: BarsInProgress=1 Action=SellShort OrderType=Limit Quantity=671 LimitPrice=1.5478'2 StopPrice=0 SignalName='Short Position' FromEntrySignal=''

                      Short entry order has been submitted: Order='6c4c295f7d43452ca5d210a03e5473ed/ScalpiusDemoForex' Name='Short Position' State=Rejected Instrument='$GBPUSD' Action=SellShort Limit price=1.54782 Stop price=0 Quantity=671 Strategy='Scalpius' Type=Limit Tif=Gtc Oco='' Filled=0 Fill price=0 Token='9c041e3b51154f95b48764bab1ad6963' Gtd='12/1/2099 12:00:00 AM'

                      7/24/2015 7:00:00 AM: One candle entry period exceeded. Canceling entry order: Order='6c4c295f7d43452ca5d210a03e5473ed/ScalpiusDemoForex' Name='Short Position' State=Rejected Instrument='$GBPUSD' Action=SellShort Limit price=1.54782 Stop price=0 Quantity=671 Strategy='Scalpius' Type=Limit Tif=Gtc Oco='' Filled=0 Fill price=0 Token='9c041e3b51154f95b48764bab1ad6963' Gtd='12/1/2099 12:00:00 AM'

                      No indication that the order was resubmitted. I think I covered all the basics - except the GTC part (which is now fixed). This should have triggered a resubmit but it doesn't seem to be working.
                      Last edited by molecool; 07-24-2015, 07:05 AM.

                      Comment


                        #12
                        Hello molecool,

                        Thank you for your response.

                        Can you attach a full Output that you have placed in a .txt file? I would like to take a look at what is occurring.

                        Comment


                          #13
                          Test Strategy

                          Alright, I was getting a bit frustrated with chasing down the rabbit hole so I wrote a simple test strategy. Here's the code:

                          Code:
                          #region Using declarations
                          using System;
                          using System.ComponentModel;
                          using System.Diagnostics;
                          using System.Drawing;
                          using System.Drawing.Drawing2D;
                          using System.Xml.Serialization;
                          using NinjaTrader.Cbi;
                          using NinjaTrader.Data;
                          using NinjaTrader.Indicator;
                          using NinjaTrader.Gui.Chart;
                          using NinjaTrader.Strategy;
                          #endregion
                          
                          // This namespace holds all strategies and is required. Do not change it.
                          namespace NinjaTrader.Strategy
                          {
                              /// <summary>
                              /// Enter the description of your strategy here
                              /// </summary>
                              [Description("Enter the description of your strategy here")]
                              public class TestLimitOrderResubmit : Strategy
                              {
                                  #region Variables
                          		private IOrder entryOrder = null;
                          		private int distance = 10;
                          		private double currentAsk = 0;
                          		private double currentBid = 0;
                          		private int unfilledPositionSize = 10000;
                          		private static String LONG_POSITION = "long position";
                          		private bool triggered = false;
                                          private int counter = 5;
                                  #endregion
                          
                                  protected override void Initialize()
                          		{ 
                          			RealtimeErrorHandling = RealtimeErrorHandling.TakeNoAction; 
                          			CalculateOnBarClose = false;
                          			BarsRequired = 0;
                          			//TimeInForce = Cbi.TimeInForce.Day;
                          			TraceOrders = true;
                          			ExitOnClose = false;
                          		}
                          		
                          		private IOrder stopLossOrder = null;
                          		
                          		protected override void OnBarUpdate() 
                          		{ 
                          			if (!triggered && !Historical)  {
                          			Print("Got into Trigger.");
                          				entryOrder = EnterLongLimit(0, true, unfilledPositionSize, currentAsk + (distance * TickSize), LONG_POSITION);
                          				triggered = true;
                          			}
                          		}
                          		
                          		protected override void OnOrderUpdate(IOrder order) 
                          		{ 
                          			Print("Got into  OnOrderUpdate()");
                          			if (entryOrder != null && entryOrder == order)
                          				{	
                          					if (order.OrderState == OrderState.Rejected && counter > 0) 
                          					{
                          						if (entryOrder.OrderAction == OrderAction.Buy) {
                          								String message = "Long Entry REJECTED - attempting again with Limit at ask: " + currentAsk;
                          								Print(message);
                          								Log(message, LogLevel.Information);
                          								entryOrder = EnterLongLimit(0, true, 10000, currentAsk, LONG_POSITION);
                                                                          counter--;
                          							
                          						} 
                          				}
                          			}
                          		}
                          		
                          		/// <summary>
                          		/// Captures the last bid or ask and sets the global vars. Also determines
                          		/// if an excessive spread is present.
                          		/// </summary>
                          		/// <param name="e"></param>
                          		protected override void OnMarketData(MarketDataEventArgs e)
                          		{	
                          			if (e.MarketDataType == MarketDataType.Ask)
                          				currentAsk = e.Price;
                          
                          			else if (e.MarketDataType == MarketDataType.Bid)
                          				currentBid = e.Price;
                          		}
                          
                                  #region Properties
                                  [Description("")]
                                  [GridCategory("Parameters")]
                                  public int Distance
                                  {
                                      get { return distance; }
                                      set { distance = Math.Max(0, value); }
                                  }
                                  #endregion
                              }
                          }
                          This will loop six times and thus pop up six alerts. So it seems at least here OOU was being called. But unfortunately the recommended mechanism would only lead to a ton of new alerts being opened and nothing else. I just tested this in production with a FXCM live feed.

                          BTW, TimeInForce was set to GTC again as Day causes the strategy to shut down no matter what. So that wasn't the problem either - FXCM does accept GTC orders just fine apparently.

                          I'm not sure how to proceed here. Please review the code and perhaps run it against FXCM if you have access.
                          Last edited by molecool; 07-24-2015, 09:02 AM.

                          Comment


                            #14
                            Hello molecool,

                            I appreciate your patience as I look into this matter for you.

                            Comment


                              #15
                              Hello molecool,

                              With your most recent code and my own version that I used, this does exactly what you want on my end.

                              Here is my most recent output:
                              Got into Trigger.
                              7/24/2015 2:06:22 PM Entered internal PlaceOrder() method at 7/24/2015 2:06:22 PM: BarsInProgress=0 Action=Buy OrderType=Limit Quantity=1,000 LimitPrice=1.0980 StopPrice=0 SignalName='long position' FromEntrySignal=''
                              Got into OnOrderUpdate()
                              Got into OnOrderUpdate()
                              Long Entry REJECTED - attempting again with Limit at ask: 1.0979
                              7/24/2015 2:06:22 PM Entered internal PlaceOrder() method at 7/24/2015 2:06:22 PM: BarsInProgress=0 Action=Buy OrderType=Limit Quantity=1,000 LimitPrice=1.0979 StopPrice=0 SignalName='long position' FromEntrySignal=''
                              Are you seeing the same issue on your end still even with the most recent code you posted?

                              If so, can you send us your Output and Log and Trace files to platformsupport[at]ninjatrader[dot]com and reference this thread?

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by Rapine Heihei, Today, 08:19 PM
                              1 response
                              6 views
                              0 likes
                              Last Post NinjaTrader_Manfred  
                              Started by Rapine Heihei, Today, 08:25 PM
                              0 responses
                              5 views
                              0 likes
                              Last Post Rapine Heihei  
                              Started by f.saeidi, Today, 08:01 PM
                              1 response
                              4 views
                              0 likes
                              Last Post NinjaTrader_Manfred  
                              Started by Rapine Heihei, Today, 07:51 PM
                              0 responses
                              6 views
                              0 likes
                              Last Post Rapine Heihei  
                              Started by frslvr, 04-11-2024, 07:26 AM
                              5 responses
                              97 views
                              1 like
                              Last Post caryc123  
                              Working...
                              X