English Русский 中文 Español Deutsch 日本語
LifeHack para traders: otimização "silenciosa" ou traço da distribuição de negociações

LifeHack para traders: otimização "silenciosa" ou traço da distribuição de negociações

MetaTrader 5Exemplos | 19 outubro 2016, 17:39
1 595 1
Vladimir Karputov
Vladimir Karputov

Tabela de conteúdos


Para que são necessários os gráficos de distribuição?

Ao desenvolver uma nova estratégia de negociação, não sabemos com antecedência quão bem-sucedida ela vai resultar. Quase sempre, o robô de negociação contém os parâmetros de entrada subjacentes às regras que serão usadas na geração de sinais para a entrada no mercado. Neste caso, após criar o robô de negociação, nós simplesmente confiaremos em que o testador de estratégias nos ajudará a encontrar as combinações de parâmetros de entrada que mostrarão bons resultados no histórico.

No entanto, este artigo oferece um olhar um pouco diferente para o processo de criação do robô de negociação. Antes de executar a otimização de parâmetros de entrada, é possível simplesmente olhar para a distribuição de lucros e perdas, dependendo da hora de entrada. Afinal, muitas estratégias têm uns momentos "favoráveis" e outros "desfavoráveis" para entrar no mercado. Este artigo considera a criação de gráficos de distribuição de rentabilidade da posição (não das transações!) dependendo de seu tempo de abertura. Tendo estudado estes gráficos, você poderá olhar para sua estratégia de um ponto de vista ligeiramente diferente.

Os gráficos são traçados chamando a Google Charts e sua exibição visual é realizada usando o formato HTML. Esquematicamente, na página, os gráficos de distribuição são exibidos em forma de tabela:

 

Fig. 1. Aparência do relatório HTML  

As duas primeiras linhas são as estatísticas de resumo para toda a conta de negociação, as linhas subsequentes representam as estatísticas para cada símbolo em termos de entradas por horas, dias e meses.


Inicialização rápida

O arquivo "DistributionOfProfits.mqh" deve ser colocado no diretório de dados, na pasta ...\MQL5\Include\. O script "test_report.mq5" chama a construção de gráficos de análise a partir da data especificada "start":

//+------------------------------------------------------------------+
//|                                                  test_report.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
//---
input datetime start=D'2010.05.11 12:05:00';
#include <DistributionOfProfits.mqh>
//---
CDistributionOfProfits Analysis;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   Analysis.AnalysisTradingHistory(start);
   Analysis.ShowDistributionOfProfits();
  }
//+------------------------------------------------------------------+


1. Reconstrução da posição a partir do histórico de negociação

Para que é necessário reconstruir a posição? O fato é que esta é a única maneira de saber -em cada posição- o lucro e seu tempo de abertura. Definimos os termos:

posição rentável — lucro total de todas as negociação numa determinada posição;

tempo de abertura da posição — tempo de envio da primeira ordem nesta posição.

No terminal, o histórico de negociação é armazenado em forma de histórico de ordens e transações. Precisamos obter o histórico de posições. Para este efeito, acessamos o histórico de negociação e focamos na propriedade da transação DEAL_POSITION_ID e propriedade da ordem ORDER_POSITION_ID. Deixe-me explicar por que escolhemos essas propriedades. Na verdade, cada posição tem um identificador único (POSITION_IDENTIFIER) que se especifica em cada ordem (ORDER_POSITION_ID) e transação (DEAL_POSITION_ID) que a abriu, alterou ou fechou:

position deals orders 

Fig. 2. Ligação entre POSITION_IDENTIFIER, DEAL_POSITION_ID e ORDER_POSITION_ID

Em outras palavras, se as transações com os mesmos DEAL_POSITION_ID são separadas do histórico de negociação, a reconstrução da posição pode ser garantida. Aqui é necessário mencionar a inversão da posição. A partir da documentação sobre o identificador de posição:

A inversão de uma posição altera seu identificador para o bilhete da ordem que levou à inversão.

1.1. Inversão de posições

Isto significa que se, durante a inversão, a posição alterar seu identificador, esta será uma posição diferente. Como é que, neste caso, o identificador é atribuído às transações? Será que a transação que levou à inversão pertence à posição anterior ou à invertida (nova)? Para responder a esta pergunta, eu escrevi um exemplo simples, trata-se do script position_reversal_v1.mq5

Esse script executa três ações de negociação:

  • buy 0.01 — apertura da posição
  • sell 0.02 — inversão da posição
  • fechamento da posição

Nos parâmetros de entrada, é necessário especificar o tempo de inicialização, pois ele será usado para pedir o histórico de negociação. No meu caso, executei o script na data 2016.09.05 às 10:32:59, enquanto nos parâmetros de entrada tinha uma pequena diferença e selecionei D'2016.09.05 10:32:00'.

