English Русский 中文 Español Deutsch 日本語
preview
Visualizações de negociações no gráfico (Parte 2): Desenho gráfico de informações

Visualizações de negociações no gráfico (Parte 2): Desenho gráfico de informações

MetaTrader 5Sistemas de negociação |
309 2
Aleksandr Seredin
Aleksandr Seredin

Introdução

Neste artigo, vamos concluir o script para visualização de negociações no gráfico, iniciado no primeiro artigo "Visualizações de negociações no gráfico (Parte 1): Escolha do período para análise". Escreveremos o código para selecionar os dados de uma única negociação escolhida pelo usuário e criaremos o código para desenhar os objetos informativos necessários no gráfico, que posteriormente serão salvos como capturas de tela dos gráficos correspondentes. Este script permitirá economizar muito tempo na criação técnica dos gráficos de suas negociações e no salvamento desses gráficos como capturas de tela para uma análise retroativa. Aqueles que desejam evitar o trabalho de montar o projeto podem baixar uma versão pronta deste script no Mercado.


Seleção de Dados de Uma Única Negociação

Diferentemente da seleção de dados de negociações por um período específico, a seleção de dados de uma única negociação simplificará bastante a implementação para escolha de ordens históricas. A principal diferença aqui será que, para solicitar dados históricos, em vez de usar a função padrão do terminal HistorySelect(), usaremos o método HistorySelectByPosition(). Nos parâmetros deste método, será necessário passar o identificador de posição POSITION_IDENTIFIER, que o usuário poderá encontrar no terminal Metatrader5 no menu de contexto "Exibir" -> "Ferramentas" -> "Histórico" -> "Coluna Ticket" e passar esse valor ao script por meio da variável global de entrada inp_d_ticket.

No restante, a lógica do caso Select_one_deal seguirá completamente a implementação da lógica do caso anterior, apresentada no código completo mais adiante, com as mesmas inserções informativas para o usuário.

      //--- if one deal is needed
      case Select_one_deal:

         res = MessageBox("You have selected analysis of one deal. Continue?","",MB_OKCANCEL); // informed in the message

         if(res == IDCANCEL)                                            // if interrupted by user
           {
            printf("%s - %d -> Scrypt was stoped by user.",__FUNCTION__,__LINE__);  // informed in the journal
            return;                                                     // interrupted
           }

         MessageBox("Please press 'Ok' and wait for the next message until script will be done."); // informed in the message

         //--- select by one position
         if(HistorySelectByPosition(inp_d_ticket))                      // select position by id
           {
            int total = HistoryDealsTotal();                            // total deals

            if(total <= 0)                                              // if nothing found
              {
               printf("%s - %d -> Deal was not found.",__FUNCTION__,__LINE__); // notify
               MessageBox("Deal was not found with this tiket: "+IntegerToString(inp_d_ticket)+". Script is done."); // informed in the message
               return;
              }

            for(int i=0; i<total; i++)                                  // iterate through the number of deals
              {
               //--- try to get deals ticket
               if((ticket=HistoryDealGetTicket(i))>0)                   // took the deal number
                 {
                  //--- get deals properties
                  position_id = HistoryDealGetInteger(ticket,DEAL_POSITION_ID);     // took the main id
                  entry = (ENUM_DEAL_ENTRY)HistoryDealGetInteger(ticket,DEAL_ENTRY);// entry or exit?

                  if(entry == DEAL_ENTRY_IN)                                        // if this is an entry
                    {
                     open = HistoryDealGetDouble(ticket,DEAL_PRICE);                // take open price
                     time_open  =(datetime)HistoryDealGetInteger(ticket,DEAL_TIME); // take open time
                     symbol=HistoryDealGetString(ticket,DEAL_SYMBOL);   	    // take symbol
                     stop_loss = HistoryDealGetDouble(ticket,DEAL_SL);  	    // take Stop Loss
                     take_profit = HistoryDealGetDouble(ticket,DEAL_TP);	    // take Take Profit
                     //---
                     magic = (int)HistoryDealGetInteger(ticket,DEAL_MAGIC);   	    // take Magic
                     comment=HistoryDealGetString(ticket,DEAL_COMMENT);       	    // take comment
                     externalID=HistoryDealGetString(ticket,DEAL_EXTERNAL_ID); 	    // take external id
                     volume = HistoryDealGetDouble(ticket,DEAL_VOLUME);             // take volume
                     commission = HistoryDealGetDouble(ticket,DEAL_COMMISSION);     // take commission value
                    }

                  if(entry == DEAL_ENTRY_OUT)                           	    // if this is an exit
                    {
                     close = HistoryDealGetDouble(ticket,DEAL_PRICE);               // take close price
                     time_close  =(datetime)HistoryDealGetInteger(ticket,DEAL_TIME);// take close time
                     //---
                     reason = (ENUM_DEAL_REASON)HistoryDealGetInteger(ticket,DEAL_REASON); // take reason
                     swap = HistoryDealGetDouble(ticket,DEAL_SWAP);     // take swap
                     profit = HistoryDealGetDouble(ticket,DEAL_PROFIT); // take profit
                     fee = HistoryDealGetDouble(ticket,DEAL_FEE);       // take fee
                    }


                  //--- enter data into the main storage
                  //--- check if there is such id
                  if(Find(PositionID,position_id)==-1)                         // if there is no such deal,
                    {
                     //--- change the dimensions of the arrays
                     ArrayResize(arr_time_open,ArraySize(arr_time_open)+1);    // open time
                     ArrayResize(arr_time_close,ArraySize(arr_time_close)+1);  // close time
                     ArrayResize(arr_symbol,ArraySize(arr_symbol)+1);          // symbols
                     ArrayResize(arr_stop_loss,ArraySize(arr_stop_loss)+1);    // stop levels
                     ArrayResize(arr_take_profit,ArraySize(arr_take_profit)+1);// profits
                     ArrayResize(arr_open,ArraySize(arr_open)+1);              // entries
                     ArrayResize(arr_close,ArraySize(arr_close)+1);            // exits
                     ArrayResize(PositionID,ArraySize(PositionID)+1);          // position id
                     //---
                     ArrayResize(arr_magic,ArraySize(arr_magic)+1);            // Magic
                     ArrayResize(arr_extermalID,ArraySize(arr_extermalID)+1);  // external id
                     ArrayResize(arr_comment,ArraySize(arr_comment)+1);        // comment
                     ArrayResize(arr_volume,ArraySize(arr_volume)+1);          // volume
                     ArrayResize(arr_commission,ArraySize(arr_commission)+1);  // commission
                     ArrayResize(arr_reason,ArraySize(arr_reason)+1);          // reason
                     ArrayResize(arr_swap,ArraySize(arr_swap)+1);              // swap
                     ArrayResize(arr_profit,ArraySize(arr_profit)+1);          // profit
                     ArrayResize(arr_fee,ArraySize(arr_fee)+1);                // fee


                     PositionID[ArraySize(arr_time_open)-1]=position_id;       // id



                     if(entry == DEAL_ENTRY_IN)                         	       // if this is an entry
                       {
                        arr_time_open[    ArraySize(arr_time_open)-1]   = time_open;   // deal time
                        arr_symbol[       ArraySize(arr_symbol)-1]      = symbol;      // instrument symbol
                        arr_stop_loss[    ArraySize(arr_stop_loss)-1]   = stop_loss;   // deal stop loss
                        arr_take_profit[  ArraySize(arr_take_profit)-1] = take_profit; // deal take profit
                        arr_open[         ArraySize(arr_open)-1]        = open;        // open price
                        //---
                        arr_magic[        ArraySize(arr_magic)-1]       = magic;       // Magic
                        arr_comment[      ArraySize(arr_comment)-1]     = comment;     // comment
                        arr_extermalID[   ArraySize(arr_extermalID)-1]  = externalID;  // external id
                        arr_volume[       ArraySize(arr_volume)-1]      = volume;      // volume
                        arr_commission[   ArraySize(arr_commission)-1]  = commission;  // commission
                       }

                     if(entry == DEAL_ENTRY_OUT)                        	       // if this is an exit
                       {
                        arr_time_close[   ArraySize(arr_time_close)-1]  = time_close;  // close time
                        arr_close[        ArraySize(arr_close)-1]       = close;       // close prices
                        //---
                        arr_reason[       ArraySize(arr_reason)-1]      = reason;      // reason
                        arr_swap[         ArraySize(arr_swap)-1]        = swap;        // swap
                        arr_profit[       ArraySize(arr_profit)-1]      = profit;      // profit
                        arr_fee[          ArraySize(arr_fee)-1]         = fee;         // fee
                       }
                    }
                  else
                    {
                     int index = Find(PositionID,position_id);          // if there was a record already,

                     if(entry == DEAL_ENTRY_IN)                         // if this was an entry
                       {
                        arr_time_open[index]   = time_open;             // deal time
                        arr_symbol[index]      = symbol;                // symbol
                        arr_stop_loss[index]   = stop_loss;             // deal stop loss
                        arr_take_profit[index] = take_profit;           // deal take profit
                        arr_open[index]        = open;                  // open price
                        //---
                        arr_magic[index]       = magic;                 // Magic
                        arr_comment[index]     = comment;               // comment
                        arr_extermalID[index]  = externalID;            // external id
                        arr_volume[index]      = volume;                // volume
                        arr_commission[index]  = commission;            // commission
                       }

                     if(entry == DEAL_ENTRY_OUT)                        // if this is an exit
                       {
                        arr_time_close[index]  = time_close;            // deal close time
                        arr_close[index]       = close;                 // deal close price
                        //---
                        arr_reason[index]      = reason;                // reason
                        arr_swap[index]        = swap;                  // swap
                        arr_profit[index]      = profit;                // profit
                        arr_fee[index]         = fee;                   // fee
                       }
                    }
                 }
              }
           }
         else
           {
            printf("%s - %d -> Error of selecting history deals: %d",__FUNCTION__,__LINE__,GetLastError());	// informed in the journal
            printf("%s - %d -> Deal was not found.",__FUNCTION__,__LINE__); 					// informed in the journal
            MessageBox("Deal was not found with this tiket: "+IntegerToString(inp_d_ticket)+". Script is done."); // informed in the message
            return;
           }
         break;

Agora que ambos os casos foram descritos e todos os dados necessários foram preenchidos no decorrer do programa, podemos prosseguir para desenhar essas informações nos gráficos do terminal.


Desenho dos Gráficos Necessários

Para salvar as negociações no gráfico, primeiro será necessário abrir uma nova janela com o instrumento desejado, configurar as propriedades de exibição, incluindo um deslocamento de margem à direita para uma visualização completa da negociação, e chamar a função predefinida que salvará a captura de tela na pasta designada.

Primeiro, declararemos variáveis locais necessárias para abrir a janela do gráfico desejado. A variável bars armazenará o valor do deslocamento do gráfico à direita, enquanto as variáveis chart_width e chart_height armazenarão os tamanhos correspondentes para o salvamento, e o identificador do novo gráfico, quando aberto, será mantido na variável handle para facilitar o acesso futuro ao gráfico. 

//--- data collected, moving on to printing
   int bars = -1;                                                       // number of bars in a shift
   int chart_width = -1;                                                // chart width
   int chart_height =-1;                                                // chart height
   long handle =-1;                                                     // chart handle

Antes de solicitar a abertura de novas janelas de instrumentos, é essencial fazer verificações de validade desses instrumentos com base no histórico. Essa verificação será essencial para evitar o erro de abertura de "símbolo inexistente" na conta. Acredito que vale a pena explicar como pode surgir um "símbolo inexistente" se ele está registrado no histórico de negociações, indicando que, em algum momento, já existiu.

Primeiramente, isso pode estar relacionado aos tipos de contas oferecidos pela corretora. Hoje em dia, a maioria das corretoras oferece aos traders várias opções de contas para otimizar seu uso, considerando as estratégias de negociação adotadas. Em algumas contas, cobra-se comissão pela abertura de negociações, com um nível de spread muito baixo, enquanto em outros tipos de conta o spread é alto, mas não há cobrança por transação. Assim, os traders de médio prazo podem evitar a comissão por transação, pois o spread nas operações de médio prazo não é tão relevante. Já os traders que operam dentro do dia, buscando pequenos impulsos, preferem pagar a comissão de abertura a sofrer perdas devido ao súbito aumento do spread. Geralmente, as corretoras categorizam essas condições em tipos de contas como Standard, Gold, Platinum, ESN, e para cada conta atribuem um nome específico ao símbolo. Por exemplo, o par EURUSD em uma conta padrão pode ter variações como EURUSDb, EURUSDz ou EURUSD_i, dependendo da corretora.

Os nomes dos símbolos também podem variar conforme a expiração de certos instrumentos que não envolvem pares de moedas no Forex, mas não abordaremos esse aspecto detalhadamente, pois o foco aqui é nos pares de moedas.

