Bot missing Stop Loss on some positions

Created at 15 Mar 2022, 08:02
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!
WA

waym77

Joined 22.07.2021

Bot missing Stop Loss on some positions
15 Mar 2022, 08:02


Hi,

I am having trouble with a bot I'm forward testing, where for certain pairs on certain trades, the bot will enter a trade with no stop loss and only with a take profit.

The stop loss is determined by an SL parameter, and I haven't found anything in the log regarding the failure of stop losses.

It tends to happen more on exotic pairs (USDZAR/AUDSGD), which makes me think it might be the spread, although I did increase the stop loss values based on the symbols pip value.

However, on these exotic pairs, there are some trades that have the required stop loss.

I there any code I can implement to ensure that no trade goes without the stop loss I determined for it?

Thanks,


@waym77
Replies

amusleh
15 Mar 2022, 08:52

Hi,

This can be caused by symbol spread or something might be wrong with your code, can you post a sample cBot code that can reproduce this issue on visual back test?


@amusleh

waym77
15 Mar 2022, 09:29

RE:

amusleh said:

Hi,

This can be caused by symbol spread or something might be wrong with your code, can you post a sample cBot code that can reproduce this issue on visual back test?

Here is the current build used:

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

namespace cAlgo.Robots
{
    [Robot(TimeZone = TimeZones.SouthAfricaStandardTime, AccessRights = AccessRights.FullAccess)]
    public class AFFS : Robot
    {
        [Parameter("Name", Group = "Info", DefaultValue = "AFFS")]
        public string _name { get; set; }

        [Parameter("Max Lots", Group = "Risk", DefaultValue = 100.0, MinValue = 0.01, MaxValue = 1000.0, Step = 1.0)]
        public double _maxlots { get; set; }

        [Parameter("Starting Risk (%)", Group = "Risk", DefaultValue = 1.0, MinValue = 0.01, MaxValue = 100.0, Step = 0.5)]
        public double _startingrisk { get; set; }

        [Parameter("Risk Step (%)", Group = "Risk", DefaultValue = 0.0, MinValue = 0.0, MaxValue = 100.0, Step = 0.5)]
        public double _riskstep { get; set; }

        [Parameter("Max Risk (%)", Group = "Risk", DefaultValue = 20.0, MinValue = 0.01, MaxValue = 100.0, Step = 0.5)]
        public double _maxrisk { get; set; }

        [Parameter("Stop Loss", Group = "Risk", DefaultValue = 10.0, MinValue = 0.1, MaxValue = 1000.0, Step = 1.0)]
        public double _stoploss { get; set; }

        [Parameter("Reward Factor", Group = "Risk", DefaultValue = 1.0, MinValue = 0.1, MaxValue = 50.0, Step = 0.5)]
        public double _reward { get; set; }

        [Parameter("Safety (Pips)", Group = "Risk", DefaultValue = 3.0, MinValue = 0.0, MaxValue = 1000.0, Step = 1.0)]
        public double _safety { get; set; }

        private double _bullprice, _bearprice, _previoushigh, _previouslow, _maxunits, _activerisk, _distance, _volume, _takeprofit;
        private bool _todaybuy, _todaysell, _intimeforbuy, _intimeforsell, _gapbuy, _gapsell;
        private int _buycount, _sellcount, _tradedaybuy, _tradedaysell;

        protected override void OnStart()
        {
            _buycount = 1;
            _sellcount = 1;

            _distance = Math.Abs(_safety * Symbol.PipSize);
            _activerisk = _startingrisk;
            _volume = GetVolume();
            _takeprofit = GetRR();

            _previoushigh = Bars.HighPrices.Last(1);
            _previouslow = Bars.LowPrices.Last(1);
            _bullprice = _previoushigh + _distance;
            _bearprice = _previouslow - _distance;

            if (Bars.LowPrices.Last(0) < _bearprice)
            {
                _intimeforsell = false;
            }

            if (Bars.HighPrices.Last(0) > _bullprice)
            {
                _intimeforbuy = false;
            }
        }

        protected override void OnTick()
        {
            if (Server.Time.Day > _tradedaybuy)
            {
                _buycount = 1;
                _intimeforbuy = true;
                _gapbuy = false;
            }

            if (Server.Time.Day > _tradedaysell)
            {
                _sellcount = 1;
                _intimeforsell = true;
                _gapsell = false;
            }

            _gapbuy = Bars.OpenPrices.Last(0) > _previoushigh;
            _gapsell = Bars.OpenPrices.Last(0) < _previouslow;

            if (_gapbuy && Symbol.Ask < _previoushigh)
            {
                _gapbuy = false;
            }

            if (_gapsell && Symbol.Bid > _previouslow)
            {
                _gapsell = false;
            }

            _maxunits = Symbol.QuantityToVolumeInUnits(_maxlots);
            if (_volume > _maxunits)
            {
                _volume = _maxunits;
            }

            _todaybuy = _buycount == 1;
            _todaysell = _sellcount == 1;

            _previoushigh = Bars.HighPrices.Last(1);
            _previouslow = Bars.LowPrices.Last(1);
            _bullprice = _previoushigh + _distance;
            _bearprice = _previouslow - _distance;

            if (Symbol.Ask > _bullprice && _todaybuy && _intimeforbuy && !_gapbuy)
            {
                _tradedaybuy = Server.Time.Day;
                _activerisk = GetRisk();
                _volume = GetVolume();
                ExecuteMarketOrder(TradeType.Buy, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                _buycount = 0;
            }

            if (Symbol.Bid < _bearprice && _todaysell && _intimeforsell && !_gapsell)
            {
                _tradedaysell = Server.Time.Day;
                _activerisk = GetRisk();
                _volume = GetVolume();
                ExecuteMarketOrder(TradeType.Sell, Symbol.Name, _volume, _name, _stoploss, _takeprofit);
                _sellcount = 0;
            }

        }

        private double GetRR()
        {
            double _result = 0.0;
            _result = Math.Abs(_stoploss * _reward);
            return _result;
        }

        private double GetRisk()
        {
            double _result = _activerisk;
            if (_result > _maxrisk)
            {
                _result = _maxrisk;
            }
            if (History.FindLast(_name) != null)
            {
                var _lastposition = History.FindLast(_name);
                bool _win = _lastposition.NetProfit > 0.0;
                if (_win && _activerisk < _maxrisk)
                {
                    _result = _activerisk + _riskstep;
                }
                else if (!_win)
                {
                    _result = _startingrisk;
                }
            }
            else
                return _startingrisk;
            return _result;
        }

        private double GetVolume()
        {
            double costPerPip = (double)((int)(Symbol.PipValue * 10000000)) / 100;

            double baseNumber = Account.Balance;

            double sizeInLots = Math.Round((baseNumber * _activerisk / 100) / (_stoploss * costPerPip), 2);

            var result = Symbol.QuantityToVolumeInUnits(sizeInLots);

            if (result > Symbol.VolumeInUnitsMax)
            {
                result = Symbol.VolumeInUnitsMax;
            }
            else if (result < Symbol.VolumeInUnitsMin)
            {
                result = Symbol.VolumeInUnitsMin;
            }
            else if (result % Symbol.VolumeInUnitsStep != 0)
            {
                result = result - (result % Symbol.VolumeInUnitsStep);
            }

            return result;
        }
    }
}

 


@waym77