Risk based on SL algorithm

Created at 29 Jul 2021, 09:13
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!
WM

wmclennan77

Joined 29.06.2021

Risk based on SL algorithm
29 Jul 2021, 09:13


Hi all,

I have created a risk management algorithm that sets the volume in accordance with account balance and stop-loss distance.

The algo gets the SL amount as well as the specified risk percentage from the user via parameters.

Examples of the desired result:

Pair - EURUSD
Account Balance - $10 000
Risk % - 1
SL - 10
Amount At Risk - $100
Volume - 100000 (1 lot)

Pair - USDCAD
Account Balance - $14 566
Risk % - 2.5
SL - 27
Amount At Risk - $364.15
Volume - 169788 (1.69 lots)

The code I have for this calculation so far:
 

_AdjRisk = _RiskPercent / 100;
_AdjStop = _SL / Symbol.PipValue;
_volume = (long)Math.Ceiling((Account.Balance * _AdjRisk) / _AdjStop) * 1000;



Although when backtesting, the lot size stays at 0.01 for the entire backtest.

Any advice as to what is wrong with the logic?
 


@wmclennan77
Replies

amusleh
29 Jul 2021, 09:53

Hi,

Please post a full cBot sample that uses your calculation code and then we will be able to help you.


@amusleh

wmclennan77
29 Jul 2021, 10:44

RE:

amusleh said:

Hi,

Please post a full cBot sample that uses your calculation code and then we will be able to help you.

Hi,