Outro fator para validar o instrumento é a ausência técnica de assinatura para os instrumentos na janela de Observação do Mercado do terminal. Mesmo que o nome do símbolo exista na conta autorizada, se ele não estiver selecionado em "Exibir" -> "Observação do mercado" no menu de contexto do terminal, não será possível abrir o gráfico, causando erro na função que tenta acessá-lo.

Implementaremos a verificação organizando um ciclo para iterar cada instrumento em nosso armazenamento, como mostrado abaixo.

   for(int i=0; i<ArraySize(arr_symbol); i++)                           // iterate through all deal symbols

Para validar o instrumento no nosso contêiner, usaremos a função SymbolSelect() predefinida do terminal. No primeiro parâmetro, passaremos o nome do instrumento em formato string, cuja validade queremos verificar, e no segundo parâmetro, passaremos o valor booleano true. Esse valor true como segundo parâmetro indica ao terminal que, se o instrumento for válido mas não estiver selecionado em "Observação do mercado", ele deve ser incluído automaticamente. A lógica completa da verificação é mostrada abaixo.

//--- check for symbol availability

   for(int i=0; i<ArraySize(arr_symbol); i++)                           // iterate through all deal symbols
     {
      if(!SymbolSelect(arr_symbol[i],true))                             // check if the symbol is in the book and add if not
        {
         printf("%s - %d -> Failed to add a symbol %s to the marketbook. Error: %d",
			__FUNCTION__,__LINE__,arr_symbol[i],GetLastError()); // informed in the journal
         MessageBox("Failed to add a symbol to the marketbook: "+arr_symbol[i]+
			". Please select 'show all' in the your market book and try again. Script is done."); // informed in the message
         return;                                                        // if failed, abort
        }
     }

Se a verificação de validade do instrumento falhar, interrompemos a execução do programa com notificações apropriadas para o usuário. Uma vez concluídas todas as verificações de validade, podemos abrir os gráficos dos instrumentos diretamente no terminal.

Inicialmente, configuraremos uma variável auxiliar deal_close_date do tipo MqlDateTime, que ajudará a organizar e categorizar os gráficos salvos nas pastas corretas conforme os períodos de tempo. Para converter explicitamente o tipo de dados datetime no nosso armazenamento para o tipo MqlDateTime, utilizaremos a função predefinida do terminal TimeToStruct(), como mostrado abaixo.

      MqlDateTime deal_close_date;                                      // deal closure date in the structure
      TimeToStruct(arr_time_close[i],deal_close_date);                  // pass date to the structure

A renderização dos gráficos seguirá os valores inseridos pelo usuário nas variáveis main_graph, addition_graph, addition_graph_2 e addition_graph_3. Se a variável contiver o valor de enumeração PERIOD_CURRENT, nenhum gráfico será desenhado. Mas, se houver um valor específico, como PERIOD_D1, o gráfico correspondente será incluído na visualização. Aplicaremos essa verificação a todas as variáveis fornecidas, conforme exemplificado a seguir para o gráfico principal:

      //--- check the main one
      if(main_graph != PERIOD_CURRENT)                                  // if the main one selected

A renderização de cada gráfico começará com a abertura de um novo gráfico do instrumento desejado. Abriremos o novo gráfico do instrumento usando a função predefinida do terminal ChartOpen(), passando como parâmetros o símbolo do instrumento do nosso armazenamento e o timeframe definido pelo usuário, como mostrado abaixo.

         //--- open the required chart
         handle = ChartOpen(arr_symbol[i],main_graph);                  // open the necessary symbol chart

Após abrir o gráfico, aplicaremos todas as configurações padrão do usuário mencionadas anteriormente. Para isso, utilizaremos a função predefinida do terminal ChartApplyTemplate(), que simplifica o processo e evita a necessidade de escrever o código de configuração manualmente. Nos parâmetros da função ChartApplyTemplate(), passaremos o handle do gráfico, obtido com a função ChartOpen(), e o nome do template definido pelo usuário para o timeframe da negociação, no formato "dailyHistorytemp". O código para chamar a função de aplicação do template é apresentado a seguir.

         ChartApplyTemplate(handle,main_template);                      // apply template

Para quem ainda não utilizou templates no terminal Metatrader5, vale mencionar que, se o template aplicado for “não-atrativo”, a captura de tela da negociação pode acabar sendo, no mínimo, “desagradável” e, possivelmente, até “inútil”. Para criar manualmente o template “dailyHistorytemp”, siga estas etapas:

  • Abra qualquer gráfico de qualquer instrumento pelo menu de contexto “Arquivo” - “Novo gráfico”.
  • Quando o gráfico abrir, pressione F8 e uma nova janela de Propriedades aparecerá, como “Propriedades GBPAUD, Diário”.
  • Na janela de “Propriedades”, há várias abas, como “Geral”, “Mostrar” e “Cores”, em cada uma faça as configurações que considerar mais convenientes, por exemplo, para gráficos diários, e pressione “OK”. Para mais detalhes sobre personalização, consulte aqui - configuração de gráficos documentação oficial do terminal.
  • Após pressionar “OK”, a janela de propriedades será fechada, e o gráfico exibirá o estilo desejado.
  • No menu de contexto, selecione “Gráficos” - “Templates” - “Salvar template”, e aparecerá a janela de salvamento do template, onde você deve digitar “dailyHistorytemp.tpl” no campo “Nome do arquivo” e clicar em “Salvar”.
  • Em seguida, o arquivo “dailyHistorytemp.tpl” será salvo na pasta ..MQL5\Profiles\Templates do terminal, e ficará disponível para uso no script. Lembre-se de que no script, o nome do template é inserido sem a extensão .tpl, apenas o nome.

Agora, vamos retornar ao nosso código. Após aplicar o template necessário, precisamos inserir um pequeno atraso na execução do código, para dar tempo ao gráfico de carregar na qualidade desejada. Caso contrário, o gráfico pode ser exibido de forma incorreta devido ao tempo necessário para carregar os dados históricos de preços no terminal. Por exemplo, se você não abriu esse gráfico no terminal há muito tempo, o terminal pode precisar de alguns instantes para exibi-lo corretamente. Usaremos a função predefinida do terminal Sleep() para essa pausa, como mostrado abaixo.

         Sleep(2000);                                                   // wait for the chart to load

Definiremos um atraso de 2000 milissegundos, ou 2 segundos, um valor prático que garante o tempo necessário para o gráfico carregar, sem que a execução do script dure muitos minutos, mesmo com um grande volume de negociações. Se preferir ajustar esse valor, você pode torná-lo um parâmetro configurável no script para acelerar ou desacelerar o processo, conforme o desempenho do seu equipamento ou a qualidade da conexão com a internet. A prática mostra que dois segundos são suficientes para a maioria dos casos.

