Adding 'Max Drawdown' to algo
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;
}
}
}
Replies
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
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