set stop loss at indicator level not amount of pips

Created at 21 Oct 2020, 11:34
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!
DU

duketv

Joined 16.09.2020

set stop loss at indicator level not amount of pips
21 Oct 2020, 11:34


Dear folks,

I created a simple strategy combining the MACD indicator and a moving average, by using snippts of code from here and there. However, I would very much like to create a Stop Loss that is set on Bollinger Bands, Parabolic SAR of ATR indicators. I know I need to use the ModifyPosition method but I cannot get it to work. Any ideas are very much appreciated!

Thank you,

Duke

 

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



/*
Simple Cbot with MACD and a long period Moving Average for entry signals. Bollilinger Band is used for stop Loss
 */


namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class GardenStrategywithBBandtrailingstop : Robot
    {
        #region User defined parameters

        [Parameter("Instance Name", DefaultValue = "001")]
        public string InstanceName { get; set; }

        [Parameter("Lot Size", DefaultValue = 0.01)]
        public double LotSize { get; set; }

        [Parameter("Source SMA #1")]
        public DataSeries SourceSma1 { get; set; }

        [Parameter("Period SMA #1", DefaultValue = 160, MinValue = 1, MaxValue = 300)]
        public int PeriodsSma1 { get; set; }

        [Parameter(DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType MaType { get; set; }

        [Parameter("Period MACD", DefaultValue = 9)]
        public int Period { get; set; }

        [Parameter("Long Cycle MACD", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle MACD", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Periods", DefaultValue = 20, Group = "Bollinger Bands")]
        public int BbPeriods { get; set; }

        [Parameter("Standart Dev", DefaultValue = 2, Group = "Bollinger Bands")]
        public double BbStdDev { get; set; }

        [Parameter("MA Type", DefaultValue = 0, Group = "Bollinger Bands")]
        public MovingAverageType BbMaType { get; set; }

        [Parameter("Source", Group = "Bollinger Bands")]
        public DataSeries BbSource { get; set; }

        [Parameter("Threshold MACD - Long", DefaultValue = 0, MinValue = -0.0003, MaxValue = 0, Step = 1E-05)]
        public double ThresLong { get; set; }

        [Parameter("Threshold MACD - Short", DefaultValue = 0, MinValue = 0, MaxValue = 0.0003, Step = 1E-05)]
        public double ThresShort { get; set; }

        [Parameter("Calculate OnBar", DefaultValue = false)]
        public bool CalculateOnBar { get; set; }

        [Parameter("Include Trailing Stop", DefaultValue = true)]
        public bool IncludeTrailingStop { get; set; }

        [Parameter("Trailing Stop Trigger (pips)", DefaultValue = 40)]
        public int TrailingStopTrigger { get; set; }

        [Parameter("Trailing Stop Step (pips)", DefaultValue = 7)]
        public int TrailingStopStep { get; set; }

        [Parameter("Include Break-Even", DefaultValue = false)]
        public bool IncludeBreakEven { get; set; }

        [Parameter("Break-Even Trigger (pips)", DefaultValue = 10, MinValue = 1)]
        public int BreakEvenPips { get; set; }

        [Parameter("Break-Even Extra (pips)", DefaultValue = 2, MinValue = 1)]
        public int BreakEvenExtraPips { get; set; }

        #endregion

        #region Indicator declarations

        private SimpleMovingAverage _sma1 { get; set; }
        private MacdCrossOver Macd { get; set; }
        private BollingerBands BollingerBands { get; set; }

        #endregion

        #region cTrader events

        /// <summary>
        /// This is called when the robot first starts, it is only called once.
        /// </summary>
        protected override void OnStart()
        {
            // construct the indicators
            _sma1 = Indicators.SimpleMovingAverage(SourceSma1, PeriodsSma1);
            Macd = Indicators.MacdCrossOver(LongCycle, ShortCycle, Period);
            BollingerBands = Indicators.BollingerBands(Bars.ClosePrices, BbPeriods, BbStdDev, BbMaType);
            double Bid = Symbol.Bid;
            double Point = Symbol.TickSize;
        }

        /// <summary>
        /// This method is called every time the price changes for the symbol
        /// </summary>
        protected override void OnTick()
        {


            if (CalculateOnBar)
            {
                return;
            }

            ManagePositions();

            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }

            if (IncludeBreakEven)
            {
                BreakEvenAdjustment();
            }

        }

        /// <summary>
        /// This method is called at every candle (bar) close, when it has formed
        /// </summary>
        protected override void OnBar()
        {
            if (!CalculateOnBar)
            {
                return;
            }

            ManagePositions();
        }

        /// <summary>
        /// This method is called when your robot stops, can be used to clean-up memory resources.
        /// </summary>
        protected override void OnStop()
        {
            // unused
        }

        #endregion

        #region Position management

        private void ManagePositions()
        {
            var bbTop = BollingerBands.Top.LastValue;
            var bbMain = BollingerBands.Main.LastValue;

            if (_sma1.Result.LastValue < Symbol.Bid & Macd.MACD.Last(0) > Macd.Signal.Last(0) & Macd.MACD.Last(0) < ThresLong)
            {
                // if there is no buy position open, open one and close any sell position that is open
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    OpenPosition(TradeType.Buy);
                    ModifyPosition(InstanceName(bbTop - bbMain) * Symbol.PipSize, null);
                }


            }

            // if a sell position is already open and signal is buy do nothing
            else if (_sma1.Result.LastValue > Symbol.Bid & Macd.MACD.Last(0) < Macd.Signal.Last(0) & Macd.MACD.Last(0) > ThresShort)
            {
                // if there is no sell position open, open one and close any buy position that is open
                if (!IsPositionOpenByType(TradeType.Sell))
                {
                    position.ModifyPosition(InstanceName, (bbTop - bbMain) * Symbol.PipSize, null);
                }


            }
        }

        /// <summary>
        /// Opens a new long position
        /// </summary>
        /// <param name="type"></param>
        private void OpenPosition(TradeType type)
        {
            // calculate volume from lot size.
            double volume = Symbol.QuantityToVolumeInUnits(LotSize);


            // open a new position
            ExecuteMarketOrder(type, this.SymbolName, volume, InstanceName, null, null);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        private void ClosePosition(TradeType type)
        {
            var p = Positions.Find(InstanceName, this.SymbolName, type);

            if (p != null)
            {
                ClosePosition(p);
            }
        }

        #endregion

        #region Position Information

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool IsPositionOpenByType(TradeType type)
        {
            var p = Positions.FindAll(InstanceName, SymbolName, type);

            if (p.Count() >= 1)
            {
                return true;
            }

            return false;
        }

        #endregion

        #region Trailing Stop

        /// <summary>
        /// When the profit in pips is above or equal to Trigger the stop loss will start trailing the spot price.
        /// TrailingStop defines the number of pips the Stop Loss trails the spot price by. 
        /// If Trigger is 0 trailing will begin immediately. 
        /// </summary>
        private void SetTrailingStop()
        {
            var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);

            foreach (Position 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, position.TakeProfit);
                }
            }

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

            foreach (Position 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, position.TakeProfit);
                }
            }
        }

        #endregion

        #region Break Even

        /// <summary>
        /// Adjusts the break even plus (x) pips
        /// </summary>
        /// <param name="tradeType"></param>
        private void BreakEvenAdjustment()
        {
            var allPositions = Positions.FindAll(InstanceName, SymbolName);

            foreach (Position position in allPositions)
            {
                if (position.StopLoss != null)
                    return;

                var entryPrice = position.EntryPrice;
                var distance = position.TradeType == TradeType.Buy ? Symbol.Bid - entryPrice : entryPrice - Symbol.Ask;

                // move stop loss to break even plus and additional (x) pips
                if (distance >= BreakEvenPips * Symbol.PipSize)
                {
                    if (position.TradeType == TradeType.Buy)
                    {
                        if (position.StopLoss <= position.EntryPrice + (Symbol.PipSize * BreakEvenExtraPips) || position.StopLoss == null)
                        {
                            ModifyPosition(position, position.EntryPrice + (Symbol.PipSize * BreakEvenExtraPips), position.TakeProfit);
                            Print("Stop Loss to Break Even set for BUY position {0}", position.Id);
                        }
                    }
                    else
                    {
                        if (position.StopLoss >= position.EntryPrice - (Symbol.PipSize * BreakEvenExtraPips) || position.StopLoss == null)
                        {
                            ModifyPosition(position, entryPrice - (Symbol.PipSize * BreakEvenExtraPips), position.TakeProfit);
                            Print("Stop Loss to Break Even set for SELL position {0}", position.Id);
                        }
                    }
                }
            }
        }

        #endregion
    }
}

 


