This post is split into 3 parts.
Part 1 explains how MT4 records Relative Drawdown, which is not well understood.
Part 2 will show my code to calculate Relative Drawdown against Balance just prior to a trade, which I inherently find much more useful.
Part 3 shows the mql4 code for calculating and displaying this Relative Drawdown against Balance.
How MT4 calculates Relative Drawdown:
Relative Drawdown in MT4’s report is calculated as a percentage of the difference of the historical equity high and equity low, against the equity high. E.g.
- Account balance at the start is $100.
- A trade is opened and then goes into floating profit of $10. This makes the equity high $100+$10 = $110.
- The trade then goes into negative territory of -$20. This makes the equity low $100-$20 = $80.
- Relative Drawdown(MT4) is calculated as: ($110-$80)/$110 * 100 = 27.27%
Go to How to Evaluate the Expert Testing Results for the actual code involved in the report generation.
Relative Drawdown against Balance:
I calculate a drawdown as the amount going below the Balance(at the start of a trade) instead of the Equity high. Rationale is that if a trade goes into profit but is not closed out, this floating profit never ‘belonged’ to the trader, or algorithm, and should not be construed as banked profit.
I will illustrate with a breakeven trade for both methods of calculation for Relative Drawdown :
- Account balance at the start is $100.
- A trade is opened and then goes into floating profit of $10. This makes the equity high $100+$10 = $110.
- A breakeven is set at the entry price.
- The price retraces and exits at breakeven.
For MT4’s Relative Drawdown, it is:
($110-$100)/$110 * 100 = 9.09%
For Relative Drawdown based on pre-trade Balance, it is:
($100-$100)/$100 * 100 = 0%
With MT4’s calculation, even though your Equity never dropped below your starting Balance, your Relative Drawdown is 9.09%. But with Relative Drawdown calculated against Balance, it is 0%. Which makes for more meaningful interpretation. (NB. technically the moment you open a trade, the spread already incurs a drawdown on the Balance, but I leave it out in the explanation here to simplify things)
Illustrating earlier example with Relative Drawdown calculated from Balance:
- Account Balance at the start is $100.
- A trade is opened and then goes into profit of $10. This makes the equity high $100+$10 = $110.
- The trade then goes into negative territory of -$20. This makes the equity low $100-$20 = $80.
- Relative Drawdown(Balance) is calculated as: ($100-$80)/$100 * 100 = 20.00%
We see now that for an account with a remaining Balance of $80 from a starting Balance of $100, it is more meaningful to state that it has suffered a 20% drawdown, instead of a 27.27% drawdown.
An extreme example to illustrate the less meaningful use of MT4’s Relative Drawdown calculation:
- Account Balance at the start is $100.
- A trade is opened and then goes into floating profit of $500. This makes the equity high $100+$500 = $600.
- The trade then goes into negative territory of -$20. This makes the equity low $100-$20 = $80.
- Relative Drawdown(MT4) is calculated as: ($600-$80)/$600 * 100 = 86.67%
Even though the account is only 20% below the starting Balance, MT4 reports the Relative Drawdown as 86.67%. Not so meaningful.
MQL4 Code:
Now the technical bit, to display this salient information, put into your code:
int start(){ //your code; MaxDD(); MaxDDM(); Comment(MaxDD(),"\n",MaxDDM()); //for displaying on your screen (adapt to your own comments as you see fit) return(0); }
Insert this function into your EA to display as a string for printing or commenting:
- Maximum Relative Drawdown % against on Balance
- Corresponding Maximum Relative Drawdown as an amount in your Deposit Currency (not so important)
- Time when the this Maximum Relative Drawdown occurred (useful for analysis)
string MaxDD(){ //Maximum drawdown data; displayed as "DD%(corresponding DD$),time of occurrence" string DC = AccountCurrency(); //Deposit Currency if(DC=="JPY")int DCdeci=0;else DCdeci=2; //to display Deposit Currency JPY and non-JPY with correct decimal places static double mddp=0, dd=0; static datetime y=0, m=0, d=0; double ddp=(NetDC()+NetSwap()+NetComm())/AccountBalance()*100; //drawdown percent if(ddp<mddp){ //if current DD%(ddp) is more than previous logged DD%(mddp) mddp=ddp; //log current DD% as latest maximum DD% dd=NetDC()+NetSwap()+NetComm(); //log DD$ at the instant that DD% is greatest y=TimeYear(TimeCurrent()); m=TimeMonth(TimeCurrent()); d=TimeDay(TimeCurrent()); } return(StringConcatenate("MaxDD: ", DoubleToStr(-mddp,2), "%", "(", DoubleToStr(-dd,DCdeci), " ", DC, "), ", y, ".", m, ".", d)); }
This function is the same as the above but with margin utilised added in. I find this is important as it gives a true picture of just how close you have come to a margin call. 😉 Particularly for accounts with low leverage.
string MaxDDM(){ //Maximum drawdown data including margin used string DC=AccountCurrency(); if(DC=="JPY")int DCdeci=0;else DCdeci=2; static double mddp=0, dd=0; static datetime y=0, m=0, d=0; double ddp=(NetDC()+NetSwap()+NetComm()-AccountMargin())/AccountBalance()*100; if(ddp<mddp){ mddp=ddp; dd=NetDC()+NetSwap()+NetComm()-AccountMargin(); y=TimeYear(TimeCurrent()); m=TimeMonth(TimeCurrent()); d=TimeDay(TimeCurrent()); } return(StringConcatenate("MaxDDM: ", DoubleToStr(-mddp,2), "%", "(", DoubleToStr(-dd,DCdeci), " ", DC, "), ", y, ".", m, ".", d)); }
Insert this into your deinit() to print it on deinitialisation. Useful when running non-visual backtests.
int deinit(){ Print(MaxDD()); //to print to Journal after Strategy Tester ends or EA disabled Print(MaxDDM()); return(0); }
The result should be that you see this on your screen:
And this in your journal:
Edit:
Include these for the MaxDD() and MaxDDM() functions to work:
double NetDC(){ //Net profit in deposit currency double ndc=0; for(int i=OrdersTotal()-1;i>=0;i--){ OrderSelect(i,SELECT_BY_POS,MODE_TRADES); if(OrderSymbol()==Symbol()&&OrderMagicNumber()==Magic)ndc+=OrderProfit(); } return(ndc); } double NetSwap(){ //Net swap in deposit currency double ns=0; for(int i=OrdersTotal()-1;i>=0;i--){ OrderSelect(i,SELECT_BY_POS,MODE_TRADES); if(OrderSymbol()==Symbol()&&OrderMagicNumber()==Magic)ns+=OrderSwap(); } return(ns); } double NetComm(){ //Net commission in deposit currency double nc=0; for(int i=OrdersTotal()-1;i>=0;i--){ OrderSelect(i,SELECT_BY_POS,MODE_TRADES); if(OrderSymbol()==Symbol()&&OrderMagicNumber()==Magic)nc+=OrderCommission(); } return(nc); }
This post is mirrored at MT4 Relative Drawdown @ Forex Factory
Discussion
No comments yet.