Trailing stop loss does not follow the parameters

Created at 15 Apr 2023, 04:41
How’s your experience with the cTrader Platform?
Your feedback is crucial to cTrader's development. Please take a few seconds to share your opinion and help us improve your trading experience. Thanks!
KH

khlopez

Joined 13.04.2023

Trailing stop loss does not follow the parameters
15 Apr 2023, 04:41


Hello,

I managed to make the trailing stop loss work in the following code, but it triggers and trails with the incorrect amount of pips. For example, even though the trigger is at 20 pips and the step at 10, some orders got stopped at a retracement of 6 pips in the price.

Could anyone please help me fix this?

Thanks a lot.

using cAlgo.API;
using cAlgo.API.Internals;
using System;
using System.Linq;

namespace cAlgo
{

    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SwingTrader : Robot
    {
    
            [Parameter(DefaultValue = 1000)]
            public double Volume { get; set; }  
                    
            [Parameter(DefaultValue = 70)]
            public double TakeProfit { get; set; }  
                    
            [Parameter(DefaultValue = 6)]
            public double StopLoss { get; set; }
            
            [Parameter("Include Trailing Stop", DefaultValue = true)]      
            public bool IncludeTrailingStop { get; set; }                  
            
            [Parameter("Trailing Stop Trigger (pips)", DefaultValue = 20)]  
            public int TrailingStopTrigger { get; set; }                   
            
            [Parameter("Trailing Stop Step (pips)", DefaultValue = 10)]    
            public int TrailingStopStep { get; set; }                  
            
            [Parameter("Instance Name", DefaultValue = "SwingTrader")]     
            public string InstanceName { get; set; }
            
      

    protected override void OnStart()
    
        
        
        {
            Positions.Closed += OnPositionClosed;
        }  
        
        

        private void OnPositionClosed(PositionClosedEventArgs args)
        {
            if (args.Position.Label != InstanceName)
                return;

            if (args.Reason == PositionCloseReason.StopLoss || args.Reason == PositionCloseReason.TakeProfit)
            {
                Print($"Position closed by {args.Reason}. Profit: {args.Position.GrossProfit}");
            }
        }
        
        protected override void OnBar()
        {
            if (Positions.Count > 0)
                return;
         
      
           
                if (if (//Condition to be met//)
            
            {
                ExecuteMarketOrder(TradeType.Buy, SymbolName, Volume, InstanceName, 6, 15, "", true);
            }
            

            if (//Condition to be met//)
          
                
            {
                ExecuteMarketOrder(TradeType.Sell, SymbolName, Volume, InstanceName, 6, 15, "", true);
            }
        }
        protected override void OnTick()
        {
            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }
        }
            
        private void SetTrailingStop()
        {
            var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);
            foreach (var position in sellPositions)
            {
                double distance = position.EntryPrice - Symbol.Ask;
                if (position.GrossProfit >= TrailingStopTrigger * Symbol.PipSize)
                    continue;

                double newStopLossPrice = Symbol.Ask + TrailingStopStep * Symbol.PipSize;
                if (position.StopLoss == null || newStopLossPrice < position.StopLoss)
                {
                    ModifyPosition(position, TrailingStopStep * Symbol.PipSize, null);
                    Print("Trailing Stop Loss triggered...");
                }
            }

            var buyPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Buy);
            foreach (var position in buyPositions)
            {
                double distance = Symbol.Bid - position.EntryPrice;
                if (distance < TrailingStopTrigger * Symbol.PipSize)
                    continue;

                double newStopLossPrice = Symbol.Bid - TrailingStopStep * Symbol.PipSize;
                if (position.StopLoss == null || newStopLossPrice > position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, null);
                    Print("Trailing Stop Loss triggered...");
                }
            }
        }    
    }
}

 

 

 

 


@khlopez
Replies

firemyst
16 Apr 2023, 05:52

I can see a potential issue on this line with sell orders:

ModifyPosition(position, TrailingStopStep * Symbol.PipSize, null);

 

You probably mean to use the following like you do under buy orders:

ModifyPosition(position, newStopLossPrice, null);

 

since the issue you have always only happens with sell orders.


@firemyst

khlopez
16 Apr 2023, 14:19 ( Updated at: 21 Dec 2023, 09:23 )

RE:

firemyst said:

I can see a potential issue on this line with sell orders:

ModifyPosition(position, TrailingStopStep * Symbol.PipSize, null);

 

You probably mean to use the following like you do under buy orders:

ModifyPosition(position, newStopLossPrice, null);

 

since the issue you have always only happens with sell orders.

Oh, I forgot about that line! Thank you so much!

Anyway, I still see something weird. For example:

Right now the code is as follows:

using cAlgo.API;
using cAlgo.API.Internals;
using System;
using System.Linq;

namespace cAlgo
{

    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SwingTrader : Robot
    {
    
            [Parameter(DefaultValue = 1000)]
            public double Volume { get; set; }  
                    
            [Parameter(DefaultValue = 70)]
            public double TakeProfit { get; set; }  
                    
            [Parameter(DefaultValue = 6)]
            public double StopLoss { get; set; }
            
            [Parameter("Include Trailing Stop", DefaultValue = true)]      
            public bool IncludeTrailingStop { get; set; }                
            
            [Parameter("Trailing Stop Trigger (pips)", DefaultValue = 20)]  
            public int TrailingStopTrigger { get; set; }               
            
            [Parameter("Trailing Stop Step (pips)", DefaultValue = 10)]   
            public int TrailingStopStep { get; set; }                  
            
            [Parameter("Instance Name", DefaultValue = "SwingTrader")]    
            public string InstanceName { get; set; }
            
      

    protected override void OnStart()
    
        
        
        {
            Positions.Closed += OnPositionClosed;
        }  
        
        

        private void OnPositionClosed(PositionClosedEventArgs args)
        {
            if (args.Position.Label != "SwingTrader")
                return;

            if (args.Reason == PositionCloseReason.StopLoss || args.Reason == PositionCloseReason.TakeProfit)
            {
                Print($"Position closed by {args.Reason}. Profit: {args.Position.GrossProfit}");
            }
        }
        
        protected override void OnBar()
        {
            if (Positions.Count > 0)
                return;
         
      
        
            //Bullish swing
           
                if (//Condition to be met)
            
            {
                ExecuteMarketOrder(TradeType.Buy, SymbolName, Volume, InstanceName, 6, 75, "", true);
            }
            //Bearish swing

            if (//Condition to be met)
          
                
            {
                ExecuteMarketOrder(TradeType.Sell, SymbolName, Volume, InstanceName, 6, 75, "", true);
            }
        }
        protected override void OnTick()
        {
            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }
        }
            
        private void SetTrailingStop()
        {
            var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);
            foreach (var position in sellPositions)
            {
                double distance = position.EntryPrice - Symbol.Ask;
                if (distance < TrailingStopTrigger * Symbol.PipSize)
                    continue;

                double newStopLossPrice = Symbol.Ask + TrailingStopStep * Symbol.PipSize;
                if (position.StopLoss == null || newStopLossPrice < position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, 75);
                    Print("Trailing Stop Loss triggered...");
                }
            }

            var buyPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Buy);
            foreach (var position in buyPositions)
            {
                double distance = Symbol.Bid - position.EntryPrice;
                if (distance < TrailingStopTrigger * Symbol.PipSize)
                    continue;

                double newStopLossPrice = Symbol.Bid - TrailingStopStep * Symbol.PipSize;
                if (position.StopLoss == null || newStopLossPrice > position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, 75);
                    Print("Trailing Stop Loss triggered...");
                }
            }
        }    
    }
}
            
    
    


Any idea why this happens?

 

Thanks again.


@khlopez