@duketv
Replies

PanagiotisCharalampous
21 Oct 2020, 11:37

Hi duketv,

You should divide by pip size, not multiply. You can also use ModifyStopLossPrice and set the exact price you wish, instead of making calculations.

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

duketv
21 Oct 2020, 12:07

RE:

Hi @PanagiotisCharalampous,

Thank you for your incredible quick reply :)

Good to point out that I should divide the pipsize or use a different method. However, I get the error "Name ModifyStopLossPrice does not exist in current context" I suppose my reference to the position is wrong?

Thank you

Duke

 

        #region Position management

        private void ManagePositions()
        {
            double bbTop = BollingerBands.Top.LastValue;
            double bbBottom = BollingerBands.Bottom.LastValue;
            double bbMain = BollingerBands.Main.LastValue;

            if (_sma1.Result.LastValue < Symbol.Bid & Macd.MACD.Last(0) > Macd.Signal.Last(0) & Macd.MACD.Last(0) < ThresLong)
            {
                // if there is no buy position open, open one and close any sell position that is open
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    OpenPosition(TradeType.Buy);
                    ModifyStopLossPrice(bbBottom);
                }


            }

            // if a sell position is already open and signal is buy do nothing
            else if (_sma1.Result.LastValue > Symbol.Bid & Macd.MACD.Last(0) < Macd.Signal.Last(0) & Macd.MACD.Last(0) > ThresShort)
            {
                // if there is no sell position open, open one and close any buy position that is open
                if (!IsPositionOpenByType(TradeType.Sell))
                {
                    ModifyStopLossPrice(bbTop);
                }


            }
        }

        /// <summary>
        /// Opens a new long position
        /// </summary>
        /// <param name="type"></param>
        private void OpenPosition(TradeType type)
        {
            // calculate volume from lot size.
            double volume = Symbol.QuantityToVolumeInUnits(LotSize);


            // open a new position
            ExecuteMarketOrder(type, this.SymbolName, volume, InstanceName, null, null);

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        private void ClosePosition(TradeType type)
        {
            var p = Positions.Find(InstanceName, this.SymbolName, type);

            if (p != null)
            {
                ClosePosition(p);
            }
        }

        #endregion

        #region Position Information

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool IsPositionOpenByType(TradeType type)
        {
            var p = Positions.FindAll(InstanceName, SymbolName, type);

            if (p.Count() >= 1)
            {
                return true;
            }

            return false;
        }

        #endregion

 


@duketv

PanagiotisCharalampous
21 Oct 2020, 12:09

Hi duketv,

The answer is in the documentation. This method is a member of the Position class.

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

duketv
22 Oct 2020, 19:36

RE:

Hi @PanagiotisCharalampous
It took me quite some hours but I have found 2 possible solutions, although neither of them work correctly yet. Again, any input is greatly appreciated.

In my first try I created an extra method to deal with the ModifyStopLossPrice. It does this correctly, but it does this continously! And so Stoploss is continiously set at a different level, creating a loop, until take-profit has been reached. My wish is to have it set only once.

In my second I worked with OpenPosition, but this gives me problems in the method definition. It gives the error that no method has been found to override..

Please advise

Thank you

        protected override void PositionOnOpened(Position openedPosition)
        {
            _position = openedPosition;
            var bbTop = BollingerBands.Top.LastValue;
            var bbBottom = BollingerBands.Bottom.LastValue;
            var bbMain = BollingerBands.Main.LastValue;
            var stopLossPipsbuy = (bbMain - bbBottom) / Symbol.PipSize;
            var stopLossPipssell = (bbMain - bbBottom) / Symbol.PipSize;

            if (_position.TradeType == TradeType.Buy)
            {
                Trade.ModifyPosition(openedPosition, stopLossPipsbuy, null);
            }
            if (_position.TradeType == TradeType.Sell)
            {
                Trade.ModifyPosition(openedPosition, stopLossPipssell, null);
            }
        }

        public override void ManagePositions()
        {
            var bbTop = BollingerBands.Top.LastValue;
            var bbBottom = BollingerBands.Bottom.LastValue;
            var bbMain = BollingerBands.Main.LastValue;

            if (_sma1.Result.LastValue < Symbol.Bid & Macd.MACD.Last(0) > Macd.Signal.Last(0) & Macd.MACD.Last(0) < ThresLong)
            {
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    var stopLossPips = (bbMain - bbBottom) / Symbol.PipSize;
                    OpenPosition(TradeType.Buy, stopLossPips);
                }

                else if (_sma1.Result.LastValue > Symbol.Bid & Macd.MACD.Last(0) < Macd.Signal.Last(0) & Macd.MACD.Last(0) > ThresShort)
                {
                    if (!IsPositionOpenByType(TradeType.Sell))
                    {
                        var stopLossPips = (bbTop - bbMain) / Symbol.PipSize;
                        OpenPosition(TradeType.Sell, stopLossPips);

                    }

                }
            }
        }

 


