Guia prático do MQL5: Registrando o histórico de negociações em um arquivo e criando gráficos de saldo para cada símbolo no Excel

Anatoli Kazharski | 24 março, 2014

Introdução

Ao me comunicar em vários fóruns, utilizei frequentemente exemplos de meus resultados de teste exibidos como capturas de tela de gráficos do Microsoft Excel. Por muitas vezes me foi pedido para explicar como tais gráficos podem ser criados. O Excel oferece características amplas para criação de gráficos e existem vários livros sobre esse assunto. Para encontrar a informação necessária em um livro, talvez seja necessário lê-lo por inteiro. Agora, enfim, eu tenho algum tempo para explicar tudo nesse artigo.

Nos dois artigos anteriores Guia prático do MQL5: Consultor Especialista multi-moeda - Abordagem simples, organizada e rápida e Guia prático do MQL5: Desenvolvendo um Consultor Especialista multi-moeda com número ilimitado de parâmetros lidamos com o desenvolvimento de CEs multi-moeda no MQL5. Sabemos que os resultados de testes no MetaTrader 5 são exibidos como uma curva de balanço/igualdade geral, isto é, se você precisa visualizar os resultados para cada símbolo separadamente, você deve, mais uma vez, ir nos parâmetros externos do Consultor Especialista para desabilitar todos os símbolos exceto daquele cujos resultados são necessários e depois executar o teste novamente. Isso é inconveniente.

Então hoje vou mostrar a você um método simples de como você pode obter gráficos de balanço para todos os símbolos juntamente com o resultado cumulativo de um Consultor Especialista multi-moeda em um único diagrama do Excel com apenas alguns cliques. Para reconstruir o exemplo, tomaremos o Consultor Especialista multi-moeda do artigo anterior. Ele será aperfeiçoado com uma função que escreverá o histórico de negociações e curvas de saldo para todos os símbolos para um arquivo .csv na conclusão do teste. Além disso, adicionaremos outra coluna para o relatório para mostrar as reduções de todos as máximas locais.

Vamos criar um catálogo do Excel montado de forma a ser capaz de conectar-se ao arquivo de dados. O catálogo pode ser aberto o tempo todo, então não será necessário ser fechado antes de executar outro teste. Na conclusão do teste, você só precisará atualizar os dados pressionando uma determinada tecla para ser capaz de ver as alterações no relatório e no gráfico.


Desenvolvimento do Consultor Especialista

Não haverão alterações significativas em nosso CE, apenas adicionaremos algumas funções. Vamos começar adicionando a estrutura e o arranjo para os balanços de símbolo ao arquivo principal.

//--- Arrays for balances
struct Balance
  {
   double            balance[];
  };
//--- Array of balances for all symbols
Balance symbol_balance[];

Depois, criamos o arquivo incluído Report.mqh em separado para funções que geram relatórios de teste e incluem-no no arquivo principal do Consultor Especialista (veja a linha destacada no código acima):

//--- Include custom libraries
#include "Include/Auxiliary.mqh"
#include "Include/Enums.mqh"
#include "Include/Errors.mqh"
#include "Include/FileFunctions.mqh"
#include "Include/InitializeArrays.mqh"
#include "Include/Report.mqh"
#include "Include/ToString.mqh"
#include "Include/TradeFunctions.mqh"
#include "Include/TradeSignals.mqh"

Vamos primeiro criar uma estrutura de propriedade de negociação, como aquela que já temos no projeto para posição e propriedades do símbolo. Para fazê-lo, adicionamos a enumeração dos identificadores de propriedade ao arquivo Enums.mqh:

//+------------------------------------------------------------------+
//| Enumeration of deal properties                                   |
//+------------------------------------------------------------------+
enum ENUM_DEAL_PROPERTIES
  {
   D_SYMBOL     = 0, // Deal symbol
   D_COMMENT    = 1, // Deal comment
   D_TYPE       = 2, // Deal type
   D_ENTRY      = 3, // Deal entry - entry in, entry out, reverse
   D_PRICE      = 4, // Deal price
   D_PROFIT     = 5, // Deal result (profit/loss)
   D_VOLUME     = 6, // Deal volume
   D_SWAP       = 7, // Cumulative swap on close
   D_COMMISSION = 8, // Deal commission
   D_TIME       = 9, // Deal time
   D_ALL        = 10 // All of the above mentioned deal properties
  };

