Lot Size Based on Risk % Parameter

Created at 21 Oct 2021, 04:30
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!
TH

thecaffeinatedtrader

Joined 22.07.2020

Lot Size Based on Risk % Parameter
21 Oct 2021, 04:30


Hi,

I have been trying to convert this bot so it enters a lot size / unit size based on a risk % parameter using either Account Balance or Account Equity.. not sure which will work better yet until I back test it... however.. when I got it to "work" it did enter trade lot sizes based on the equity or balance, but did not continue to update as the value of the account changed. 

This is the parameter I would like to use:

[Parameter("Risk %", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
public double RiskPerTrade { get; set; }

I have posted the original algo where it traded just based off a specified lot size ... If anyone knows how convert this properly it would be GREATLY appreciated.. I've been playing with this for days and nothing seems to be working for me. 

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.EasternStandardTime, AccessRights = AccessRights.None)]
    public class HighVolumeHours : Robot
    {

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

        [Parameter("Start Trading", DefaultValue = 6)]
        public double StartTime { get; set; }

        [Parameter("Stop Trading", DefaultValue = 16)]
        public double StopTime { get; set; }

        [Parameter("Source")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("Fast Type")]
        public MovingAverageType Fast { get; set; }

        [Parameter("Fast Period", DefaultValue = 21)]
        public int FastPeriod { get; set; }

        [Parameter("Medium Type")]
        public MovingAverageType Medium { get; set; }

        [Parameter("Medium Period", DefaultValue = 55)]
        public int MediumPeriod { get; set; }

        [Parameter("Bias Type")]
        public MovingAverageType Bias { get; set; }

        [Parameter("Bias Period", DefaultValue = 233)]
        public int BiasPeriod { get; set; }

        [Parameter("Stop Loss", DefaultValue = 20)]
        public int StopLoss { get; set; }

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

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

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

        [Parameter("Position Limit", MinValue = 1, Step = 1)]
        public int PositionLimit { get; set; }

        [Parameter("Quantity (Lots)", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double Quantity { get; set; }


        private double _volumeInUnits;
        private MovingAverage slowMa;
        private MovingAverage mediumMa;
        private MovingAverage fastMa;
        private DateTime _startTime;
        private DateTime _stopTime;

        protected override void OnStart()
        {
            fastMa = Indicators.MovingAverage(SourceSeries, FastPeriod, Fast);
            mediumMa = Indicators.MovingAverage(SourceSeries, MediumPeriod, Medium);
            slowMa = Indicators.MovingAverage(SourceSeries, BiasPeriod, Bias);
            _volumeInUnits = Symbol.QuantityToVolumeInUnits(Quantity);
            _startTime = Server.Time.Date.AddHours(StartTime);
            _stopTime = Server.Time.Date.AddHours(StopTime);
        }

        protected override void OnTick()
        {
            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }
        }

        protected override void OnBar()
        {
            int index = Bars.Count - 2;
            Entry(index);
        }

        private void Entry(int index)
        {
            var currentHours = Server.Time.TimeOfDay.TotalHours;
            bool istimecorrect = currentHours > StartTime && currentHours < StopTime;
            if (!istimecorrect)
                return;

            // Buy Only
            if (Bars.ClosePrices[index] > slowMa.Result[index])
            {
                // if fast crosses medium upward
                if (Positions.Count < PositionLimit && fastMa.Result[index] > mediumMa.Result[index] && fastMa.Result[index - 1] < mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, _volumeInUnits, InstanceName, StopLoss, null);
                }
            }
            // Sell only
            else if (Bars.ClosePrices[index] < slowMa.Result[index])
            {
                // if fast crosses medium downward
                if (Positions.Count < PositionLimit && fastMa.Result[index] < mediumMa.Result[index] && fastMa.Result[index - 1] > mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, _volumeInUnits, InstanceName, StopLoss, null);
                }
            }
        }

        private void SetTrailingStop()
        {

            var sellPositions = Positions.FindAll(InstanceName, SymbolName, TradeType.Sell);


            foreach (var 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, null);
                }
            }

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

            foreach (var 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, null);
                }
            }
        }
    }
}

 


@thecaffeinatedtrader
Replies

