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

trialing in strategy doesn't work

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

    trialing in strategy doesn't work

    Hello,

    I'm in the process of developing a strategy and am considering implementing trailing rather than sticking to a fixed profit target and stop-loss. My current setup isn't performing as expected. Here's the issue:

    I aim to create a trailing mechanism that, upon entry, sets a stop-loss at 50 ticks. As the market moves favorably, I want the mechanism to track the market movement tick by tick, maintaining a 10-tick distance. I attempted to utilize the setrtrailstop method, but it hasn't achieved the desired results. Can anyone identify a mistake in my approach or offer any advice on how to improve it?​

    protected override void OnStateChange()
    {
    if (State == State.SetDefaults)
    {
    Description = @"Enter the description for your new custom Strategy here.";
    Name = "MyCustomStrategy";
    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 = true;
    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;


    }
    else if (State == State.Configure)
    {
    // Add Bollinger Bands and Stochastics indicators
    bollinger = Bollinger(2, 20);
    stochastics = Stochastics(3, 14, 1);
    }
    else if (State == State.DataLoaded)
    {
    // Add your custom indicator calls here
    AddChartIndicator(bollinger);
    AddChartIndicator(stochastics);
    }
    }

    protected override void OnBarUpdate()
    {
    //Ensure we have enough bars for the Bollinger Bands calculation
    if (CurrentBar < 20) return;

    CheckEntryConditions();
    TrailingStrategy();
    }


    private void CheckEntryConditions()
    {

    // Check to ensure we're not already in a position
    if (Position.MarketPosition == MarketPosition.Flat)
    {
    if ("entry condition long")
    {
    EnterLong("LongEntry");
    CurrentTriggerPriceLong = Close[0] + (TrailFrequency * TickSize);
    CurrentStopPriceLong = Close[0] - (TrailStopDistance * TickSize);

    double initialStopLossPrice = Close[0] - (50 * TickSize); // 50 ticks above the entry price
    SetStopLoss("longEntry", CalculationMode.Price, initialStopLossPrice, false);

    Draw.ArrowUp(this, "buySignal" + CurrentBar, false, 0, Low[0] - TickSize * 5, Brushes.Green);
    }
    else if ("entry condition short")
    {
    // Enter short position
    EnterShort("ShortEntry");
    CurrentTriggerPriceShort = Close[0] - (TrailFrequency * TickSize);
    CurrentStopPriceShort = Close[0] + (TrailStopDistance * TickSize);

    double initialStopLossPrice = Close[0] + (50 * TickSize);
    SetStopLoss("shortEntry", CalculationMode.Price, initialStopLossPrice, false);

    // Draw an arrow down for a sell signal
    Draw.ArrowDown(this, "sellSignal" + CurrentBar, false, 0, High[0] + TickSize * 5, Brushes.Red);
    }

    }
    }

    private void TrailingStrategy()
    {
    if (Position.MarketPosition == MarketPosition.Long)
    {
    // For a long position, update the trailing stop only if the price has moved favorably.
    if (Close[0] > CurrentTriggerPriceLong)
    {
    CurrentTriggerPriceLong = Close[0] + (TrailFrequency * TickSize);
    CurrentStopPriceLong = Close[0] - (TrailStopDistance * TickSize);

    ExitLongStopMarket(0, true, Position.Quantity, CurrentStopPriceLong, "LongExit", "LongEntry");
    }
    }
    else if (Position.MarketPosition == MarketPosition.Short)
    {
    // For a short position, update the trailing stop only if the price has moved favorably.
    if (Close[0] < CurrentTriggerPriceShort)
    {
    CurrentTriggerPriceShort = Close[0] - (TrailFrequency * TickSize);
    CurrentStopPriceShort = Close[0] + (TrailStopDistance * TickSize);

    ExitShortStopMarket(0, true, Position.Quantity, CurrentStopPriceShort, "ShortExit", "ShortEntry");
    }
    }
    }​

    this is what currently happens and it should hit the stopp loss instead of keeping the position open until the end of the day.

    #2
    Hello trimpy,

    Thanks for your post.

    I see you are using Set methods and Exit methods in your script and this goes against the Managed Approach Internal Order Handling Rules.\

    Managed Approach Internal Order Handling Rules: https://ninjatrader.com/support/help...antedPositions

    The strategy must be modified to use only Set methods or only Exit methods. You will likely want to use Exit methods to accomplish your goal of implementing that specific trailing logic.

    ​Educational examples of breakeven and trailing stop in a NinjaScript strategy could be found here:
    https://ninjatrader.com/support/foru...der#post806596

    When a strategy is not behaving as expected it is necessary to add debugging prints to the strategy to understand exactly how the logic is behaving.

    In the strategy add prints (outside of any conditions) that print the values of every variable used in every condition that places or changes an order along with the time of that bar.

    Prints will appear in the NinjaScript Output window (New > NinjaScript Output window).

    Below is a link to a forum post that demonstrates how to use prints to understand behavior.




    Last edited by NinjaTrader_BrandonH; 03-17-2024, 03:20 PM.
    Brandon H.NinjaTrader Customer Service

    Comment


      #3
      Hi NinjaTrader_BrandonH,

      First of all thank you for your response and the help you provided. I have used the principles of the Managed Approach by only using exit methods, which works for my case. Yet, I still have one more issue.

      When I enter a short position I would like the trailing to be activated starting from a 20 tick profit. For some reason it works for the long because it hits the stop loss before the trailing starts at a 20 tick profit. For the short as you can see in the attachment the stoploss is never hit even though I have set an exit short stop market at 50 ticks. Do you have any suggestions as to why it doesn’t work the same as it does for the long?

      I also added the print as well.

      public class MyCustomStrategy : Strategy
      {
      region Variables
      private Bollinger bollinger;
      private Stochastics stochastics;
      private double bfMinPct = 0;
      private double bfMaxPct = 100.0;

      // Your existing variables and indicators...
      private double CurrentTriggerPriceLong;
      private double CurrentTriggerPriceShort;
      private double CurrentStopPriceLong;
      private double CurrentStopPriceShort;
      private int TrailFrequency = 5; // Number of ticks the price must move to update the trail
      private int TrailStopDistance = 10; // Trailing stop distance in ticks

      private double EntryPriceLong = 0;
      private double EntryPriceShort = 0;
      #endregion
      protected override void OnStateChange()
      {
      if (State == State.SetDefaults)
      {
      Description = @"Enter the description for your new custom Strategy here.";
      Name = "MyCustomStrategy";
      Calculate = Calculate.OnEachTick;
      EntryHandling = EntryHandling.AllEntries;
      IsExitOnSessionCloseStrategy = true;
      ExitOnSessionCloseSeconds = 30;
      IsFillLimitOnTouch = false;
      MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix;
      OrderFillResolution = OrderFillResolution.Standard;
      Slippage = 0;
      StartBehavior = StartBehavior.WaitUntilFlat;
      TimeInForce = TimeInForce.Gtc;
      TraceOrders = true;
      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;


      }
      else if (State == State.Configure)
      {
      // Add Bollinger Bands and Stochastics indicators
      Indicator 1;
      Indicator 2;
      }
      else if (State == State.DataLoaded)
      {
      // Add your custom indicator calls here
      AddChartIndicator(bollinger);
      AddChartIndicator(stochastics);
      }
      }

      protected override void OnBarUpdate()
      {
      if (CurrentBar < 20) return; // Ensure enough data

      if (Position.MarketPosition == MarketPosition.Flat)
      {
      CheckEntryConditions();
      }

      if (Position.MarketPosition == MarketPosition.Long)
      {
      ManageLongPosition();
      }

      if (Position.MarketPosition == MarketPosition.Short)
      {
      ManageShortPosition();
      }
      }



      private void CheckEntryConditions()
      {
      // Check to ensure we're not already in a position
      if (Position.MarketPosition == MarketPosition.Flat)
      {
      if ("condition 1")
      {
      EnterLong(quantity: 1, signalName: "LongEntry");
      EntryPriceLong = Close[0]; // Record the entry price
      CurrentStopPriceLong = EntryPriceLong - (50 * TickSize); // Set an initial stop loss 50 ticks below entry
      ExitLongStopMarket(Position.Quantity, CurrentStopPriceLong, "InitialStopLong", "LongEntry");

      Draw.ArrowUp(this, "buySignal" + CurrentBar, false, 0, Low[0] - TickSize * 5, Brushes.Green);
      }
      else if ("condition 2")
      {
      EnterShort(quantity: 1, signalName: "ShortEntry");
      EntryPriceShort = Close[0]; // Record the entry price
      CurrentStopPriceShort = EntryPriceShort + (50 * TickSize); // Set an initial stop loss 50 ticks above entry
      ExitShortStopMarket(Position.Quantity, CurrentStopPriceShort, "InitialStopShort", "ShortEntry");

      // Draw an arrow down for a sell signal
      Draw.ArrowDown(this, "sellSignal" + CurrentBar, false, 0, High[0] + TickSize * 5, Brushes.Red);
      }

      }
      }

      private void ManageLongPosition()
      {
      // Start trailing if we're at least 20 ticks in profit
      if (Close[0] - EntryPriceLong >= 20 * TickSize)
      {
      double trailStopPrice = Close[0] - (TrailStopDistance * TickSize);

      if (trailStopPrice > CurrentStopPriceLong)
      {
      CurrentStopPriceLong = trailStopPrice;
      ExitLongStopMarket(Position.Quantity, CurrentStopPriceLong, "TrailingStopLong", "LongEntry");
      }
      }
      }


      private void ManageShortPosition()
      {
      double price20TicksBelowEntry = EntryPriceShort - (20 * TickSize);
      // Check if we're at least 20 ticks in profit
      if (Close[0] <= price20TicksBelowEntry)
      {
      // Define the trailing stop price as 10 ticks above the current price
      double trailStopPrice = Close[0] + (TrailStopDistance * TickSize);

      // Only adjust the trailing stop if it is more favorable than the current stop price
      if (trailStopPrice < CurrentStopPriceShort)
      {
      CurrentStopPriceShort = trailStopPrice;
      ExitShortStopMarket(Position.Quantity, CurrentStopPriceShort, "TrailingStopShort", "ShortEntry");
      }
      }


      Print($"EntryPrice: {EntryPriceShort} && Price 20 below: {price20TicksBelowEntry} && Close: {Close[0]}");
      }

      }


      The print:
      3/1/2024 7:00:00 PM Strategy 'MyCustomStrategy/320686696': Entered internal SubmitOrderManaged() method at 3/1/2024 7:00:00 PM: BarsInProgress=0 Action=SellShort OrderType=Market Quantity=1 LimitPrice=0 StopPrice=0 SignalName='ShortEntry' FromEntrySignal=''
      3/1/2024 7:00:00 PM Strategy 'MyCustomStrategy/320686696': Entered internal SubmitOrderManaged() method at 3/1/2024 7:00:00 PM: BarsInProgress=0 Action=BuyToCover OrderType=StopMarket Quantity=0 LimitPrice=0 StopPrice=18298.50 SignalName='InitialStopShort' FromEntrySignal='ShortEntry'
      3/1/2024 7:00:00 PM Strategy 'MyCustomStrategy/320686696': Ignored SubmitOrderManaged() method at 3/1/2024 7:00:00 PM: BarsInProgress=0 Action=BuyToCover OrderType=StopMarket Quantity=0 LimitPrice=0 StopPrice=18298.50 SignalName='InitialStopShort' FromEntrySignal='ShortEntry' Reason='This was an exit order but no position exists to exit'
      EntryPrice: 18286 && Price 20 below: 18281 && Close: 18291.5

      Last edited by trimpy; 03-19-2024, 10:28 AM.

      Comment


        #4
        I forgot the attachment.
        Attached Files

        Comment


          #5
          Hello trimpy,

          Thanks for your notes.

          In the "private void CheckEntryConditions()" section of code you shared, I see that you are calling the Exit methods at the same time that the Enter methods are being called which could lead to issues.

          You should create a separate condition in your script that checks if you are in a Long or Short position using Position.MarketPosition and then call your Exit order methods within that condition.

          Position.MarketPosition: https://ninjatrader.com/support/help...etposition.htm

          It seems you are also using different signal names for the Exit methods in your script. You should make sure that you are passing in the same signal name when calling the Exit method again to move the stop.

          I recommend studying the TrailLongShortBuilder reference sample linked on the forum thread below to see how to implement a trailing stop for long and short positions.



          To understand exactly how your trailing logic for the short position is functioning compared to the trailing logic for the long position, you would need to further debug your script using prints. It is necessary to add prints to the script that print the values used for the logic of the script to understand how the script is evaluating.

          Add prints to the script that print out all the values being used for your trailing logic along with labels and operator comparisons being used to see exactly how those values are evaluating when the strategy is run to see if the conditions to trail the stop are becoming true or not.

          Below is a link to a forum post that demonstrates how to use prints to understand behavior.

          Last edited by NinjaTrader_BrandonH; 03-19-2024, 11:09 AM.
          Brandon H.NinjaTrader Customer Service

          Comment


            #6
            Hey NinjaTrader_BrandonH

            Thanks for the reply.

            I have looked at the TrailLongShortExample and used a similar approach for the trailing. The trailing itself works like it should be working when the market moves in a favorable way, based on the position we enter. Yet I still get the issue that when, lets say we enter a Long position and the market goes short it never exits its position or hits a stoploss. I have tried many different ways to put a stoploss for each entry position but it won't work. Do you have any suggestions based on the code below? I have also added the necessary prints with the values and timeframes based on the image in attachement.

            Kind regards

            2024-03-07 01:30:00 - FLIP DIRECTION TO LONG. Entry Price: 18245
            2024-03-07 10:15:00 - UPDATE LONG POSITION. Trigger Price: 18257, Stop Price: 18254
            2024-03-07 10:15:00 - EXITING LONG POSITION. Progress state reset to 1.
            2024-03-07 16:50:00 - FLIP DIRECTION TO SHORT. Entry Price: 18519.75
            2024-03-07 16:55:00 - UPDATE SHORT POSITION. Trigger Price: 18489.75, Stop Price: 18492.75
            2024-03-07 16:55:00 - EXITING SHORT POSITION. Progress state reset to 1.



            public class StochAndBBStrategy : Strategy
            {
            region Variables
            private Bollinger bollinger;
            private Stochastics stochastics;
            private double bfMinPct = 0;
            private double bfMaxPct = 100.0;

            // Your existing variables and indicators...
            private double CurrentTriggerPrice;
            private double CurrentStopPrice;
            private bool FlipDirection;
            private int ProgressState = 0;

            private double EntryPriceLong = 0;
            private double EntryPriceShort = 0;
            #endregion

            protected override void OnStateChange()
            {
            if (State == State.SetDefaults)
            {
            Description = @"Enter the description for your new custom Strategy here.";
            Name = "StochAndBBStrategy";
            Calculate = Calculate.OnBarClose;
            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;
            TrailFrequency = 2; // Adjusted for example
            TrailStopDistance = 10; // Adjusted for example
            CurrentTriggerPrice = 0;
            CurrentStopPrice = 0;
            FlipDirection = false;
            }
            else if (State == State.Configure)
            {
            // Add Bollinger Bands and Stochastics indicators
            bollinger = Bollinger(2, 20);
            stochastics = Stochastics(3, 14, 1);
            }
            else if (State == State.DataLoaded)
            {
            // Add your custom indicator calls here
            AddChartIndicator(bollinger);
            AddChartIndicator(stochastics);
            }
            }

            protected override void OnBarUpdate()
            {
            if (CurrentBar < 20) return; // Ensure enough data

            if (Position.MarketPosition == MarketPosition.Flat)
            {
            CheckEntryConditions();
            }

            if (Position.MarketPosition == MarketPosition.Long)
            {
            ManageLongPosition();
            }

            if (Position.MarketPosition == MarketPosition.Short)
            {
            ManageShortPosition();
            }
            }



            private void CheckEntryConditions()
            {
            //Ensure we have enough bars for the Bollinger Bands calculation
            if (CurrentBar < 20) return;



            // Check to ensure we're not already in a position
            if (Position.MarketPosition == MarketPosition.Flat)
            {
            if (longEntryCondition && (!FlipDirection || FirstTrade()))

            {
            EnterLong(quantity: 1, signalName: "LongEntry");
            EntryPriceLong = Close[0]; // Record the entry price
            FlipDirection = true; // Set to flip direction after a long entry

            Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - FLIP DIRECTION TO LONG. Entry Price: " + EntryPriceLong);

            Draw.ArrowUp(this, "buySignal" + CurrentBar, false, 0, Low[0] - TickSize * 5, Brushes.Green);
            }
            else if (shortEntryCondition && (FlipDirection || FirstTrade()))
            {
            EnterShort(quantity: 1, signalName: "ShortEntry");
            EntryPriceShort = Close[0]; // Record the entry price
            FlipDirection = false; // Set to flip direction after a short entry

            Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - FLIP DIRECTION TO SHORT. Entry Price: " + EntryPriceShort);

            // Draw an arrow down for a sell signal
            Draw.ArrowDown(this, "sellSignal" + CurrentBar, false, 0, High[0] + TickSize * 5, Brushes.Red);
            }

            }
            }

            private void ManageLongPosition()
            {
            if (Close[0] - EntryPriceLong >= TrailFrequency * TickSize && ProgressState < 3)
            {
            CurrentTriggerPrice = Close[0] + (TrailFrequency * TickSize);
            CurrentStopPrice = Close[0] - (TrailStopDistance * TickSize);
            ProgressState = 2; // Mark the position for trailing stop update

            Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - UPDATE LONG POSITION. Trigger Price: " + CurrentTriggerPrice + ", Stop Price: " + CurrentStopPrice);
            }

            if (ProgressState == 2)
            {
            ExitLong("TrailingStopLong", "LongEntry");
            ProgressState = 1; // Reset progress state after updating stop

            Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - EXITING LONG POSITION. Progress state reset to 1.");

            }
            }

            private void ManageShortPosition()
            {
            if (EntryPriceShort - Close[0] >= TrailFrequency * TickSize && ProgressState < 3)
            {
            CurrentTriggerPrice = Close[0] - (TrailFrequency * TickSize);
            CurrentStopPrice = Close[0] + (TrailStopDistance * TickSize);
            ProgressState = 2; // Mark the position for trailing stop update

            Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - UPDATE SHORT POSITION. Trigger Price: " + CurrentTriggerPrice + ", Stop Price: " + CurrentStopPrice);
            }

            if (ProgressState == 2)
            {
            ExitShort("TrailingStopShort", "ShortEntry");
            ProgressState = 1; // Reset progress state after updating stop

            Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - EXITING SHORT POSITION. Progress state reset to 1.");

            }
            }

            private bool FirstTrade()
            {
            // Implement logic to determine if this is the first trade.
            // This could be as simple as checking if both EntryPriceLong and EntryPriceShort are 0,
            // or based on other criteria suitable for your strategy.
            return EntryPriceLong == 0 && EntryPriceShort == 0;
            }


            region Properties
            [NinjaScriptProperty]
            [Range(1, int.MaxValue)]
            [Display(Name = "TrailFrequency", Description = "This will be how often trail action triggers.", Order = 1, GroupName = "Parameters")]
            public int TrailFrequency
            { get; set; }

            [NinjaScriptProperty]
            [Range(1, int.MaxValue)]
            [Display(Name = "TrailStopDistance", Description = "Distance stop for exit order will be placed. This needs to be less than the TrailLimitDistance to exit a long position.", Order = 2, GroupName = "Parameters")]
            public int TrailStopDistance
            { get; set; }
            #endregion
            }​

            Comment


              #7
              Hello trimpy,

              Thanks for your notes.

              In the code you shared I see you are calculating the CurrentTriggerPrice and CurrentStopPrice but nowhere in the code you share are you submitting an Exit method to act as a trailing stop.

              You should call ExitLongStopMarket() to submit a stop loss order for a long position that would trail based on the trailing logic in the script. You should also call ExitShortStopMarket() to submit a stop loss order for a short position that would trail based on the trailing logic in the script.

              The ExitLongStopMarket() method is called in Set 6 of the TrailLongShortBuilderExample script.

              The ExitShortStopMarket() method is called in Set 11 of the TrailLongShortBuilderExample script.

              Further, ExitLong() / ExitShort() when ProgressState == 2. Prints should be added one line above this condition that prints out the ProgressState variable along with the time of the bar to see how that condition is evaluating.

              If you do not see ExitLong() / ExitShort() being called when running your script then the ProgressState condition is likely not evaluating to true.

              More debugging prints should be added to the strategy to understand how each condition to place or trail an order is evaluating to understand how the script is behaving. Add prints one line above each condition that prints out all the values used in the condition along with the time of the bar. Make sure to include labels and comparison operators in the prints also so that you know what is being compared.

              Below is a link to a forum post that demonstrates how to use prints to understand behavior.

              Brandon H.NinjaTrader Customer Service

              Comment


                #8
                Hello NinjaTrader_BrandonH,

                Thanks for your reply.

                I am trimpy's friend and we are working on this together. I don't really think you understood the problem. The trailing does work when the market moves in a favorable way from the entry point as you can see on image 1. We enter a short position and the market goes short so it moves in the right direction and the trailing works perfectly fine. Yet for some reason whenever the market moves in the opposite way just like in image 2, you can see we enter a long position but the market goes short. For some reason at that point the code wont set the stoploss right. I have tried multiple ways to set that stoploss and you mentioned in one of the previous posts that i shouldn't add the initial stoploss when in a flat position in the market so i tried putting in the long or short market position, but it won't work.

                So essentially the problem lies when we enter a long and the market goes short OR when we enter a short and the market goes long. There is no issue when we enter a long and the market goes long because the trailing works perfectly fine then. I have added the enterlongstopmarket and shortstopmarket as you mentioned in the previous post.

                Thanks for your help.

                CODE:

                public class StochAndBBStrategy : Strategy
                {
                region Variables

                private double bfMinPct = 0;
                private double bfMaxPct = 100.0;

                // Your existing variables and indicators...
                private double CurrentTriggerPrice;
                private double CurrentStopPrice;
                private bool FlipDirection;
                private int ProgressState = 0;

                private double EntryPriceLong = 0;
                private double EntryPriceShort = 0;
                #endregion

                protected override void OnStateChange()
                {
                if (State == State.SetDefaults)
                {
                Description = @"Enter the description for your new custom Strategy here.";
                Name = "StochAndBBStrategy";
                Calculate = Calculate.OnBarClose;
                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;
                TrailFrequency = 2; // Adjusted for example
                TrailStopDistance = 10; // Adjusted for example
                CurrentTriggerPrice = 0;
                CurrentStopPrice = 0;
                FlipDirection = false;
                }
                else if (State == State.Configure)
                {
                // Add Bollinger Bands and Stochastics indicators
                }
                else if (State == State.DataLoaded)
                {
                // Add your custom indicator calls here
                }
                }

                protected override void OnBarUpdate()
                {
                if (CurrentBar < 20) return; // Ensure enough data

                if (Position.MarketPosition == MarketPosition.Flat)
                {
                CheckEntryConditions();
                }

                if (Position.MarketPosition == MarketPosition.Long)
                {
                ManageLongPosition();
                }

                if (Position.MarketPosition == MarketPosition.Short)
                {
                ManageShortPosition();
                }
                }



                private void CheckEntryConditions()
                {
                //Ensure we have enough bars for the Bollinger Bands calculation
                if (CurrentBar < 20) return;



                // Check to ensure we're not already in a position
                if (Position.MarketPosition == MarketPosition.Flat)
                {
                if (longEntryCondition && (!FlipDirection || FirstTrade()))

                {
                EnterLong(quantity: 1, signalName: "LongEntry");
                EntryPriceLong = Close[0]; // Record the entry price
                FlipDirection = true; // Set to flip direction after a long entry

                Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - FLIP DIRECTION TO LONG. Entry Price: " + EntryPriceLong);

                Draw.ArrowUp(this, "buySignal" + CurrentBar, false, 0, Low[0] - TickSize * 5, Brushes.Green);
                }
                else if (shortEntryCondition && (FlipDirection || FirstTrade()))
                {
                EnterShort(quantity: 1, signalName: "ShortEntry");
                EntryPriceShort = Close[0]; // Record the entry price
                FlipDirection = false; // Set to flip direction after a short entry

                Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - FLIP DIRECTION TO SHORT. Entry Price: " + EntryPriceShort);

                // Draw an arrow down for a sell signal
                Draw.ArrowDown(this, "sellSignal" + CurrentBar, false, 0, High[0] + TickSize * 5, Brushes.Red);
                }

                }
                }

                private void ManageLongPosition()
                {
                if (Close[0] - EntryPriceLong >= TrailFrequency * TickSize && ProgressState < 3)
                {
                CurrentTriggerPrice = Close[0] + (TrailFrequency * TickSize);
                CurrentStopPrice = Close[0] - (TrailStopDistance * TickSize);
                ProgressState = 2; // Mark the position for trailing stop update

                Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - UPDATE LONG POSITION. Trigger Price: " + CurrentTriggerPrice + ", Stop Price: " + CurrentStopPrice);
                }

                if (ProgressState == 2)
                {
                // Place a new trailing stop order
                ExitLongStopMarket(0, true, DefaultQuantity, CurrentStopPrice, "TrailingStopLong", "LongEntry");

                // Optionally, adjust ProgressState to indicate the trailing stop has been updated
                ProgressState = 1; // Reset progress state after updating stop

                Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - UPDATED LONG TRAILING STOP. New Stop Price: " + CurrentStopPrice + ". Progress state reset to 1.");
                }
                }

                private void ManageShortPosition()
                {
                if (EntryPriceShort - Close[0] >= TrailFrequency * TickSize && ProgressState < 3)
                {
                CurrentTriggerPrice = Close[0] - (TrailFrequency * TickSize);
                CurrentStopPrice = Close[0] + (TrailStopDistance * TickSize);
                ProgressState = 2; // Mark the position for trailing stop update

                Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - UPDATE SHORT POSITION. Trigger Price: " + CurrentTriggerPrice + ", Stop Price: " + CurrentStopPrice);
                }

                if (ProgressState == 2)
                {

                // Place a new trailing stop order for the short position
                ExitShortStopMarket(0, true, DefaultQuantity, CurrentStopPrice, "TrailingStopShort", "ShortEntry");

                // Optionally, adjust ProgressState to indicate the trailing stop has been updated
                ProgressState = 1; // Reset progress state after updating stop

                Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - UPDATED SHORT TRAILING STOP. New Stop Price: " + CurrentStopPrice + ". Progress state reset to 1.");
                }
                }

                private bool FirstTrade()
                {
                // Implement logic to determine if this is the first trade.
                // This could be as simple as checking if both EntryPriceLong and EntryPriceShort are 0,
                // or based on other criteria suitable for your strategy.
                return EntryPriceLong == 0 && EntryPriceShort == 0;
                }


                region Properties
                [NinjaScriptProperty]
                [Range(1, int.MaxValue)]
                [Display(Name = "TrailFrequency", Description = "This will be how often trail action triggers.", Order = 1, GroupName = "Parameters")]
                public int TrailFrequency
                { get; set; }

                [NinjaScriptProperty]
                [Range(1, int.MaxValue)]
                [Display(Name = "TrailStopDistance", Description = "Distance stop for exit order will be placed. This needs to be less than the TrailLimitDistance to exit a long position.", Order = 2, GroupName = "Parameters")]
                public int TrailStopDistance
                { get; set; }
                #endregion
                }​



                PRINTS of when the issue happens in image 2:

                2024-03-07 01:30:00 - FLIP DIRECTION TO LONG. Entry Price: 18245
                2024-03-07 10:15:00 - UPDATE LONG POSITION. Trigger Price: 18257, Stop Price: 18254
                2024-03-07 10:15:00 - UPDATED LONG TRAILING STOP. New Stop Price: 18254. Progress state reset to 1.
                2024-03-07 10:20:00 - UPDATE LONG POSITION. Trigger Price: 18274, Stop Price: 18271
                2024-03-07 10:20:00 - UPDATED LONG TRAILING STOP. New Stop Price: 18271. Progress state reset to 1.
                2024-03-07 10:25:00 - UPDATE LONG POSITION. Trigger Price: 18293.5, Stop Price: 18290.5
                2024-03-07 10:25:00 - UPDATED LONG TRAILING STOP. New Stop Price: 18290.5. Progress state reset to 1.
                2024-03-07 10:30:00 - UPDATE LONG POSITION. Trigger Price: 18315, Stop Price: 18312
                2024-03-07 10:30:00 - UPDATED LONG TRAILING STOP. New Stop Price: 18312. Progress state reset to 1.
                2024-03-07 16:50:00 - FLIP DIRECTION TO SHORT. Entry Price: 18519.75
                2024-03-07 16:55:00 - UPDATE SHORT POSITION. Trigger Price: 18489.75, Stop Price: 18492.75
                2024-03-07 16:55:00 - UPDATED SHORT TRAILING STOP. New Stop Price: 18492.75. Progress state reset to 1.​




                Attached Files

                Comment


                  #9
                  Hello Salahinh099,

                  Thanks for your notes.

                  The trailing stop as seen in the TrailLongShortBuilder reference sample trails when the market moves in your favor, it does not move when the market is moving against you.

                  See the demonstration video below showing that the TrailLongShortBuilder reference sample only trails the stop when the market moves in your favor. The stop does not trail when the market moves against you, such as entering a long position and the market price moving below the entry price. The stop does trail when the market moves in your favor, such as entering a long position and the market price moving above the entry price.

                  Demonstration video: https://brandonh-ninjatrader.tinytak...NF8yMzAwMzEwNg

                  If you want the stop to move when the logic is moving against you, custom logic would need to be added to the script to accomplish that.

                  To understand exactly how the strategy logic is behaving when running the script, futher debugging prints need to be added to the strategy.

                  In the strategy, add prints (outside of all conditions) in the script that prints out all the values being used in those conditions to see how they are evaluating. This will allow you to see how the values of the conditions are evaluating and if they are becoming true or not. Also, print out the Close[0] price to see how that is evaluating in comparison to the price you are submitting the Exit order to.

                  For example, a print would look something like this:

                  Print("Time[0]: + Time[0] + " EntryPriceShort: " + EntryPriceShort + " - Close[0]: " + Close[0] + " >= TrailFrquency * TickSize: " + TrailFrquency * TickSize + " ProgressState < 3: " + ProgressState);
                  if (EntryPriceShort - Close[0] >= TrailFrequency * TickSize && ProgressState < 3)
                  {
                  CurrentTriggerPrice = Close[0] - (TrailFrequency * TickSize);
                  CurrentStopPrice = Close[0] + (TrailStopDistance * TickSize);
                  ProgressState = 2; // Mark the position for trailing stop update

                  Print(Time[0].ToString("yyyy-MM-dd HH:mm:ss") + " - UPDATE SHORT POSITION. Trigger Price: " + CurrentTriggerPrice + ", Stop Price: " + CurrentStopPrice + " ProgressState: " + ProgressState);
                  }


                  ​Note how all the values used in the condition are printed outside the condition along with labels and comparison operators to how those values are calculating and if the condition is evaluating as true.

                  Here is a forum thread detailing how to debug a strategy's logic using prints: https://ninjatrader.com/support/foru...121#post791121
                  Brandon H.NinjaTrader Customer Service

                  Comment


                    #10
                    Hey NinjaTrader_BrandonH,

                    Thanks for your quick response.

                    Alright I understand that the trailing moves only when the market goes in your favor. But in my strategy as you can see I let it enter a position automatically right, so it means at the point of entering i cannot know whether it the market will move in my favor or not. So basically what i would like is for it to trail whenever it goes in my favor but whenever it goes the opposite way, I would like it to have a standard stoploss of for example 20 ticks. Because now when the market goes the opposite way what happens is the position stays open until the market moves up again above my entry price and than it starts trailing which is normal, but my issue is I don't want it to keep the position open until the market goes up again, because that would mean I make an insanely high loss first before making a little gain just like what happened in image 2.

                    So is there a way to basically have a set stoploss at the moment we enter the position so that if the market moves in an unfavorable way I have a security so that the position does not stay open until the market moves up again above my entry point ?

                    Kind regards

                    Comment


                      #11
                      Hello Salahinho99,

                      Yes, you can submit the exit orders from OnExecutionUpdate() at the time the entry fills.

                      Then you can have logic to trail in OnBarUpdate().

                      Please see the 'ProfitChaseStopTrailExitOrdersExample' example linked below on line 237.

                      Chelsea B.NinjaTrader Customer Service

                      Comment

                      Latest Posts

                      Collapse

                      Topics Statistics Last Post
                      Started by ageeholdings, Today, 07:43 AM
                      0 responses
                      10 views
                      0 likes
                      Last Post ageeholdings  
                      Started by pibrew, Today, 06:37 AM
                      0 responses
                      4 views
                      0 likes
                      Last Post pibrew
                      by pibrew
                       
                      Started by rbeckmann05, Yesterday, 06:48 PM
                      1 response
                      14 views
                      0 likes
                      Last Post bltdavid  
                      Started by llanqui, Today, 03:53 AM
                      0 responses
                      9 views
                      0 likes
                      Last Post llanqui
                      by llanqui
                       
                      Started by burtoninlondon, Today, 12:38 AM
                      0 responses
                      12 views
                      0 likes
                      Last Post burtoninlondon  
                      Working...
                      X