Após cada ação, o script imprime a posição e seu indicador, bem com o histórico de transações e o DEAL_POSITION_ID da transação. Eis a impressão:

10:32:59.487    position_reversal_v1 (EURUSD,M3)    Buy 0.01, "EURUSD"
10:33:00.156    position_reversal_v1 (EURUSD,M3)    Position EURUSD POSITION_IDENTIFIER #96633525
10:33:00.156    position_reversal_v1 (EURUSD,M3)    Deal EURUSD volume 0.01 DEAL_POSITION_ID #96633525 profit 0.00
10:33:00.156    position_reversal_v1 (EURUSD,M3)    
10:33:06.187    position_reversal_v1 (EURUSD,M3)    Sell 0.02, "EURUSD"
10:33:06.871    position_reversal_v1 (EURUSD,M3)    Position EURUSD POSITION_IDENTIFIER #96633564
10:33:06.871    position_reversal_v1 (EURUSD,M3)    Deal EURUSD volume 0.01 DEAL_POSITION_ID #96633525 profit 0.00
10:33:06.871    position_reversal_v1 (EURUSD,M3)    Deal EURUSD volume 0.02 DEAL_POSITION_ID #96633525 profit -0.06
10:33:06.871    position_reversal_v1 (EURUSD,M3)    
10:33:12.924    position_reversal_v1 (EURUSD,M3)    PositionClose, "EURUSD"
10:33:13.593    position_reversal_v1 (EURUSD,M3)    Deal EURUSD volume 0.01 DEAL_POSITION_ID #96633525 profit 0.00
10:33:13.593    position_reversal_v1 (EURUSD,M3)    Deal EURUSD volume 0.02 DEAL_POSITION_ID #96633525 profit -0.06
10:33:13.593    position_reversal_v1 (EURUSD,M3)    Deal EURUSD volume 0.01 DEAL_POSITION_ID #96633564 profit -0.10
10:33:13.593    position_reversal_v1 (EURUSD,M3)    

Primeira operação de negociação, buy 0.01. Seu POSITION_IDENTIFIER é igual a 96633525. No histórico de negociação existe uma transação, para ela é definido DEAL_POSITION_ID 96633525. Para esta transação, o DEAL_POSITION_ID coincide com o POSITION_IDENTIFIER da posição, o que significa que esta transação pertence à nossa posição. 

Segunda operação, sell 0.02. Esta operação levou à inversão da posição: nós tínhamos a posição buy 0.01, realizamos sell 0.02, como resultado obtivemos sell 0.01. Na posição atual, o POSITION_IDENTIFIER mudou e se tornou igual a 96633564, o que indica que obtivemos uma nova posição. E, então, o que é que está acontecendo no histórico de negociações nesse momento? Vemos que nele já existem dois transações com o mesmo DEAL_POSITION_ID e iguais a 96633525. Além disso, na segunda transação vemos "profit -0.06".

Significa que a transação -que levou à inversão da posição- tem a ver com a posição anterior.

Terceira operação, buy 0.01. Nesta fase, já não existe a posição (uma vez que foi fechada por nós), enquanto, no histórico de negociações há três transações: a primeira e a segunda têm o mesmo DEAL_POSITION_ID e são guais a 96633525, no entanto na terceira este identificador foi alterado para "96633564", além de aparecer "profit -0.10". Ou seja, a terceira transação pertence à segunda posição obtida como resultado da inversão da primeira.

1.2. Cálculo do lucro de posição

Com base na informação comprovada na seção 1.1. , é possível determinar com precisão o algoritmo de cálculo de lucro para cada uma das posições reconstruídas. O resultado financeiro total de todas as transações com o mesmo DEAL_POSITION_ID será o lucro calculado da posição cujo POSITION_IDENTIFIER seja igual ao DEAL_POSITION_ID. Mas como as únicas transações relevantes são buy e sell, é necessário introduzir uma restrição quanto ao tipo de negociação, quer dizer, a partir da numeração ENUM_DEAL_TYPE, será preciso selecionar apenas as seguintes transações:

ENUM_DEAL_TYPE

Identificador

Descrição

DEAL_TYPE_BUY

Compra

DEAL_TYPE_SELL

Venda

 

Alteramos um pouco nosso primeiro script e armazenamo-o sob o nome position_reversal_v2.mq5. No script position_reversal_v2.mq5 como sempre existem três blocos de negociação, isto é, buy 0.01, sell 0.02 e fechamento de posição. A novidade, neste script, é a função PrintProfitPositions(): nela é calculado o lucro para as posições reconstruídas. Vamos examinar essa função em detalhe:

