Use MoneyFixed Class in MQL5

 

Hello,

Based on another post of a person using the Money Fixed Risk in MQL5 to create a random expert advisor I write the following.

Can someone say please why it doesn't work? Sometimes it uses up to 3 times the risk as the input. The idea here is to use this file to open trades with the same risk each time (Expert\Money\MoneyFixedRisk.mqh). In this case the Stop Loss is based in ATR. I need to use it to test in Cryptos, FX, Stocks, and Futures. All CFD asset classes a broker can have.

#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>  
#include <Trade\AccountInfo.mqh>
#include <Expert\Money\MoneyFixedRisk.mqh>
CSymbolInfo    m_symbol;                     // symbol info object
CAccountInfo   m_account;                    // account info wrapper
CMoneyFixedRisk m_money;
CTrade         m_trade;                      // trading object

input int Factor=1;
input int Riesgo=1;
input int Periodo_EMA_ATR=12;
int ATR_handle, SMA_handle;
double  ATRArray[], SMAArray[];

int OnInit()
{
   ATR_handle = iCustom(_Symbol, _Period, "ATR_TV", Periodo_EMA_ATR);
   SMA_handle = iMA(_Symbol, _Period, Periodo_EMA_ATR, 0, MODE_SMA, PRICE_CLOSE);
   m_symbol.Name(Symbol());
   m_symbol.Refresh();
      if(!RefreshRates())
     {
      Print("Error RefreshRates. Bid=",DoubleToString(m_symbol.Bid(),Digits()),
            ", Ask=",DoubleToString(m_symbol.Ask(),Digits()));
      return(INIT_FAILED);
     }
//--- tuning for 3 or 5 digits
   int digits_adjust=1;
   if(m_symbol.Digits()==3 || m_symbol.Digits()==5)
      digits_adjust=10;
//---
   if(!m_money.Init(GetPointer(m_symbol),Period(),m_symbol.Point()*digits_adjust))
      return(INIT_FAILED);
   m_money.Percent(Riesgo); // 1% risk
//---
return(INIT_SUCCEEDED);}

void OnDeinit(const int reason)
{}

void OnTick()
  {
MqlRates PriceInfo [];
ArraySetAsSeries (PriceInfo,true);
int Data=CopyRates(Symbol(),Period(),0,Barras+1,PriceInfo);

ArraySetAsSeries (SMAArray, true);
CopyBuffer (SMA_handle, 0, 0, 5, SMAArray);

ArraySetAsSeries (ATRArray, true);
CopyBuffer (ATR_handle, 0, 0, 5, ATRArray);

   if(!RefreshRates())
      return;
//--- protection against the return value of "zero"
   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
      return;

double StopLossPips=Factor*ATRArray[1]; 


longCondition = // Here a I have a the conditions for trade the long side
shortCondition = // Here a I have a the conditions for trade the short side

if ( longCondition && shortCondition==false)
{
   double sl=0.0;
      double check_open_long_lot=0.0;

      //--- getting lot size for open long position (CMoneyFixedRisk)
      //--- variant #1: StopLoss=0.0
      sl=0.0;
      check_open_long_lot=m_money.CheckOpenLong(m_symbol.Ask(),sl);
      //Print("sl=0.0",
      //      ", CheckOpenLong: ",DoubleToString(check_open_long_lot,2),
      //      ", Balance: ",    DoubleToString(m_account.Balance(),2),
      //      ", Equity: ",     DoubleToString(m_account.Equity(),2),
      //      ", FreeMargin: ", DoubleToString(m_account.FreeMargin(),2));
      //--- variant #2: StopLoss!=0.0
      sl=m_symbol.Ask()-StopLossPips;
      check_open_long_lot=m_money.CheckOpenLong(m_symbol.Ask(),sl);
      //Print("sl=",DoubleToString(sl,m_symbol.Digits()),
      //      ", CheckOpenLong: ",DoubleToString(check_open_long_lot,2),
      //      ", Balance: ",    DoubleToString(m_account.Balance(),2),
      //      ", Equity: ",     DoubleToString(m_account.Equity(),2),
      //      ", FreeMargin: ", DoubleToString(m_account.FreeMargin(),2));
      if(check_open_long_lot==0.0)
         return;

      //--- check volume before OrderSend to avoid "not enough money" error (CTrade)
      double check_volume_lot=m_trade.CheckVolume(m_symbol.Name(),check_open_long_lot,m_symbol.Ask(),ORDER_TYPE_BUY);

      if(check_volume_lot!=0.0)
         if(check_volume_lot>=check_open_long_lot)
           {
            if(m_trade.Buy(check_volume_lot,NULL,m_symbol.Ask(),m_symbol.Ask()-StopLossPips,m_symbol.Ask()+Factor_profit*StopLossPips))
              {
               if(m_trade.ResultDeal()==0)
                  Print("Trade result Deal = 0, we have a problem opening trades");
              }
            else
               return; //Print("Trade was open");
           }
      else
         Print("CMoneyFixedRisk lot = ",DoubleToString(check_open_long_lot,2),
               ", CTrade lot = ",DoubleToString(check_volume_lot,2));
   
}
  
if ( longCondition==false && shortCondition)
{    double sl=0.0;
      double check_open_short_lot=0.0;

      //--- getting lot size for open long position (CMoneyFixedRisk)
      //--- variant #1: StopLoss=0.0
      sl=0.0;
      check_open_short_lot=m_money.CheckOpenShort(m_symbol.Bid(),sl);
      //Print("sl=0.0",
      //      ", CheckOpenLong: ",DoubleToString(check_open_long_lot,2),
      //      ", Balance: ",    DoubleToString(m_account.Balance(),2),
      //      ", Equity: ",     DoubleToString(m_account.Equity(),2),
      //      ", FreeMargin: ", DoubleToString(m_account.FreeMargin(),2));
      //--- variant #2: StopLoss!=0.0
      sl=m_symbol.Bid()+StopLossPips;
      check_open_short_lot=m_money.CheckOpenShort(m_symbol.Bid(),sl);
      //Print("sl=",DoubleToString(sl,m_symbol.Digits()),
      //      ", CheckOpenLong: ",DoubleToString(check_open_long_lot,2),
      //      ", Balance: ",    DoubleToString(m_account.Balance(),2),
      //      ", Equity: ",     DoubleToString(m_account.Equity(),2),
      //      ", FreeMargin: ", DoubleToString(m_account.FreeMargin(),2));
      if(check_open_short_lot==0.0)
         return;

      //--- check volume before OrderSend to avoid "not enough money" error (CTrade)
      double check_volume_lot=m_trade.CheckVolume(m_symbol.Name(),check_open_short_lot,m_symbol.Bid(),ORDER_TYPE_SELL);

      if(check_volume_lot!=0.0)
         if(check_volume_lot>=check_open_short_lot)
           {

            if(m_trade.Sell(check_volume_lot,NULL,m_symbol.Bid(),m_symbol.Bid()+StopLossPips,m_symbol.Bid()-Factor_profit*StopLossPips))
              { 
               if(m_trade.ResultDeal()==0)
                  Print("Trade result Deal = 0, we have a problem opening trades");
              }
            else
               return; //Print("Trade was open");
           }
      else
         Print("CMoneyFixedRisk lot = ",DoubleToString(check_open_short_lot,2),
               ", CTrade lot = ",DoubleToString(check_volume_lot,2));
   
}}
bool RefreshRates()
  {
//--- refresh rates
   if(!m_symbol.RefreshRates())
      return(false);
//--- protection against the return value of "zero"
   if(m_symbol.Ask()==0 || m_symbol.Bid()==0)
      return(false);
//---
   return(true);
  }
 
patagonia2015:

... Can someone say please why it doesn't work? Sometimes it uses up to 3 times the risk as the input. The idea here is to use this file to open trades with the same risk each time (Expert\Money\MoneyFixedRisk.mqh). In this case the Stop Loss is based in ATR...

It looks like you calculate the stop loss wrong. In this line:

double StopLossPips=Factor*ATRArray[1];

you multiply the ATR value by Factor (1 by default) but not by digits_adjust, so that for a 5 digit symbol your stop loss is in points but not in pips.

CheckOpenLong/Short will then return a volume that is too high for the true stop loss.

 
lippmaje:

It looks like you calculate the stop loss wrong. In this line:

you multiply the ATR value by Factor (1 by default) but not by digits_adjust, so that for a 5 digit symbol your stop loss is in points but not in pips.

CheckOpenLong/Short will then return a volume that is too high for the true stop loss.

That work for the Risk Calculation, thanks for the help.

I changed that line to:

double StopLossPips=Factor*ATRArray[1]*_Digits;

However I found another problem. Seems the calculation for the Stop Loss is not correct. The problem is the StopLoss is way higher of what is supposed to be.

For example in the case of the factor being "1", meaning the StopLoss should be only "1 time the ATR value of the period", actually is more than that. I noticed because is way higher, even 6 times the correct value on some trades.

Someone know why this happens? I cannot see the problem.

Basic Principles - Trading Operations - MetaTrader 5
Basic Principles - Trading Operations - MetaTrader 5
  • www.metatrader5.com
is an instruction given to a broker to buy or sell a financial instrument. There are two main types of orders: Market and Pending. In addition, there are special Take Profit and Stop Loss levels. is the commercial exchange (buying or selling) of a financial security. Buying is executed at the demand price (Ask), and Sell is performed at the...
 
patagonia2015:

That work for the Risk Calculation, thanks for the help.

I changed that line to: ...

However I found another problem. Seems the calculation for the Stop Loss is not correct. The problem is the StopLoss is way higher of what is supposed to be.

This cannot work:

double StopLossPips=Factor*ATRArray[1]*_Digits;

What's the value of ATRArray[1], show us some examples.

 
lippmaje:

This cannot work:

What's the value of ATRArray[1], show us some examples.

You are right. I need to use digits_adjust in order to get it right.

However, I found some problems in some stocks. It doesn't make much sense, I don't think is the digits problem because some stocks of 2 or 4 digits have problems while other don't.

Do you know if there is another step I need to take to correct this.

The problem now seems to be on some stocks, It works correctly on FX and futures.

 

You need to show more data for the cases where it seems to fail. You've already put some Print statements in, show this output. Looks like either your custom ATR is wrong, or the stop loss. Also check the balance that you set in Tester.

 
lippmaje:

You need to show more data for the cases where it seems to fail. You've already put some Print statements in, show this output. Looks like either your custom ATR is wrong, or the stop loss. Also check the balance that you set in Tester.

I'm using now the ATR by default in MT5.

One Stock CFD have the problem of [invalid stoploss] and for example send a market order to buy at 122.50 but the stoploss was at 50 and take profit at 195. Clearly the ATR is not that high.

 
patagonia2015:

I'm using now the ATR by default in MT5.

One Stock CFD have the problem of [invalid stoploss] and for example send a market order to buy at 122.50 but the stoploss was at 50 and take profit at 195. Clearly the ATR is not that high.

Then leave it as it was before:

double StopLossPips=Factor*ATRArray[1];

And check with the standard iATR if it works now. I assume your custom ATR computes values in pips, iATR does it in point.

Reason: