Trailing Stop Loss with Trailing Distance

Spotware's avatar

Spotware since: 23 Sep 2013;

  17 Jul 2017, 10:58
Trailing Stop Loss with Trailing Distance

This robot is intended to be used as a sample and does not guarantee any particular outcome or profit of any kind. Use it at your own risk.

// -------------------------------------------------------------------------------------------------
//
//    This robot is intended to be used as a sample and does not guarantee any particular outcome or
//    profit of any kind. Use it at your own risk
//
//    The "Trailing Stop Loss Sample" Robot places a Buy or Sell Market order according to user input.  
//    When the order is filled it implements trailing stop loss.
//
// -------------------------------------------------------------------------------------------------

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class TrailingStopLossSample : Robot
    {
        [Parameter("Volume", DefaultValue = 1000)]
        public int Volume { get; set; }
        [Parameter("Buy")]
        public bool Buy { get; set; }
        [Parameter("Stop Loss", DefaultValue = 5)]
        public double StopLoss { get; set; }
        [Parameter("Trigger When Gaining", DefaultValue = 1)]
        public double TriggerWhenGaining { get; set; }
        [Parameter("Trailing Stop Loss Distance", DefaultValue = 1)]
        public double TrailingStopLossDistance { get; set; }

        private double _highestGain;
        private bool _isTrailing;

        protected override void OnStart()
        {
            //Execute a market order based on the direction parameter
            ExecuteMarketOrder(Buy ? TradeType.Buy : TradeType.Sell, Symbol, Volume, "SampleTrailing", StopLoss, null);
            //Set the position's highest gain in pips
            _highestGain = Positions[0].Pips;
        }

        protected override void OnTick()
        {
            var position = Positions.Find("SampleTrailing");

            if (position == null)
            {
                Stop();
                return;
            }
            //If the trigger is reached, the robot starts trailing
            if (!_isTrailing && position.Pips >= TriggerWhenGaining)
            {
                _isTrailing = true;
            }
            //If the cBot is trailing and the profit in pips is at the highest level, we need to readjust the stop loss
            if (_isTrailing && _highestGain < position.Pips)
            {
                //Based on the position's direction, we calculate the new stop loss price and we modify the position
                if (position.TradeType == TradeType.Buy)
                {
                    var newSLprice = Symbol.Ask - (Symbol.PipSize * TrailingStopLossDistance);
                    if (newSLprice > position.StopLoss)
                    {
                        ModifyPosition(position, newSLprice, null);
                    }
                }
                else
                {
                    var newSLprice = Symbol.Bid + (Symbol.PipSize * TrailingStopLossDistance);
                    if (newSLprice < position.StopLoss)
                    {
                        ModifyPosition(position, newSLprice, null);
                    }
                }
                //We reset the highest gain
                _highestGain = position.Pips;
            }
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}
TRADERS FIRST™ Vote for your favorite features: https://ctrader.com/forum/suggestions

Drummond360 since: 22 Dec 2017;

  04 Jan 2018, 20:18

Could you please explain why you use PipValue to calculate the trailing stop distance instead of PipSize?

var newSLprice = Symbol.Ask - (Symbol.PipValue * TrailingStopLossDistance);

I've implemented this but am getting the error TRADING_BAD_STOPS

PanagiotisCharalampous's avatar

PanagiotisCharalampous since: 13 Jan 2017;

  05 Jan 2018, 11:50

Hi Drummond360,

Indeed it should have been PipSize. I fixed the code. Can you try now please?

Best Regards,

Panagiotis

Head of Community Management at cTrader

Drummond360 since: 22 Dec 2017;

  05 Jan 2018, 12:37

Yep all good now, thank you for confirming...

jani's avatar

jani since: 05 Apr 2019;

  20 Nov 2019, 23:56
Trailing Stop Loss with Trailing Distance and Step

Hello,

thank you for the example. It is really valuable to get these examples here, especially for a beginner programmer like myself.

It would be great if you could show how to add a "STEP to the trailing stop. More often than not,  it is not necessary to update the trailing stop on every tick advanced to the trade's direction and it would save a lot of resources to add a "STEP" to the trail, so that the trailing stop is only updated when price has moved the "STEP" amount to profit.

Below is my version of a trailing stop function (stop is trailing a custom indicator value : maketemaExit(1) )

private void SetT3ExitTrailingStop()
        {
            var sellPositions = Positions.FindAll(InstanceName, Symbol, TradeType.Sell);

            foreach (Position position in sellPositions)
            {
               
                double distance = position.EntryPrice - maketemaExit(1);

                if (distance < MinT3DistanceExit * Symbol.PipSize)
                    continue;

                double newStopLossPrice = maketemaExit(1) + T3StopFromLineExit * Symbol.PipSize;

                if (position.StopLoss == null || newStopLossPrice < position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, position.TakeProfit);
                }
            }

            var buyPositions = Positions.FindAll(InstanceName, Symbol, TradeType.Buy);

            foreach (Position position in buyPositions)
            {
                double distance = maketemaExit(1) - position.EntryPrice;

                if (distance < MinT3DistanceExit * Symbol.PipSize)
                    continue;

                double newStopLossPrice = maketemaExit(1) - T3StopFromLineExit * Symbol.PipSize;
                if (position.StopLoss == null || newStopLossPrice > position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, position.TakeProfit);
                }
            }
        }
“Markets can remain irrational longer than you can remain solvent.” ― John Maynard Keynes // https://www.youtube.com/watch?v=8GP87dgTqF8
PanagiotisCharalampous's avatar

PanagiotisCharalampous since: 13 Jan 2017;

  21 Nov 2019, 12:01

Hi Jan,

See the example below

// -------------------------------------------------------------------------------------------------
//
//    This robot is intended to be used as a sample and does not guarantee any particular outcome or
//    profit of any kind. Use it at your own risk
//
//    The "Trailing Stop Loss Sample" Robot places a Buy or Sell Market order according to user input.  
//    When the order is filled it implements trailing stop loss.
//
// -------------------------------------------------------------------------------------------------

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class TrailingStopLossSample : Robot
    {
        [Parameter("Volume", DefaultValue = 1000)]
        public int Volume { get; set; }
        [Parameter("Buy")]
        public bool Buy { get; set; }
        [Parameter("Stop Loss", DefaultValue = 5)]
        public double StopLoss { get; set; }
        [Parameter("Trigger When Gaining", DefaultValue = 1)]
        public double TriggerWhenGaining { get; set; }
        [Parameter("Trailing Stop Loss Distance", DefaultValue = 1)]
        public double TrailingStopLossDistance { get; set; }
        [Parameter("Step (pips)", DefaultValue = 5)]
        public double Step { get; set; }

        private double _highestGain;
        private bool _isTrailing;

        protected override void OnStart()
        {
            //Execute a market order based on the direction parameter
            ExecuteMarketOrder(Buy ? TradeType.Buy : TradeType.Sell, Symbol, Volume, "SampleTrailing", StopLoss, null);
            //Set the position's highest gain in pips
            _highestGain = Positions[0].Pips;
        }

        protected override void OnTick()
        {
            var position = Positions.Find("SampleTrailing");

            if (position == null)
            {
                Stop();
                return;
            }
            //If the trigger is reached, the robot starts trailing
            if (position.Pips >= TriggerWhenGaining)
            {         
                //Based on the position's direction, we calculate the new stop loss price and we modify the position
                if (position.TradeType == TradeType.Buy)
                {
                    var newSLprice = Symbol.Ask - (Symbol.PipSize * TrailingStopLossDistance);
                    if (newSLprice > position.StopLoss)
                    {
                        ModifyPosition(position, newSLprice, null);
                    }
                }
                else
                {
                    var newSLprice = Symbol.Bid + (Symbol.PipSize * TrailingStopLossDistance);
                    if (newSLprice < position.StopLoss)
                    {
                        ModifyPosition(position, newSLprice, null);
                    }
                }
                TriggerWhenGaining += Step;
            }
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

Best Regards,

Panagiotis

Head of Community Management at cTrader
driftingprogrammer's avatar

driftingprogrammer since: 08 Dec 2019;

  01 Feb 2020, 16:28
Is this not available in API already

Hi,

The documentation says 

public TradeResult ExecuteMarketOrder(TradeType tradeType, string symbolName, double volume, string label, double? stopLossPips, double? takeProfitPips, string comment, bool hasTrailingStop)

So it seems by setting the last boolean parameter to true cAlgo will implement the trailing stop loss so I am not able to understand in which situation will one need to use the code that is provided in this thread.

Please let me know.

Thanks in advance,

Warm Regards,

Vipin.

PanagiotisCharalampous said:

Hi Jan,

See the example below

// -------------------------------------------------------------------------------------------------
//
//    This robot is intended to be used as a sample and does not guarantee any particular outcome or
//    profit of any kind. Use it at your own risk
//
//    The "Trailing Stop Loss Sample" Robot places a Buy or Sell Market order according to user input.  
//    When the order is filled it implements trailing stop loss.
//
// -------------------------------------------------------------------------------------------------

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

namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class TrailingStopLossSample : Robot
    {
        [Parameter("Volume", DefaultValue = 1000)]
        public int Volume { get; set; }
        [Parameter("Buy")]
        public bool Buy { get; set; }
        [Parameter("Stop Loss", DefaultValue = 5)]
        public double StopLoss { get; set; }
        [Parameter("Trigger When Gaining", DefaultValue = 1)]
        public double TriggerWhenGaining { get; set; }
        [Parameter("Trailing Stop Loss Distance", DefaultValue = 1)]
        public double TrailingStopLossDistance { get; set; }
        [Parameter("Step (pips)", DefaultValue = 5)]
        public double Step { get; set; }

        private double _highestGain;
        private bool _isTrailing;

        protected override void OnStart()
        {
            //Execute a market order based on the direction parameter
            ExecuteMarketOrder(Buy ? TradeType.Buy : TradeType.Sell, Symbol, Volume, "SampleTrailing", StopLoss, null);
            //Set the position's highest gain in pips
            _highestGain = Positions[0].Pips;
        }

        protected override void OnTick()
        {
            var position = Positions.Find("SampleTrailing");

            if (position == null)
            {
                Stop();
                return;
            }
            //If the trigger is reached, the robot starts trailing
            if (position.Pips >= TriggerWhenGaining)
            {         
                //Based on the position's direction, we calculate the new stop loss price and we modify the position
                if (position.TradeType == TradeType.Buy)
                {
                    var newSLprice = Symbol.Ask - (Symbol.PipSize * TrailingStopLossDistance);
                    if (newSLprice > position.StopLoss)
                    {
                        ModifyPosition(position, newSLprice, null);
                    }
                }
                else
                {
                    var newSLprice = Symbol.Bid + (Symbol.PipSize * TrailingStopLossDistance);
                    if (newSLprice < position.StopLoss)
                    {
                        ModifyPosition(position, newSLprice, null);
                    }
                }
                TriggerWhenGaining += Step;
            }
        }

        protected override void OnStop()
        {
            // Put your deinitialization logic here
        }
    }
}

Best Regards,

Panagiotis

driftingprogrammer@gmail.com
PanagiotisCharalampous's avatar

PanagiotisCharalampous since: 13 Jan 2017;

  03 Feb 2020, 09:36

Hi driftingprogrammer,

The built-in TSL does not allow you to set a trigger distance for your trailing stop loss. It starts trailing immediately. This sample does (TriggerWhenGaining parameter).

Best Regards,

Panagiotis 

Join us on Telegram

Head of Community Management at cTrader
jani's avatar

jani since: 05 Apr 2019;

  08 Feb 2020, 23:31
RE:

Hi Panagiotis ,

thanks for your message, sorry a bit late reply from me...

if I understood correctly

if (position.Pips >= TriggerWhenGaining)

Allow trailing to start if EITHER buy or sell position is in profit for more than TriggerWhenGaining ?,  

Say we use Step=5 and buy has moved to Step but Sell only halfway,  if (position.Pips >= TriggerWhenGaining)  would allow also the Sell stop to be moved/trailed even though it has not yet reached the step, am I correct?

Do you think this would work?

  private void SetMultiMaTrailingStop()
        {
            var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);

            foreach (Position position in sellPositions)
            {
                   double distance = position.EntryPrice - neutral1;
                if (distance < BuyTriggerWhenGaining)
                    continue;

                 BuyTriggerWhenGaining += Step * Symbol.PipSize;

                double newStopLossPrice = neutral1 + T3StopFromLineExit * Symbol.PipSize;

                if (position.StopLoss == null || newStopLossPrice < position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, position.TakeProfit);
                }

                BuyTriggerWhenGaining += Step * Symbol.PipSize;
            }

            //---------

            var buyPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Buy);

            foreach (Position position in buyPositions)
            {
                double distance = neutral1 - position.EntryPrice;
        
                if (distance < SellTriggerWhenGaining)
                    continue;
                  double newStopLossPrice = neutral1 - T3StopFromLineExit * Symbol.PipSize;

                if (position.StopLoss == null || newStopLossPrice > position.StopLoss)
                {
                    ModifyPosition(position, newStopLossPrice, position.TakeProfit);
                }
                SellTriggerWhenGaining += Step * Symbol.PipSize;
            }
           
        }

 

Step feature is a bit hard to verify by backtesting, but I think I was getting the correct results.....

“Markets can remain irrational longer than you can remain solvent.” ― John Maynard Keynes // https://www.youtube.com/watch?v=8GP87dgTqF8
PanagiotisCharalampous's avatar

PanagiotisCharalampous since: 13 Jan 2017;

  10 Feb 2020, 08:34

Hi Jan,

Say we use Step=5 and buy has moved to Step but Sell only halfway,  if (position.Pips >= TriggerWhenGaining)  would allow also the Sell stop to be moved/trailed even though it has not yet reached the step, am I correct?

I am not sure how you came to this conclusion but seems wrong. Can you please explain? The cBot is designed to trigger a TSL only for one position as soon as it has reached the trigger level. If you want to use it on multiple positions. then you will need to have multiple instances with multiple labels. Each instance should be independent and not affect other positions.

 Best Regards,

Panagiotis 

Join us on Telegram

Head of Community Management at cTrader