Adding 'Max Drawdown' to algo

Created at 26 May 2022, 00: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

Adding 'Max Drawdown' to algo
26 May 2022, 00:30


Hi,

I am looking to add a feature to this bot that would allow me to optimize it under new parameters where it would stop trading all together if it reaches a max drawdown amount.. 

currently I have it to trade based on set amount of 'risk per trade %" but I would like to add the feature of 'max drawdown %'.

Please let me know if this is something that could even be done with Calgo and how to go about writing that, 

Thank you!

 

This is the current bot:

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 MovingAverageBot : Robot
    {

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

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

        [Parameter("Evening Close", DefaultValue = 16.5)]
        public double StopTime { get; set; }

        [Parameter("Evening Start", DefaultValue = 18.5)]
        public double StartTime2 { get; set; }

        [Parameter("Midnight Stop", DefaultValue = 24)]
        public double StopTime2 { get; set; }

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

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

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

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

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

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

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

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

        [Parameter("Exit Period")]
        public int ExitPeriod { get; set; }

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

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

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

        private MovingAverage ExitMA;
        private MovingAverage slowMa;
        private MovingAverage mediumMa;
        private MovingAverage fastMa;
        private DateTime _startTime;
        private DateTime _stopTime;
        private DateTime _startTime2;
        private DateTime _stopTime2;

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

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

        private void Exits(int index)
        {
            var positions = Positions.FindAll(InstanceName, SymbolName);

            foreach (var position in positions)

                if ((position.TradeType == TradeType.Buy && Bars.ClosePrices[index] < ExitMA.Result[index]) || (position.TradeType == TradeType.Sell && Bars.ClosePrices[index] > ExitMA.Result[index]))

                    ClosePosition(position);
        }


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

            // Buy Only
            if (Bars.ClosePrices[index] > slowMa.Result[index])
            {
                // if fast crosses medium upward
                if (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 (fastMa.Result[index] < mediumMa.Result[index] && fastMa.Result[index - 1] > mediumMa.Result[index - 1])
                {
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, GetVolume(StopLoss), InstanceName, StopLoss, null);
                }
            }
        }

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

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

            double sizeInLots = Math.Round((baseNumber * RiskPerTrade / 100) / (stopLossPips.Value * costPerPip), 1);

            var result = Symbol.QuantityToVolumeInUnits(sizeInLots);

            return result;
        }

    }
}

 


@thecaffeinatedtrader
Replies

amusleh
26 May 2022, 10:01

Hi,

Yes, you can do it, you have to use the history for getting historical trades to calculate drawdown.

You also need an initial value which can be your account initial balance/equity when cBot started, you can store it on a field variable.

Here is drawdown calculation formula: Maximum Drawdown (MDD) Definition (investopedia.com)

If you want to calculate equity drawdown then you have to use Positions net profit.


@amusleh

thecaffeinatedtrader
28 May 2022, 05:02

RE: Thank you, I will work on figuring that out. Good to know it can be done.

amusleh said:

Hi,

Yes, you can do it, you have to use the history for getting historical trades to calculate drawdown.

You also need an initial value which can be your account initial balance/equity when cBot started, you can store it on a field variable.

Here is drawdown calculation formula: Maximum Drawdown (MDD) Definition (investopedia.com)

If you want to calculate equity drawdown then you have to use Positions net profit.

 


@thecaffeinatedtrader