//+------------------------------------------------------------------+
//| Print profit positions                                           |
//+------------------------------------------------------------------+
void PrintProfitPositions(void)
  {
//--- structure profit positions;
   struct struct_positions
     {
      long              position_id;
      double            position_profit;
      //--- constructor
                        struct_positions() {position_id=0; position_profit=0.0;}
     };
   struct_positions arr_struct_positions[];
//--- request trade history 
   HistorySelect(start,TimeCurrent());
   uint     total    =HistoryDealsTotal();
   ulong    ticket   =0;
   long     deal_id  =0;
   double   profit   =0;
   long     type     =0;
//--- for all deals 
   for(uint i=0;i<total;i++)
     {
      //--- try to get deals ticket 
      if((ticket=HistoryDealGetTicket(i))>0)
        {
         //--- get deals properties 
         deal_id  =HistoryDealGetInteger(ticket,DEAL_POSITION_ID);
         profit   =HistoryDealGetDouble(ticket,DEAL_PROFIT);
         type     =HistoryDealGetInteger(ticket,DEAL_TYPE);
         //--- only buy or sell; apenas buy e sell
         if(type==DEAL_TYPE_BUY || type==DEAL_TYPE_SELL)
           {
            bool seach=false;
            int number=ArraySize(arr_struct_positions);
            for(int j=0;j<number;j++)
              {
               if(arr_struct_positions[j].position_id==deal_id)
                 {
                  arr_struct_positions[j].position_profit+=profit;
                  seach=true;
                  break;
                 }
              }
            if(!seach)
              {
               ArrayResize(arr_struct_positions,number+1);
               arr_struct_positions[number].position_id=deal_id;
               arr_struct_positions[number].position_profit+=profit;
              }
           }
        }
     }
//---
   int number=ArraySize(arr_struct_positions);
   for(int i=0;i<number;i++)
     {
      Print("id ",arr_struct_positions[i].position_id," profit ",arr_struct_positions[i].position_profit);
     }
  }

Primeiro é declarada a estrutura struct_positions:

//--- structure profit positions;
   struct struct_positions
     {
      long              id;
      double            profit;
      //--- constructor
                        struct_positions() {id=0; profit=0.0;}
     };
   struct_positions arr_struct_positions[];

Na estrutura struct_positions dois campos:

id — identificador de posição;

profit — lucro da posição.

Imediatamente após isto, declaramos a matriz de estrutura arr_struct_positions[].

Abaixo está o bloco de variáveis auxiliares para acessar o histórico de transações:

//--- request trade history 
   HistorySelect(start,TimeCurrent());
   uint     total    =HistoryDealsTotal();
   ulong    ticket   =0;
   long     deal_id  =0;
   double   profit   =0;
   long     type     =0;

Em seguida, o ciclo para chamar o histórico de transações:

//--- for all deals 
   for(uint i=0;i<total;i++)
     {
      //--- try to get deals ticket 
      if((ticket=HistoryDealGetTicket(i))>0)
        {
...
         //--- only buy or sell; apenas buy e sell
         if(type==DEAL_TYPE_BUY || type==DEAL_TYPE_SELL)
           {
...
           }
        }
     }

Ao mesmo tempo, conforme mencionado acima, chamamos a atenção apenas para as transações "Buy" e "Sell".

Eis o código que itera sobre a matriz de estruturas arr_struct_positions[], se, nessa matriz, for encontrada uma correspondência dos campos position_id e o DEAL_POSITION_ID da transação a partir do histórico de negociação, no respetivo índice da matriz de estruturas, o lucro da transação atual será somado:

            bool seach=false;
            int number=ArraySize(arr_struct_positions);
            for(int j=0;j<number;j++)
              {
               if(arr_struct_positions[j].id==deal_id)
                 {
                  arr_struct_positions[j].profit+=profit;
                  seach=true;
                  break;
                 }
              }
            if(!seach)
              {
               ArrayResize(arr_struct_positions,number+1);
               arr_struct_positions[number].id=deal_id;
               arr_struct_positions[number].profit+=profit;
              }

Se, na matriz de estruturas, não forem encontradas coincidências do campo id e o DEAL_POSITION_ID da transação, a matriz de estruturas é aumentada um elemento, e esse novo elemento é imediatamente preenchido com valores.

Após preencher a matriz de estruturas, este código itera sobre a matriz e imprime os valores de identificador de posição e seu lucro: 

//---
   int number=ArraySize(arr_struct_positions);
   for(int i=0;i<number;i++)
     {
      Print("id ",arr_struct_positions[i].id," profit ",arr_struct_positions[i].profit);
     }

1.3. Tempo de abertura de posição