Agora, precisamos desativar a rolagem automática para os valores mais recentes dos candles, pois estamos analisando o histórico e não queremos que novos ticks movam o gráfico para a direita constantemente. Para isso, definiremos a propriedade CHART_AUTOSCROLL como false para o gráfico desejado, utilizando a função predefinida ChartSetInteger(), conforme mostrado a seguir.

         ChartSetInteger(handle,CHART_AUTOSCROLL,false);                // disable auto scroll

Com a rolagem automática desativada, precisamos deslocar o gráfico para o período de fechamento da negociação em análise, calculando o número de barras para a esquerda no timeframe correspondente. Podemos obter esse valor com a função predefinida iBarShift(), passando como parâmetros o símbolo do nosso instrumento, o timeframe do gráfico, a data de fechamento da negociação, pois queremos ver toda a negociação, do início ao fim. Além disso, definimos o parâmetro exact como false para acomodar casos em que o histórico é muito extenso. Contudo, para nossa implementação, isso não é tão crítico. A chamada completa do método com os parâmetros é mostrada abaixo.

         bars = iBarShift(arr_symbol[i],main_graph,arr_time_close[i],false); // get the shift for the deal time

Com o deslocamento necessário determinado, podemos exibir o período exato que cobre a negociação no histórico. Para ajustar o gráfico na direção e distância necessárias, utilizamos a função predefinida ChartNavigate(), passando os seguintes parâmetros, conforme indicado a seguir.

         ChartNavigate(handle,CHART_CURRENT_POS,-bars+bars_from_right_main); // shifted the chart with a custom margin

Para realizar o deslocamento, passamos o handle do gráfico, o valor CHART_CURRENT_POS da enumeração ENUM_CHART_POSITION, e o deslocamento calculado para a negociação na variável bars, com um ajuste adicional inserido pelo usuário para avaliar o potencial de movimento do preço após a saída da posição.

Após esses ajustes, por precaução, chamamos o método ChartRedraw() e podemos começar a desenhar os dados adicionais no gráfico para a análise das negociações históricas.

Para desenhar os elementos personalizados da interface de informações e as linhas que indicam a abertura, o fechamento das posições e os níveis de Stop Loss e Take Profit, usaremos as funções personalizadas paintDeal() e paintPanel(). Definiremos essas funções com base nos padrões do terminal, onde paintDeal() desenha as linhas de preço da abertura e do fechamento da negociação, bem como os níveis de Take Profit e Stop Loss , e o método paintPanel() exibe uma tabela com informações completas sobre a negociação no canto da tela.

A definição detalhada desses dois métodos será abordada em um próximo capítulo, intitulado "Desenho de Objetos Informativos nos Gráficos", mas para concluir este capítulo, apenas indicamos que esses métodos serão chamados aqui no código, conforme mostrado a seguir. Essa estrutura permite que, caso deseje redefinir a implementação desses métodos, mantendo a assinatura, você ainda possa chamá-los no ponto adequado do código. A implementação fornecida neste artigo serve como exemplo de um equilíbrio ideal entre clareza visual e riqueza de informações no gráfico na data de escrita do código. O mais importante é manter a posição dos métodos no código principal nesta seção.

         //--- draw the deal
         paintDeal(handle,PositionID[i],arr_stop_loss[i],arr_take_profit[i],arr_open[i],arr_close[i],arr_time_open[i],arr_time_close[i]);

         //--- draw the information panel
         paintPanel(handle,PositionID[i],arr_stop_loss[i],arr_take_profit[i],arr_open[i],
                    arr_close[i],arr_time_open[i],arr_time_close[i],arr_magic[i],arr_comment[i],
                    arr_extermalID[i],arr_volume[i],arr_commission[i],arr_reason[i],arr_swap[i],
                    arr_profit[i],arr_fee[i],arr_symbol[i],(int)SymbolInfoInteger(arr_symbol[i],SYMBOL_DIGITS));

Após os métodos desenharem as linhas da negociação e a interface de informações no gráfico, podemos prosseguir para a captura de tela de tudo o que foi gerado no gráfico atual. Primeiro, definiremos a largura e altura da captura de tela, obtendo esses dados do gráfico aberto por meio da função predefinida do terminal ChartSetInteger(), conforme mostrado abaixo.

         //--- get data by screen size
         chart_width = (int) ChartGetInteger(handle,CHART_WIDTH_IN_PIXELS);   // look at the chart width
         chart_height = (int) ChartGetInteger(handle,CHART_HEIGHT_IN_PIXELS); // look at the chart height

Para os parâmetros de exibição do gráfico, usamos os valores da enumeração ENUM_CHART_PROPERTY_INTEGER para a largura CHART_WIDTH_IN_PIXELS e para a altura CHART_HEIGHT_IN_PIXELS, respectivamente.

Com os dados dimensionais em mãos, precisamos definir o caminho para salvar a captura de tela da negociação na pasta padrão do terminal. Para que o EA não salve todos os arquivos em uma única pasta, mas os organize de forma conveniente para o usuário, automatizaremos esse processo com uma estrutura de diretórios específica.

         string name_main_screen = brok_name+"/"+
                                   IntegerToString(account_num)+"/"+
                                   IntegerToString(deal_close_date.year)+"-"+IntegerToString(deal_close_date.mon)+
				   "-"+IntegerToString(deal_close_date.day)+"/"+
                                   IntegerToString(PositionID[i])+"/"+
                                   EnumToString(main_graph)+IntegerToString(PositionID[i])+".png"; // assign the name

A estrutura gráfica de pastas para os arquivos no diretório padrão será conforme mostrado na Figura 1.

Figura 1. Estrutura de diretórios para salvar capturas de tela das negociações

Figura 1. Estrutura de diretórios para salvar capturas de tela das negociações

Como podemos ver, os arquivos dos gráficos serão organizados pelo nome da corretora, número da conta, ano, mês e dia da negociação, para que o usuário encontre facilmente a negociação desejada sem precisar buscar o nome do arquivo em uma lista única. Diferentes timeframes serão armazenados na pasta correspondente ao número da posição no terminal.

Finalmente, realizaremos o salvamento chamando a função predefinida ChartScreenShot(), passando como parâmetros o handle do gráfico, as dimensões definidas da captura de tela que correspondem ao tamanho do gráfico, além do nome do arquivo que contém toda a estrutura de diretórios mencionada, conforme ilustrado na Figura 1 e no código abaixo.

         ChartScreenShot(handle,name_main_screen,chart_width,chart_height,ALIGN_LEFT);             // make a screenshot

