Stop Loss and Take Profit set but not working

Created at 08 Jul 2022, 01:43
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!
DA

darkoliveinthepasta

Joined 08.07.2022

Stop Loss and Take Profit set but not working
08 Jul 2022, 01:43


Hello, I am trying to code a bot based on Bollinger Bands.
The stop loss I want to use is set correctly when a trade is opened yet every trade is closed at random prices (sometimes more than double the pips I set).
The take profit is instead set to trigger when a candle crosses the upper band and this works fine if I use it to open a trade, but it seems it doesn't work when used as a take profit somehow since every trade is closed not at the first close over the band but is closed in a (random) following close.
The code for these are both onBar, but I tried to open the position onTick and the stop loss is still executed wrong.


@darkoliveinthepasta
Replies

PanagiotisCharalampous
08 Jul 2022, 11:50

Hi there,

Please provide the complete cBot code and steps to reproduce this behavior.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook


@PanagiotisCharalampous

darkoliveinthepasta
08 Jul 2022, 14:26

RE:

PanagiotisCharalampous said:

Hi there,

Please provide the complete cBot code and steps to reproduce this behavior.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi, this is the code, and the spread settings I was using is 0.2 since that's the most common spread I've seen with my broker in the time sessions I want it to run in.

You should see the stop loss is never executed correctly after 0.8 pips but is most often beyond that. The take profit is also never at the first close after crossing the band.

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.WEuropeStandardTime, AccessRights = AccessRights.None)]
    public class BollingerBot : Robot // v0.4
    {
        #region Session
        [Parameter("Start Hour", DefaultValue = 6.0)]
        public double StartTime { get; set; }

        [Parameter("Stop Hour", DefaultValue = 23.0)]
        public double StopTime { get; set; }
        #endregion

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

        [Parameter("Deviation", DefaultValue = 2, Group = "Bollinger Bands")]
        public double Deviation { get; set; }
        #endregion

        #region Trade Parameters Input
        [Parameter("Risk in percent", DefaultValue = 0.08, Group = "Risk Paramaters")]
        public double Risk { get; set; }

        [Parameter("Stop Loss in pips", DefaultValue = 0.8, Group = "Risk Paramaters")]
        public double StopLoss { get; set; }

        [Parameter("Take Profit in pips", DefaultValue = 0, Group = "Risk Paramaters")]
        public double TakeProfit { get; set; }
        #endregion

        private double _volumeInUnits;

        private DateTime _startTime;
        private DateTime _stopTime;

        private BollingerBands _bollingerBands;

        public string Label = "BollingerBot";
        
        public bool buyConditionA = false;
        public bool buyConditionB = false;
        
        public bool sellConditionA = false;
        public bool sellConditionB = false;

        protected override void OnStart()
        {
            _startTime = Server.Time.Date.AddHours(StartTime);
            _stopTime = Server.Time.Date.AddHours(StopTime);

            _bollingerBands = Indicators.BollingerBands(Bars.ClosePrices, Periods, Deviation, MovingAverageType.Simple);
        }

        protected override void OnBar()
        {
            var currentHours = Server.Time.TimeOfDay.TotalHours;
            bool tradeTime = StartTime < StopTime ? currentHours > StartTime && currentHours < StopTime : currentHours < StopTime || currentHours > StartTime;

            if (!tradeTime)
                return;

            double SLVolume = StopLoss * 1.25;
            double riskSource = Account.Balance;
            _volumeInUnits = CalculateVolume(SLVolume, Risk, riskSource);

            #region Entry Conditions
            var buyProfit = Bars.ClosePrices.Last(1) > _bollingerBands.Top.Last(1);
            var buyTriggerA = Bars.ClosePrices.Last(1) < _bollingerBands.Bottom.Last(1);
            var buyTriggerB = Bars.ClosePrices.Last(1) > _bollingerBands.Bottom.Last(1);

            var sellProfit = Bars.ClosePrices.Last(1) < _bollingerBands.Bottom.Last(1);
            var sellTriggerA = Bars.ClosePrices.Last(1) > _bollingerBands.Top.Last(1);
            var sellTriggerB = Bars.ClosePrices.Last(1) < _bollingerBands.Top.Last(1);

            var isClosedCandleUp = Bars.ClosePrices.Last(1) > Bars.OpenPrices.Last(1);
            #endregion

            #region Long Conditions Check
            if (buyTriggerA && !buyConditionA)
            {
                buyConditionA = true;
                return;
            }

            if (buyTriggerB && buyConditionA)
            {
                buyConditionB = true;
                buyConditionA = false;
            }
            #endregion

            if (buyConditionB && isClosedCandleUp)
            {
                buyConditionB = false;
                OpenPosition(TradeType.Buy, StopLoss);
            }

            #region Short Conditions Check
            if (sellTriggerA && !sellConditionA)
            {
                sellConditionA = true;
                return;
            }
            
            if (sellTriggerB && sellConditionA)
            {
                sellConditionB = true;
                sellConditionA = false;
            }
            #endregion

            if (sellConditionB && !isClosedCandleUp)
            {
                sellConditionB = false;
                OpenPosition(TradeType.Sell, StopLoss);
            }
            
            #region Close Open Positions
            var openedPosition = Positions.FirstOrDefault(p => p.SymbolName == SymbolName && p.Label == Label);

            if (openedPosition == null)
                return;

            if (buyProfit && openedPosition.TradeType == TradeType.Buy)
            {
                ClosePosition(openedPosition);
            }

            if (sellProfit && openedPosition.TradeType == TradeType.Sell)
            {
                ClosePosition(openedPosition);
            }
            #endregion
        }

        protected override void OnTick()
        {
        }

        private void OpenPosition(TradeType side, double StopLoss)
        {
            if (Positions.Any(p => p.SymbolName == SymbolName && p.Label == Label))
                return;

            ExecuteMarketOrder(side, SymbolName, _volumeInUnits, Label, StopLoss, null);
        }

        private double CalculateVolume(double StopLoss, double Risk, double riskSource)
        {
            double riskPerTrade = riskSource * Risk / 100;

            double totalPips = StopLoss;

            double _volume;

            double exactVolume = riskPerTrade / (Symbol.PipValue * totalPips);

            if (exactVolume >= Symbol.VolumeInUnitsMin)
            {
                _volume = Symbol.NormalizeVolumeInUnits(exactVolume);
            }
            else
            {
                _volume = -1;
                Print("Not enough Equity to place minimum trade, exactVolume " + exactVolume + " is not >= Symbol.VolumeInUnitsMin " + Symbol.VolumeInUnitsMin);
            }

            return _volume;
        }
    }
}

 