Complementando o script position_reversal_v1.mq5, adicionamos a saída -a partir do histórico de negociação- de todas as ordens junto com seus parâmetros. Salvamos o script sob o nome position_reversal_v3.mq5.

2016.09.06 15:05:34.399 position_reversal_v3 (USDJPY,M1)        Buy 0.01, "EURUSD"
2016.09.06 15:05:35.068 position_reversal_v3 (USDJPY,M1)        Position EURUSD POSITION_IDENTIFIER #96803513
2016.09.06 15:05:35.068 position_reversal_v3 (USDJPY,M1)        Deal EURUSD volume 0.01 DEAL_POSITION_ID #96803513 profit 0.00
2016.09.06 15:05:35.068 position_reversal_v3 (USDJPY,M1)        Order EURUSD initial_volume 0.01 ORDER_POSITION_ID #96803513 ORDER_TICKET 96803513
2016.09.06 15:05:35.068 position_reversal_v3 (USDJPY,M1)        
2016.09.06 15:05:41.088 position_reversal_v3 (USDJPY,M1)        Sell 0.02, "EURUSD"
2016.09.06 15:05:41.767 position_reversal_v3 (USDJPY,M1)        Position EURUSD POSITION_IDENTIFIER #96803543
2016.09.06 15:05:41.767 position_reversal_v3 (USDJPY,M1)        Deal EURUSD volume 0.01 DEAL_POSITION_ID #96803513 profit 0.00
2016.09.06 15:05:41.767 position_reversal_v3 (USDJPY,M1)        Deal EURUSD volume 0.02 DEAL_POSITION_ID #96803513 profit -0.08
2016.09.06 15:05:41.767 position_reversal_v3 (USDJPY,M1)        Order EURUSD initial_volume 0.01 ORDER_POSITION_ID #96803513 ORDER_TICKET 96803513
2016.09.06 15:05:41.767 position_reversal_v3 (USDJPY,M1)        Order EURUSD initial_volume 0.02 ORDER_POSITION_ID #96803543 ORDER_TICKET 96803543
2016.09.06 15:05:41.767 position_reversal_v3 (USDJPY,M1)        
2016.09.06 15:05:47.785 position_reversal_v3 (USDJPY,M1)        PositionClose, "EURUSD"
2016.09.06 15:05:48.455 position_reversal_v3 (USDJPY,M1)        Deal EURUSD volume 0.01 DEAL_POSITION_ID #96803513 profit 0.00
2016.09.06 15:05:48.455 position_reversal_v3 (USDJPY,M1)        Deal EURUSD volume 0.02 DEAL_POSITION_ID #96803513 profit -0.08
2016.09.06 15:05:48.455 position_reversal_v3 (USDJPY,M1)        Deal EURUSD volume 0.01 DEAL_POSITION_ID #96803543 profit -0.05
2016.09.06 15:05:48.455 position_reversal_v3 (USDJPY,M1)        Order EURUSD initial_volume 0.01 ORDER_POSITION_ID #96803513 ORDER_TICKET 96803513
2016.09.06 15:05:48.455 position_reversal_v3 (USDJPY,M1)        Order EURUSD initial_volume 0.02 ORDER_POSITION_ID #96803543 ORDER_TICKET 96803543
2016.09.06 15:05:48.455 position_reversal_v3 (USDJPY,M1)        Order EURUSD initial_volume 0.01 ORDER_POSITION_ID #96803543 ORDER_TICKET 96803561

Esse script exibe claramente a seguinte citação a partir do guia:

O identificador de posição é um número exclusivo atribuído a cada posição reaberta e não se altera durante toda sua vida. Ele corresponde ao bilhete da ordem com ajuda do qual foi aberta a posição

Que dizer, para definir o tempo de abertura da posição, basta encontrar, no histórico de negociação, a ordem cujo bilhete (ORDER_TICKET) seja igual ao identificador de posição (POSITION_IDENTIFIER) e obter o tempo da ordem encontrada (ORDER_TIME_DONE).

1.4. Armazenamento intermediário das posições reconstruídas

As posições reconstruídas serão armazenadas na matriz de estruturas struct_positions:

struct struct_positions
  {
   long              id;
   datetime          time;
   double            loss;
   double            profit;
   string            symbol_name;
   //--- constructor 
                     struct_positions() {id=0; time=0; loss=0.0; profit=0.0; symbol_name=NULL;}
  };

Onde

id — identificador de posição;

time — tempo de abertura de posição;

loss — posição desfavorável, aqui, nesse campo, o registro terá o signo "+" (o que é necessário para uma melhor representação visual do gráfico)

profit — posição rentável

symbol_name — nome do símbolo de acordo com o qual é aberta a posição.