Além disso, no arquivo Report.mqh criamos a estrutura da propriedade da negociação e a função GetHistoryDealProperties() que retorna uma propriedade da negociação. A função aceita dois parâmetros: tíquete de negociação e identificador de propriedade.

Abaixo, você pode ver o código da estrutura e a função GetHistoryDealProperties():

//--- Deal properties in the history
struct HistoryDealProperties
  {
   string            symbol;     // Symbol
   string            comment;    // Comment
   ENUM_DEAL_TYPE    type;       // Deal type
   ENUM_DEAL_ENTRY   entry;      // Direction
   double            price;      // Price
   double            profit;     // Profit/Loss
   double            volume;     // Volume
   double            swap;       // Swap
   double            commission; // Commission
   datetime          time;       // Time
  };
//--- Variable of deal properties
HistoryDealProperties  deal;
//+------------------------------------------------------------------+
//| Gets deal properties by ticket                                   |
//+------------------------------------------------------------------+
void GetHistoryDealProperties(ulong ticket_number,ENUM_DEAL_PROPERTIES history_deal_property)
  {
   switch(history_deal_property)
     {
      case D_SYMBOL     : deal.symbol=HistoryDealGetString(ticket_number,DEAL_SYMBOL);                 break;
      case D_COMMENT    : deal.comment=HistoryDealGetString(ticket_number,DEAL_COMMENT);               break;
      case D_TYPE       : deal.type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket_number,DEAL_TYPE);    break;
      case D_ENTRY      : deal.entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_number,DEAL_ENTRY); break;
      case D_PRICE      : deal.price=HistoryDealGetDouble(ticket_number,DEAL_PRICE);                   break;
      case D_PROFIT     : deal.profit=HistoryDealGetDouble(ticket_number,DEAL_PROFIT);                 break;
      case D_VOLUME     : deal.volume=HistoryDealGetDouble(ticket_number,DEAL_VOLUME);                 break;
      case D_SWAP       : deal.swap=HistoryDealGetDouble(ticket_number,DEAL_SWAP);                     break;
      case D_COMMISSION : deal.commission=HistoryDealGetDouble(ticket_number,DEAL_COMMISSION);         break;
      case D_TIME       : deal.time=(datetime)HistoryDealGetInteger(ticket_number,DEAL_TIME);          break;
      case D_ALL        :
         deal.symbol=HistoryDealGetString(ticket_number,DEAL_SYMBOL);
         deal.comment=HistoryDealGetString(ticket_number,DEAL_COMMENT);
         deal.type=(ENUM_DEAL_TYPE)HistoryDealGetInteger(ticket_number,DEAL_TYPE);
         deal.entry=(ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket_number,DEAL_ENTRY);
         deal.price=HistoryDealGetDouble(ticket_number,DEAL_PRICE);
         deal.profit=HistoryDealGetDouble(ticket_number,DEAL_PROFIT);
         deal.volume=HistoryDealGetDouble(ticket_number,DEAL_VOLUME);
         deal.swap=HistoryDealGetDouble(ticket_number,DEAL_SWAP);
         deal.commission=HistoryDealGetDouble(ticket_number,DEAL_COMMISSION);
         deal.time=(datetime)HistoryDealGetInteger(ticket_number,DEAL_TIME);                           break;
         //---
      default: Print("The passed deal property is not listed in the enumeration!");                          return;
     }
  }

Também precisaremos de várias funções que converterão algumas propriedades de negociação aos valores da cadeia. Essas simples funções retornam um hífen ("-") se o valor passado for vazio ou zero. Vamos registrá-los no arquivo ToString.mqh:

//+------------------------------------------------------------------+
//| Returns the symbol name, otherwise - dash                        |
//+------------------------------------------------------------------+
string DealSymbolToString(string deal_symbol)
  {
   return(deal_symbol=="" ? "-" : deal_symbol);
  }
