Expert Advisor Debugging Errors

 
Criei um EA com a ajuda do MQL5 Coder. A estratégia usada é a de Paridade de Risco, aplicada a uma cesta de ativos que inclui metais, indices e moedas. A ideia principal é alocar o risco de forma equilibrada entre os ativos, baseando-se na volatilidade de cada um.

Aqui está uma descrição da lógica do EA:

  1. Seleção dos Ativos: Utilizo uma lista de símbolos que quero negociar ( XAUUSD , XAGUUSD , SP500m, ND100m,  EURUSD , USJPY ).
  2. Cálculo da Volatilidade (ATR): Calculo a volatilidade de cada ativo usando o indicador Average True Range (ATR).
  3. Determinação dos Pesos: Os pesos de cada ativo são calculados inversamente proporcional à sua volatilidade.
  4. Alocação de Capital: O capital é alocado para cada ativo com base nos pesos calculados e na equidade da conta.
  5. Execução das Negociações: Abro posições de compra (Buy) para os ativos com os lotes calculados.

Código do EA:

#include <Trade\Trade.mqh>
CTrade trade;

input int ATRPeriod = 14; //ATR period
input double RiskFactor = 0.02; //Risk per trade
input double AccountRisk = 0.05;  //Total account risk

//Symbols to trade
string Symbols[] = {"XAUUSD", "EURUSD","XAGUSD","SP500m","ND100m","USDJPY"};


//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   for(int i = 0; i < ArraySize(Symbols); i++)
     {
      if(!SymbolSelect(Symbols[i], true))
        {
         Print("Failed to select symbol: ", Symbols[i]);
         return(INIT_FAILED);
        }
     }
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   double weights[];
   ArrayResize(weights, ArraySize(Symbols));

   double totalWeight = 0.0;

//Calculate weights based on ATR
   for(int i = 0; i < ArraySize(Symbols); ++i)
     {
      double atr = iATR(Symbols[i], PERIOD_D1, ATRPeriod);
      weights[i] = 1.0 / atr;
      totalWeight += weights[i];
     }

//Normalize weights
   for(int i = 0; i < ArraySize(Symbols); ++i)
     {
      weights[i] /= totalWeight;
     }

//Calculate the capital to allocate to each asset
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   for(int i = 0; i < ArraySize(Symbols); ++i)
     {
      double symbolRisk = AccountRisk * equity * weights[i];
      double lots = symbolRisk / (MarketInfo(Symbols[i], MODE_TICKVALUE) * ATR(Symbols[i]));

     }

//Adjust the lot size to the minimum lot size of the symbol
   double minLot = MarketInfo(Symbols[i], MODE_MINLOT);
   if(lots < minLot)
      lots = minLot;

//Check if is ready in a trade for the symbol
   if(PositionSelect(Symbols[i]) == false)
     {
      //Open a new trade
      trade.Buy(lots, Symbols[i]);
     }


  }

//+------------------------------------------------------------------+
//| Function to calculate ATR                                        |
//+------------------------------------------------------------------+
double ATR(string symbol)
  {
   double atr = iATR(symbol, PERIOD_D1, ATRPeriod);
   return(atr);
  }
//+------------------------------------------------------------------+

Estou enfrentando vários errors. Principalmente  com essa linha: 

double lots = symbolRisk / (MarketInfo(Symbols[i], MODE_TICKVALUE) * ATR(Symbols[i]));

O que Já Tentei

  1. Verificação de Símbolos: Certifiquei-me de que todos os símbolos estão corretamente selecionados no OnInit .
  2. Cálculo do ATR: Verifiquei que a função ATR está retornando valores válidos.
  3. Substituição de MarketInfo: Usei SymbolInfoDouble para obter os valores dos ticks e do lote mínimo.

Apesar dessas tentativas, os erros persistem. Acredito que possa haver problemas de lógica ou de sintaxe que estou deixando passar.

Gostaria de pedir a ajuda de vocês para:

  1. Revisar o código e identificar possíveis problemas de lógica e/ou sintaxe.
  2. Sugerir correções para os erros mencionados.
  3. Qualquer outra melhoria que possa ser feita no EA para garantir que ele funcione conforme o esperado.

Agradeço antecipadamente pela ajuda!

 

Os código gerados pelas IAs sempre apresentam falhas que precisam ser corrigidas: https://www.mql5.com/en/forum/442670#comment_45314226... Dê uma olhada também nesse artigo (ainda sem tradução para o Português): https://www.mql5.com/en/articles/14651...

 

Corrigi os erros de compilação (acho que não mexi na sua lógica), mas dê uma olhada no cálculo dos lotes porque não está legal:

#include <Trade\Trade.mqh>
CTrade trade;

input int ATRPeriod = 14; //ATR period
input double RiskFactor = 0.02; //Risk per trade
input double AccountRisk = 0.05;  //Total account risk
input double StopLoss = 0.0; //Stop Loss (% ADR)
input double TakeProfit = 0.0; //Take Profit (% ADR)

//Symbols to trade
string Symbols[] = {"XAUUSD", "EURUSD","XAGUSD","SP500m","ND100m","USDJPY"};
//---
int SYM_NR = ArraySize(Symbols);
int handleAdr[];
//+--------------------------------------------------------------------------------------------------------------------+
//| Expert initialization function                                                                                     |
//+--------------------------------------------------------------------------------------------------------------------+
int OnInit()
  {
   if(ArrayResize(handleAdr, SYM_NR) < 0)
     {
      Print(__FUNCTION__, " - Error redefining the size of the handleAdr[] array.");
      return(INIT_FAILED);
     }
//---
   for(int i = 0; i < SYM_NR; i++)
     {
      if(!SymbolSelect(Symbols[i], true))
        {
         Print("Failed to select symbol: ", Symbols[i]);
         return(INIT_FAILED);
        }
      //--- Average Daily Range indicator
      handleAdr[i] = iATR(Symbols[i], PERIOD_D1, ATRPeriod);
      if(handleAdr[i] == INVALID_HANDLE)
        {
         Print(__FUNCTION__, " - Error creating ADR indicator: ", Symbols[i]);
         return(INIT_FAILED);
        }
     }
   return(INIT_SUCCEEDED);
  }
//+--------------------------------------------------------------------------------------------------------------------+
//| Expert deinitialization function                                                                                   |
//+--------------------------------------------------------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- Free the handle of the indicators - Multiple Symbols
   for(int i = SYM_NR - 1; i == 0; i --)
     {
      if(handleAdr[i] != INVALID_HANDLE)
        {
         IndicatorRelease(handleAdr[i]);
        }
     }
  }
//+--------------------------------------------------------------------------------------------------------------------+
//| Expert tick function                                                                                               |
//+--------------------------------------------------------------------------------------------------------------------+
void OnTick()
  {
   double weights[], adr[1], adrSymbol[];
   if(ArrayResize(weights, SYM_NR) < 0)
     {
      Print(__FUNCTION__, " - Error redefining the size of the weights[] array.");
      return;
     }
   if(ArrayResize(adrSymbol, SYM_NR) < 0)
     {
      Print(__FUNCTION__, " - Error redefining the size of the adrSymbol[] array.");
      return;
     }
   double totalWeight = 0.0;

//Calculate weights based on ATR
   for(int i = 0; i < SYM_NR; ++i)
     {
      //--- Average Daily Range indicator
      if(CopyBuffer(handleAdr[i], MAIN_LINE, 1, 1, adr) < 0)
        {
         Print(__FUNCTION__, " - Failed to copy data from ADR indicator: ", Symbols[i]);
         return;
        }
      adrSymbol[i] = adr[0];
      weights[i] = 1.0 / adrSymbol[i];
      totalWeight += weights[i];
     }

//Normalize weights
   for(int i = 0; i < SYM_NR; ++i)
     {
      weights[i] /= totalWeight;
      Print(weights[i], " - ", Symbols[i]);
     }
   return;
//Calculate the capital to allocate to each asset
   double equity = AccountInfoDouble(ACCOUNT_EQUITY);
   for(int i = 0; i < SYM_NR; ++i)
     {
      double symbolRisk = AccountRisk * equity * weights[i];
      double tickValue;
      if(!SymbolInfoDouble(Symbols[i], SYMBOL_TRADE_TICK_VALUE, tickValue))
        {
         Print(__FUNCTION__, " - Error getting the SYMBOL_TRADE_TICK_VALUE: ", Symbols[i]);
         return;
        }
      double lots = symbolRisk / (tickValue * adrSymbol[i]);
      //Adjust the lot size to the minimum lot size of the symbol
      if(!NormalizeVolume(Symbols[i], lots))
        {
         Print(__FUNCTION__, " - Error ", GetLastError(), " when normalizing the volume: ", Symbols[i]);
         return;
        }

      //Check if is ready in a trade for the symbol
      if(PositionSelect(Symbols[i]) == false)
        {
         double ask;
         if(!SymbolInfoDouble(Symbols[i], SYMBOL_ASK, ask))
           {
            Print(__FUNCTION__, " - Error getting the SYMBOL_ASK: ", Symbols[i]);
            return;
           }
         double sl = 0.0;
         if(StopLoss > 0.0)
           {
            sl = NormalizePrice(Symbols[i], ask - StopLoss * adrSymbol[i]);
           }
         double tp = 0.0;
         if(TakeProfit > 0.0)
           {
            tp = NormalizePrice(Symbols[i], ask + TakeProfit * adrSymbol[i]);
           }
         //Open a new trade
         trade.Buy(lots, Symbols[i], ask, sl, tp);
        }
     }
  }
//+--------------------------------------------------------------------------------------------------------------------+
//| This function normalizes the volume according to the minimum volume change step                                    |
//+--------------------------------------------------------------------------------------------------------------------+
bool NormalizeVolume(string symbol, double &lots)
  {
   ResetLastError();
//--- Minimal and maximal allowed volume for trade operations
   double LotMin  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MIN);
   double LotMax  = SymbolInfoDouble(symbol, SYMBOL_VOLUME_MAX);
//--- Get minimal step of volume changing
   double LotStep = SymbolInfoDouble(symbol, SYMBOL_VOLUME_STEP);

//--- Check if an execution error occurred
   if(GetLastError() != ERR_SUCCESS)
     {
      return(false);
     }

//--- Normalizes the volume
   lots = LotMin + MathFloor((lots - LotMin) / LotStep) * LotStep;
   lots = NormalizeDouble(MathMin(LotMax, MathMax(LotMin, lots)), 2);

//--- Normalized volume
   return(true);
  }
//+--------------------------------------------------------------------------------------------------------------------+
//| This function normalizes and adjusts the price to the TICK SIZE                                                    |
//+--------------------------------------------------------------------------------------------------------------------+
double NormalizePrice(string symbol, double price)
  {
   ResetLastError();
//--- Get the minimal price change
   double tick_size = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_SIZE);
//--- Get the number of decimal digits
   int decimal_digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);

//--- Return the price normalized
   if(tick_size == 0.0 || GetLastError() != ERR_SUCCESS)
     {
      return(NormalizeDouble(price, decimal_digits));
     }

//--- Return the price normalized and adjusted to the TICK SIZE
   return(NormalizeDouble(MathRound(price / tick_size) * tick_size, decimal_digits));
  }
//+--------------------------------------------------------------------------------------------------------------------+
 

No código que enviei no comentário anterior, esqueci de apagar as duas linhas destacadas abaixo:

//Normalize weights
   for(int i = 0; i < SYM_NR; ++i)
     {
      weights[i] /= totalWeight;
      Print(weights[i], " - ", Symbols[i]);
     }
   return;
//Calculate the capital to allocate to each asset
 
Vinicius Pereira De Oliveira #:

No código que enviei no comentário anterior, esqueci de apagar as duas linhas destacadas abaixo:

Obrigado pela prontidão e conselhos. Vou testar suas sugestões e tentar melhorar o cálculo dos lotes.