@duketv

PanagiotisCharalampous
23 Oct 2020, 08:37

Hi duketv,

In my second I worked with OpenPosition, but this gives me problems in the method definition. It gives the error that no method has been found to override..

Then skip the override keyword :)

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

duketv
23 Oct 2020, 16:40

RE:

PanagiotisCharalampous said:

Hi duketv,

In my second I worked with OpenPosition, but this gives me problems in the method definition. It gives the error that no method has been found to override..

Then skip the override keyword :)

Best Regards,

Panagiotis 

Join us on Telegram

Ha! :) yes, I did think about that, but then I get the error that "No override for method OpenPosision requires 2 arguments"

Am I missing something ?

Have a good weekend!


@duketv

PanagiotisCharalampous
23 Oct 2020, 16:47

Hi duketv,

You are probably calling the method somewhere using 2 arguments. But I am just guessing since you haven't posted the complete cBot code.

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

duketv
23 Oct 2020, 17:09

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



/*
Simple Cbot with MACD and a long period Moving Average for entry signals. Bollilinger Band is used for stop Loss
 */


namespace cAlgo
{
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class GardenStrategywithBBandtrailingstop : Robot
    {
        #region User defined parameters

        [Parameter("Instance Name", DefaultValue = "001")]
        public string InstanceName { get; set; }

        [Parameter("Lot Size", DefaultValue = 0.01)]
        public double LotSize { get; set; }

        [Parameter("Source SMA #1")]
        public DataSeries SourceSma1 { get; set; }

        [Parameter("Period SMA #1", DefaultValue = 160, MinValue = 1, MaxValue = 300)]
        public int PeriodsSma1 { get; set; }

        [Parameter(DefaultValue = MovingAverageType.Simple)]
        public MovingAverageType MaType { get; set; }

        [Parameter("Period MACD", DefaultValue = 9)]
        public int Period { get; set; }

        [Parameter("Long Cycle MACD", DefaultValue = 26)]
        public int LongCycle { get; set; }

        [Parameter("Short Cycle MACD", DefaultValue = 12)]
        public int ShortCycle { get; set; }

        [Parameter("Periods", DefaultValue = 20, Group = "Bollinger Bands")]
        public int BbPeriods { get; set; }

        [Parameter("Standart Dev", DefaultValue = 2, Group = "Bollinger Bands")]
        public double BbStdDev { get; set; }

        [Parameter("MA Type", DefaultValue = 0, Group = "Bollinger Bands")]
        public MovingAverageType BbMaType { get; set; }

        [Parameter("Source", Group = "Bollinger Bands")]
        public DataSeries BbSource { get; set; }

        [Parameter("Threshold MACD - Long", DefaultValue = 0, MinValue = -0.0003, MaxValue = 0, Step = 1E-05)]
        public double ThresLong { get; set; }

        [Parameter("Threshold MACD - Short", DefaultValue = 0, MinValue = 0, MaxValue = 0.0003, Step = 1E-05)]
        public double ThresShort { get; set; }

        [Parameter("Calculate OnBar", DefaultValue = false)]
        public bool CalculateOnBar { get; set; }

        [Parameter("Include Trailing Stop", DefaultValue = true)]
        public bool IncludeTrailingStop { get; set; }

        [Parameter("Trailing Stop Trigger (pips)", DefaultValue = 40)]
        public int TrailingStopTrigger { get; set; }

        [Parameter("Trailing Stop Step (pips)", DefaultValue = 7)]
        public int TrailingStopStep { get; set; }

        [Parameter("Include Break-Even", DefaultValue = false)]
        public bool IncludeBreakEven { get; set; }

        [Parameter("Break-Even Trigger (pips)", DefaultValue = 10, MinValue = 1)]
        public int BreakEvenPips { get; set; }

        [Parameter("Break-Even Extra (pips)", DefaultValue = 2, MinValue = 1)]
        public int BreakEvenExtraPips { get; set; }

        #endregion

        #region Indicator declarations

        private SimpleMovingAverage _sma1 { get; set; }
        private MacdCrossOver Macd { get; set; }
        private BollingerBands BollingerBands { get; set; }

        #endregion

        #region cTrader events

        /// <summary>
        /// This is called when the robot first starts, it is only called once.
        /// </summary>
        protected override void OnStart()
        {
            // construct the indicators
            _sma1 = Indicators.SimpleMovingAverage(SourceSma1, PeriodsSma1);
            Macd = Indicators.MacdCrossOver(LongCycle, ShortCycle, Period);
            BollingerBands = Indicators.BollingerBands(Bars.ClosePrices, BbPeriods, BbStdDev, BbMaType);
            double Bid = Symbol.Bid;
            double Point = Symbol.TickSize;
        }

        /// <summary>
        /// This method is called every time the price changes for the symbol
        /// </summary>
        protected override void OnTick()
        {


            if (CalculateOnBar)
            {
                return;
            }

            ManagePositions();

            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }

            if (IncludeBreakEven)
            {
                BreakEvenAdjustment();
            }

        }