No futuro, ao construir diferentes gráficos, a matriz de estruturas struct_positions será usada como banco de dados do histórico de negociação que é consolidado na posição.


2. Google Charts

Para exibição de análises, será usado o serviço Google Charts. Para fazer isso, os gráficos serão colocados numa página HTML. A seguir, esta página será aberta no navegador definido -por padrão- no sistema operacional (usando o Win API da função ShellExecuteW).

No artigo, serão usados dois tipos de gráficos: histograma e pizza. Vamos olhá-los em detalhe.

2.1. Histograma (tipo 'bar')

O tipo 'bar' permite exibir os seguintes gráficos em uma página HTML:

bar  bar1

Aqui está o código para o primeiro gráfico. Salve-o num arquivo com a extensão *.html (ou baixe o arquivo bar.html no final do artigo) e, em seguida, execute esse arquivo no seu navegador:

<html>
  <head>
    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">

      google.charts.load('current', {'packages':['bar']});
      google.charts.setOnLoadCallback(drawChart1);
      function drawChart1() {
        var data1 = google.visualization.arrayToDataTable([
          ['Symbol', 'Profit', 'Loss'],
          ['Si-6.16', 82.00, 944.00],
          ['Si-9.16', 56.00, 11.00],
          ['SBRF-9.16', 546.00, 189.00],
        ]);

        var options1 = {
          chart: {
            title: 'Profit/loss by Symbols',
            subtitle: 'Summary',
          },
          bars: 'vertical',
          vAxis: {format: 'decimal'},
          width: 440,
          height: 400,
          colors: ['#5b9bd5', '#ed7d31', '#7570b3']
        };
        var chart = new google.charts.Bar(document.getElementById('chart_div1'));
        chart.draw(data1, options1);
      }

    </script>
  </head>

  <body>
    <!--Div that will hold the pie chart-->
      <div id="chart_div1"></div>
    <br/>
  </body>
</html>

Para usar Google Charts, é necessário respeitar as seguintes regras sobre a colocação do código.

Os arquivos de carregador e de biblioteca são incluídos no bloco <head>:

    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">

Em seguida, especifica-se o tipo de gráfico e função que contém os dados para desenhar (drawChart):

      google.charts.load('current', {'packages':['bar']});
      google.charts.setOnLoadCallback(drawChart1);

A função drawChart1() é composta por três blocos:

  • "var data1" — bloco de dados segundo os quais é construído o gráfico
  • "var options1" — bloco de opções que especificam as configurações do gráfico
  • bloco que aponta para o recipiente para exibir o gráfico:

      function drawChart1() {
        var data1 = google.visualization.arrayToDataTable([
          ['Symbol', 'Profit', 'Loss'],
          ['Si-6.16', 82.00, 944.00],
          ['Si-9.16', 56.00, 11.00],
          ['SBRF-9.16', 546.00, 189.00],
        ]);

        var options1 = {
          chart: {
            title: 'Profit/loss by Symbols',
            subtitle: 'Summary',
          },
          bars: 'vertical',
          vAxis: {format: 'decimal'},
          width: 440,
          height: 400,
          colors: ['#5b9bd5', '#ed7d31', '#7570b3']
        };
        var chart = new google.charts.Bar(document.getElementById('chart_div1'));
        chart.draw(data1, options1);
      }

neste caso, há presença ou ausência da última vírgula na cadeia de caracteres

          ['SBRF-9.16', 546.00, 189.00],

não afeta o desempenho do código de página HTML, e isso simplifica grandemente o algoritmo para criar o bloco de dados. Por favor, note: uma vez construído gráfico do tipo 'bar', especificamos esse tipo como:

        var chart = new google.charts.Bar(document.getElementById('chart_div1'));

O recipiente é localizado no <body>:

    </script>
  </head>

  <body>
    <!--Div that will hold the pie chart-->
      <div id="chart_div1"></div>
    <br/>
  </body>
</html>

2.2. Gráfico de pizza (tipo 'corechart')

Neste artigo vamos usar este diagrama:

corechart 

O código da página HTML, que gera a criação do gráfico de pizza, é mostrado abaixo. Salve este código num arquivo com a extensão *.html (ou baixe o arquivo corechart.html no final do artigo) e, em seguida, execute esse arquivo no seu navegador.

