English Русский 中文 Español Deutsch 日本語
preview
Anotação de dados na análise de série temporal (Parte 1): Criação de um conjunto de dados com rótulos de tendência usando um gráfico EA

Anotação de dados na análise de série temporal (Parte 1): Criação de um conjunto de dados com rótulos de tendência usando um gráfico EA

MetaTrader 5Experts | 12 fevereiro 2024, 14:05
240 0
Yuqiang Pan
Yuqiang Pan

Introdução

Quando desenvolvemos modelos de inteligência artificial, geralmente precisamos treinar os dados primeiro. Dados de boa qualidade nos permitem obter resultados duas vezes melhores com a metade do esforço de treinamento e validação do modelo. Entretanto, os dados relacionados a moedas ou ações são peculiares. Eles possuem informações de mercado e de tempo complexas, têm um processo de rotulação difícil, mas, mesmo assim, podemos analisar facilmente a tendência dos dados históricos disponíveis no gráfico.

 

Esta seção apresenta um método para criar conjuntos de dados rotulados por tendências usando gráficos do Expert Advisor. Você pode manusear intuitivamente os dados implementando suas ideias. É claro que você também pode usar esse método para expandir e personalizar seus próprios conjuntos de dados!

Conteúdo:

  1. Formatação dos dados para rotulação
  2. Inicialização de gráficos e arquivos
  3. Lógica de trabalho
  4. Organização de dados e gravação em arquivo
  5. Apêndice: exemplo completo de código do EA


Formatação dos dados para rotulação

Quando recebemos dados sobre moedas ou ações que vêm de um cliente (este artigo não aborda dados externos lidos de arquivos ou baixados de outros sites), a situação geral é a seguinte:

Time Open High Low Close Tick_volume
2021-12-10 01:15:00
1775.94
1775.96
1775.58
1775.58
173
2021-12-10 01:30:00
1775.58
1776.11
1775.48
1775.88
210
2021-12-10 01:45:00
1775.88
1776.22
1775.68
1776.22
212
2021-12-10 02:00:00
1776.22
1777.57
1775.98
1777.02
392
2021-12-10 02:15:00
1776.99
1777.72
1776.89
1777.72
264

Acima, vemos como aparecem os dados das cinco séries temporais. Os valores Close e Open estão relacionados entre si do início ao fim, e a relação é muito forte. Partimos do princípio de que as duas primeiras linhas são de uma tendência ascendente e as demais são de uma tendência descendente (os dados acima são apenas um exemplo). O método convencional de rotulação dividiria os dados em duas partes:

Time

Open High   Low   Close Tick_volume
2021-12-10 01:15:00
1775.94
1775.96
1775.58
1775.58
173
2021-12-10 01:30:00
1775.58
1776.11
1775.48
1775.88
210

Time Open High   Low Close Tick_volume
2021-12-10 01:45:00
1775.88
1776.22
1775.68
1776.22
212
2021-12-10 02:00:00
1776.22
1777.57
1775.98
1777.02
392
2021-12-10 02:15:00
1776.99
1777.72
1776.89
1777.72
264

Em seguida, o método informa ao nosso modelo qual parte representa uma tendência ascendente e qual representa uma tendência descendente, mas ao fazer isso, ignora seus atributos comuns e compromete a integridade dos dados. Como podemos resolver esse problema?

Temos a possibilidade de adicionar uma agrupação de tendências à nossa série temporal da seguinte forma (tome os cinco pedaços de dados acima como exemplo ou siga as suposições mencionadas anteriormente):

Time Open High Low Close Tick_volume Trend_group
2021-12-10 01:15:00
1775.94
1775.96
1775.58
1775.58
173 0
2021-12-10 01:30:00
1775.58
1776.11
1775.48
1775.88
210 0
2021-12-10 01:45:00
1775.88
1776.22
1775.68
1776.22
212 1
2021-12-10 02:00:00
1776.22
1777.57
1775.98
1777.02
392 1
2021-12-10 02:15:00
1776.99
1777.72
1776.89
1777.72
264 1

Mas se quisermos implementar a análise do desenvolvimento da tendência no modelo, em particular o quanto a tendência atual se desenvolveu (por exemplo, a teoria das ondas nos diz que uma tendência geral geralmente inclui uma fase de tendência e uma fase de correção, uma fase de tendência tem 5 fases de onda e uma fase de correção tem 3 ajustes de onda, etc.), precisamos dividir adicionalmente os dados. Podemos fazer isso adicionando outra coluna que represente o desenvolvimento da tendência contida nos dados (supondo que os primeiros 2 dos próximos 10 dados estejam em tendência ascendente, os últimos 5 estejam em tendência ascendente e o restante no meio esteja em tendência descendente), assim:

Time Open High Low Close Tick_volume Trend_group Trend_index
2021-12-10 03:15:00 1776.38 1777.94 1775.47 1777.71 565 0 0
2021-12-10 03:30:00 1777.75 1778.93 1777.68 1778.61 406 0 1
2021-12-10 03:45:00 1778.58 1778.78 1777.65 1778.16 388 1 0
2021-12-10 04:00:00 1778.14 1779.42 1778.06 1779.14 393 1 1
2021-12-10 04:15:00 1779.16 1779.49 1778.42 1779.31 451 1 2
2021-12-10 04:30:00 1779.22 1779.42 1778.36 1778.37 306 0 0
2021-12-10 04:45:00 1778.42 1778.51 1777.60 1777.78 411 0 1
2021-12-10 05:00:00 1777.81 1778.68 1777.61 1778.57 372 0 2
2021-12-10 05:15:00 1778.54 1779.29 1778.42 1779.02 413 0 3
2021-12-10 05:30:00 1778.97 1779.49 1778.48 1778.50 278 0 4

Notas:

1. Trend_group, que define uma tendência ascendente, é igual a 0

2. Trend_group, que define uma tendência descendente, é igual a 1.

 Então, começaremos a controlar o gráfico no lado do cliente, colocando os dados de acordo com o padrão desejado.