//+------------------------------------------------------------------+
//| Converts deal type to string                                     |
//+------------------------------------------------------------------+
string DealTypeToString(ENUM_DEAL_TYPE deal_type)
  {
   string str="";
//---
   switch(deal_type)
     {
      case DEAL_TYPE_BUY                      : str="buy";                      break;
      case DEAL_TYPE_SELL                     : str="sell";                     break;
      case DEAL_TYPE_BALANCE                  : str="balance";                  break;
      case DEAL_TYPE_CREDIT                   : str="credit";                   break;
      case DEAL_TYPE_CHARGE                   : str="charge";                   break;
      case DEAL_TYPE_CORRECTION               : str="correction";               break;
      case DEAL_TYPE_BONUS                    : str="bonus";                    break;
      case DEAL_TYPE_COMMISSION               : str="commission";               break;
      case DEAL_TYPE_COMMISSION_DAILY         : str="commission daily";         break;
      case DEAL_TYPE_COMMISSION_MONTHLY       : str="commission monthly";       break;
      case DEAL_TYPE_COMMISSION_AGENT_DAILY   : str="commission agent daily";   break;
      case DEAL_TYPE_COMMISSION_AGENT_MONTHLY : str="commission agent monthly"; break;
      case DEAL_TYPE_INTEREST                 : str="interest";                 break;
      case DEAL_TYPE_BUY_CANCELED             : str="buy canceled";             break;
      case DEAL_TYPE_SELL_CANCELED            : str="sell canceled";            break;
      //--- Unknown deal type
      default : str="unknown";
     }
//---
   return(str);
  }
//+------------------------------------------------------------------+
//| Converts direction of deal to string                             |
//+------------------------------------------------------------------+
string DealEntryToString(ENUM_DEAL_ENTRY deal_entry)
  {
   string str="";
//---
   switch(deal_entry)
     {
      case DEAL_ENTRY_IN    : str="in";            break;
      case DEAL_ENTRY_OUT   : str="out";           break;
      case DEAL_ENTRY_INOUT : str="in/out";        break;
      case DEAL_ENTRY_STATE : str="status record"; break;
      //--- Unknown direction type
      default : str="unknown";
     }
//---
   return(str);
  }
//+------------------------------------------------------------------+
//| Converts volume to string                                        |
//+------------------------------------------------------------------+
string DealVolumeToString(double deal_volume)
  {
   return(deal_volume<=0 ? "-" : DoubleToString(deal_volume,2));
  }
//+------------------------------------------------------------------+
//| Converts price to string                                         |
//+------------------------------------------------------------------+
string DealPriceToString(double deal_price,int digits)
  {
   return(deal_price<=0 ? "-" : DoubleToString(deal_price,digits));
  }
//+------------------------------------------------------------------+
//| Converts deal result to string                                   |
//+------------------------------------------------------------------+
string DealProfitToString(string deal_symbol,double deal_profit)
  {
   return((deal_profit==0 || deal_symbol=="") ? "-" : DoubleToString(deal_profit,2));
  }
//+------------------------------------------------------------------+
//| Converts swap to string                                          |
//+------------------------------------------------------------------+
string DealSwapToString(double deal_swap)
  {
   return(deal_swap<=0 ? "-" : DoubleToString(deal_swap,2));
  }

Agora, tudo está pronto para escrever a função CreateSymbolBalanceReport() que prepara os dados para o relatório e os escreve no arquivo LastTest.csv. É muito simples: primeiro escrevemos o cabeçalho (note como a cadeia é ajustada se o teste foi executado para mais de um símbolo), depois as propriedades da negociação necessárias para o relatório são concatenadas consecutivamente dentro da cadeia que é escrita em seguida ao arquivo.

Abaixo está o código da função CreateSymbolBalanceReport():