Se as pastas especificadas na hierarquia não existirem na pasta padrão do terminal, o terminal as criará automaticamente, sem intervenção do usuário.

Após concluir o salvamento do arquivo, podemos fechar o gráfico para evitar sobrecarregar a interface do terminal, especialmente se estamos exportando um grande volume de negociações históricas. O fechamento do gráfico será feito pela função predefinida do terminal ChartClose(), passando o handle do gráfico para garantir que apenas o gráfico desejado seja fechado. A chamada da função é apresentada a seguir.

         ChartClose(handle);                                            // closed the chart

Repetiremos essa operação para todos os timeframes especificados pelo usuário nos parâmetros de entrada. Agora, para finalizar nosso script, falta apenas definir o comportamento dos métodos paintDeal() e paintPanel() fora do código principal.


Desenho de Objetos Informativos nos Gráficos

Para posicionar as informações de forma prática no gráfico da captura de tela, só precisamos redefinir dois métodos, que determinam como a informação relevante para o usuário será exibida para análise da negociação.

Vamos começar com a descrição do método paintDeal(), cuja função será desenhar os elementos gráficos da posição, como os preços de abertura, fechamento, Stop Loss e Take Profit. Para isso, fora do corpo do código principal, declararemos a definição desse método com a seguinte assinatura:

void paintDeal(long handlE,
               ulong tickeT,
               double stop_losS,
               double take_profiT,
               double opeN,
               double closE,
               datetime timE,
               datetime time_closE)

Os parâmetros do método incluem: handlE (handle do gráfico onde os elementos serão desenhados), tickeT (ticket da negociação), stop_losS (preço do Stop Loss, se houver), take_profiT (Take Profit, se definido), preço de abertura - opeN, preço de fechamento - closE, tempo de abertura da negociação - timE e, respectivamente, o de fechamento - time_closE.

Começamos o desenho criando um nome de objeto que seja único, evitando duplicações. No nome, indicamos que o objeto corresponde ao Stop Loss com o prefixo "name_sl_" e, para garantir unicidade, incluímos o número do ticket da negociação, como mostrado abaixo.

   string name_sl = "name_sl_"+IntegerToString(tickeT);                    // assign the name

Agora podemos criar o objeto gráfico em si, utilizando a função predefinida do terminal ObjectCreate(), que desenhará o nível de preço do Stop Loss da posição histórica no gráfico. Nos parâmetros, passaremos o handle do gráfico, o nome único da variável name_sl, o tipo de objeto OBJ_ARROW_LEFT_PRICE, que indica uma marca de preço à esquerda da enumeração ENUM_OBJECT, além do valor do preço e o tempo de colocação da marca no gráfico, como mostrado a seguir.

   ObjectCreate(handlE,name_sl,OBJ_ARROW_LEFT_PRICE,0,timE,stop_losS);     // create the left label object

Com o objeto criado, configuramos seus atributos OBJPROP_COLOR e OBJPROP_TIMEFRAMES. Definimos OBJPROP_COLOR como clrRed, já que, tradicionalmente, o Stop Loss é representado em vermelho, e OBJPROP_TIMEFRAMES como OBJ_ALL_PERIODS para exibição em todos os timeframes. Esse último ajuste, no entanto, não é essencial para nossa implementação. No geral, o bloco de desenho do Stop Loss terá o aspecto mostrado abaixo.

//--- draw stop loss
   string name_sl = "name_sl_"+IntegerToString(tickeT);                    // assign the name
   ObjectCreate(handlE,name_sl,OBJ_ARROW_LEFT_PRICE,0,timE,stop_losS);     // create the left label object
   ObjectSetInteger(handlE,name_sl,OBJPROP_COLOR,clrRed);                  // add color
   ObjectSetInteger(handlE,name_sl,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);    // set visibility
   ChartRedraw(handlE);                                                    // redraw

Após desenhar cada bloco, chamamos o método ChartRedraw() para atualizar o gráfico.

A renderização do bloco Take Profit seguirá a mesma lógica do Stop Loss, com as seguintes diferenças. Primeiro, no nome único do objeto, adicionaremos "name_tp_" seguido pelo ticket da negociação, e a cor será um tom de verde, tradicionalmente associado a lucros, definido como clrLawnGreen. No restante, a lógica é idêntica ao bloco Stop Loss e está completamente ilustrada aqui.

//--- draw take profit
   string name_tp = "name_tp_"+IntegerToString(tickeT);                    // assign the name
   ObjectCreate(handlE,name_tp,OBJ_ARROW_LEFT_PRICE,0,timE,take_profiT);   // create the left label object
   ObjectSetInteger(handlE,name_tp,OBJPROP_COLOR,clrLawnGreen);            // add color
   ObjectSetInteger(handlE,name_tp,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);    // set visibility
   ChartRedraw(handlE);                                                    // redraw

Agora, vamos implementar a renderização do preço de entrada na negociação também com uma marca de preço à esquerda. A diferença em relação aos blocos anteriores está no nome único do objeto, que usará o prefixo "name_open_", e na cor da linha, clrWhiteSmoke, que é discreta e evita chamar muita atenção no gráfico; o restante segue a mesma lógica dos outros blocos.

//--- draw entry price
   string name_open = "name_open_"+IntegerToString(tickeT);                // assign the name
   ObjectCreate(handlE,name_open,OBJ_ARROW_LEFT_PRICE,0,timE,opeN);        // create the left label object
   ObjectSetInteger(handlE,name_open,OBJPROP_COLOR,clrWhiteSmoke);         // add color
   ObjectSetInteger(handlE,name_open,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);  // set visibility
   ChartRedraw(handlE);                                                    // redraw

Usaremos a mesma cor para a linha que conecta as marcas de preço de abertura e fechamento da negociação. O tipo dessa linha será diferente, e ao criar o objeto no método ObjectCreate(), passaremos o valor OBJ_TREND como terceiro parâmetro, da enumeração ENUM_OBJECT, para criar uma linha de tendência. Para posicionar corretamente a linha de tendência no gráfico, precisaremos fornecer parâmetros adicionais para as duas extremidades da linha, onde cada ponto é definido por um valor de preço e de tempo. Assim, passaremos os preços de abertura e fechamento opeN e closE, bem como os tempos de abertura e fechamento nas variáveis timE e time_closE, como mostrado abaixo.