amusleh
21 Oct 2021, 09:35

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.EasternStandardTime, AccessRights = AccessRights.None)]
    public class HighVolumeHours : Robot
    {
        [Parameter("Instance Name", DefaultValue = "")]
        public string InstanceName { get; set; }

        [Parameter("Start Trading", DefaultValue = 6)]
        public double StartTime { get; set; }

        [Parameter("Stop Trading", DefaultValue = 16)]
        public double StopTime { get; set; }

        [Parameter("Source")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("Fast Type")]
        public MovingAverageType Fast { get; set; }

        [Parameter("Fast Period", DefaultValue = 21)]
        public int FastPeriod { get; set; }

        [Parameter("Medium Type")]
        public MovingAverageType Medium { get; set; }

        [Parameter("Medium Period", DefaultValue = 55)]
        public int MediumPeriod { get; set; }

        [Parameter("Bias Type")]
        public MovingAverageType Bias { get; set; }

        [Parameter("Bias Period", DefaultValue = 233)]
        public int BiasPeriod { get; set; }

        [Parameter("Stop Loss", DefaultValue = 20)]
        public int StopLoss { get; set; }

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

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

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

        [Parameter("Position Limit", MinValue = 1, Step = 1)]
        public int PositionLimit { get; set; }

        [Parameter("Risk %", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double RiskPerTrade { get; set; }

        private MovingAverage slowMa;
        private MovingAverage mediumMa;
        private MovingAverage fastMa;
        private DateTime _startTime;
        private DateTime _stopTime;

        protected override void OnStart()
        {
            fastMa = Indicators.MovingAverage(SourceSeries, FastPeriod, Fast);
            mediumMa = Indicators.MovingAverage(SourceSeries, MediumPeriod, Medium);
            slowMa = Indicators.MovingAverage(SourceSeries, BiasPeriod, Bias);
            _startTime = Server.Time.Date.AddHours(StartTime);
            _stopTime = Server.Time.Date.AddHours(StopTime);
        }

        protected override void OnTick()
        {
            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }
        }

        protected override void OnBar()
        {
            int index = Bars.Count - 2;
            Entry(index);
        }

        private void Entry(int index)
        {
            var currentHours = Server.Time.TimeOfDay.TotalHours;
            bool istimecorrect = currentHours > StartTime && currentHours < StopTime;
            if (!istimecorrect)
                return;

            // Buy Only
            if (Bars.ClosePrices[index] > slowMa.Result[index])
            {
                // if fast crosses medium upward
                if (Positions.Count < PositionLimit && fastMa.Result[index] > mediumMa.Result[index] && fastMa.Result[index - 1] < mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, GetVolume(StopLoss), InstanceName, StopLoss, null);
                }
            }
            // Sell only
            else if (Bars.ClosePrices[index] < slowMa.Result[index])
            {
                // if fast crosses medium downward
                if (Positions.Count < PositionLimit && fastMa.Result[index] < mediumMa.Result[index] && fastMa.Result[index - 1] > mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, GetVolume(StopLoss), InstanceName, StopLoss, null);
                }
            }
        }

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

            foreach (var 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, null);
                }
            }

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

            foreach (var 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, null);
                }
            }
        }

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

            // Change this to Account.Balance if you want to
            double baseNumber = Account.Equity;

            double sizeInLots = Math.Round((baseNumber * RiskPerTrade / 100) / (stopLossPips.Value * 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

thecaffeinatedtrader
21 Oct 2021, 13:46

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.EasternStandardTime, AccessRights = AccessRights.None)]
    public class HighVolumeHours : Robot
    {
        [Parameter("Instance Name", DefaultValue = "")]
        public string InstanceName { get; set; }

        [Parameter("Start Trading", DefaultValue = 6)]
        public double StartTime { get; set; }

        [Parameter("Stop Trading", DefaultValue = 16)]
        public double StopTime { get; set; }

        [Parameter("Source")]
        public DataSeries SourceSeries { get; set; }

        [Parameter("Fast Type")]
        public MovingAverageType Fast { get; set; }

        [Parameter("Fast Period", DefaultValue = 21)]
        public int FastPeriod { get; set; }

        [Parameter("Medium Type")]
        public MovingAverageType Medium { get; set; }

        [Parameter("Medium Period", DefaultValue = 55)]
        public int MediumPeriod { get; set; }

        [Parameter("Bias Type")]
        public MovingAverageType Bias { get; set; }

        [Parameter("Bias Period", DefaultValue = 233)]
        public int BiasPeriod { get; set; }

        [Parameter("Stop Loss", DefaultValue = 20)]
        public int StopLoss { get; set; }

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

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

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

        [Parameter("Position Limit", MinValue = 1, Step = 1)]
        public int PositionLimit { get; set; }

        [Parameter("Risk %", DefaultValue = 1, MinValue = 0.01, Step = 0.01)]
        public double RiskPerTrade { get; set; }

        private MovingAverage slowMa;
        private MovingAverage mediumMa;
        private MovingAverage fastMa;
        private DateTime _startTime;
        private DateTime _stopTime;

        protected override void OnStart()
        {
            fastMa = Indicators.MovingAverage(SourceSeries, FastPeriod, Fast);
            mediumMa = Indicators.MovingAverage(SourceSeries, MediumPeriod, Medium);
            slowMa = Indicators.MovingAverage(SourceSeries, BiasPeriod, Bias);
            _startTime = Server.Time.Date.AddHours(StartTime);
            _stopTime = Server.Time.Date.AddHours(StopTime);
        }

        protected override void OnTick()
        {
            if (IncludeTrailingStop)
            {
                SetTrailingStop();
            }
        }

        protected override void OnBar()
        {
            int index = Bars.Count - 2;
            Entry(index);
        }

        private void Entry(int index)
        {
            var currentHours = Server.Time.TimeOfDay.TotalHours;
            bool istimecorrect = currentHours > StartTime && currentHours < StopTime;
            if (!istimecorrect)
                return;

            // Buy Only
            if (Bars.ClosePrices[index] > slowMa.Result[index])
            {
                // if fast crosses medium upward
                if (Positions.Count < PositionLimit && fastMa.Result[index] > mediumMa.Result[index] && fastMa.Result[index - 1] < mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, GetVolume(StopLoss), InstanceName, StopLoss, null);
                }
            }
            // Sell only
            else if (Bars.ClosePrices[index] < slowMa.Result[index])
            {
                // if fast crosses medium downward
                if (Positions.Count < PositionLimit && fastMa.Result[index] < mediumMa.Result[index] && fastMa.Result[index - 1] > mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, GetVolume(StopLoss), InstanceName, StopLoss, null);
                }
            }
        }

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

            foreach (var 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, null);
                }
            }

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

            foreach (var 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, null);
                }
            }
        }

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

            // Change this to Account.Balance if you want to
            double baseNumber = Account.Equity;

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

 

 

So far so good... Thank you so much for your help! 


@thecaffeinatedtrader