@darkoliveinthepasta

PanagiotisCharalampous
08 Jul 2022, 14:31

Hi there,

You also need to provide me with examples from backtesting where the SL and TP do not execute correctly. I need to be able to see the symbol and broker as well.

Also make sure you are testing using tick data.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook


@PanagiotisCharalampous

darkoliveinthepasta
09 Jul 2022, 00:22 ( Updated at: 09 Jul 2022, 00:29 )

RE:

PanagiotisCharalampous said:

Hi there,

You also need to provide me with examples from backtesting where the SL and TP do not execute correctly. I need to be able to see the symbol and broker as well.

Also make sure you are testing using tick data.

Best Regards,

Panagiotis 

Join us on Telegram and Facebook

Hi again, so the symbol I'm using is EURUSD on the 1 minute timeframe and the broker is Pepperstone with Razor.

Here are some examples:

the first one is the trade History tab where you can see a tp being hit (which is the same trade the second screenshot shows), also a few stop losses executed at random prices, even if my stop loss is set at 0.8 pips.

As I said, the second one shows a tp being hit but as you can see it doesn't respect the variable I use for it (which checks if the previous candle closed under the lower Bollinger Band), I really can't understand why it closes where it does when it had multiple opportunities to close it correctly.

The third one is an extreme example of a wrong stop loss, it closes in a seemingly random point that the price doesn't even reach.

The fourth one is a normal example of a wrong stop loss, it closes at -1.3 pips instead of 0.8 pips. If I look at the Events tab, the stop loss is always set correctly at 0.8 pips.

 


@darkoliveinthepasta

PanagiotisCharalampous
11 Jul 2022, 15:14

Hi there,

I ran the cBot but I do not see any problem with SL. The fact that you set the SL at 0.8 does not mean it will execute exaclty there. The SL is triggered when the loss is equal or higher than the set price. Actual execution depends on market prices. Also you need to note that SL for sell orders is triggered by ask prices. Candles are drawn by bid prices.

Regarding the TP, it seems your logic is buggy. There are sections of the code that do not allow the TP to execute but I don't know what are they supposed to do. You need to debug the logic of the cBot yourself

Best Regards,

Panagiotis 

Join us on Telegram and Facebook


@PanagiotisCharalampous