        /// <summary>
        /// This method is called at every candle (bar) close, when it has formed
        /// </summary>
        protected override void OnBar()
        {
            if (!CalculateOnBar)
            {
                return;
            }

            ManagePositions();
        }

        /// <summary>
        /// This method is called when your robot stops, can be used to clean-up memory resources.
        /// </summary>
        protected override void OnStop()
        {
            // unused
        }

        #endregion

        #region Position management

        public void ManagePositions()
        {
            var bbTop = BollingerBands.Top.LastValue;
            var bbBottom = BollingerBands.Bottom.LastValue;
            var bbMain = BollingerBands.Main.LastValue;

            if (_sma1.Result.LastValue < Symbol.Bid & Macd.MACD.Last(0) > Macd.Signal.Last(0) & Macd.MACD.Last(0) < ThresLong)
            {
                if (!IsPositionOpenByType(TradeType.Buy))
                {
                    var stopLossPips = (bbMain - bbBottom) / Symbol.PipSize;
                    OpenPosition(TradeType.Buy, stopLossPips);
                }

                else if (_sma1.Result.LastValue > Symbol.Bid & Macd.MACD.Last(0) < Macd.Signal.Last(0) & Macd.MACD.Last(0) > ThresShort)
                {
                    if (!IsPositionOpenByType(TradeType.Sell))
                    {
                        var stopLossPips = (bbTop - bbMain) / Symbol.PipSize;
                        OpenPosition(TradeType.Sell, stopLossPips);

                    }

                }
            }
        }