Inicialização de gráficos e arquivos

    Inicialização do gráfico

          Como precisamos olhar para o gráfico para rotular os dados, ele deve ser rolado de acordo com o que fazemos manualmente, por isso, precisamos desativar CHART_AUTOSCROLL e CHART_SHIFT:

           ChartSetInteger (0, CHART_AUTOSCROLL, false);
          
            ChartSetInteger (0, CHART_SHIFT, true);
          
            ChartSetInteger (0, CHART_MOUSE_SCROLL ,1);
          Nota: A parte em verde do código é destinada ao controle do gráfico usando a roda do mouse
            Inicialização do arquivo

                Ao inicializar o arquivo, primeiramente é necessário verificar se existe um arquivo de rotulação e um arquivo de dados históricos, e então armazenar o nome do arquivo na variável reName:

                 do
                     {
                       //---Find if there are files that match the chart
                       if (StringFind(name, Symbol())!=-1 && StringFind(name,".csv")!=-1)
                         reName=name;
                     }
                
                   while (FileFindNext(hd,name));
                Nota: Usamos o laço do - while, que difere do laço while porque primeiro executa a instrução e depois avalia a expressão. O principal problema aqui é a inicialização do nome
                int hd= FileFindFirst("*",name,0);


                  Se houver um arquivo original rotulado, vamos abri-lo e obter o último tempo rotulado pela função read_csv():

                    read_csv(file_handle,a);
                    Em seguida, rolamos o gráfico até o último tempo rotulado:
                    shift = - iBarShift(Symbol(),PERIOD_CURRENT,(datetime)a[i-8]);
                    ChartNavigate(0, CHART_END ,shift);


                    Criamos um arquivo de histórico se não houver nenhum:

                    file_handle = FileOpen(StringFormat("%s%d-%d.csv",Symbol(),Period(),start_t), FILE_WRITE | FILE_CSV | FILE_READ);
                    Depois, rolamos o gráfico até a posição especificada pela variável global start_t.
                     shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)start_t);
                      ChartNavigate(0,CHART_END,shift);
                    Adicionamos uma linha vermelha vertical para rotular a coluna inicial:
                     ObjectCreate (0,"Start",OBJ_VLINE,0,(datetime)start_t,0)
                    A lógica dessa parte está estruturada da seguinte forma:
                     if (FileIsExist(reName))
                         {
                          file_handle = FileOpen(reName, FILE_WRITE | FILE_CSV | FILE_READ );
                           string a[];
                           int i= 0 ;
                          read_csv(file_handle,a);
                          i = ArraySize (a);
                          shift = -iBarShift(Symbol(), PERIOD_CURRENT,(datetime)a[i-8]);
                           ChartNavigate(0,CHART_END,shift);
                         }
                       else
                         {
                          file_handle = FileOpen (StringFormat ("%s%d-%d.csv", Symbol(), Period(),start_t), FILE_WRITE | FILE_CSV | FILE_READ );
                           Print ("There is no history file,create file:" , StringFormat ( "%s%d-%d",Symbol(), Period(),start_t));
                           shift = - iBarShift (Symbol(), PERIOD_CURRENT ,(datetime)start_t);
                           ChartNavigate (0, CHART_END ,shift);
                           ObjectCreate (0,"Start", OBJ_VLINE,0,(datetime)start_t,0);
                         }
                    Atenção: Como queremos mover o gráfico para a esquerda, antes da função iBarShift(), é necessário adicionar "-".
                    shift = -iBarShift(Symbol(), PERIOD_CURRENT ,(datetime)start_t);
                    Claro que a lógica também pode ser implementada na função ChartNavigate(), por exemplo:
                    ChartNavigate(0,CHART_END,-shift);
                    No entanto, o código deste artigo é implementado usando o primeiro método.
                      Essas ações de inicialização serão implementadas em nosso OnInit(), incluindo a definição das variáveis de que precisamos. O mais importante é especificar para onde queremos deslocar o gráfico e começar a rotulação. Isso é controlado em grande parte pelas variáveis shift e start_t. O código final será como este:
                        int OnInit()
                          {
                        //---initial
                           string name;
                           string reName="1";
                           int hd=FileFindFirst("*",name,0);
                           int shift;
                        
                           ChartSetInteger(0,CHART_AUTOSCROLL,false);
                           ChartSetInteger(0,CHART_SHIFT,false);
                           ChartSetInteger(0,CHART_MOUSE_SCROLL,1);
                        
                        
                           do
                             {
                              //---check File
                              if(StringFind(name,Symbol())!=-1 && StringFind(name,".csv")!=-1)
                                 reName=name;
                             }
                           while(FileFindNext(hd,name));
                        
                           if(FileIsExist(reName))
                             {
                              file_handle = FileOpen(reName,FILE_WRITE|FILE_CSV|FILE_READ);
                              string a[];
                              int i=0;
                              read_csv(file_handle,a);
                              i = ArraySize(a);
                              shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)a[i-8]);
                              ChartNavigate(0,CHART_END,shift);
                             }
                           else
                             {
                              file_handle = FileOpen(StringFormat("%s%d-%d.csv",Symbol(),Period(),start_t),FILE_WRITE|FILE_CSV|FILE_READ);
                              Print(FileTell(file_handle));
                              Print("No history file,create file:",StringFormat("%s%d-%d",Symbol(),Period(),start_t));
                              shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)start_t);
                              ChartNavigate(0,CHART_END,shift);
                              ObjectCreate(0,"Start",OBJ_VLINE,0,(datetime)start_t,0);
                             }
                           return(INIT_SUCCEEDED);
                          }

                          Notas:

                          1. start_t variable - timeframe para dar início;

                          2. Shift variable - número de colunas a serem deslocadas; o código de exemplo mostra o número de colunas que serão deslocadas por meio da conversão do tempo especificado;

                          3. A função read_csv() será definida posteriormente.

                            Definição da função read_csv():
                               void read_csv(int hd,
                                             string &arry[])
                                {
                                 int i= 0;
                                 while(!FileIsEnding(hd))
                                   {
                                    ArrayResize(arry,i+1);
                                    arry[i]= FileReadString(hd);
                                    i++;
                                   }
                                }

                              Nota: Usamos um laço while para encontrar a linha final do arquivo de anotações históricas, obter a última linha de dados no arquivo e encontrar o tempo de término da nossa última anotação. A anotação rolará o gráfico de preços até o gráfico de barras, para que possamos continuar comentando a partir daqui.


                              Lógica de trabalho

                                Gerenciamento de gráficos: Essa seção pode ser facilmente encontrada na ajuda do cliente.
                                  • Home — ir para a última barra do gráfico;
                                  • End — ir para a primeira barra do gráfico;
                                  • Page Up — mover o gráfico uma janela para trás;
                                  • Page Down — mover o gráfico uma janela para frente;
                                  • Ctrl+I — abrir a janela com a lista de indicadores;
                                  • Ctrl+B — abrir a janela com a lista de objetos;
                                  • Alt+1 — o gráfico é exibido como uma série de barras;
                                  • Alt+2 — o gráfico é exibido como uma sequência de velas japonesas;
                                  • Alt+3 — o gráfico é exibido como uma linha que conecta os preços de fechamento;
                                  • Ctrl+G — mostrar/ocultar a grade na janela do gráfico;
                                  • "+" — aumentar o zoom no gráfico;
                                  • "-" — reduzir a escala do gráfico;
                                  • F12 — rolar o gráfico passo a passo (barra por barra);
                                  • F8 — abrir a janela de propriedades;
                                  • Backspace — remover o último objeto adicionado ao gráfico;
                                  • Excluir — remover todos os objetos selecionados;
                                  • Ctrl+Z — desfazer o apagamento do último objeto.
                                    Lógica de controle:
                                      1. Pressione uma tecla para informar ao Expert Advisor qual será a tendência dos dados rotulados a seguir.
                                        Definiremos as teclas b e s. São definidas pelo código virtual da tecla:
                                           #define KEY_B     66
                                           #define KEY_S     83
                                            Pressione b e então s para uma tendência ascendente ou s e então b para uma tendência descendente. Tomemos como exemplo uma tendência ascendente:
                                              1) Pressionamos b para uma tendência ascendente. Configuramos a variável typ como 0, a variável tp como start, a cor da seta como clrBlue e aumentamos o número de rótulos Num em 1. Precisamos apenas aumentar a variável no início do segmento de dados e especificar que pressionar o botão novamente executará a parte "final" do segmento de dados rotulado, invertendo-a;
                                              b_press
                                              2) Pressionamos s para rotular o fim da tendência ascendente, a variável typ ainda é 0, a variável tp é definida como end, a cor da seta ainda é clrBlue e o número de rótulos Num permanece inalterado. Só precisamos aumentar a variável no início do segmento de dados, e a inversão de first é usada para indicar que pressionar o botão novamente fará com que a parte "inicial" do segmento de dados rotulado seja executada. s_press
                                              3) Depois de executar a instrução switch, vamos chamar a função ChartRedraw() para redesenhar o gráfico.
                                              if(id==CHARTEVENT_KEYDOWN)
                                                   {
                                                    switch(lparam)
                                                      {
                                                       case KEY_B:
                                                          if(first)
                                                            {
                                                             col=clrBlue ;
                                                             typ =0;
                                                             Num+=1;
                                                             tp = "start";
                                                            }
                                                          else
                                                            {
                                                             col=clrRed ;
                                                             typ = 1;
                                                             tp = "end";
                                                            }
                                                          ob =OBJ_ARROW_BUY;
                                                          first = !first;
                                                          Name = StringFormat("%d-%d-%s",typ,Num,tp);
                                                          break;
                                                       case KEY_S:
                                                          if(first)
                                                            {
                                                             col=clrRed ;
                                                             typ =1;
                                                             Num+=1;
                                                             tp = "start";
                                                            }
                                                          else
                                                            {
                                                             col=clrBlue ;
                                                             typ = 0;
                                                             tp = "end";
                                                            }
                                                          ob =OBJ_ARROW_SELL;
                                                          first = !first;
                                                          Name = StringFormat("%d-%d-%s",typ,Num,tp);
                                                          break;
                                              
                                                       default:
                                                          Print("You pressed:"+lparam+" key, do nothing!");
                                                      }
                                                    ChartRedraw(0);
                                                   }

                                              Notas:

                                              1. variável type — 0 significa tendência ascendente, 1 — tendência descendente;

                                              2. variável "Num" - número de rótulos, que será intuitivamente exibido no gráfico;

                                              3. variável first controla que nossos rótulos sempre vêm em pares, o que garante que cada grupo represente b e s ou s e b, evitando confusão;

                                              4. variável tp é usada para determinar o início ou fim do segmento de dados.

                                              2. Clique com o botão esquerdo do mouse no gráfico para definir a posição do rótulo

                                              if(id==CHARTEVENT_CLICK)
                                                   {
                                                    //--- definition
                                                    int x=(int)lparam;
                                                    int y=(int)dparam;
                                                    datetime dt    =0;
                                                    double   price =0;
                                                    int      window=0;
                                                    if(ChartXYToTimePrice(0,x,y,window,dt,price))
                                                      {
                                                       ObjectCreate(0,Name,ob,window,dt,price);
                                                       ObjectSetInteger(0,Name,OBJPROP_COLOR,col);
                                                       //Print("time:",dt,"shift:",iBarShift(Symbol(),PERIOD_CURRENT,dt));
                                                       if(tp=="start")
                                                          Start=dt;
                                                       else
                                                         {
                                                          if(file_handle)
                                                             file_write(Start,dt);
                                                         }
                                                       ChartRedraw(0);
                                                      }
                                                    else
                                                       Print("ChartXYToTimePrice return error code: ",GetLastError());
                                                   }
                                              //--- object delete
                                                 if(id==CHARTEVENT_OBJECT_DELETE)
                                                   {
                                                    Print("The object with name ",sparam," has been deleted");
                                                   }
                                              //--- object create
                                                 if(id==CHARTEVENT_OBJECT_CREATE)
                                                   {
                                                    Print("The object with name ",sparam," has been created!");
                                                   }

                                              Notas:

                                              1. A função ChartXYToTimePrice() é usada principalmente para obter as propriedades do gráfico no local do clique, incluindo o tempo atual e o preço. A variável global dt é necessária para obter o tempo atual;

                                              2. Com o clique do mouse, também precisamos determinar se a ação atual é o início ou o fim do segmento de dados. Usamos a variável global tp para avaliação. 

                                              3. Ações a serem realizadas


                                                Se você deseja rotular uma tendência ascendente, primeiro pressione a tecla b, clique com o botão esquerdo do mouse na coluna que começa a ser rotulada no gráfico, então pressione a tecla s, e então clique com o botão esquerdo do mouse no final da coluna no gráfico para completar a rotulação. Uma par de setas azuis aparecerá no gráfico, como mostrado na imagem abaixo:

                                                  para cima


                                                      Se você deseja rotular uma tendência descendente, primeiro pressione a tecla s, clique com o botão esquerdo do mouse na coluna que começa a ser rotulada no gráfico, então pressione a tecla b, e então clique com o botão esquerdo do mouse no final da coluna no gráfico. Após completar a rotulação, um par de setas vermelhas aparecerá, como mostrado na imagem abaixo:

                                                        para baixo


                                                          A coluna de saída de rotulação exibirá a ação de rotulação a qualquer momento, o que é muito conveniente para acompanhar o processo, conforme mostrado na figura:

                                                            outNota: Esta parte, na verdade, poderia ser melhor otimizada, por exemplo, adicionando uma função para desfazer a última ação, permitindo que você ajuste a posição do rótulo a qualquer momento, além de evitar operações incorretas, mas sou uma pessoa preguiçosa... (^о^)


                                                            Organização de dados e gravação em arquivo

                                                              Definimos as variáveis Start e MqlRatesrates[] para armazenar o tempo de início e a série de dados da tendência:
                                                                datetime Start;
                                                                MqlRates rates[];
                                                                ArraySetAsSeries(rates, false);
                                                                  Nota: 1. Aqui não precisamos definir o tempo final, porque o último tempo obtido do gráfico é o tempo final; 2. O sinalizador na função ArraySetAsSeries(rates,false) é definido como false para garantir a concatenação sequencial dos períodos de tempo.
                                                                    Quando tp = "end", gravamos o segmento de dados em um arquivo (parte verde do código):
                                                                         if(id==CHARTEVENT_CLICK)
                                                                           {
                                                                            //--- definition
                                                                            int x=(int)lparam;
                                                                            int y=(int)dparam;
                                                                            datetime dt    =0;
                                                                            double   price =0;
                                                                            int      window=0;
                                                                            if(ChartXYToTimePrice(0,x,y,window,dt,price))
                                                                              {
                                                                               ObjectCreate(0,Name,ob,window,dt,price);
                                                                               ObjectSetInteger(0,Name,OBJPROP_COLOR,col);
                                                                               //Print("time:",dt,"shift:",iBarShift(Symbol(),PERIOD_CURRENT,dt));
                                                                               if(tp=="start")
                                                                                  Start=dt;
                                                                               else
                                                                                 {
                                                                                  if(file_handle)
                                                                                     file_write(Start,dt);
                                                                                 }
                                                                               ChartRedraw(0);
                                                                              }
                                                                            else
                                                                               Print("ChartXYToTimePrice return error code: ",GetLastError());
                                                                           }

                                                                        Obtemos os dados do segmento usando CopyRates() e adicionamos as colunas trend_group e trend_index, inspecionando cada parte dos dados contidos em rates[]. Precisamos implementar essas funções em file_write():
                                                                          void file_write(datetime start,
                                                                                          datetime end)
                                                                            {
                                                                             MqlRates rates[];
                                                                             ArraySetAsSeries(rates,false);
                                                                             int n_cp=CopyRates(Symbol(),PERIOD_CURRENT,start,end,rates);
                                                                             if(n_cp>0)
                                                                               {
                                                                                if(FileTell(file_handle)==2)
                                                                                  {
                                                                                   FileWrite(file_handle,"time","open","high","low","close","tick_volume","trend_group","trend_index");
                                                                                   for(int i=0; i<n_cp; i++)
                                                                                     {
                                                                                      FileWrite(file_handle,
                                                                                                rates[i].time,
                                                                                                rates[i].open,
                                                                                                rates[i].high,
                                                                                                rates[i].low,
                                                                                                rates[i].close,
                                                                                                rates[i].tick_volume,
                                                                                                typ,
                                                                                                i);
                                                                                     }
                                                                                  }
                                                                                else
                                                                                  {
                                                                                   for(int i=0; i<n_cp; i++)
                                                                                     {
                                                                                      FileWrite(file_handle,
                                                                                                rates[i].time,
                                                                                                rates[i].open,
                                                                                                rates[i].high,
                                                                                                rates[i].low,
                                                                                                rates[i].close,
                                                                                                rates[i].tick_volume,
                                                                                                typ,
                                                                                                i);
                                                                                     }
                                                                                  }
                                                                               }
                                                                             else
                                                                                Print("No data copied!");
                                                                             FileFlush(file_handle);
                                                                             typ=3;
                                                                            }



                                                                          Notas:

                                                                          1. Precisamos escrever o cabeçalho do índice na primeira vez que o arquivo for gravado;

                                                                          2. Trend_group é na verdade um tipo de variável global;

                                                                          3. Não chamamos FileClose() neste ponto porque nossa rotulação ainda não está concluída. Vamos chamar essa função na função OnDeinit(), para gravar o resultado final no arquivo.

                                                                          4. É necessário prestar especial atenção à parte amarela do código.

                                                                          if(FileTell(file_handle)==2)
                                                                          Ao determinar a presença de dados (certamente, também é possível usar outros métodos, por exemplo, adicionar uma variável para atribuir um valor a ela durante a inicialização), se não houver dados no arquivo, é preciso adicionar um cabeçalho como este:
                                                                          FileWrite(file_handle,"time","open","high","low","close","tick_volume","trend_group","trend_index");
                                                                          Se houver dados no arquivo, não será necessário adicionar um cabeçalho; caso contrário, os dados serão cortados, o que é muito importante!
                                                                            Exemplo de arquivo gravado:
                                                                              data_0


                                                                                Vamos verificar se os diferentes segmentos de dados são consistentes:

                                                                                  data_1


                                                                                  Apêndice: exemplo completo de código do EA

                                                                                  1. Definição de variáveis globais e constantes. O parâmetro start_t pode ser definido a partir dos dados em segundos desde 01.01.1970. Claro, ele também pode ser definido usando o datetime padrão ou a variável de entrada input int start_t=1403037112; para que possa ser alterado a qualquer momento em execuções futuras do Expert Advisor:
                                                                                  #define KEY_B     66
                                                                                  #define KEY_S     83
                                                                                  
                                                                                  
                                                                                  int Num= 0;
                                                                                  int typ= 3;
                                                                                  string Name;
                                                                                  string tp;
                                                                                  color col;
                                                                                  bool first= true;
                                                                                  ENUM_OBJECT ob;
                                                                                  int file_handle=0;
                                                                                  int start_t=1403037112;
                                                                                  datetime Start;

                                                                                  Nota: Claro que você também pode definir uma tecla como uma variável de entrada conforme preferir.

                                                                                  input int KEY_B=66;
                                                                                  input int KEY_S=83;

                                                                                  A vantagem é que, se você achar que as teclas não são fáceis de usar, poderá alterá-las como quiser cada vez que executar o EA até ficar satisfeito, já que o código não será alterado temporariamente.


                                                                                  2. A função OnInit(), onde inicializamos nossos preparativos:

                                                                                  int OnInit()
                                                                                    {
                                                                                  //---initial
                                                                                     string name;
                                                                                     string reName="1";
                                                                                     int hd=FileFindFirst("*",name,0);
                                                                                     int shift;
                                                                                  
                                                                                     ChartSetInteger(0,CHART_AUTOSCROLL,false);
                                                                                     ChartSetInteger(0,CHART_SHIFT,false);
                                                                                     ChartSetInteger(0,CHART_MOUSE_SCROLL,1);
                                                                                  
                                                                                  
                                                                                     do
                                                                                       {
                                                                                        //---check File
                                                                                        if(StringFind(name,Symbol())!=-1 && StringFind(name,".csv")!=-1)
                                                                                           reName=name;
                                                                                       }
                                                                                     while(FileFindNext(hd,name));
                                                                                  
                                                                                     if(FileIsExist(reName))
                                                                                       {
                                                                                        file_handle = FileOpen(reName,FILE_WRITE|FILE_CSV|FILE_READ);
                                                                                        string a[];
                                                                                        int i=0;
                                                                                        read_csv(file_handle,a);
                                                                                        i = ArraySize(a);
                                                                                        shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)a[i-8]);
                                                                                        ChartNavigate(0,CHART_END,shift);
                                                                                       }
                                                                                     else
                                                                                       {
                                                                                        file_handle = FileOpen(StringFormat("%s%d-%d.csv",Symbol(),Period(),start_t),FILE_WRITE|FILE_CSV|FILE_READ);
                                                                                        Print(FileTell(file_handle));
                                                                                        Print("No history file,create file:",StringFormat("%s%d-%d",Symbol(),Period(),start_t));
                                                                                        shift = -iBarShift(Symbol(),PERIOD_CURRENT,(datetime)start_t);
                                                                                        ChartNavigate(0,CHART_END,shift);
                                                                                        ObjectCreate(0,"Start",OBJ_VLINE,0,(datetime)start_t,0);
                                                                                       }
                                                                                  //---
                                                                                     Print("EA:",MQL5InfoString(MQL5_PROGRAM_NAME),"Working!");
                                                                                  //---
                                                                                     ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_CREATE,true);
                                                                                  //---
                                                                                     ChartSetInteger(ChartID(),CHART_EVENT_OBJECT_DELETE,true);
                                                                                  //---
                                                                                     ChartRedraw(0);
                                                                                  //---
                                                                                     return(INIT_SUCCEEDED);
                                                                                    }


                                                                                  3. Como todas as nossas operações com teclado e mouse no gráfico foram concluídas, colocamos as principais funções lógicas na função OnChartEvent():

                                                                                  void OnChartEvent(const int id,
                                                                                                    const long &lparam,
                                                                                                    const double &dparam,
                                                                                                    const string &sparam)
                                                                                    {
                                                                                  //Comment(__FUNCTION__,": id=",id," lparam=",lparam," dparam=",dparam," sparam=",sparam);
                                                                                     if(id==CHARTEVENT_KEYDOWN)
                                                                                       {
                                                                                        switch(lparam)
                                                                                          {
                                                                                           case KEY_B:
                                                                                              if(first)
                                                                                                {
                                                                                                 col=clrBlue ;
                                                                                                 typ =0;
                                                                                                 Num+=1;
                                                                                                 tp = "start";
                                                                                                }
                                                                                              else
                                                                                                {
                                                                                                 col=clrRed ;
                                                                                                 typ = 1;
                                                                                                 tp = "end";
                                                                                                }
                                                                                              ob =OBJ_ARROW_BUY;
                                                                                              first = !first;
                                                                                              Name = StringFormat("%d-%d-%s",typ,Num,tp);
                                                                                              break;
                                                                                           case KEY_S:
                                                                                              if(first)
                                                                                                {
                                                                                                 col=clrRed ;
                                                                                                 typ =1;
                                                                                                 Num+=1;
                                                                                                 tp = "start";
                                                                                                }
                                                                                              else
                                                                                                {
                                                                                                 col=clrBlue ;
                                                                                                 typ = 0;
                                                                                                 tp = "end";
                                                                                                }
                                                                                              ob =OBJ_ARROW_SELL;
                                                                                              first = !first;
                                                                                              Name = StringFormat("%d-%d-%s",typ,Num,tp);
                                                                                              break;
                                                                                  
                                                                                           default:
                                                                                              Print("You pressed:"+lparam+" key, do nothing!");
                                                                                          }
                                                                                        ChartRedraw(0);
                                                                                       }
                                                                                  //---
                                                                                     if(id==CHARTEVENT_CLICK&&(typ!=3))
                                                                                       {
                                                                                        //--- definition
                                                                                        int x=(int)lparam;
                                                                                        int y=(int)dparam;
                                                                                        datetime dt    =0;
                                                                                        double   price =0;
                                                                                        int      window=0;
                                                                                        if(ChartXYToTimePrice(0,x,y,window,dt,price))
                                                                                          {
                                                                                           ObjectCreate(0,Name,ob,window,dt,price);
                                                                                           ObjectSetInteger(0,Name,OBJPROP_COLOR,col);
                                                                                           //Print("time:",dt,"shift:",iBarShift(Symbol(),PERIOD_CURRENT,dt));
                                                                                           if(tp=="start")
                                                                                              Start=dt;
                                                                                           else
                                                                                             {
                                                                                              if(file_handle)
                                                                                                 file_write(Start,dt);
                                                                                             }
                                                                                           ChartRedraw(0);
                                                                                          }
                                                                                        else
                                                                                           Print("ChartXYToTimePrice return error code: ",GetLastError());
                                                                                       }
                                                                                  //--- object delete
                                                                                     if(id==CHARTEVENT_OBJECT_DELETE)
                                                                                       {
                                                                                        Print("The object with name ",sparam," has been deleted");
                                                                                       }
                                                                                  //--- object create
                                                                                     if(id==CHARTEVENT_OBJECT_CREATE)
                                                                                       {
                                                                                        Print("The object with name ",sparam," has been created!");
                                                                                       }
                                                                                  
                                                                                    }

                                                                                  Nota: Modificamos o código acima ao implementar essa função.

                                                                                   if (id==CHARTEVENT_CLICK&&(typ!=3))

                                                                                  A razão pela qual fazemos isso é muito simples: evitamos operações incorretas causadas por cliques acidentais do mouse e usamos a variável typ para controlar a validade da ação do mouse. Quando rotulamos uma tendência, executamos a função file_write(). Adicionamos a seguinte linha no final da função.

                                                                                  typ=3;

                                                                                  Então, você pode usar o mouse para periodicamente gerenciar o gráfico antes de começar a próxima série de rotulação sem qualquer ação adicional, até encontrar a posição adequada e estar pronto para rotular a próxima tendência.


                                                                                  4. Implementação da função de gravação de dados - file_write():

                                                                                  void file_write(datetime start,
                                                                                                  datetime end)
                                                                                    {
                                                                                     MqlRates rates[];
                                                                                     ArraySetAsSeries(rates,false);
                                                                                     int n_cp=CopyRates(Symbol(),PERIOD_CURRENT,start,end,rates);
                                                                                     if(n_cp>0)
                                                                                       {
                                                                                        if(FileTell(file_handle)==2)
                                                                                          {
                                                                                           FileWrite(file_handle,"time","open","high","low","close","tick_volume","trend_group","trend_index");
                                                                                           for(int i=0; i<n_cp; i++)
                                                                                             {
                                                                                              FileWrite(file_handle,
                                                                                                        rates[i].time,
                                                                                                        rates[i].open,
                                                                                                        rates[i].high,
                                                                                                        rates[i].low,
                                                                                                        rates[i].close,
                                                                                                        rates[i].tick_volume,
                                                                                                        typ,
                                                                                                        i);
                                                                                             }
                                                                                          }
                                                                                        else
                                                                                          {
                                                                                           for(int i=0; i<n_cp; i++)
                                                                                             {
                                                                                              FileWrite(file_handle,
                                                                                                        rates[i].time,
                                                                                                        rates[i].open,
                                                                                                        rates[i].high,
                                                                                                        rates[i].low,
                                                                                                        rates[i].close,
                                                                                                        rates[i].tick_volume,
                                                                                                        typ,
                                                                                                        i);
                                                                                             }
                                                                                          }
                                                                                       }
                                                                                     else
                                                                                        Print("No data copied!");
                                                                                     FileFlush(file_handle);
                                                                                     typ=3;
                                                                                    }

                                                                                  5. Implementação da função de leitura de arquivo - read_csv():
                                                                                  void read_csv(int hd,
                                                                                                string &arry[])
                                                                                    {
                                                                                     int i=0;
                                                                                     while(!FileIsEnding(hd))
                                                                                       {
                                                                                        ArrayResize(arry,i+1);
                                                                                        arry[i]=FileReadString(hd);
                                                                                        i++;
                                                                                       }
                                                                                    }

                                                                                  6. Existe outro problema importante que não foi abordado aqui, o identificador do arquivo file_handle, aberto durante a inicialização do Expert Advisor, não é liberado. Liberamos o identificador na última função OnDeinit(). Ao chamar a função FileClose(file_handle), todos os dados serão gravados no arquivo csv, portanto, é especialmente importante não tentar abrir o arquivo csv durante a operação do Expert Advisor:
                                                                                  void OnDeinit(const int reason)
                                                                                    {
                                                                                     FileClose(file_handle);
                                                                                     Print("Write data!");
                                                                                    }


                                                                                  Nota: O código mostrado neste artigo é apenas para demonstração. Se você deseja usar este código na prática, é recomendável aprimorá-lo adicionalmente. Este artigo vem acompanhado do arquivo CSV e do arquivo MQL5 final usados na demonstração. O próximo artigo da série descreverá como anotar dados através de um cliente usando Python.

                                                                                  Obrigado por sua atenção!

                                                                                  Traduzido do Inglês pela MetaQuotes Ltd.
                                                                                  Artigo original: https://www.mql5.com/en/articles/13225

                                                                                  Arquivos anexados |
                                                                                  Colocação de ordens no MQL5 Colocação de ordens no MQL5
                                                                                  Ao criar um sistema de negociação, há sempre uma tarefa que deve ser resolvida com eficiência. Essa tarefa é a colocação de ordens ou seu processamento automático pelo sistema de negociação. Neste artigo, apresentamos a criação de um sistema de negociação do ponto de vista da colocação eficiente de ordens.
                                                                                  Redes neurais de maneira fácil (Parte 56): Utilização da norma nuclear para estimular a pesquisa Redes neurais de maneira fácil (Parte 56): Utilização da norma nuclear para estimular a pesquisa
                                                                                  A pesquisa do ambiente em tarefas de aprendizado por reforço é um problema atual. Anteriormente, já examinamos algumas abordagens. E hoje, eu proponho que nos familiarizemos com mais um método, baseado na maximização da norma nuclear. Ele permite que os agentes destaquem estados do ambiente com alto grau de novidade e diversidade.
                                                                                  Modelos prontos para integrar indicadores nos Expert Advisors (Parte 1): Osciladores Modelos prontos para integrar indicadores nos Expert Advisors (Parte 1): Osciladores
                                                                                  Neste artigo, examinaremos os indicadores padrão da categoria Osciladores. Criaremos modelos prontos a serem usados em Expert Advisors, modelos esses que incluirão: declaração e configuração de parâmetros, inicialização/desinicialização de indicadores e recuperação de dados/sinais a partir de buffers de indicador em EAs.
                                                                                  Teoria das Categorias em MQL5 (Parte 18): Quadrado de naturalidade Teoria das Categorias em MQL5 (Parte 18): Quadrado de naturalidade
                                                                                  Este artigo dá continuidade à série sobre a teoria das categorias, abordando as transformações naturais, que são um elemento fundamental da teoria. Vamos examinar a definição que parece complexa à primeira vista, depois mergulhar em exemplos e formas de aplicar as transformações na previsão de volatilidade.