Here is an example of the calculation code implemented in an example basic MA cross strategy.

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.UTC, AccessRights = AccessRights.FullAccess)]
    public class RiskonSL : Robot
    {
        private double _volume;
        private double _AdjRisk;
        private double _AdjStop;
        private double _MaxUnits;

        [Parameter("Label", DefaultValue = "")]
        public string _Label { get; set; }

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

        [Parameter("Max Allowed Lots", DefaultValue = 10.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.01)]
        public double _MaxLots { get; set; }

        [Parameter("Stop Loss", DefaultValue = 10.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _SL { get; set; }

        [Parameter("Take Profit", DefaultValue = 15.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _TP { get; set; }

        private ExponentialMovingAverage _ema_12;
        private ExponentialMovingAverage _ema_26;
        private bool _ema_buy, _ema_sell;

        protected override void OnStart()
        {
            _ema_12 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 12);
            _ema_26 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 26);
        }

        protected override void OnBar()
        {
            var ActiveBuy = Positions.Find(_Label, SymbolName, TradeType.Buy);
            var ActiveSell = Positions.Find(_Label, SymbolName, TradeType.Sell);

            _MaxUnits = Symbol.QuantityToVolumeInUnits(_MaxLots);
            _AdjRisk = _RiskPercent / 100;
            _AdjStop = _SL / Symbol.PipValue;
            _volume = (long)Math.Ceiling((Account.Balance * _AdjRisk) / _AdjStop) * 1000;
            if (_volume > _MaxUnits)
            {
                _volume = _MaxUnits;
            }

            if (_ema_12.Result.HasCrossedAbove(_ema_26.Result.Last(1), 1))
            {
                _ema_buy = true;
                _ema_sell = false;
            }
            else if (_ema_12.Result.HasCrossedBelow(_ema_26.Result.Last(1), 1))
            {
                _ema_sell = true;
                _ema_buy = false;
            }

            if (ActiveBuy == null && _ema_buy)
            {
                if (ActiveSell != null)
                {
                    ClosePosition(ActiveSell);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, _volume, _Label, _SL, _TP);
            }

            if (ActiveSell == null && _ema_sell)
            {
                if (ActiveBuy != null)
                {
                    ClosePosition(ActiveBuy);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, _volume, _Label, _SL, _SL);
            }
        }
    }
}

 


@wmclennan77

amusleh
29 Jul 2021, 12:52

Hi,

Try this:

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.UTC, AccessRights = AccessRights.FullAccess)]
    public class RiskonSL : Robot
    {
        [Parameter("Label", DefaultValue = "")]
        public string _Label { get; set; }

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

        [Parameter("Max Allowed Lots", DefaultValue = 10.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.01)]
        public double _MaxLots { get; set; }

        [Parameter("Stop Loss", DefaultValue = 10.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _SL { get; set; }

        [Parameter("Take Profit", DefaultValue = 15.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _TP { get; set; }

        private ExponentialMovingAverage _ema_12;
        private ExponentialMovingAverage _ema_26;
        private bool _ema_buy, _ema_sell;

        protected override void OnStart()
        {
            _ema_12 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 12);
            _ema_26 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 26);
        }

        protected override void OnBar()
        {
            var ActiveBuy = Positions.Find(_Label, SymbolName, TradeType.Buy);
            var ActiveSell = Positions.Find(_Label, SymbolName, TradeType.Sell);

            var volume = GetVolume();

            if (_ema_12.Result.HasCrossedAbove(_ema_26.Result.Last(1), 1))
            {
                _ema_buy = true;
                _ema_sell = false;
            }
            else if (_ema_12.Result.HasCrossedBelow(_ema_26.Result.Last(1), 1))
            {
                _ema_sell = true;
                _ema_buy = false;
            }

            if (ActiveBuy == null && _ema_buy)
            {
                if (ActiveSell != null)
                {
                    ClosePosition(ActiveSell);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, volume, _Label, _SL, _TP);
            }

            if (ActiveSell == null && _ema_sell)
            {
                if (ActiveBuy != null)
                {
                    ClosePosition(ActiveBuy);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, volume, _Label, _SL, _SL);
            }
        }

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

            double baseNumber = Account.Equity;

            double sizeInLots = Math.Round((baseNumber * _RiskPercent / 100) / (_SL * 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;
        }
    }
}

 


@amusleh

wmclennan77
29 Jul 2021, 13:27

RE:

amusleh said:

Hi,

Try this:

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.UTC, AccessRights = AccessRights.FullAccess)]
    public class RiskonSL : Robot
    {
        [Parameter("Label", DefaultValue = "")]
        public string _Label { get; set; }

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

        [Parameter("Max Allowed Lots", DefaultValue = 10.0, MaxValue = 100.0, MinValue = 0.01, Step = 0.01)]
        public double _MaxLots { get; set; }

        [Parameter("Stop Loss", DefaultValue = 10.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _SL { get; set; }

        [Parameter("Take Profit", DefaultValue = 15.0, MaxValue = 50.0, MinValue = 0.1, Step = 0.1)]
        public double _TP { get; set; }

        private ExponentialMovingAverage _ema_12;
        private ExponentialMovingAverage _ema_26;
        private bool _ema_buy, _ema_sell;

        protected override void OnStart()
        {
            _ema_12 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 12);
            _ema_26 = Indicators.ExponentialMovingAverage(Bars.ClosePrices, 26);
        }

        protected override void OnBar()
        {
            var ActiveBuy = Positions.Find(_Label, SymbolName, TradeType.Buy);
            var ActiveSell = Positions.Find(_Label, SymbolName, TradeType.Sell);

            var volume = GetVolume();

            if (_ema_12.Result.HasCrossedAbove(_ema_26.Result.Last(1), 1))
            {
                _ema_buy = true;
                _ema_sell = false;
            }
            else if (_ema_12.Result.HasCrossedBelow(_ema_26.Result.Last(1), 1))
            {
                _ema_sell = true;
                _ema_buy = false;
            }

            if (ActiveBuy == null && _ema_buy)
            {
                if (ActiveSell != null)
                {
                    ClosePosition(ActiveSell);
                }
                ExecuteMarketOrder(TradeType.Buy, SymbolName, volume, _Label, _SL, _TP);
            }

            if (ActiveSell == null && _ema_sell)
            {
                if (ActiveBuy != null)
                {
                    ClosePosition(ActiveBuy);
                }
                ExecuteMarketOrder(TradeType.Sell, SymbolName, volume, _Label, _SL, _SL);
            }
        }

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

            double baseNumber = Account.Equity;

            double sizeInLots = Math.Round((baseNumber * _RiskPercent / 100) / (_SL * 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;
        }
    }
}

 

Hi, 

Works perfect, thanks!


@wmclennan77