//--- deal line
   string name_deal = "name_deal_"+IntegerToString(tickeT);                // assign the name
   ObjectCreate(handlE,name_deal,OBJ_TREND,0,timE,opeN,time_closE,closE);  // create the left label object
   ObjectSetInteger(handlE,name_deal,OBJPROP_COLOR,clrWhiteSmoke);         // add color
   ObjectSetInteger(handlE,name_deal,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);  // set visibility
   ChartRedraw(handlE);                                                    // redraw

Para finalizar a visualização da negociação no gráfico, resta desenhar a marca de preço de fechamento. Desta vez, usaremos uma marca de preço à direita para uma exibição mais organizada na captura de tela. Para desenhar a marca à direita, passaremos no método ObjectCreate() o valor OBJ_ARROW_RIGHT_PRICE como terceiro parâmetro, indicando a marca à direita da enumeração ENUM_OBJECT. Para o restante do desenho, precisaremos apenas dos valores de preço e tempo, que passaremos pelas variáveis time_closE e closE, conforme mostrado abaixo.

//--- draw exit price
   string name_close = "name_close"+IntegerToString(tickeT);                // assign the name
   ObjectCreate(handlE,name_close,OBJ_ARROW_RIGHT_PRICE,0,time_closE,closE);// create the left label object
   ObjectSetInteger(handlE,name_close,OBJPROP_COLOR,clrWhiteSmoke);         // add color
   ObjectSetInteger(handlE,name_close,OBJPROP_TIMEFRAMES,OBJ_ALL_PERIODS);  // set visibility
   ChartRedraw(handlE);                                                     // redraw

Com isso, concluímos nosso método personalizado paintDeal() para desenhar as linhas de entrada e saída da posição, e agora podemos descrever o método para renderizar a interface completa de informações da negociação no método paintPanel().

A criação da interface no método paintPanel() exigirá uma estrutura de métodos mais complexa para desenhar etiquetas de texto do tipo OBJ_LABEL (enumeração ENUM_OBJECT) e um objeto OBJ_RECTANGLE_LABEL para organizar a interface gráfica personalizada. Declararemos os métodos auxiliares com os nomes: LabelCreate() para criar as etiquetas de texto e RectLabelCreate() para criar a etiqueta retangular. Começaremos descrevendo os métodos auxiliares e depois passaremos ao método principal paintPanel(), onde usaremos esses métodos auxiliares.

A estrutura geral dos métodos do nosso script está ilustrada na Figura 2.

Figura 2. Estrutura dos métodos personalizados para renderização gráfica

Figura 2. Estrutura dos métodos personalizados para renderização gráfica

Declararemos o método LabelCreate() com a seguinte assinatura de parâmetros:

bool LabelCreate(const long              chart_ID=0,               // chart ID
                 const string            name="Label",             // label name
                 const int               sub_window=0,             // subwindow number
                 const long              x=0,                      // X coordinate
                 const long              y=0,                      // Y coordinate
                 const ENUM_BASE_CORNER  corner=CORNER_LEFT_UPPER, // chart corner for anchoring
                 const string            text="Label",             // text
                 const string            font="Arial",             // font
                 const int               font_size=10,             // font size
                 const color             clr=clrRed,               // color
                 const double            angle=0.0,                // text angle
                 const ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER, // anchor type
                 const bool              back=false,               // in the background
                 const bool              selection=false,          // select to move
                 const bool              hidden=true,              // hidden in the list of objects
                 const long              z_order=0)                // priority for clicking with a mouse

No parâmetro chart_ID, passaremos o handle do gráfico onde o objeto será desenhado; name será o nome único do objeto, e o valor 0 no parâmetro sub_window indicará que queremos desenhar o objeto na janela principal do gráfico. As coordenadas do canto superior esquerdo do objeto serão definidas pelos parâmetros X e Y, respectivamente. Podemos ajustar a ancoragem do objeto a partir do canto superior esquerdo padrão, configurando o parâmetro corner, mas manteremos o valor padrão ANCHOR_LEFT_UPPER. No parâmetro text, transmitiremos a string com a informação a ser exibida, e as características visuais, como tipo e tamanho da fonte, cor e ângulo, serão especificadas nos parâmetros font, font_size, clr e angle. Também faremos com que o objeto fique invisível na lista de objetos e não seja selecionável pelo mouse, por meio dos parâmetros selection e hidden. O parâmetro z_order definirá a prioridade para cliques do mouse.

Iniciaremos a descrição do método resetando a variável de erro, para monitorar corretamente o sucesso da criação do objeto posteriormente, com a função predefinida do terminal ResetLastError(). Verificaremos o resultado da criação do objeto do tipo OBJ_LABEL por meio de um operador lógico if com a chamada da função ObjectCreate(), conforme mostrado abaixo. Se o objeto não for criado, informaremos o usuário no log do expert e interromperemos a execução do método com um retorno, como de costume.

//--- reset the error value
   ResetLastError();
//--- create a text label
   if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0))
     {
      Print(__FUNCTION__,
            ": failed to create the text label! Error code = ",GetLastError());
      return(false);
     }

Se o objeto for criado com sucesso, inicializaremos suas propriedades para o estilo desejado usando as funções predefinidas do terminal ObjectSetInteger(), ObjectSetString() e ObjectSetDouble(). Com a função ObjectSetInteger(), definiremos as coordenadas, a âncora do objeto, o tamanho da fonte, o modo de fixação, a cor e a visibilidade do objeto para o usuário. Usaremos a função ObjectSetDouble() para ajustar o ângulo da fonte, e com a função ObjectSetString() definiremos o conteúdo do texto e o tipo de fonte para exibição. A implementação completa do método é apresentada abaixo.

//--- reset the error value
   ResetLastError();
//--- create a text label
   if(!ObjectCreate(chart_ID,name,OBJ_LABEL,sub_window,0,0))
     {
      Print(__FUNCTION__,
            ": failed to create the text label! Error code = ",GetLastError());
      return(false);
     }
//--- set label coordinates
   ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);
   ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);
//--- set the chart's corner, relative to which point coordinates are defined
   ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner);
//--- set the text
   ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);
//--- set the text font
   ObjectSetString(chart_ID,name,OBJPROP_FONT,font);
//--- set font size
   ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size);
//--- set the text angle
   ObjectSetDouble(chart_ID,name,OBJPROP_ANGLE,angle);
//--- set anchor type
   ObjectSetInteger(chart_ID,name,OBJPROP_ANCHOR,anchor);