<html>
  <head>
    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">

      google.charts.load('current', {'packages':['corechart']});
      google.charts.setOnLoadCallback(drawChart2);
      function drawChart2() {
        var data2 = google.visualization.arrayToDataTable([
          ['Symbols', 'Profit'],
          ['Si-6.16', 82.00],
          ['Si-9.16', 56.00],
          ['SBRF-9.16', 546.00],
        ]);

        var options2 = {
            title: 'Profit by Symbols, %',
            pieHole: 0.4,
            width: 440,
            height: 400,
        };
        var chart = new google.visualization.PieChart(document.getElementById('chart_div2'));
        chart.draw(data2, options2);
      }

    </script>
  </head>

  <body>
    <!--Div that will hold the pie chart-->
      <div id="chart_div2"></div>
    <br/>
  </body>
</html>

Funcionalmente, os blocos são dispostos da mesma maneira como no exemplo acima, apenas com ligeiras alterações na representação de dados. Para o gráfico de pizza, os dados são especificados como segue:

        var data2 = google.visualization.arrayToDataTable([
          ['Symbols', 'Profit'],
          ['Si-6.16', 82.00],
          ['Si-9.16', 56.00],
          ['SBRF-9.16', 546.00],
        ]);

        var options2 = {
            title: 'Profit by Symbols, %',
            pieHole: 0.4,
            width: 440,
            height: 400,
        };

e já que estamos construindo um gráfico do tipo 'corechart', o bloco, que especifica o recipiente, tem a seguinte aparência:

        var chart = new google.visualization.PieChart(document.getElementById('chart_div2'));
        chart.draw(data2, options2);

2.3. Histograma (tipo 'bar') + gráfico de pizza (tipo 'corechart') + histograma (tipo 'bar')

O código deste exemplo é armazenado no arquivo bar_corechart_bar.html e está disponível para ser baixado no final do artigo. O exemplo em si parece com isso (imagem reduzida): 

bar+ corechart + bar 

A configuração, onde diferentes tipos de gráficos estão presentes em simultâneo, é mais difícil, porque aqui é necessário distribuir adequadamente, na página, as funções function drawChart***() e blocos que apontam para o recipiente em que o gráfico será exibido. Ao colocar gráficos de vários tipos (por exemplo, histograma e gráfico de pizza) numa única página, eles são incluídos da seguinte forma:

      google.charts.load('current', {'packages':['bar', 'corechart']});

O esquema geral do arquivo bar_corechart_bar.html será:

<html>
  <head>
    <!--Load the AJAX API-->
    <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
    <script type="text/javascript">

      google.charts.load('current', {'packages':['bar', 'corechart']});
      google.charts.setOnLoadCallback(drawChart1);
      google.charts.setOnLoadCallback(drawChart2);
      google.charts.setOnLoadCallback(drawChart4);
      function drawChart1() {
        var data1 = ...

        var options1 = ...

        var chart = new google.charts.Bar(document.getElementById('chart_div1'));
        chart.draw(data1, options1);
      }

      function drawChart2() {
        var data2 = ...

        var options2 = ...

        var chart = new google.visualization.PieChart(document.getElementById('chart_div2'));
        chart.draw(data2, options2);
      }

      function drawChart4() {
        var data4 = ...

        var options4 = ...

        var chart = new google.charts.Bar(document.getElementById('chart_div4'));
        chart.draw(data4, options4);
      }

    </script>
  </head>

  <body>
    <!--Div that will hold the pie chart-->
      <table>
        <tr>
          <td><div id="chart_div1"></div></td>
          <td><div id="chart_div2"></div></td>
          <td><div id="chart_div4"></div></td>
      </table>
    <br/>
  </body>
</html>

As funções drawChart1 e drawChart4 desenham histogramas, enquanto a função drawChart2, gráficos de pizza.


3. Execução de gráficos de análise a partir do terminal (para a conta de negociação atual)

A opção mais fácil é um pequeno script que após se juntar ao gráficos executa o navegador e exibe os gráficos de distribuição de análise dependendo da hora de entrada. O mais importante é indicar a data a partir da qual é preciso construir da análise (parâmetro de entrada "start"):

//+------------------------------------------------------------------+
//|                                                  test_report.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
//---
input datetime start=D'2010.05.11 12:05:00';
#include <DistributionOfProfits.mqh>
//---
CDistributionOfProfits Analysis;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   Analysis.AnalysisTradingHistory(start);
   Analysis.ShowDistributionOfProfits();
  }
//+------------------------------------------------------------------+

Como, no arquivo "DistributionOfProfits.mqh", usa-se a chamada pelo sistema dll, ao executar o script de teste, é necessário permitir a importação dll:

dependencies 


4. Execução de gráficos de análise a partir do testador de estratégias

Por exemplo, vamos tomar o Expert Advisor "MACD Sample.mq5", que vem no conjunto padrão (diretório de dados\MQL5\Experts\Examples\MACD\MACD Sample.mq5). Copiamos este Expert Advisor para uma pasta separada para assegurar que as nossas alterações não afectarão o arquivo original. Em seguida, mudamos seu nome para "MACD Sample report.mq5".  Fazemos as seguintes alterações no Expert Advisor:

//+------------------------------------------------------------------+
//|                                           MACD Sample report.mq5 |
//|                   Copyright 2009-2016, MetaQuotes Software Corp. |
//|                                              https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright   "Copyright 2009-2016, MetaQuotes Software Corp."
#property link        "https://www.mql5.com"
#property version     "5.50"
#property description "It is important to make sure that the expert works with a normal"
#property description "chart and the user did not make any mistakes setting input"
#property description "variables (Lots, TakeProfit, TrailingStop) in our case,"
#property description "we check TakeProfit on a chart of more than 2*trend_period bars"

#define MACD_MAGIC 1234502
//---
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\AccountInfo.mqh>
#include <DistributionOfProfits.mqh>
//---
input double InpLots          =0.1; // Lots
input int    InpTakeProfit    =50;  // Take Profit (in pips)
input int    InpTrailingStop  =30;  // Trailing Stop Level (in pips)
input int    InpMACDOpenLevel =3;   // MACD open level (in pips)
input int    InpMACDCloseLevel=2;   // MACD close level (in pips)
input int    InpMATrendPeriod =26;  // MA trend period
//---
int ExtTimeOut=10; // time out in seconds between trade operations
CDistributionOfProfits ExtDistribution;
//+------------------------------------------------------------------+
//| MACD Sample expert class                                         |
//+------------------------------------------------------------------+
class CSampleExpert
  {
protected:

No final do mesmo, adicionamos a função OnTester():

//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---
   double ret=0.0;
   ExtDistribution.AnalysisTradingHistory(0);
   ExtDistribution.ShowDistributionOfProfits();
//---
   return(ret);
  }

Antes de executar o testador, é preciso, nas configurações do terminal, permitir o uso de dll:

options ea 

Como resultado, obtivemos uma página com gráficos de análise na qual eu sugiro que você confira o gráfico de distribuição de limites de lucro/perdas:

profit/loss hours

É claro a que horas são abertas as posições rentáveis e as não rentáveis. O gráfico que eu identifiquei dois períodos com perdas. O que acontecerá se nós limitarmos a negociação nas horas desfavoráveis especificadas? Ou talvez consigamos ir ainda mais longe, que dizer, reverter os sinais de negociação para os opostos, a fim de obter lucros em vez de perdas? Convido o leitor a verificá-lo sozinho.

Também é possível obter resultados interessantes se, no testador de estratégias, é executado um Expert Advisor multimoeda. Como modelo, usei a partir do CodeBase o EA gratuito Multicurrency Expert. Adicionalmente, no cabeçalho do EA foi registrado o arquivo "#include <DistributionOfProfits.mqh>", declarada a variável "CDistributionOfProfits ExtDistribution", enquanto, no final do código, foi adicionada a função "OnTester()". Após o teste único, é obtida a seguinte estatística: "TestAnalysis.htm".

Observe que todos os elementos gráficos são interativos. Por exemplo, no primeiro histograma, isto é, "lucro/perda de acordo com os símbolos (total)", ao colocar o cursor do mouse, é possível ver os números para cada símbolo:

profit/loss 1 profit/loss 2

Agora, os gráficos de pizza: eles mostram que contribuição foi feita por cada símbolo para o lucro e perda durante a negociação:

profit percent  loss percent

No resto dos diagramas, é possível ver o lucro de acordo com cada símbolo, dependendo do tempo de entrada na posição: distribuição por horas de entrada, por dias e meses.

 

Isto é a otimização "silenciosa" sem barulho e poeira

A tarefa do desenho de distribuições de transações foi concluída. Com isso, o histórico de negociação se consolida na posição, e todos os gráficos analíticos são representados exclusivamente para as posições. O lucro ou perda da posição se analisa por tempo de entrada, de três maneiras: por horas, por dias da semana e por meses.

Com a ajuda dos códigos-fonte fornecidos no artigo, qualquer estratégia pode ser verificada de acordo com as horas e dias favoráveis e desfavoráveis para negociar. E quem sabe, talvez, em vez de uma estratégia inicial, você obtenha um par de novas, por exemplo, uma estratégia de tendência e outra contra-tendência, ou você note qual sessão (asiática, europeia ou norte-americana) deve ser evitada, e não negociar. Sinta-se livre para tentar este método de otimização "silenciosa", ele não exige quaisquer execuções adicionais no testador de estratégias.

 

Alterações

Brevemente sobre as alterações que foram feitas no código, após a primeira publicação do artigo:

"DistributionOfProfits.mqh" v.1.027: é introduzida a proteção ao trabalhar com o programa durante a otimização. No construtor, o nome do arquivo é "Non File", enquanto nas duas funções públicas é verificada a constante MQL_OPTIMIZATION:

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CDistributionOfProfits::CDistributionOfProfits(void) : m_name_file("Non File"),
                                                       m_color_loss("ed7d31"),
                                                       m_color_profit("5b9bd5"),
                                                       m_width("440"),
                                                       m_height("400"),
                                                       m_data_number(1)
  {
  }
//+------------------------------------------------------------------+
//| Analysis Trading History                                         |
//+------------------------------------------------------------------+
bool CDistributionOfProfits::AnalysisTradingHistory(const datetime start_time=0)
  {
//---
   if(MQLInfoInteger(MQL_OPTIMIZATION))
      return(false);
//+------------------------------------------------------------------+
//| Show Distribution Of Profits (start of the browser)              |
//+------------------------------------------------------------------+
void CDistributionOfProfits::ShowDistributionOfProfits(void)
  {
//---
   if(MQLInfoInteger(MQL_OPTIMIZATION))
      return;

"DistributionOfProfits.mqh" v.1.033: agora é possível analisar as posições em dinheiro, pontos, ou em ambas as duas.

A seleção do tipo de análise é definido como segue:

//+------------------------------------------------------------------+
//|                                                  test_report.mq5 |
//|                        Copyright 2016, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property script_show_inputs
//+------------------------------------------------------------------+
//| type of report                                                   |
//+------------------------------------------------------------------+
enum ANALYSIS_TYPE
  {
   ONLY_MONEY=0,        // in money 
   ONLY_POINTS=1,       // in points 
   MONEY_AND_POINTS=2,  // in money and points
  };
//---
input datetime start=D'2016.06.28 09:10:00';
input ANALYSIS_TYPE report_type=MONEY_AND_POINTS;
//---
#include <DistributionOfProfits.mqh>
//---
CDistributionOfProfits Analysis;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   Analysis.SetTypeOfAnalysis(report_type);
   Analysis.AnalysisTradingHistory(start);
   Analysis.ShowDistributionOfProfits();
  }
//+------------------------------------------------------------------+


 

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

Últimos Comentários | Ir para discussão (1)
Rodrigo da Silva Boa
Rodrigo da Silva Boa | 25 out 2016 em 02:42

Obrigado pela contribuição,

Excelente material. 

MQL5 vs QLUA - Por que operações de negociação no MQL5 são até 28 vezes mais rápidas? MQL5 vs QLUA - Por que operações de negociação no MQL5 são até 28 vezes mais rápidas?
Você já se perguntou como a sua ordem é entregue tão rápida na bolsa? Também já se perguntou quanto tempo seu terminal precisa para receber o resultado da operação? Nós fizemos uma comparação da velocidade de execução da operação de negociação, pois ninguém nunca mediu esses valores utilizando aplicações nas linguagens de programação MQL5 ou QLUA.
Interfaces Gráficas VIII: O Controle Calendário (Capítulo 1) Interfaces Gráficas VIII: O Controle Calendário (Capítulo 1)
Na parte VIII da série de artigos dedicados à criação de interfaces gráficas no MetaTrader, nós vamos introduzir os controles compostos complexos como os calendários, lista hierárquica e o navegador de arquivos. Devido à grande quantidade de informações, os artigos foram escritos separadamente para cada assunto. O primeiro capítulo desta parte descreve o controle calendário e sua versão expandida — um calendário suspenso.
Avaliação rápida do sinal: atividade comercial, gráficos de abaixamento/carregamento e distribuição de MFE/MAE Avaliação rápida do sinal: atividade comercial, gráficos de abaixamento/carregamento e distribuição de MFE/MAE
Ao procurar por um sinal, os assinantes são orientados principalmente para o aumento global na conta do Provedor, e isto é, na verdade, lógico. No entanto, além disso, é importante levar em conta os riscos potenciais incorridos por uma estratégia de negociação específica. Neste artigo, nós lhe mostraremos como avaliar simples e claramente o Sinal de interesse utilizando diversos indicadores.
Rede neural: Expert Advisor auto-otimizável Rede neural: Expert Advisor auto-otimizável
Será que é possível criar um Expert Advisor que, de acordo com os comandos do código, otimize os critérios de abertura e fechamento das posições automaticamente e em intervalos regulares? O que acontecerá se nós implementarmos no EA uma rede neural (um perceptron multi-camada) que, sendo módulo, analise o histórico e avalie a estratégia? É possível dar ao código um comando para uma otimização mensal (semanal, diária ou por hora) de rede neural com um processo subsequente. Assim, é possível criar um Expert Advisor que se auto-otimize.