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

Issue with Unmanaged Stop Order placement

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

    Issue with Unmanaged Stop Order placement

    I tested the following Unmanaged Order code:

    initialExitOrderLong = SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, 1, 0, Position.AveragePrice - 30*TickSize, "", @"Exit Long FULL STOP" );



    It is intended to place an Exit Stop order for my manual Long entries, 30 ticks below the entry average filled price.

    I also tested it like this:

    initialExitOrderLong = SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, 1, 0, (Position.AveragePrice + (- 30 * TickSize)), "", @"Exit Long FULL STOP" );



    For some reason the Order is placed at price $ -0.30.





    Why doesn't it set the Stop Exit Long order at 72.02 - 30 ticks instead (71.72)?
    Last edited by Cormick; 07-28-2021, 06:33 AM.

    #2
    Hello Cormick,

    Thank you for your note.

    Where within your code are you submitting the exit stop order? Could you give a larger example of your code that illustrates?

    Thanks in advance; I look forward to assisting you further.
    Kate W.NinjaTrader Customer Service

    Comment


      #3
      Hi Kate,

      Thank you for your reply.

      I have it in the OnBarUpdate section.

      My private variable section:

      public class MultiStepBreakEvenLongAndShort : Strategy
      {
      private int StopLossModeLong;
      private int StopLossModeShort;


      private Order initialExitOrderLong = null;
      //private Order firstMoveExitOrderLong = null;

      // private Order initialExitOrderShort = null;
      // private Order firstMoveExitOrderShort = null;

      My OnstateChange section:

      protected override void OnStateChange()
      {
      if (State == State.SetDefaults)
      {
      Description = @"Enter the description for your new custom Strategy here.";
      Name = "MultiStepBreakEvenLongAndShort";
      Calculate = Calculate.OnEachTick;
      EntriesPerDirection = 1;
      EntryHandling = EntryHandling.AllEntries;
      IsExitOnSessionCloseStrategy = true;
      ExitOnSessionCloseSeconds = 30;
      IsFillLimitOnTouch = false;
      MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
      OrderFillResolution = OrderFillResolution.Standard;
      Slippage = 0;
      StartBehavior = StartBehavior.WaitUntilFlat;
      TimeInForce = TimeInForce.Gtc;
      TraceOrders = false;
      RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose;
      StopTargetHandling = StopTargetHandling.PerEntryExecution;
      BarsRequiredToTrade = 20;
      // Disable this property for performance gains in Strategy Analyzer optimizations
      // See the Help Guide for additional information
      IsInstantiatedOnEachOptimizationIteration = true;
      IsAdoptAccountPositionAware = true;
      StartBehavior = StartBehavior.AdoptAccountPosition;
      IsUnmanaged = true;
      StopLossModeLong = 0;
      // StopLossModeShort = 0;
      }
      else if (State == State.Configure)
      {
      }
      else if (State == State.Realtime)
      {
      if (initialExitOrderLong != null)
      initialExitOrderLong = GetRealtimeOrder(initialExitOrderLong);
      // if (initialExitOrderShort != null)
      // initialExitOrderShort = GetRealtimeOrder(initialExitOrderShort);
      }
      }

      My OnBarUpdate Section (I have the If(0 Else Structure for adding the Short side, from here:
      https://ninjatrader.com/support/foru...71#post1165471 )

      protected override void OnBarUpdate()
      {

      if (CurrentBar < BarsRequiredToTrade)
      return;


      if (BarsInProgress != 0)
      return;

      if (PositionAccount.MarketPosition == MarketPosition.Long)
      {
      {
      StopLossModeLong = 0;
      }


      // Set 2
      if ((PositionAccount.MarketPosition == MarketPosition.Long)
      && (initialExitOrderLong == null)
      && (StopLossModeLong == 0))
      {
      initialExitOrderLong = SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, 1, 0, Position.AveragePrice - 30*TickSize, "", @"Exit Long FULL STOP" );
      }


      // Set 3
      if ((PositionAccount.MarketPosition == MarketPosition.Long)
      && (initialExitOrderLong != null)
      && (StopLossModeLong == 1))
      {
      ChangeOrder(initialExitOrderLong, initialExitOrderLong.Quantity, 0, Position.AveragePrice + 10*TickSize);

      // Set 4
      if ((PositionAccount.MarketPosition == MarketPosition.Long)
      && (initialExitOrderLong != null)
      && (StopLossModeLong == 0)
      && (Close[0] >= (Position.AveragePrice + (5 * TickSize / 2)) ))
      {
      StopLossModeLong = 1;
      }
      }


      My OnOrderUpdate Section:

      protected override void OnOrderUpdate(Order order, double limitPrice, double stopPrice, int quantity, int filled, double averageFillPrice, OrderState orderState, DateTime time, ErrorCode error, string nativeError)
      {
      if (order.Name == "Exit Long FULL STOP")
      {
      {
      initialExitOrderLong = order;
      }

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

      if (initialExitOrderLong.OrderState == OrderState.Cancelled)
      {
      initialExitOrderLong = null;
      }
      }
      }

      Thank you for you help.

      Comment


        #4
        Hello Cormick,

        Thank you for your reply.

        I've plugged your code into a strategy and had it enter long once state is realtime, and I am seeing the initial stop placed 30 ticks away as I would expect:

        Click image for larger version

Name:	2021-07-28_12-16-51.png
Views:	77
Size:	112.4 KB
ID:	1165581

        I've attached my test script as well so you can take a look at the few modifications I made and test on your end.

        Please let us know if we may be of further assistance to you.
        Kate W.NinjaTrader Customer Service

        Comment


          #5
          Hi Kate,

          Thank you for the test and results on your end.

          I've retested on my end and the issue persists.

          2nd Demo video:

          https://drive.google.com/file/d/1sSg...ew?usp=sharing

          Do you still have your test script available? It's not yet displaying on your previous post.
          I'd like to test it on my end to check if my NT8 is not working as it should.

          I'll be back tomorrow.

          Have a good day!

          Be well!

          Comment


            #6
            Hello Cormick,

            I'm able to see it as an attachment on my previous post, but I'll attach it again below:

            Please let us know if we may be of further assistance to you.
            Attached Files
            Kate W.NinjaTrader Customer Service

            Comment


              #7
              Hi Kate,

              Thanks for the attachment.

              Your code:
              Why did you add this part to the OnBarUpdate?
              1. if (Position.MarketPosition == MarketPosition.Flat && entryOrder == null)
              2. {
              3. oco = GetAtmStrategyUniqueId() + "entry";
              4. SubmitOrderUnmanaged(0, OrderAction.Buy, OrderType.Market, 1, 0, 0, oco, "EntryOrder");
              5. }
              And why did you add those parts to the OnOrderUpdate?
              1. if (order.Name == "EntryOrder")
              2. {
              3. entryOrder = order;
              4. }
              1. if (entryOrder != null && entryOrder == order)
              2. {
              3. if (entryOrder.OrderState == OrderState.Cancelled || entryOrder.OrderState == OrderState.Filled)
              4. {
              5. entryOrder = null;
              6. }
              7. }
              My code is just for automatic placement of initial Stop and moving it on Manually entered orders (when I manually click the ChartTrader Buy Mkt or Buy Ask or Buy Bid buttons).

              I need for the strategy to automatically place an initial stop order at -30 ticks from the average entry price.
              I need it to do that instantly when I press any of the Buy Mkt or Buy Ask or Buy Bid buttons.

              I don't need the EntryOrder/entryOrder:
              if (Position.MarketPosition == MarketPosition.Flat && entryOrder == null)

              What I need is for the MultiStepBreakEvenLongTest strategy to automatically detect if/the instant a Long order is filled,
              and only place a stop order 30 ticks below the long entry.
              Then if X number of ticks of profit is realized, move the Stop order Y number of ticks.


              Noticed issues with your code:

              Your script automatically enters an Entry order when I tick the Enabled checkbox in the Strategy Tab of the Control center window/or when I tick the enabled checkbox on the strategy.
              I intend the script to manage Manually entered Long orders, without any entry made by the strategy.

              at timestamp 0:16

              Why does it place an Entry Order?
              How to make it not place an entry order and work as intended?

              I tried commenting out your unnecessary for my purpose EntryOrder/entryOrder snippets and it produces again the - $ 0.30 result:

              Your script does not move the stop when the number of ticks to move it is reached.
              For quick test, I updated the move order action to trigger a 1 tick move on a 3 ticks profit.

              ChangeOrder(initialExitOrderLong, initialExitOrderLong.Quantity, 0, Position.AveragePrice + 1*TickSize);

              Close[0] >= (Position.AveragePrice + (3 * TickSize / 2))

              at timestamps:
              0:00
              1:40
              4:40

              Why does it not move the stop?
              How to make it move the stop?

              Your script sometimes places the Stop instantly, sometimes on new tick and sometimes multiple seconds after the new tick.
              at timestamps:
              0:19
              0:53
              3:10
              3:47
              4:37
              Why does it not places the order instantly?
              How to make it do so?

              Comment


                #8
                Hello Cormick,

                This is Jim responding on behalf of Kate who is out of the office at this time.

                It does not look like it was clear involving the intention to adopt the account position. It looks like Kate added code to place an initial entry order to be able to test the script.

                Any question of "why is my strategy not taking actions that are expected" needs to be investigated with debugging steps. For example, we would check if the code to modify the stop loss is being reached by adding a print beside the code that moves the stop loss.

                If this code is not reached, why is it not? We would then add prints outside of that condition to check each item in the condition to see why the condition evaluates as false and does not allow the action to be reached.

                After we see why the condition evaluates to false, we would pinpoint what specific parts are not the values we expect. For example, if you see that ChangeOrder is not reached, you will need to take debugging steps to see what the values in the condition controlling it are. If StopLossModeLong is never 1 by the time the condition is evaluated, why would that be? What parts of the code would be controlling that variable, and why would it not be 1? If you add additional prints checking this value in your code with something unique so you know where the print comes from, you can see where that value changes. You can also use Ctrl + F to find where in the code that variable is getting set.

                The questions above are questions you would ask yourself to understand how your code is executing. I have included some tips for debugging below.

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

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

                Debugging in the Strategy Builder - https://drive.google.com/file/d/1mTq...w?usp=drivesdk

                Playback Connection - https://ninjatrader.com/support/help...connection.htm

                Debugging Demo - https://drive.google.com/file/d/1rOz...w?usp=drivesdk

                Another item to think about: You are triggering the move the stop loss when you see more than 2 ticks of profit:

                Close[0] >= (Position.AveragePrice + (5 * TickSize / 2)) )

                But when you change the stop loss, you want to move it further than how the actual market moved.

                ChangeOrder(initialExitOrderLong, initialExitOrderLong.Quantity, 0, Position.AveragePrice + 10*TickSize);

                As you are working with the unmanaged approach and inquiring on why OnOrderUpdate code was added in relation to the initial entry order, it is going to be critical to understand the more complex NinjaScript concepts like using the advanced order handling methods, and order objects. Our SampleOnOrderUpdatre strategy explains this well, but I suggest going through all of our examples to learn as much about NinjaScript strategies as you can as this information will help you to understand how the logic works and can help you when you are writing your own strategies.

                We have had several inquiries involving more advanced concepts where the previous building blocks are not yet understood. Going over these examples will help to bridge that gap.

                NinjaScript strategy examples - https://ninjatrader.com/support/help.../strategy2.htm

                We look forward to assisting.
                JimNinjaTrader Customer Service

                Comment


                  #9
                  Hi Jim,

                  Thanks a lot for the extensive guidance and reasoning process steps!

                  I'll go through the resources and update the code according to the new gleaned insights.

                  Be back when I make significant progresses.

                  Have a good day!

                  Be well!

                  Comment


                    #10
                    Hi Jim,

                    I've made some progresses.

                    I could establish that the Logic is ok.

                    Video Demo:
                    timestamps:
                    1:12:37 / 1:19:03 / 1:27:22 / 1:29:07 / 1:30:09




                    The Syntax is also ok.

                    Video Demo:
                    timestamps:
                    1:32:02



                    The snippets scope (order of executions) was the cause of the issue.

                    The ChangeOrder() if() statement came before the StopLossModeLong = 1 if() statement.
                    The ChangeOrder() if() statement needs to come after the StopLossModeLong = 1 if() statement.
                    Because if it comes before, then the machine does not process it in the code once the StopLossModeLong = 1 is TRUE.
                    The machine can only process it as FALSE before.

                    Video Demo:
                    timestamps:
                    1:45:18 (Consecutive Order snippets Set 4 then Set 3)
                    1:53:53 (Stop Order Move from - $ 3.0 to $ 0.1)
                    1:55:40 (Prints: ChangeOrder SLMode 1)



                    The ChangeOrder() executes in the video with confirmation in the Prints.

                    But for some reason in your original code from this post

                    the reverse order (sets 5 and 6, lines 101-115, https://pastebin.com/9hga9EKA ) do execute the
                    StopLossMode == 1
                    and StopLossMode == 2
                    if() statements actions in spite of those latter (sets 4 and 5, c.f. lines 87-99, https://pastebin.com/9hga9EKA) ones coming before the former ones in your code.

                    Why does the reverse order work in your code, but not in mine?
                    Is it because of some UnmanagedOrder() or ChangeOrder() special processing order that required the consecutive order,
                    while the managed orders do not require the consecutive execution order?
                    Or something else? If something else, what else?



                    The Adopted Position.AveragePrice Issue:

                    Now that the ChangeOrder() issue is solved, I need to solve next the incorrect adopted Position.AveragePrice issue.

                    I could establish that the Strategy detects the adopted Position.AveragePrice as being $ 0.0.

                    It then sets the stops 30 ticks below at first, at - $3 for GC, and at - $ 0.30 for CL.

                    And then it changes the order to $ 0.10 for GC (1 GC tick above its detected Position.AveragePrice of $ 0.0).

                    Could you please help me find the documentation that addresses the UnmanagedOrder Position.AveragePrice adoption?

                    I could not find it in the links below:

                    Also why does the ChangeOder() / UnmanagedOrder() method do not automatically detect the right Position.AveragePrice
                    ($1827.7 for my latest GC trade test, instead of the $ 0.0 gotten when testing)?


                    Last edited by Cormick; 07-30-2021, 09:19 AM.

                    Comment


                      #11
                      Hello Cormick,

                      There is no additional magic to my MultiStepBreakeven Strategy Builder example. OnBarUpdate logic is processed bar by bar, and within each OnBarUpate iteration, code is executed line by line. Logical conditions become true because the values of the conditions allow them to evaluate as true when the code reaches those conditions.

                      As for checking Position.AveragePrice, try printing this from OnStateChange > State == State.Realtime from my examples when we detect that we are in a position. When I test this I see the average entry price from the manually entered position, which we would expect.

                      Click image for larger version

Name:	NinjaTrader_2021-07-30_12-23-10.png
Views:	85
Size:	17.8 KB
ID:	1165908

                      The Position object is the strategy position object. If you are using Adopt Account Position, this Position object will reflect the account position after strategy start up, but this does not mean the strategy follows the account position. I.E. if you submit a manual trade after the strategy is enabled, the strategy will not know about this. If you want to reference the Account position of that instrument, use PositionAccount.

                      PositionAccount - https://ninjatrader.com/support/help...ionaccount.htm
                      JimNinjaTrader Customer Service

                      Comment


                        #12
                        Hi Jim,

                        Thanks for the answers.

                        I must preface I only executed your MultiStepBreakeven Strategy Builder on historical data.
                        But on historical data the strategy works and executes the stop movement (not ChangeOrder() method but it does move the stop).
                        Whereas on my strategy I need to put the snippets in logical consecutive order for it to execute the ChangeOrder() method—
                        if I follow your example and put the stop movement if() statements out of logical consecutive order ( the setting of StopLossMode to 1 and 2 after the stop movement if() statements),
                        then the ChangeOrder() does not execute.

                        Why does it work out of order on your example (on historical data) but not on live data with my code?



                        Thanks for the OnStateChange > State == State.Realtime prints direction. I'll test it tomorrow.



                        Yes I used this in the State.SetDefauls section:
                        IsAdoptAccountPositionAware = true;

                        I'm not sure what you mean by
                        If you want to reference the Account position of that instrument, use PositionAccount.
                        Do you mean referencing it in my OnBarUpdate If() statements?


                        I already have my OnBarUpdate if() statements set with PositionAccount:

                        My Full Code:
                        My OnBarUpdate Section:

                        protected override void OnBarUpdate()
                        {
                        if (CurrentBar < BarsRequiredToTrade)
                        return;
                        if (State == State.Historical)
                        return;

                        if (BarsInProgress != 0)
                        return;
                        // if (Position.MarketPosition == MarketPosition.Flat && entryOrder == null)
                        // {
                        // oco = GetAtmStrategyUniqueId() + "entry";

                        // SubmitOrderUnmanaged(0, OrderAction.Buy, OrderType.Market, 1, 0, 0, oco, "EntryOrder");
                        // }

                        if (PositionAccount.MarketPosition == MarketPosition.Long)
                        {
                        StopLossModeLong = 0;
                        }


                        if ((PositionAccount.MarketPosition == MarketPosition.Long)
                        && (initialExitOrderLong == null)
                        && (StopLossModeLong == 0))
                        {
                        initialExitOrderLong = SubmitOrderUnmanaged(0, OrderAction.Sell, OrderType.StopMarket, 1, 0, Position.AveragePrice - 30*TickSize, "", @"Exit Long FULL STOP" );
                        }

                        Print("ChangeOrder P " + initialExitOrderLong);


                        Print("ChangeOrder Q " + initialExitOrderLong);
                        // Set 4
                        if ((PositionAccount.MarketPosition == MarketPosition.Long)
                        && (initialExitOrderLong != null)
                        && (StopLossModeLong == 0)
                        && (Close[0] >= (Position.AveragePrice + (3 * TickSize / 2)) ))
                        {
                        StopLossModeLong = 1;
                        Print("ChangeOrder Trig. Pri. Mode " + StopLossModeLong);
                        Print("ChangeOrder Trigger Price Move " + initialExitOrderLong);
                        }
                        Print("ChangeOrder R " + initialExitOrderLong);

                        // Set 3
                        if ((PositionAccount.MarketPosition == MarketPosition.Long)
                        && (initialExitOrderLong != null)
                        && (StopLossModeLong == 1))
                        {
                        ChangeOrder(initialExitOrderLong, initialExitOrderLong.Quantity, 0, Position.AveragePrice + 1*TickSize);
                        Print("ChangeOrder SLMode " + StopLossModeLong);
                        Print("ChangeOrder values " + initialExitOrderLong);

                        }

                        }

                        Or do you mean referencing as in the example of your shared link in the Prints:

                        protected override void OnBarUpdate()
                        {
                        // Print out the average entry price
                        Print("The average entry price is " + PositionAccount.AveragePrice);
                        }

                        If you mean referencing in the prints,
                        I'm not sure of the use because we already know about the strategy currently detecting the Position.AveragePrice as $ 0.0 .
                        And the Print won't let us know why it detects the Position.AveragePrice as $ 0.0,
                        nor what next to do to make it detect it instead as the manual entry price.
                        Or am I missing something else to grasp the cause?
                        If I am I can't see it from the link you shared.
                        Could you please tell me what solving information to take from your link?


                        Or do you mean something else?
                        If something else, what else?—

                        —I just infered you meant PositionAccount.AveragePrice, from reviewing your link example.
                        I did not notice it before, because the documentation states:

                        AveragePrice Gets the average entry price of the account position

                        We have to look at the example to get the PositionAccount possibility.

                        Before that I expected only the MarketPosition could be changed to PositionAccount.
                        MarketPosition Gets the current market position of the account



                        Possible values:

                        MarketPosition.Flat

                        MarketPosition.Long

                        MarketPosition.Short

                        Thanks for the clues.

                        I'll test the update tomorrow and be back with result asap.

                        Have a good Week End!

                        Be well!

                        Comment


                          #13
                          Hello Cormick,

                          OnBarUpdate does not evaluate differently in my script or yours. If it is not clear how my strategy works, try using the playback connection to repeat behaviors of the strategy that are in question, and use prints to follow each value for each variable in the strategy to see how it is executing. Print out the values of each variable used in a condition before that condition evaluates to see the values used of each condition to see why the condition evaluates the way it does.

                          Also keep in mind, PositionAccount will only be relevant after we pass State.Realtime. PositionAccount will not have relevance for historical processing because it reflects the account position, which we are not working with when the strategy processes historical data.

                          As mentioned in post #9 it will provide great value to set up simple strategies and to use prints to understand how Position and PositionAccount work in a simple script, as well as how barsAgo indexing and how bar indexing works before trying to tackle those challenges in an actual script.
                          JimNinjaTrader Customer Service

                          Comment


                            #14
                            Hi Jim,

                            I've updated each instance of the PositionAccount.AveragePrice in the code.

                            Now it's working! You rock! Thanks a lot!

                            The stop is set 1st 30 ticks below the correct Long entry price.
                            And then upon condition met the stop moves to Long Entry Price + 1 tick as indented in the test.


                            Full code:


                            Thanks for the recommendation
                            it will provide great value to set up simple strategies and to use prints to understand how Position and PositionAccount work in a simple script
                            What simple strategy would you use? I thought using if(Close[0] > Open[0]) simple strategy but I'm not sure it will help to see the extra differences between Position and PositionAccount.
                            From the tests done so far I understand that Position is for the managed strategies only.
                            Basically the Position method manages orders that are not unmanaged (it detects the managed order's properties on its own).
                            While PositionAccount is for the Unmanaged strategies.
                            Basically the PositionAccount method manages orders that are unmanaged (it detects the unmanaged order's properties on its own, if and only if we add the 'Account' to Position.AveragePrice).
                            Is there something more to that to understand?
                            Is there a special documentation about it?

                            I found more example from the PositionsAccount page:
                            protected override void OnBarUpdate()
                            {
                            Print("ES account position is " + PositionsAccount[0].MarketPosition);
                            Print("NQ account position is " + PositionsAccount[2].MarketPosition);

                            // Alternative approach. By checking what Bars object is calling the OnBarUpdate()
                            // method, we can just use the Position property since its pointing to the correct
                            // position.
                            if (BarsInProgress == 0)
                            Print("ES account position is " + PositionAccount.MarketPosition);
                            else if (BarsInProgress == 2)
                            Print("NQ account position is " + PositionAccount.MarketPosition);
                            }

                            I see now we can Print the PositionAccount.MarketPosition value.

                            I'll test it.

                            Next I'll add the Short Side Logic and be back asap.

                            Thanks again a lot!

                            Comment

                            Latest Posts

                            Collapse

                            Topics Statistics Last Post
                            Started by 7robert, Today, 11:50 AM
                            0 responses
                            10 views
                            0 likes
                            Last Post 7robert
                            by 7robert
                             
                            Started by ezrollin, Today, 10:40 AM
                            8 responses
                            12 views
                            0 likes
                            Last Post ezrollin  
                            Started by sidlercom80, Today, 10:20 AM
                            2 responses
                            6 views
                            0 likes
                            Last Post sidlercom80  
                            Started by TraderElegante, Today, 09:53 AM
                            2 responses
                            18 views
                            0 likes
                            Last Post TraderElegante  
                            Started by Kreyenhagen, Today, 09:03 AM
                            1 response
                            8 views
                            0 likes
                            Last Post NinjaTrader_ChrisL  
                            Working...
                            X