//--- set the color
   ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- enable (true) or disable (false) the mode of moving the label by mouse
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
   ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- hide (true) or display (false) graphical object name in the object list
   ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- set the priority for receiving the event of a mouse click on the chart
   ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- successful execution
   return(true);

Declararemos o método RectLabelCreate() com a seguinte assinatura de parâmetros para a criação do objeto:

bool RectLabelCreate(const long             chart_ID=0,               // chart ID
                     const string           name="RectLabel",         // label name
                     const int              sub_window=0,             // subwindow number
                     const int              x=19,                     // X coordinate
                     const int              y=19,                     // Y coordinate
                     const int              width=150,                // width
                     const int              height=20,                // height
                     const color            back_clr=C'236,233,216',  // background color
                     const ENUM_BORDER_TYPE border=BORDER_SUNKEN,     // border type
                     const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER, // chart corner for anchoring
                     const color            clr=clrRed,               // flat border color (Flat)
                     const ENUM_LINE_STYLE  style=STYLE_SOLID,        // flat border style
                     const int              line_width=1,             // flat border width
                     const bool             back=true,                // 'true' in the background
                     const bool             selection=false,          // select to move
                     const bool             hidden=true,              // hidden in the list of objects
                     const long             z_order=0)                // priority for clicking with a mouse

Os parâmetros do método RectLabelCreate() são muito semelhantes aos do método LabelCreate() definido anteriormente, mas incluem configurações adicionais para a borda do retângulo, que servirá de fundo para os dados exibidos pelo objeto anterior. Os parâmetros adicionais de configuração da borda do objeto incluem: border - tipo da borda, definido pela enumeração ENUM_BORDER_TYPE com o valor padrão BORDER_SUNKEN, style - estilo da borda, definido pela enumeração ENUM_LINE_STYLE com o valor padrão STYLE_SOLID, e line_width - espessura da linha da borda em valor inteiro.

A definição do corpo do método será semelhante à anterior e, assim como ela, consistirá em duas seções principais: criação do objeto e definição de suas propriedades por meio dos métodos predefinidos do terminal, conforme mostrado abaixo.

//--- reset the error value
   ResetLastError();                                                    // reset error
//--- create a rectangle label
   if(ObjectCreate(chart_ID,name,OBJ_RECTANGLE_LABEL,sub_window,0,0))   // create object
     {
      //--- set label coordinates
      ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);              // assign x coordinate
      ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);              // assign y coordinate
      //--- set label size
      ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width);              // width
      ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height);             // height
      //--- set the background color
      ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr);         // background color
      //--- set border type
      ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_TYPE,border);       // border type
      //--- set the chart corner, relative to which point coordinates are defined
      ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner);            // anchor corner
      //--- set flat border color (in Flat mode)
      ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);                // frame
      //--- set flat border line style
      ObjectSetInteger(chart_ID,name,OBJPROP_STYLE,style);              // style
      //--- set flat border width
      ObjectSetInteger(chart_ID,name,OBJPROP_WIDTH,line_width);         // width
      //--- display in the foreground (false) or background (true)
      ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);                // default is background
      //--- enable (true) or disable (false) the mode of moving the label by mouse
      ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);     // is it possible to select
      ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);       //
      //--- hide (true) or display (false) graphical object name in the object list
      ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);            // is it visible in the list
      //--- set the priority for receiving the event of a mouse click on the chart
      ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);           // no events
      //--- successful execution
     }
   return(true);

Agora que todos os métodos auxiliares estão descritos, vamos definir o corpo do método principal que desenhará a interface completa – paintPanel(). Os parâmetros de entrada incluirão os campos necessários para exibir todas as informações sobre as negociações para o usuário, conforme mostrado abaixo.

void paintPanel(long handlE,                 
                ulong tickeT,                
                double stop_losS,            
                double take_profiT,          
                double opeN,                 
                double closE,                
                datetime timE,               
                datetime time_closE,         
                int magiC,                   
                string commenT,              
                string externalIDD,          
                double volumE,               
                double commissioN,           
                ENUM_DEAL_REASON reasoN,     
                double swaP,                 
                double profiT,               
                double feE,                  
                string symboL,               
                int digitS                   
               )

O primeiro parâmetro, assim como nos métodos anteriores, definirá o handle do gráfico, onde todos os objetos da interface de informações serão criados. Os demais parâmetros repetirão os campos do objeto da negociação histórica.

Começaremos a implementação do método de renderização da interface informativa definindo variáveis para o tamanho da interface e as coordenadas de fixação das colunas, que contêm os títulos das informações e os valores, conforme mostrado abaixo.

int height=20, max_height =0, max_width = 0;	// column height and max values for indent
int x_column[2] = {10, 130};			// columns X coordinates
int y_column[17];				// Y coordinates

A variável height terá um valor fixo de 20, representando a altura de cada linha para garantir uma exibição uniforme, enquanto max_height e max_width armazenarão as larguras máximas de cada coluna para um alinhamento visual adequado. As coordenadas em X e Y serão armazenadas nos arrays x_column[] e y_column[], respectivamente.

Agora, precisamos declarar dois arrays que armazenarão os valores das linhas para exibir os títulos e os valores das colunas. Declararemos o array de títulos como um array de dados do tipo string, conforme mostrado no código a seguir.

   string column_1[17] =
     {
      "Symbol",
      "Position ID",
      "External ID",
      "Magic",
      "Comment",
      "Reason",
      "Open",
      "Close",
      "Time open",
      "Time close",
      "Stop loss",
      "Take profit",
      "Volume",
      "Commission",
      "Swap",
      "Profit",
      "Fee"
     };

Todos os valores do array são declarados e inicializados estaticamente, pois a estrutura da interface permanecerá a mesma, e os dados sempre serão exibidos na mesma ordem, facilitando a leitura das informações sobre diferentes negociações para o usuário. Poderíamos implementar uma funcionalidade que excluísse dados sem valor ou iguais a zero, mas isso prejudicaria a consistência visual, dificultando a busca rápida das informações. É mais prático seguir um padrão fixo de exibição, permitindo ao usuário encontrar as informações em uma estrutura familiar.

Na mesma sequência de dados, declararemos o segundo array, que conterá os valores das colunas conforme os títulos declarados anteriormente. Descrevere a declaração do array da seguinte forma:

   string column_2[17] =
     {
      symboL,
      IntegerToString(tickeT),
      externalIDD,
      IntegerToString(magiC),
      commenT,
      EnumToString(reasoN),
      DoubleToString(opeN,digitS),
      DoubleToString(closE,digitS),
      TimeToString(timE),
      TimeToString(time_closE),
      DoubleToString(stop_losS,digitS),
      DoubleToString(take_profiT,digitS),
      DoubleToString(volumE,2),
      DoubleToString(commissioN,2),
      DoubleToString(swaP,2),
      DoubleToString(profiT,2),
      DoubleToString(feE,2)
     };