        /// <summary>
        /// Opens a new long position
        /// </summary>
        /// <param name="type"></param>
        private void OpenPosition(TradeType type)
        {
            // calculate volume from lot size.
            double volume = Symbol.QuantityToVolumeInUnits(LotSize);


            // open a new position
            ExecuteMarketOrder(type, this.SymbolName, volume, InstanceName, null, null);
        }





        /// <summary>
        /// closes position
        /// </summary>
        /// <param name="type"></param>
        private void ClosePosition(TradeType type)
        {
            var p = Positions.Find(InstanceName, this.SymbolName, type);

            if (p != null)
            {
                ClosePosition(p);
            }
        }

        #endregion

        #region Position Information

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool IsPositionOpenByType(TradeType type)
        {
            var p = Positions.FindAll(InstanceName, SymbolName, type);

            if (p.Count() >= 1)
            {
                return true;
            }

            return false;
        }

        #endregion

        #region Trailing Stop

        /// <summary>
        /// When the profit in pips is above or equal to Trigger the stop loss will start trailing the spot price.
        /// TrailingStop defines the number of pips the Stop Loss trails the spot price by. 
        /// If Trigger is 0 trailing will begin immediately. 
        /// </summary>
        private void SetTrailingStop()
        {
            var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);

            foreach (Position 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, position.TakeProfit);
                }
            }

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

            foreach (Position 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, position.TakeProfit);
                }
            }
        }

        #endregion

        #region Break Even

        /// <summary>
        /// Adjusts the break even plus (x) pips
        /// </summary>
        /// <param name="tradeType"></param>
        private void BreakEvenAdjustment()
        {
            var allPositions = Positions.FindAll(InstanceName, SymbolName);

            foreach (Position position in allPositions)
            {
                if (position.StopLoss != null)
                    return;

                var entryPrice = position.EntryPrice;
                var distance = position.TradeType == TradeType.Buy ? Symbol.Bid - entryPrice : entryPrice - Symbol.Ask;

                // move stop loss to break even plus and additional (x) pips
                if (distance >= BreakEvenPips * Symbol.PipSize)
                {
                    if (position.TradeType == TradeType.Buy)
                    {
                        if (position.StopLoss <= position.EntryPrice + (Symbol.PipSize * BreakEvenExtraPips) || position.StopLoss == null)
                        {
                            ModifyPosition(position, position.EntryPrice + (Symbol.PipSize * BreakEvenExtraPips), position.TakeProfit);
                            Print("Stop Loss to Break Even set for BUY position {0}", position.Id);
                        }
                    }
                    else
                    {
                        if (position.StopLoss >= position.EntryPrice - (Symbol.PipSize * BreakEvenExtraPips) || position.StopLoss == null)
                        {
                            ModifyPosition(position, entryPrice - (Symbol.PipSize * BreakEvenExtraPips), position.TakeProfit);
                            Print("Stop Loss to Break Even set for SELL position {0}", position.Id);
                        }
                    }
                }
            }
        }

        #endregion
    }
}

 

 