//+------------------------------------------------------------------+
//| Creates the test report on deals in .csv format                  |
//+------------------------------------------------------------------+
void CreateSymbolBalanceReport()
  {
   int    file_handle =INVALID_HANDLE; // File handle
   string path        ="";             // File path

//--- If an error occurred when creating/getting the folder, exit
   if((path=CreateInputParametersFolder())=="")
      return;
//--- Create file to write data in the common folder of the terminal
   file_handle=FileOpen(path+"\\LastTest.csv",FILE_CSV|FILE_WRITE|FILE_ANSI|FILE_COMMON);
//--- If the handle is valid (file created/opened)
   if(file_handle>0)
     {
      int    digits          =0;   // Number of decimal places in the price
      int    deals_total     =0;   // Number of deals in the specified history
      ulong  ticket          =0;   // Deal ticket
      double drawdown_max    =0.0; // Maximum drawdown
      double balance         =0.0; // Balance
      //---
      string delimeter       =","; // Delimiter
      string string_to_write ="";  // To generate the string for writing

      //--- Generate the header string
      string headers="TIME,SYMBOL,DEAL TYPE,ENTRY TYPE,VOLUME,PRICE,SWAP($),PROFIT($),DRAWDOWN(%),BALANCE";
      //--- If more than one symbol is involved, modify the header string
      if(SYMBOLS_COUNT>1)
        {
         for(int s=0; s<SYMBOLS_COUNT; s++)
            StringAdd(headers,","+InputSymbols[s]);
        }
      //--- Write the report headers
      FileWrite(file_handle,headers);
      //--- Get the complete history
      HistorySelect(0,TimeCurrent());
      //--- Get the number of deals
      deals_total=HistoryDealsTotal();
      //--- Resize the array of balances according to the number of symbols
      ArrayResize(symbol_balance,SYMBOLS_COUNT);
      //--- Resize the array of deals for each symbol
      for(int s=0; s<SYMBOLS_COUNT; s++)
         ArrayResize(symbol_balance[s].balance,deals_total);
      //--- Iterate in a loop and write the data
      for(int i=0; i<deals_total; i++)
        {
         //--- Get the deal ticket
         ticket=HistoryDealGetTicket(i);
         //--- Get all the deal properties
         GetHistoryDealProperties(ticket,D_ALL);
         //--- Get the number of digits in the price
         digits=(int)SymbolInfoInteger(deal.symbol,SYMBOL_DIGITS);
         //--- Calculate the overall balance
         balance+=deal.profit+deal.swap+deal.commission;
         //--- Generate a string for writing via concatenation
         StringConcatenate(string_to_write,
                           deal.time,delimeter,
                           DealSymbolToString(deal.symbol),delimeter,
                           DealTypeToString(deal.type),delimeter,
                           DealEntryToString(deal.entry),delimeter,
                           DealVolumeToString(deal.volume),delimeter,
                           DealPriceToString(deal.price,digits),delimeter,
                           DealSwapToString(deal.swap),delimeter,
                           DealProfitToString(deal.symbol,deal.profit),delimeter,
                           MaxDrawdownToString(i,balance,max_drawdown),delimeter,
                           DoubleToString(balance,2));

         //--- If more than one symbol is involved, write their balance values
         if(SYMBOLS_COUNT>1)
           {
            //--- Iterate over all symbols
            for(int s=0; s<SYMBOLS_COUNT; s++)
              {
               //--- If the symbols are equal and the deal result is non-zero
               if(deal.symbol==InputSymbols[s] && deal.profit!=0)
                 {
                  //--- Display the deal in the balance for the corresponding symbol
                  //    Take into consideration swap and commission
                  symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1]+
                                               deal.profit+
                                               deal.swap+
                                               deal.commission;
                  //--- Add to the string
                  StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                 }
               //--- Otherwise write the previous value
               else
                 {
                  //--- If the deal type is "Balance" (the first deal)
                  if(deal.type==DEAL_TYPE_BALANCE)
                    {
                     //--- the balance is the same for all symbols
                     symbol_balance[s].balance[i]=balance;
                     StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                    }
                  //--- Otherwise write the previous value to the current index
                  else
                    {
                     symbol_balance[s].balance[i]=symbol_balance[s].balance[i-1];
                     StringAdd(string_to_write,","+DoubleToString(symbol_balance[s].balance[i],2));
                    }
                 }
              }
           }
         //--- Write the generated string
         FileWrite(file_handle,string_to_write);
         //--- Mandatory zeroing out of the variable for the next string
         string_to_write="";
        }
      //--- Close the file
      FileClose(file_handle);
     }
//--- If the file could not be created/opened, print the appropriate message
   else
      Print("Error creating file: "+IntegerToString(GetLastError())+"");
  }

A função MaxDrawdownToString() destacada no código acima calcula todas as reduções da máxima local e retorna uma representação de cadeia do tempo do novo máximo local. Em todos os outros casos a função retorna uma cadeia contendo "-" (um hífen).