A declaração do array será feita localmente, no nível do método, com a inicialização dos campos diretamente a partir dos parâmetros do método e das funções predefinidas do terminal.

Agora que temos os contêineres com os dados necessários, precisamos calcular as coordenadas de cada célula, considerando o valor máximo de largura em cada uma delas. Podemos fazer isso com o código a seguir:

   int count_rows = 1;
   for(int i=0; i<ArraySize(y_column); i++)
     {
      y_column[i] = height * count_rows;
      max_height = y_column[i];
      count_rows++;

      int width_curr = StringLen(column_2[i]);

      if(width_curr>max_width)
        {
         max_width = width_curr;
        }
     }

   max_width = max_width*10;
   max_width += x_column[1];
   max_width += x_column[0];

Aqui, calculamos as coordenadas de cada objeto percorrendo as linhas em um loop, multiplicando a altura fixa em Y e verificando o maior valor em largura para ajustar a posição em X.

Com todas as coordenadas definidas, usaremos o método LabelCreate() para renderizar cada linha de informação. Chamaremos esse método em um loop conforme o número de linhas de exibição, como mostrado abaixo.

   color back_Color = clrWhiteSmoke;
   color font_Color = clrBlueViolet;

   for(int i=0; i<ArraySize(column_1); i++)
     {
      //--- draw 1
      string name_1 = column_1[i]+"_1_"+IntegerToString(tickeT);            
      LabelCreate(handlE,name_1,0,x_column[0],y_column[i],CORNER_LEFT_UPPER,column_1[i],"Arial",10,font_Color,0,ANCHOR_LEFT_UPPER,false);
      //--- draw 2
      string name_2 = column_1[i]+"_2_"+IntegerToString(tickeT);            
      LabelCreate(handlE,name_2,0,x_column[1],y_column[i],CORNER_LEFT_UPPER,column_2[i],"Arial",10,font_Color,0,ANCHOR_LEFT_UPPER,false);
     }

Para concluir o método, adicionaremos o fundo da interface usando o método RectLabelCreate(), definido anteriormente, e atualizaremos o gráfico com ChartRedraw(), conforme mostrado abaixo.

//--- draw the background
   RectLabelCreate(handlE,"RectLabel",0,1,height,max_width,max_height,back_Color);                   

   ChartRedraw(handlE);                                                 

Com isso, finalizamos a descrição de todos os métodos, e o projeto está pronto para compilação e uso.

Após a execução do script, o arquivo gráfico será exibido conforme mostrado na Figura 3.

Figura 3. Resultado do script com informações da negociação.

Figura 3. Resultado do script com informações da negociação

Como podemos ver, todas as informações sobre a negociação são apresentadas de forma resumida em um único gráfico, facilitando a análise e avaliação das operações pelo usuário. O script organiza esses arquivos nas pastas correspondentes, permitindo que o usuário localize facilmente qualquer informação sobre operações no histórico da conta.


Considerações finais

Com este artigo, concluímos o desenvolvimento do script para visualização automatizada de negociações no gráfico. Usando essa solução, você poderá melhorar sua negociação ao corrigir possíveis erros na escolha dos pontos de entrada, além de aumentar a expectativa matemática de sua estratégia com a seleção adequada de instrumentos e pontos de impulso de preço. Além disso, o uso deste script poupará muito tempo na preparação técnica dos arquivos gráficos, permitindo dedicar mais tempo à análise e à busca de novas ideias de negociação. Lembre-se de que o mercado está em constante mudança, e para garantir estabilidade é essencial estar sempre “de olho” nas atualizações, e essa ferramenta pode ajudá-lo a se manter informado. Desejo-lhe sucesso no seu trabalho e ficarei feliz em receber seu feedback nos comentários deste artigo.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/14961

Arquivos anexados |
DealsPrintScreen.mq5 (104.52 KB)
Últimos Comentários | Ir para discussão (2)
Alexander Piechotta
Alexander Piechotta | 1 dez. 2024 em 15:17
Uma ótima ideia e uma explicação de primeira classe para entender. Muito obrigado.
Aleksandr Seredin
Aleksandr Seredin | 1 dez. 2024 em 17:01
Alexander Piechotta #:
Uma ótima ideia e uma explicação de primeira classe para entender. Muito obrigado.

Muito obrigado por seu comentário. Ficarei muito feliz se isso o ajudar em seu trabalho. Muito obrigado! :)

Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 5): Sistema de Notificação (Parte II) Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 5): Sistema de Notificação (Parte II)
Hoje, estamos discutindo uma integração funcional do Telegram para notificações do Indicador MetaTrader 5 usando o poder do MQL5, em parceria com Python e a API do Bot do Telegram. Explicaremos tudo em detalhes para que ninguém perca nenhum ponto. Ao final deste projeto, você terá adquirido conhecimentos valiosos para aplicar em seus projetos.
Dominando a Dinâmica do Mercado: Criando um Expert Advisor (EA) para Estratégia de Suporte e Resistência Dominando a Dinâmica do Mercado: Criando um Expert Advisor (EA) para Estratégia de Suporte e Resistência
Um guia abrangente para desenvolver um algoritmo de negociação automatizado baseado na estratégia de Suporte e Resistência. Informações detalhadas sobre todos os aspectos da criação de um expert advisor em MQL5 e testá-lo no MetaTrader 5 – desde a análise dos comportamentos de faixa de preço até o gerenciamento de risco.
Otimização Automatizada de Parâmetros para Estratégias de Trading Usando Python e MQL5 Otimização Automatizada de Parâmetros para Estratégias de Trading Usando Python e MQL5
Existem vários tipos de algoritmos para auto-otimização de estratégias de trading e parâmetros. Esses algoritmos são usados para melhorar automaticamente as estratégias de trading com base em dados históricos e atuais de mercado. Neste artigo, veremos um desses algoritmos com exemplos em Python e MQL5.
Redes neurais de maneira fácil (Parte 94): Otimização da sequência de dados iniciais Redes neurais de maneira fácil (Parte 94): Otimização da sequência de dados iniciais
Ao trabalhar com séries temporais, geralmente usamos os dados na sequência histórica. Mas isso é realmente o mais eficiente? Há quem acredite que modificar a sequência dos dados iniciais pode aumentar a eficácia dos modelos de aprendizado. Neste artigo, vou apresentar um desses métodos.