@duketv

PanagiotisCharalampous
26 Oct 2020, 07:51

Hi duketv,

Thanks, I was correct then.

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

duketv
26 Oct 2020, 19:29

RE:

Hi @PanagiotisCharalampous
 

I think I see what you mean, but I have no clue how to solve right now.. Could you help? I spend almost 20 hours working on this problem, learned a lot! But no clue anymore how to solve it.

Regards,

Duke


@duketv

prosteel1
26 Oct 2020, 19:56

I have found working with SL quite difficult too - mostly because of slippage. I don't think you are trying to fix slippage so I'm guessing it's because of the rounding to pips that is your issue when working with forex and precious metals?

In global I set:

int round = 1;

For rounding to SL in pips I use this check on start to fix the issue of Symbol.Digits for Forex and Symbol.Digits for metals being screwed up:

if (Symbol.PipSize == 0.01 && Symbol.Digits == 2)
{
      round = 0;
 }

Then when placing the order I use this to calculate the stoploss in pips:

double slpips = Math.Round(((x) / Symbol.PipSize), round);

I cant see any way to calculate the rounding figure apart from setting it to 1 for forex and then checking on start if the pipsize and digits requires it to be set to 0. Yes this is stupid lol. And I still have a bug somewhere due to this. This bug makes everything incredibly complex, could easily spend another week on it myself :P So far I have wasted about 1 month of my life on this... so far... more to come lol

 


@prosteel1

prosteel1
26 Oct 2020, 20:33

ModifyPosition() example

I think this is what you were asking for:

You can also paste this special line in OnStart so it calls the PositionsOnOpened when a Position is opened:

Positions.Opened += PositionsOnOpened;

Then you have a new method: that get run each time a position is opened which can modify stoploss etc. I use the comment to store the entry price, stoploss, take profit etc

private void PositionsOnOpened(PositionOpenedEventArgs args)
{
     var pos = args.Position;

       if (pos.Comment != "")
       {

                var splitted = pos.Comment.Split(' ');
                double ep = Convert.ToDouble(splitted[2]);
                double sl = Convert.ToDouble(splitted[4]);
                double tp = Convert.ToDouble(splitted[5]);
                if (pos.StopLoss != sl || pos.TakeProfit != tp)
                {
                    ModifyPosition(pos, sl, tp);

                }

      }

}


@prosteel1

prosteel1
26 Oct 2020, 20:53

Or if you want to impliment a trailing stoploss or partial take profit then OnTick or OnBar you can search positions for the comment of Short or Long if you set it in your order:

var Shortpos = Positions.FindAll("Short");
foreach (var pos in Shortpos)

{

     if (pos.SymbolName == SymbolName)
        {

            if (pos.StopLoss != ShortTradeSLPrice)
            {
                     ModifyPosition(pos, ShortTradeSLPrice, ShortTradeTPPrice);

            }

      }

}

Note how the ModifyPosition uses prices whereas the orders uses pips - Yes this is stupid lol.

Orders that fill at a different price to the order entry price will have a Stoploss and TakeProfit the set number of pips from the filled price and not the calculated pips from the entry price in the order - my above PositionsOnOpened fixes that bug by checking new positions and setting the stoploss and take profit to the prices in the comment.


@prosteel1

PanagiotisCharalampous
27 Oct 2020, 07:47

Hi duketv,

You are calling OpenPosition() using two arguments e.g.

OpenPosition(TradeType.Buy, stopLossPips);

but you should be using only one e.g.

OpenPosition(TradeType.Buy);

Best Regards,

Panagiotis 

Join us on Telegram


@PanagiotisCharalampous

duketv
04 Nov 2020, 11:47

RE: ModifyPosition() example

prosteel1 said:

I think this is what you were asking for:

You can also paste this special line in OnStart so it calls the PositionsOnOpened when a Position is opened:

Positions.Opened += PositionsOnOpened;

Then you have a new method: that get run each time a position is opened which can modify stoploss etc. I use the comment to store the entry price, stoploss, take profit etc

private void PositionsOnOpened(PositionOpenedEventArgs args)
{
     var pos = args.Position;

       if (pos.Comment != "")
       {

                var splitted = pos.Comment.Split(' ');
                double ep = Convert.ToDouble(splitted[2]);
                double sl = Convert.ToDouble(splitted[4]);
                double tp = Convert.ToDouble(splitted[5]);
                if (pos.StopLoss != sl || pos.TakeProfit != tp)
                {
                    ModifyPosition(pos, sl, tp);

                }

      }

}

Hi @prosteel1

Thank you for your elaborate reply! Really appreciated. And slippage is not exactly the reason I am trying to do this. I am more a beginning coder/trader who wants to set dynamic stop loss that respond to market fluctuations, rather than setting a specefic amount of pips.

Your solution on working with comments looks very elegant, but I couldn't make it work. I think were it went wrong is that I made a seperate variable called "stopLossPips" (to calcluate a stop  loss based on Bollinger Bands) but by doing that I couldn't connect this to the variable "sl" that you suggested in your code.

I may have found a new solution (still testing it), but your 'comment' solution looks a lot easier. Would gladly learn more from it.

Thanks again for your replies, really happy with that!

var bbTop = BollingerBands.Top.LastValue;
var bbBottom = BollingerBands.Bottom.LastValue;
var bbMain = BollingerBands.Main.LastValue;
var stopLossPips = (bbMain - bbBottom) / Symbol.PipSize

 

 


@duketv