//+------------------------------------------------------------------+
//| Returns the maximum drawdown from the local maximum              |
//+------------------------------------------------------------------+
string MaxDrawdownToString(int deal_number,double balance,double &max_drawdown)
  {
//--- The string to be displayed in the report
   string str="";
//--- To calculate the local maximum and drawdown
   static double max=0.0;
   static double min=0.0;
//--- If this is the first deal
   if(deal_number==0)
     {
      //--- No drawdown yet
      max_drawdown=0.0;
      //--- Set the initial point as the local maximum
      max=balance;
      min=balance;
     }
   else
     {
      //--- If the current balance is greater than in the memory
      if(balance>max)
        {
         //--- calculate the drawdown using the previous values
         max_drawdown=100-((min/max)*100);
         //--- update the local maximum
         max=balance;
         min=balance;
        }
      else
        {
         //--- Return zero value of the drawdown
         max_drawdown=0.0;
         //--- Update the minimum
         min=fmin(min,balance);
        }
     }
//--- Determine the string for the report
   if(max_drawdown==0)
      str="-";
   else
      str=DoubleToString(max_drawdown,2);
//--- Return result
   return(str);
  }

Então todas as funções de geração de relatório estão prontas. Precisamos somente ver como devemos utilizar todo o acima. Isso necessitará da função OnTester() acionada diante da conclusão do teste. Certifique-se de verificar a descrição detalhada dessa função na referência do MQL5.

Simplesmente escreva algumas linhas de código no corpo da função OnTester() para especificar a condição na qual o relatório deve ser gerado. O trecho de código correspondente é fornecido abaixo:

//+------------------------------------------------------------------+
//| Handler of the event of testing completion                       |
//+------------------------------------------------------------------+
double OnTester()
  {
//--- Write the report only after testing
   if(IsTester() && !IsOptimization() && !IsVisualMode())
      //--- Generate the report and write it to the file
      CreateSymbolBalanceReport();
//---
   return(0.0);
  }

Agora, se você executar o Consultor Especialista no testador de estratégia, no final dos testes você verá uma pasta do Consultor Especialista criada na pasta de terminais comuns C:\ProgramData\MetaQuotes\Terminal\Common\Files. E o arquivo do relatório LastTest.csv será gerado na pasta do Consultor Especialista. Se você abrir o arquivo com o bloco de notas, você verá algo como:

Figura 1. O arquivo do relatório no formato .csv

Figura 1. O arquivo do relatório no formato .csv.

Criando gráficos no Excel

Podemos abrir o arquivo criado no Excel e ver que cada tipo de dados está em uma coluna diferente. Dessa forma os dados se apresentam muito mais convenientes para visualização. Nesse ponto, estamos tecnicamente preparados para criar gráficos e gravar o arquivo como catálogos do Excel no formato *.xlsx. No entanto, se depois executarmos o teste e abrirmos o catálogo novamente, ainda veremos os dados antigos.

Se tentarmos atualizar os dados, enquanto e arquivo LastTest.csv ainda estiver sendo usado no Excel, o arquivo não será atualizado, já que o Consultor Especialista não será capaz de abrí-lo para escrita enquanto ele estiver sendo utilizado por outra aplicação.

Figura 2. O arquivo do relatório no formato .csv no Excel 2010

Figura 2. O arquivo do relatório no formato .csv no Excel 2010.

Existe uma solução que pode ser utilizada em nosso caso. Primeiro criamos um catálogo do Excel no formato *.xlsx em qualquer pasta que desejar. Depois abra-a e vá para a aba Dados.

Figura 3. A aba Dados no Excel 2010

Figura 3. A aba Dados no Excel 2010.

Na faixa desta aba, selecione a opção Do Texto. O diálogo Importar Arquivo de Texto aparecerá onde você precisa selecionar o arquivo "LastTest.csv". Selecione o arquivo e clique no botão Abrir. O diálogo Assistente de Importação de Texto - Etapa 1 de 3 aparecerá conforme mostrado abaixo:

Figura 4. O diálogo

Figura 4. O diálogo "Assistente de Importação de Texto - Etapa 1 de 3".

Ajuste as configurações conforme mostrado acima e clique em Próximo >. Aqui, (Etapa 2 de 3) você precisa especificar o delimitador utilizado no arquivo de dados. Em nosso arquivo, é a "," (vírgula).

Figura 5. O diálogo

Figura 5. O diálogo "Assistente de Importação de Texto - Etapa 2 de 3".

Clique em Próximo > para avançar para o Assistente de Importação de Texto - Etapa 3 de 3. Aqui, deixe como Geral o formato de dados para todas as colunas. Você pode alterar o formato mais tarde.

