OrderClose with Drawdown error

 

I'm trying to do something very simple, but at the same time it's resisting me. I want to close the operations when the DD exceeds a value.

But when the backtest ends, I check it and the value has not been respected, what could it be due to?

Any ideas guys? Thank you in advance

void OnTick()
  {
double  DrawdownAllowed = 2.0;
double Balance = AccountInfoDouble(ACCOUNT_BALANCE); double Equity = AccountInfoDouble(ACCOUNT_EQUITY); double DrawDown = ((Equity - Balance) / Equity) * 100; if(DrawDown >= DrawdownAllowed) { CloseAllBuyPositions(); CloseAllSellPositions(); } //....all rest code }
void CloseAllBuyPositions()
  {
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      long PositionDirection = PositionGetInteger(POSITION_TYPE);
      if(PositionDirection== POSITION_TYPE_BUY)
         Trade.PositionClose(ticket);
     }
  }

void CloseAllSellPositions()
  {
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      long PositionDirection = PositionGetInteger(POSITION_TYPE);
      if(PositionDirection== POSITION_TYPE_SELL)
         Trade.PositionClose(ticket);
     }
  }


The funny thing about the case is that when I check the chart, I don't see that upper Drawdown, and I have the feeling that everything is fine. However, the report says that it has even reached 5%


Maximum Balance Drawdown: 561.25 (4.71%)

Maximum Equity Reduction: 666.34 (5.59%)

Relative balance sheet reduction: 4.71% (561.25)

Relative equity reduction: 5.59% (666.34)


Note - I thought this could be because running the backtest on OHLC M1 had moved the price further. However, it happens exactly the same on every tick based on actual ticks.

Testing trading strategies on real ticks
Testing trading strategies on real ticks
  • www.mql5.com
The article provides the results of testing a simple trading strategy in three modes: "1 minute OHLC", "Every tick" and "Every tick based on real ticks" using actual historical data.
 
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseAllBuyPositions()
  {
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      long PositionDirection = PositionGetInteger(POSITION_TYPE);
      if(PositionDirection== POSITION_TYPE_BUY)
        {
         closed = false;
         while(!closed && RetriesToClose > 0)
           {
            if(Trade.PositionClose(ticket) == true)
              {
               closed = true;
              }
            else
              {
               RetriesToClose--;
               Sleep(1000);
               if(RetriesToClose == 0)
                 {
                  Print("Position with ticket ",ticket," could not be closed after 5 retries");
                 }
              }
           }
        }
     }
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CloseAllSellPositions()
  {
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      ulong ticket = PositionGetTicket(i);
      long PositionDirection = PositionGetInteger(POSITION_TYPE);
      if(PositionDirection== POSITION_TYPE_SELL)
        {
         closed = false;
         while(!closed && RetriesToClose > 0)
           {
            if(Trade.PositionClose(ticket) == true)
              {
               closed = true;
              }
            else
              {
               RetriesToClose--;
               Sleep(1000);
               if(RetriesToClose == 0)
                 {
                  Print("Position with ticket ",ticket," could not be closed after 5 retries");
                 }
              }
           }
        }
     }
  }

Later I improved the code in case some operation was lost along the way, but it is not the case

 

I've been hesitating a bit between the two versions because I'm a little sleepy, but definitely neither of them works as expected


void OnTick()
  {

   double Balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double Equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double DrawDown = ((Equity - Balance) / Equity) * 100;
   if(DrawDown >= DrawdownAllowed)
     {
      CloseAllBuyPositions();
      CloseAllSellPositions();
     }
   double Balance = AccountInfoDouble(ACCOUNT_BALANCE);
   double Equity = AccountInfoDouble(ACCOUNT_EQUITY);
   double DrawDown = ((Balance - Equity)/ Balance)*100;
   if(DrawDown >= DrawdownAllowed)
     {
      CloseAllBuyPositions();
      CloseAllSellPositions();
     }
 

My last try. I give up

   double  DrawdownAllowed = 2.0;
   double  balance;
   double  equity;
   double  max_equity =0;


   equity = AccountInfoDouble(ACCOUNT_EQUITY);
   balance = AccountInfoDouble(ACCOUNT_BALANCE);
   max_equity = MathMax(equity, max_equity);

   double DD = (max_equity - equity)/max_equity*100;

   if(DD >= DrawdownAllowed)
     {
      CloseAllBuyPositions();
      CloseAllSellPositions();
     }
 
Enrique Enguix: I'm trying to do something very simple, but at the same time it's resisting me. I want to close the operations when the DD exceeds a value. But when the backtest ends, I check it and the value has not been respected, what could it be due to? Any ideas guys? Thank you in advance

That is not how you measure drawdown. Your equation "DrawDown = ((Equity - Balance) / Equity) * 100" is not how you measure drawdown.

void OnTick( void ) {
   static double dbEquityMaximum           = WRONG_VALUE,
                 dbBalanceMaximum          = WRONG_VALUE;

          double dbEquityCurrent           = AccountInfoDouble( ACCOUNT_EQUITY  ),
                 dbBalanceCurrent          = AccountInfoDouble( ACCOUNT_BALANCE );

                 dbEquityMaximum           = fmax( dbEquityCurrent,  dbEquityMaximum  );
                 dbBalanceMaximum          = fmax( dbBalanceCurrent, dbBalanceMaximum );

          double dbEquityDrawdown          = dbEquityMaximum   - dbEquityCurrent,
                 dbBalanceDrawdown         = dbBalanceMaximum  - dbBalanceCurrent,
                 dbEquityDrawdownRelative  = dbEquityDrawdown  / dbEquityMaximum,
                 dbBalanceDrawdownRelative = dbBalanceDrawdown / dbBalanceMaximum;
};

Please note that with the above equations, a positive value is a drawdown, and a negative value is NOT drawdown.

If you prefer negative to be a drawdown, then change it to ( Current - Maximum ) instead of ( Maximum - Current ) as I used above.

 
Fernando Carreiro #:

That is not how you measure drawdown. Your equation "DrawDown = ((Equity - Balance) / Equity) * 100" is not how you measure drawdown.

Please note that with the above equations, a positive value is a drawdown, and a negative value is NOT drawdown.

If you prefer negative to be a drawdown, then change it to ( Current - Maximum ) instead of ( Maximum - Current ) as I used above.

Things I've learned from your answer:

1. WRONG_VALUE

2. fmax

3. The rest of what you have written


You are my n1 mentor! THANKS!

 
Enrique Enguix #: THANKS!

You are welcome!

 
Enrique Enguix #: Things I've learned from your answer: 1. WRONG_VALUE

Please note that my example is incompatible with accounts that allow negative equity or balance. So, it may be better to use this instead ...

static double dbEquityMaximum  = -DBL_MAX,
              dbBalanceMaximum = -DBL_MAX;
Reason: