Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

SetStopLoss() with dynamic SL-offset doesn't trigger

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

    SetStopLoss() with dynamic SL-offset doesn't trigger

    Hi,
    My strategies use the SetStopLoss() method in OnExcecution() with a dynamic SL-offset in Ticks that is calculated in OnBarUpdate(). I have noticed that SetStopLoss() doesn't trigger an exit order when price "jumps" above/ below the SL-level. When I say that price "jumps" I mean that the dynamic SL-level passes 0 ticks and gets negative without touching the zero-level . To avoid this problem I have added an extra "JumpStopLoss" exit in the OnBarUpdate() that catches this situations. But this extra "Jump Stop" executes one bar later and some ticks below/ above the true StopLoss compared to if SetStopLoss() would trigger also when price jumps above/below 0. How can I make the SetStopLoss() trigger also when price jumps above/ below 0?

    I'v attached two screenshots and a simple as possible example code that uses your MACrossOver strategy and the OnExceution sample code. The first screen shot shows the strategy with the extra "Jumpstop" and the seccond screen shot shows the same image without the "JumpStop".

    Code:
    namespace NinjaTrader.Strategy
    {
        /// <summary>
        /// Simple moving average cross over strategy.
        /// </summary>
        [Description("Simple moving average cross over strategy.")]
        public class SL_Example_MACrossOver : Strategy
        {
            #region Variables
            private int        fast    = 10;
            private int        slow    = 25;
            
            private double    stopLoss;    // StoppLoss offset in SetStopLoss()
            
            private IOrder long1         = null; // This variable holds an object representing our entry order
            private IOrder short1         = null; // This variable holds an object representing our entry order
            #endregion
    
            /// <summary>
            /// This method is used to configure the strategy and is called once before any strategy method is called.
            /// </summary>
            protected override void Initialize()
            {
                SMA(Fast).Plots[0].Pen.Color = Color.Orange;
                SMA(Slow).Plots[0].Pen.Color = Color.Green;
    
                Add(SMA(Fast));
                Add(SMA(Slow));
    
                // Entry handling
                EntriesPerDirection = 1;
                   EntryHandling         = EntryHandling.UniqueEntries;
                CalculateOnBarClose    = true;
            }
    
            /// <summary>
            /// Called on each bar update event (incoming tick).
            /// </summary>
            protected override void OnBarUpdate()
            {    if(Position.MarketPosition == MarketPosition.Flat)
                {
                    if (CrossAbove(SMA(Fast), SMA(Slow), 1))
                    {
                        long1 = EnterLong("Long");
                    }
                    else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
                    {
                        short1 = EnterShort("Short");
                    }
                }
                    
                #region 1 Tick SL-strategy
                    // Calculate stopLoss in ticks.        
    
                    // Recalculate StopLoss before position                                    
                    if (Position.MarketPosition == MarketPosition.Flat)
                    {
                        stopLoss = (High[0]-Low[0])/TickSize +1;
                    }
                    
                    
                    // Set SL 1 tick below highest low since entry
                    if (Position.MarketPosition == MarketPosition.Long)
                    {
                            stopLoss = (Position.AvgPrice - MAX(Low, BarsSinceEntry() +1 )[0])/ TickSize + 1;
                    }
                    // Set SL 1 tick above lowest high since entry
                    else if (Position.MarketPosition == MarketPosition.Short)
                    {
                            stopLoss = (MIN(High, BarsSinceEntry() +1 )[0] - Position.AvgPrice)/ TickSize + 1;
                    }
                    
                    /*
                    Print("");
                    Print(Time[0]);
                    Print("Position.AvgPrice: " + Position.AvgPrice);
                    Print("MIN(High, BarsSinceEntry() +1 )[0]: " + MIN(High, BarsSinceEntry() +1 )[0]);
                    Print("MAX(Low, BarsSinceEntry() +1 )[0]: " + MAX(Low, BarsSinceEntry() +1 )[0]);
                    Print("stopLoss: " + stopLoss);
                    Print("");
                    */
                    
                    [COLOR=Red]/*
                    //[B]EXTRA JUMP STOP[/B] - Check if the StopLoss level is hit. If price jumps above the StopLoss level , exit position since StopLoss is hit        
                    if (Position.MarketPosition == MarketPosition.Long && Low[0] <= Position.AvgPrice - stopLoss*TickSize )
                    { 
                        ExitLong("JumpStopLoss", "Long" );
    
                    }
                    //If price jumps below the StopLoss level , exit position since StopLoss is hit
                    else if (Position.MarketPosition == MarketPosition.Short && High[0] >= Position.AvgPrice + stopLoss*TickSize )
                    {
                        ExitShort("JumpStopLoss", "Short" );
    
                    }
                    */[/COLOR]
                    
                #endregion    
    
            }
            
        
        
            #region OnExecution    
            protected override void OnExecution(IExecution execution)
            {        
                if (long1 != null && long1.Token == execution.Order.Token)
                {
                    if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
                    {
                        SetStopLoss("Long", CalculationMode.Ticks, stopLoss, false);
                                                                
                        // Resets the entryOrder object to null after the order has been partially filled
                        if (execution.Order.OrderState != OrderState.PartFilled)
                        {
                            long1    = null;
                        }
                    }
                }
                if (short1 != null && short1.Token == execution.Order.Token)
                {
                    if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
                    {
                        SetStopLoss("Short", CalculationMode.Ticks, stopLoss, false);
                                                                
                        // Resets the entryOrder object to null after the order has been partially filled
                        if (execution.Order.OrderState != OrderState.PartFilled)
                        {
                            short1    = null;
                        }
                    }
                }
            }
            #endregion
            
            
            #region Properties
            /// <summary>
            /// </summary>
            [Description("Period for fast MA")]
            [GridCategory("Parameters")]
            public int Fast
            {
                get { return fast; }
                set { fast = Math.Max(1, value); }
            }
    
            /// <summary>
            /// </summary>
            [Description("Period for slow MA")]
            [GridCategory("Parameters")]
            public int Slow
            {
                get { return slow; }
                set { slow = Math.Max(1, value); }
            }
            #endregion
        }
    }
    Attached Files
    Last edited by poseidon_sthlm; 06-21-2010, 07:56 AM.

    #2
    Strategy attached. (The extra JumpStop exit condition is commented out in the attached strategy.)
    Attached Files

    Comment


      #3
      Hello Poseidon_shtml,

      That behavior is expected when using ExitLong when CalculateOnBarClose == true. Orders are submitted on the next bar following the condition.

      What you may consider doing is adding a check for > 0 for the stoploss price.

      SetStopLoss("Long", CalculationMode.Ticks, Math.Max(stopLoss, 1), false);
      Ryan M.NinjaTrader Customer Service

      Comment


        #4
        Thanks for the prompt reply.

        Your suggestion looks very attractive, but I can't make it work. I'v tried:
        SetStopLoss("Long", CalculationMode.Ticks, Math.Max(stopLoss, 1), false);
        as well as
        SetStopLoss("Long", CalculationMode.Ticks, Math.Max(stopLoss, 0), false);

        No exitorder is triggerd when Math.Max(stopLoss, 0) = 0.
        Any suggestions?

        /Regards


        Code:
        2008-06-11 21:20:00
        [COLOR=Red]Position.AvgPrice: 1329,5[/COLOR]
        MIN(High, BarsSinceEntry() +1 )[0]: 1330
        MAX(Low, BarsSinceEntry() +1 )[0]: 1326,5
        stopLoss: 3
        Math.Max(stopLoss, 0): [COLOR=Red]3[/COLOR]
        
        
        2008-06-11 21:25:00
        [COLOR=Red]Position.AvgPrice: 1329,5[/COLOR]
        MIN(High, BarsSinceEntry() +1 )[0]: 1328
        MAX(Low, BarsSinceEntry() +1 )[0]: 1326,5
        stopLoss: -5
        Math.Max(stopLoss, 0): [COLOR=Red]0[/COLOR]
        
        
        2008-06-11 21:30:00
        [COLOR=Red]Position.AvgPrice: 1329,5[/COLOR]
        MIN(High, BarsSinceEntry() +1 )[0]: 1328
        MAX(Low, BarsSinceEntry() +1 )[0]: 1326,5
        stopLoss: -5
        Math.Max(stopLoss, 0): [COLOR=Red]0[/COLOR]
        
        
        2008-06-11 21:35:00
        [COLOR=Red]Position.AvgPrice: 1329,5[/COLOR]
        MIN(High, BarsSinceEntry() +1 )[0]: 1328
        MAX(Low, BarsSinceEntry() +1 )[0]: 1327,25
        stopLoss: -5
        Math.Max(stopLoss, 0):[COLOR=Red] 0[/COLOR]

        Comment


          #5
          poseidon_sthlm,

          The idea was to submit the higher of your stoploss value or 1. If you are submitting stop loss values at zero or lower, then you will likely get exited at the same price you entered or your order will be rejected.

          Your ExitLong() and ExitShort() statements will likely function as you expect in a real-time environment with CalculateOnBarClose == false. Orders are then submitted as soon as conditions evaluate to true.
          Ryan M.NinjaTrader Customer Service

          Comment


            #6
            Yes, I understand. I tried Math.Max(stopLoss, 1) as well, but I get the same results.
            I did also adjust the code so that stopLoss offset is calculated immediately in OnBarUpdate(). Any other suggestions?


            Code:
            #region 1 Tick SL-strategy
                            // Calculate stopLoss in ticks.        
            
                            // Calculate StopLoss before position                                    
                            if (Position.MarketPosition == MarketPosition.Flat)
                            {
                                stopLoss = (High[0]-Low[0])/TickSize +1;
                            }
                            
                            
                            // Set SL 1 tick below highest low since entry
                            if (Position.MarketPosition == MarketPosition.Long)
                            {
                                    stopLoss = [COLOR=Red]Math.Max((Position.AvgPrice - MAX(Low, BarsSinceEntry() +1 )[0])/ TickSize + 1, 1);[/COLOR]
                            }
                            // Set SL 1 tick above lowest high since entry
                            else if (Position.MarketPosition == MarketPosition.Short)
                            {
                                    stopLoss = [COLOR=Red]Math.Max((MIN(High, BarsSinceEntry() +1 )[0] - Position.AvgPrice)/ TickSize + 1, 1);[/COLOR]
                            }
                            
                            
                            Print("");
                            Print(Time[0]);
                            Print("Position.AvgPrice: " + Position.AvgPrice);
                            Print("MIN(High, BarsSinceEntry() +1 )[0]: " + MIN(High, BarsSinceEntry() +1 )[0]);
                            Print("MAX(Low, BarsSinceEntry() +1 )[0]: " + MAX(Low, BarsSinceEntry() +1 )[0]);
                            Print("stopLoss: " + stopLoss);
                            Print("");
                                            
                        #endregion

            Same result as before:
            Code:
            008-06-11 21:20:00
            Position.AvgPrice: 1329,5
            MIN(High, BarsSinceEntry() +1 )[0]: 1330
            MAX(Low, BarsSinceEntry() +1 )[0]: 1326,5
            stopLoss: 3
            Math.Max(stopLoss, 1): 3
            
            
            2008-06-11 21:25:00
            Position.AvgPrice: [COLOR=Red]1329,5[/COLOR]
            MIN(High, BarsSinceEntry() +1 )[0]: 1328
            MAX(Low, BarsSinceEntry() +1 )[0]: 1326,5
            stopLoss: -5
            Math.Max(stopLoss, 1): [COLOR=Red]1[/COLOR]
            
            
            2008-06-11 21:30:00
            Position.AvgPrice: [COLOR=Red]1329,5[/COLOR]
            MIN(High, BarsSinceEntry() +1 )[0]: 1328
            MAX(Low, BarsSinceEntry() +1 )[0]: 1326,5
            stopLoss: -5
            Math.Max(stopLoss, 1): [COLOR=Red]1[/COLOR]
            
            
            2008-06-11 21:35:00
            Position.AvgPrice: [COLOR=Red]1329,5[/COLOR]
            MIN(High, BarsSinceEntry() +1 )[0]: 1328
            MAX(Low, BarsSinceEntry() +1 )[0]: 1327,25
            stopLoss: -5
            Math.Max(stopLoss, 1): [COLOR=Red]1[/COLOR]
            
            
            2008-06-11 21:40:00
            Position.AvgPrice: 1329,5
            MIN(High, BarsSinceEntry() +1 )[0]: 1328
            MAX(Low, BarsSinceEntry() +1 )[0]: 1327,25
            stopLoss: -5
            Math.Max(stopLoss, 1): 1
            
            
            2008-06-11 21:45:00
            Position.AvgPrice: 1329,5
            MIN(High, BarsSinceEntry() +1 )[0]: 1327
            MAX(Low, BarsSinceEntry() +1 )[0]: 1327,25
            stopLoss: -9
            Math.Max(stopLoss, 1): 1
            
            
            2008-06-11 21:50:00
            Position.AvgPrice: 1329,5
            MIN(High, BarsSinceEntry() +1 )[0]: 1325,25
            MAX(Low, BarsSinceEntry() +1 )[0]: 1327,25
            stopLoss: -16
            Math.Max(stopLoss, 1): 1
            
            
            2008-06-11 21:55:00
            Position.AvgPrice: 1329,5
            MIN(High, BarsSinceEntry() +1 )[0]: 1324,25
            MAX(Low, BarsSinceEntry() +1 )[0]: 1327,25
            stopLoss: -20
            Math.Max(stopLoss, 1): 1

            Comment


              #7
              What results are you seeing with this? It should submit a stop loss at 1 tick anytime the calculated value is below 1.
              Ryan M.NinjaTrader Customer Service

              Comment


                #8
                Hi again,

                I have adjusted the code as highlited in blue in the code example below according to your suggestion. But I don't get the expected result. The SetStopLoss() still doesn't trigger any exitorder when stopLoss = 1 as you can see from the attached image and the print output below. I have also attched the strategy.I would rellay appreciate if this idea would work so that I can get rid of my extra "JumpStop".

                /Regards


                Code:
                namespace NinjaTrader.Strategy
                {
                    /// <summary>
                    /// Simple moving average cross over strategy.
                    /// </summary>
                    [Description("Simple moving average cross over strategy.")]
                    public class SL_Example_MACrossOver : Strategy
                    {
                        #region Variables
                        private int        fast    = 10;
                        private int        slow    = 25;
                        
                        private double    stopLoss;    // StoppLoss offset in SetStopLoss()
                        
                        private IOrder long1         = null; // This variable holds an object representing our entry order
                        private IOrder short1         = null; // This variable holds an object representing our entry order
                        #endregion
                
                        /// <summary>
                        /// This method is used to configure the strategy and is called once before any strategy method is called.
                        /// </summary>
                        protected override void Initialize()
                        {
                            SMA(Fast).Plots[0].Pen.Color = Color.Orange;
                            SMA(Slow).Plots[0].Pen.Color = Color.Green;
                
                            Add(SMA(Fast));
                            Add(SMA(Slow));
                
                            // Entry handling
                            EntriesPerDirection = 1;
                               EntryHandling         = EntryHandling.UniqueEntries;
                            CalculateOnBarClose    = true;
                        }
                
                        /// <summary>
                        /// Called on each bar update event (incoming tick).
                        /// </summary>
                        protected override void OnBarUpdate()
                        {    if(Position.MarketPosition == MarketPosition.Flat)
                            {
                                if (CrossAbove(SMA(Fast), SMA(Slow), 1))
                                {
                                    long1 = EnterLong("Long");
                                }
                                else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
                                {
                                    short1 = EnterShort("Short");
                                }
                            }
                                
                            #region 1 Tick SL-strategy
                                // Calculate stopLoss in ticks.        
                
                                // Calculate StopLoss before position                                    
                                if (Position.MarketPosition == MarketPosition.Flat)
                                {
                                    stopLoss = (High[0]-Low[0])/TickSize +1;
                                }
                                
                                
                                // Set SL 1 tick below highest low since entry
                                if (Position.MarketPosition == MarketPosition.Long)
                                {
                                        stopLoss = (Position.AvgPrice - MAX(Low, BarsSinceEntry() +1 )[0])/ TickSize + 1;
                                }
                                // Set SL 1 tick above lowest high since entry
                                else if (Position.MarketPosition == MarketPosition.Short)
                                {
                                        stopLoss = (MIN(High, BarsSinceEntry() +1 )[0] - Position.AvgPrice)/ TickSize + 1;
                                }
                                
                [COLOR=Blue][B]                // Ensure that stopLoss always is equal or greater than 1
                                [/B]stopLoss = Math.Max(stopLoss, 1);[/COLOR]
                            
                                
                                //Trouble Shooting
                                Print("");
                                Print(Time[0]);
                                Print("stopLoss: " + stopLoss);
                                Print("Position.MarketPosition: " + Position.MarketPosition);
                                Print("");
                                
                            #endregion    
                
                        }
                        
                    
                    
                        #region OnExecution    
                        protected override void OnExecution(IExecution execution)
                        {        
                            if (long1 != null && long1.Token == execution.Order.Token)
                            {
                                if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
                                {
                                    SetStopLoss("Long", CalculationMode.Ticks, stopLoss, false);
                                                                            
                                    // Resets the entryOrder object to null after the order has been partially filled
                                    if (execution.Order.OrderState != OrderState.PartFilled)
                                    {
                                        long1    = null;
                                    }
                                }
                            }
                            if (short1 != null && short1.Token == execution.Order.Token)
                            {
                                if (execution.Order.OrderState == OrderState.Filled || execution.Order.OrderState == OrderState.PartFilled || (execution.Order.OrderState == OrderState.Cancelled && execution.Order.Filled > 0))
                                {
                                    SetStopLoss("Short", CalculationMode.Ticks, stopLoss, false);
                                                                            
                                    // Resets the entryOrder object to null after the order has been partially filled
                                    if (execution.Order.OrderState != OrderState.PartFilled)
                                    {
                                        short1    = null;
                                    }
                                }
                            }
                        }
                        #endregion
                        
                        
                        #region Properties
                        /// <summary>
                        /// </summary>
                        [Description("Period for fast MA")]
                        [GridCategory("Parameters")]
                        public int Fast
                        {
                            get { return fast; }
                            set { fast = Math.Max(1, value); }
                        }
                
                        /// <summary>
                        /// </summary>
                        [Description("Period for slow MA")]
                        [GridCategory("Parameters")]
                        public int Slow
                        {
                            get { return slow; }
                            set { slow = Math.Max(1, value); }
                        }
                        #endregion
                    }
                }
                Output from the print statment in the code above:
                Code:
                2009-06-22 16:30:00
                stopLoss: 3
                Position.MarketPosition: Short
                
                
                2009-06-22 16:31:00
                stopLoss: 2
                Position.MarketPosition: Short
                
                
                2009-06-22 16:32:00
                stopLoss: [COLOR=Red]1[/COLOR]
                Position.MarketPosition: [COLOR=Red]Short[/COLOR]
                
                
                2009-06-22 16:33:00
                stopLoss: [COLOR=Red]1[/COLOR]
                Position.MarketPosition: [COLOR=Red]Short[/COLOR]
                
                
                2009-06-22 16:34:00
                stopLoss: [COLOR=Red]1[/COLOR]
                Position.MarketPosition: [COLOR=Red]Short[/COLOR]
                Attached Files

                Comment


                  #9
                  poseidon_sthlm,

                  The SetStopLoss() still doesn't trigger any exitorder when stopLoss = 1
                  Let's clarify what it is you expect this to do. What do you mean by any exitorder? The statement will submit a stop loss order at 1 tick whenever your calculated value stoploss is below 1. Is it doing this?
                  Ryan M.NinjaTrader Customer Service

                  Comment


                    #10
                    Sorry for the confusion. The obvious solution is to modify the Stop Loss with a seccond SetStopLoss() statment in OnBarUpdate() (besides the one in OnExecution() ). Everything now works as expected.

                    //Regards

                    Comment


                      #11
                      Thanks for sharing your solution, poseidon. Glad you got it sorted.
                      Ryan M.NinjaTrader Customer Service

                      Comment

                      Latest Posts

                      Collapse

                      Topics Statistics Last Post
                      Started by Geovanny Suaza, 02-11-2026, 06:32 PM
                      0 responses
                      648 views
                      0 likes
                      Last Post Geovanny Suaza  
                      Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                      0 responses
                      369 views
                      1 like
                      Last Post Geovanny Suaza  
                      Started by Mindset, 02-09-2026, 11:44 AM
                      0 responses
                      108 views
                      0 likes
                      Last Post Mindset
                      by Mindset
                       
                      Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                      0 responses
                      572 views
                      1 like
                      Last Post Geovanny Suaza  
                      Started by RFrosty, 01-28-2026, 06:49 PM
                      0 responses
                      573 views
                      1 like
                      Last Post RFrosty
                      by RFrosty
                       
                      Working...
                      X