Figura 6. O diálogo

Figura 6. O diálogo "Assistente de Importação de Texto - Etapa 3 de 3".

Após clicar no botão Finalizar, a janela Importar Dados aparecerá onde você precisa especificar a planilha e a célula para importar os dados.

Figura 7. Selecionando a célula para a importação de dados no Excel 2010

Figura 7. Selecionando a célula para a importação de dados no Excel 2010.

Geralmente, selecionamos a célula do topo esquerdo A1. Antes de clicar em OK, clique em no botão Propriedades... para ajustar as propriedades do intervalo de dados externos. Você verá uma caixa de diálogo conforme mostrado abaixo.

Figura 8. Propriedades do intervalo de dados externos ao importar dados de arquivos de texto no Excel 2010

Figura 8. Propriedades do intervalo de dados externos ao importar dados de arquivos de texto no Excel 2010.

Ajuste as configurações exatamente conforme mostrado acima e clique em OK na janela atual e na subsequente.

Como resultado, seus dados aparecerão da mesma forma como se você tivesse simplesmente carregado o arquivo .csv. Mas agora você pode executar repetidos testes no MetaTrader 5 sem ter que fechar o catálogo do Excel. Tudo o que você precisa fazer após executar o teste é simplesmente atualizar os dados utilizando o atalho Ctrl+Alt+F5 ou o botão Atualizar Tudo na faixa da aba Dados.

Utilizando as opções da Formatação Condicional na faixa da aba Início, você pode ajustar as propriedades visuais necessárias para a representação dos dados.

Figura 9. Formatação condicional no Excel 2010

Figura 9. Formatação condicional no Excel 2010.

Agora precisamos exibir os dados em gráficos do Excel. Um gráfico mostrará todos os gráficos de saldo e o outro exibirá todas as reduções da máxima local como um histograma.

Primeiro vamos criar um diagrama para os gráficos de saldo. Selecione os cabeçalhos de todos os saldos e o arranjo de dados todo do topo ao final (enquanto mantém pressionada a tecla Shift, pressione a tecla End e depois a tecla Seta para Baixo). Agora na aba Inserir, selecione o tipo de gráfico desejado.

Figura 10. Selecionando um tipo de gráfico no Excel 2010

Figura 10. Selecionando um tipo de gráfico no Excel 2010.

Como resultado, o gráfico será criado e poderá ser deslocado para outra planilha para conveniência. Para fazê-lo, simplesmente selecione-o e pressione Ctrl+X (Recortar). Depois vá para a planilha recém-criada, selecione a célula A1 e pressione Ctrl+V (Colar).

O gráfico criado com configurações padrão é mostrado na imagem abaixo:

Figura 11. Aparência do gráfico com as configurações padrão

Figura 11. Aparência do gráfico com as configurações padrão.

Você pode personalizar qualquer elemento do gráfico: alterar seu tamanho, cor, estilo, etc.

Na imagem acima, o eixo horizontal mostra o número de negociações. Vamos modificá-lo de modo a fazê-lo exibir datas ao invés disso. Para essa finalidade, clique direito no gráfico e selecione a opção Selecionar Dados no menu de contexto. O diálogo Selecionar Fonte de Dados aparecerá. Clique no botão Editar, depois selecione o intervalo de dados necessário na coluna TEMPO e clique em OK.

Figura 12. A caixa de diálogo

Figura 12. A caixa de diálogo "Selecione a Fonte de Dados".

Tente criar o gráfico de retirada sozinho e o posicionar sob o primeiro gráfico. Agora suas propriedades visuais podem ser personalizadas, se necessário. Pessoalmente, eu geralmente o faço:

Figura 13. Gráficos personalizados no Excel 2010

Figura 13. Gráficos personalizados no Excel 2010.


Conclusão

Então, temos os gráficos do Excel com resultados de testes que parecem bastantes decentes. Em um de meus futuros artigos, mostrarei a você como criar ainda mais relatórios informativos. Anexo no artigo está o arquivo que pode ser transferido com os arquivos do Consultor Especialista para sua consideração.

Após extrair os arquivos do arquivo, coloque a pasta ReportInExcel dentro do diretório MetaTrader 5\MQL5\Experts . Além disso, o indicador EventsSpy.mq5 deve ser colocado dentro do diretório MetaTrader 5\MQL5\Indicators.