English Русский 中文 Español Deutsch 日本語
Monitoramento de sinais de negociação multimoeda (Parte 3): Introdução de algoritmos de busca

Monitoramento de sinais de negociação multimoeda (Parte 3): Introdução de algoritmos de busca

MetaTrader 5Negociação |
1 794 5
Alexander Fedosov
Alexander Fedosov

Conteúdo

Introdução

Nos artigos anteriores, nós criamos a estrutura do aplicativo para o monitoramento de sinais de negociação. Nós também implementamos a interface do aplicativo com os recursos básicos de interação. Agora é hora de preencher a parte visual do algoritmo para configurar e buscar os símbolos. Nós vamos usar o projeto do artigo anterior como base e continuará adicionando novas funcionalidades a cada passo.

Sistema de armazenamento do conjunto de símbolos

Na última vez, na primeira etapa de configuração do aplicativo, nós criamos as ferramentas para selecionar os símbolos na Observação de Mercado. Os símbolos podem ser selecionados de três maneiras diferentes:

  • Manual. Tendo que marcar os símbolos necessários e clicar em Next.
  • Um conjunto predefinido. Um clique em All, Major ou Crosses selecionará automaticamente um conjunto de símbolos predefinido específico.
  • Conjunto salvo. Um conjunto de símbolos previamente preparado, configurado usando os dois primeiros métodos e salvo em um arquivo com um nome específico.

Fig.1 Etapa 1 de configuração do aplicativo e configurações do conjunto salvo.

As duas primeiras maneiras são bastante simples e foram criadas anteriormente. A terceira maneira precisa ser criada. Agora vamos definir com mais precisão o que vamos fazer. Nós iremos nos aprofundar na interação dos elementos no quadro vermelho na Fig.1, o que implica o seguinte:

  • Os símbolos desejados são marcados com as marcas de seleção, o usuário digita o nome no campo 'Template name' e clica em Save ou pressiona a tecla de atalho S. Se salvo com sucesso, uma mensagem apropriada será exibida.
  • Para acessar um modelo configurado e salvo anteriormente, o nome do modelo deve ser digitado no campo e carregado ou, de modo alternativo, pressionar a tecla de atalho L.

Abrimos o projeto, encontramos a classe base CProgram e adicionamos dois métodos em sua seção private. Os métodos serão responsáveis por carregar e salvar o modelo de símbolos.

   bool              SaveSymbolSet(string file_name);
   bool              LoadSymbolSet(string file_name);

Abaixo encontramos como esses métodos são implementados. 

//+------------------------------------------------------------------+
//| Save template to a file                                          |
//+------------------------------------------------------------------+
bool CProgram::SaveSymbolSet(string file_name)
{
   if(file_name=="")
   {
      MessageBox("Select the template name to record","Signal Monitor");
      return(false);
   }
   int h=FileOpen("Signal Monitor\\"+file_name+".bin",FILE_WRITE|FILE_BIN);
   if(h==INVALID_HANDLE)
   {
      MessageBox("Failed to create a configuration file","Signal Monitor");
      return(false);
   }
   else
      MessageBox("The "+file_name+" configuration has been successfully saved","Signal Monitor");
//--- Save the selection of timeframes and patterns
   for(int i=0; i<m_all_symbols; i++)
      m_save.tf[i]=m_checkbox[i].IsPressed();
//---
   FileWriteStruct(h,m_save);
   FileClose(h);
//---
   return(true);
}
//+------------------------------------------------------------------+
//| Load data to a panel                                             |
//+------------------------------------------------------------------+
bool CProgram::LoadSymbolSet(string file_name)
{
   if(file_name=="")
   {
      MessageBox("Select the template name to load","Signal Monitor");
      return(false);
   }
   int h=FileOpen("Signal Monitor\\"+file_name+".bin",FILE_READ|FILE_BIN);
   if(h==INVALID_HANDLE)
   {
      MessageBox("Configuration "+file_name+" not found","Signal Monitor");
      return(false);
   }
   ZeroMemory(m_save);
   FileReadStruct(h,m_save);
//--- Loading timeframes
   for(int i=0; i<m_all_symbols; i++)
   {
      m_checkbox[i].IsPressed(m_save.tf[i]);
      m_checkbox[i].Update(true);
   }
//---
   FileClose(h);
//---
   return(true);
}

No entanto, se você tentar compilar o projeto agora, isso disparará um erro conectado à variável m_save. Essa estrutura possui um parâmetro do tipo bool chamado tf. Ela lembra a escolha do usuário em um arquivo. Portanto, nós criamos essa estrutura na classe do aplicativo e adicionamos a sua instância à classe base.

//+------------------------------------------------------------------+
//| Class for creating the application                               |
//+------------------------------------------------------------------+
struct SAVE
{
   bool     tf[100];
};
class CProgram : public CWndEvents
{
...
        SAVE            m_save;

Vamos para o método da OnEvent(), inserimos a seção relacionada ao evento de clique no botão e adicionamos o seguinte código na condição de Etapa 1:

         //--- Save the template
         if(lparam==m_save_button.Id())
         {
            SaveSymbolSet(m_text_edit.GetValue());
         }
         //--- Load the template
         if(lparam==m_load_button.Id())
         {
            LoadSymbolSet(m_text_edit.GetValue());
         }

Além disso, nós implementamos o uso das teclas de atalho para os botões acima. No mesmo método, nós adicionamos uma verificação para o evento de pressionamento de tecla e adicionamos o código para as teclas usadas.

//--- Key press
   if(id==CHARTEVENT_KEYDOWN)
   {
      if(m_current_step==1)
      {
         short sym=TranslateKey((int)lparam);
         //--- if the entered character is successfully converted to Unicode
         if(sym>0)
         {
            if(ShortToString(sym)=="l" || ShortToString(sym)=="д")
               LoadSymbolSet(m_text_edit.GetValue());
            if(ShortToString(sym)=="s" || ShortToString(sym)=="ы")
               SaveSymbolSet(m_text_edit.GetValue());
         }
      }
   }

Compilamos o projeto. A compilação bem sucedida produzirá o seguinte resultado.

Fig.2 Salvando e carregando um modelo de usuário

Adição e edição de um sinal de negociação

Agora, vamos para a parte principal do aplicativo, responsável pela criação e edição dos sinais de negociação, bem como pelo monitoramento adicional no monitor. Abaixo está como é a criação e edição do sinal. 

Fig.3 Janela de criação e edição do sinal.

No estágio atual, a janela aparece como um conjunto de elementos da GUI que controlam vários parâmetros. No entanto, essas configurações não são usadas em nenhum lugar. Começamos com a adição de dois botões na interface. Eles adicionam/salvam um sinal de negociação. Outro botão cancela a criação/edição. Abrimos o arquivo Program.mqh e adicionamos o método de implementação para esses dois botões à classe base:

bool              CreateButton3(CButton &button,string text,const int x_gap,const int y_gap);

Duas instâncias de botão CButton:

   CButton           m_new_signal;
   CButton           m_cancel_button;

Agora vamos para o arquivo SetWindow.mqh e implementamos esse método.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateButton3(CButton &button,string text,const int x_gap,const int y_gap)
{
//---
   color baseclr=C'70,180,70';
   color pressed=C'70,170,70';
//--- Save the window pointer
   button.MainPointer(m_set_window);
//--- Set up properties before creation
   button.XSize(60);
   button.YSize(30);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(pressed);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(pressed);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
//--- Create the control
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Add the element pointer to the base
   CWndContainer::AddToElementsArray(1,button);
   return(true);
}

Para fazer esses dois botões aparecerem na interface da janela de negociação e adicionando um sinal, nós inserimos as seguintes linhas no final do corpo do método CreateSetWindow():

//--- Add/Cancel Buttons
   if(!CreateButton3(m_new_signal,"Add",m_set_window.XSize()-2*(60+10),m_set_window.YSize()-(30+10)))
      return(false);
   if(!CreateButton3(m_cancel_button,"Cancel",m_set_window.XSize()-(60+10),m_set_window.YSize()-(30+10)))
      return(false);

Após a compilação do projeto, dois botões aparecerão na parte inferior da janela de criação do sinal de negociação. 

Fig.4 Adicionando os botões de criação e cancelamento de sinal.

Agora, nós precisamos adicionar os eventos que ocorrerão com o clique do botão. O efeito do botão Cancel é óbvio: ele não salva nenhuma ação e configuração na janela especificada e fecha a janela sem adicionar um sinal. Vamos considerar o botão Add com mais detalhes.

Primeiro, vamos determinar a sequência de ações a serem executadas quando clicarmos em Add.

  1. Um clique no botão salva os parâmetros selecionados usando os elementos da interface do usuário na janela de criação do sinal de negociação.
  2. Após salvá-lo com êxito, a janela é fechada e o primeiro registro com o nome do sinal aparece na lista de sinais na janela principal.
  3. Ao clicar no registro, o conjunto salvo anteriormente é aplicado aos elementos da interface do usuário da configuração do sinal e o botão Add é convertido em Save.

Para habilitar o salvamento das configurações em um arquivo, nós precisamos criar um conjunto universal de configurações que serão usadas para a exibição visual na janela de edição, bem como para a busca subsequente de sinais. Portanto, vamos criar uma estrutura e chamá-la de SIGNAL. A configuração das configurações na janela de criação e edição será gravada nessa estrutura.

struct SIGNAL
{
   int      ind_type;
   int      ind_period;
   int      app_price;
   int      rule_type;
   double   rule_value;
   int      label_type;
   uchar    label_value[10];
   color    label_color;
   color    back_color;
   color    border_color;
   bool     tooltip;
   uchar    tooltip_text[100];
   bool     image;
   int      img_index;
   bool     timeframes[21];
   TFNAME   tf_name[21];
};

Vamos ver cada um dos elementos na estrutura:

  • ind_type — contém o tipo do indicador que foi selecionado como base de busca do sinal. Ele é exibido como Indicator Type na interface.
  • ind_period — o período do indicador selecionado.
  • app_price — preço usado para o cálculo do indicador. Este valor não está disponível para todos os indicadores e, portanto, ele é gravado apenas quando aplicável. Por exemplo, ele é usado para o RSI, mas não para o WPR.
  • rule_type — define o tipo de regra a ser usada ao buscar um sinal de negociação. Ele aparece na interface como um menu suspenso contendo os caracteres como ==,>=,<= e outros.
  • rule_value — um valor do limiar do indicador selecionado na qual a regra de busca deve ser aplicada.
  • label_type — este elemento armazenará o tipo de exibição do rótulo de texto. Ele é o valor atual do indicador ou um rótulo personalizado com até 3 caracteres.
  • label_value — se o segundo tipo de exibição do rótulo de texto for selecionado, esse parâmetro armazenará o texto do rótulo personalizado especificado pelo usuário.
  • label_color — armazena a cor do rótulo do texto.
  • back_color — armazena a cor de fundo do bloco de sinal no monitor se esta opção estiver selecionada.
  • border_color — armazena a cor da borda do bloco de sinal no monitor se esta opção estiver selecionada.
  • tooltip — contém uma indicação se uma dica de ferramenta é usada.
  • tooltip_text — se a dica de ferramenta for usada, esse parâmetro conterá o texto.
  • image — uma indicação do uso da imagem.
  • img_index — salva o número da sequência da imagem, se usada.
  • timeframes — matriz contendo informações sobre as configurações do período selecionado na segunda etapa.
  • tf_name — salva os períodos nos quais o sinal de negociação será pesquisado. 

Agora, declaramos na classe base uma matriz de estruturas para salvar as configurações dos sinais criados.

SIGNAL            m_signal_set[5];

Além disso, nós criamos dois métodos na área private da CProgram para salvar um conjunto de parâmetros em um arquivo e carregá-lo do arquivo na estrutura.

   bool              SaveSignalSet(int index);
   bool              LoadSignalSet(int index);

Aqui está a implementação:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::SaveSignalSet(int index)
{
//---
   int h=FileOpen("Signal Monitor\\signal_"+string(index)+".bin",FILE_WRITE|FILE_BIN);
   if(h==INVALID_HANDLE)
   {
      MessageBox("Failed to create a configuration file","Signal Monitor");
      return(false);
   }
//--- Save the selection
   //--- Indicator type
   m_signal_set[index].ind_type=m_indicator_type.GetListViewPointer().SelectedItemIndex();
   //--- Indicator period
   m_signal_set[index].ind_period=(int)m_period_edit.GetValue();
   //--- Type of applied price
   m_signal_set[index].app_price=m_applied_price.GetListViewPointer().SelectedItemIndex();
   //--- Rule type
   m_signal_set[index].rule_type=m_rule_type.GetListViewPointer().SelectedItemIndex();
   //--- Rule value
   m_signal_set[index].rule_value=(double)m_rule_value.GetValue();
   //--- Text label display type
   m_signal_set[index].label_type=m_label_button[0].IsPressed()?0:1;
   //--- Save the value of the text field for the second type
   if(m_label_button[1].IsPressed())
      StringToCharArray(StringSubstr(m_text_box.GetValue(),0,3),m_signal_set[index].label_value);
   //--- Color of the text label
   m_signal_set[index].label_color=m_color_button[0].CurrentColor();
   //--- Background color
   if(m_set_param[0].IsPressed())
      m_signal_set[index].back_color=m_color_button[1].CurrentColor();
   else
      m_signal_set[index].back_color=clrNONE;
   //--- Border color
   if(m_set_param[1].IsPressed())
      m_signal_set[index].border_color=m_color_button[2].CurrentColor();
   else
      m_signal_set[index].border_color=clrNONE;
   //--- Tooltip value
   m_signal_set[index].tooltip=m_set_param[2].IsPressed();
   if(m_signal_set[index].tooltip)
      StringToCharArray(m_tooltip_text.GetValue(),m_signal_set[index].tooltip_text);
   //--- Selected image
   m_signal_set[index].image=m_set_param[3].IsPressed();
   if(m_signal_set[index].image)
      m_signal_set[index].img_index=m_pictures_slider.GetRadioButtonsPointer().SelectedButtonIndex();
   //--- Selected timegrames
   int tf=0;
   for(int i=0; i<21; i++)
   {
      if(!m_tf_button[i].IsLocked() && m_tf_button[i].IsPressed())
      {
         m_signal_set[index].timeframes[i]=true;
         StringToCharArray(m_tf_button[i].LabelText(),m_signal_set[index].tf_name[i].tf);
         tf++;
      }
      else
         m_signal_set[index].timeframes[i]=false;
   }
   //---
   if(tf<1)
   {
      MessageBox("No timeframes selected","Signal Monitor");
      FileClose(h);
      return(false);
   }
//---
   FileWriteStruct(h,m_signal_set[index]);
   FileClose(h);
   Print("Configuration signal_"+string(index)+" has been successfully saved");
//---
   return(true);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::LoadSignalSet(int index)
{
   int h=FileOpen("Signal Monitor\\signal_"+string(index)+".bin",FILE_READ|FILE_BIN);
   if(h==INVALID_HANDLE)
   {
      MessageBox("Configuration not found","Signal Monitor");
      return(false);
   }
   ZeroMemory(m_signal_set[index]);
   FileReadStruct(h,m_signal_set[index]);
//--- Loading indicator type
   m_indicator_type.SelectItem(m_signal_set[index].ind_type);
   RebuildParameters(m_signal_set[index].ind_type);
   m_indicator_type.GetButtonPointer().Update(true);
//--- Loading indicator period
   m_period_edit.SetValue((string)m_signal_set[index].ind_period);
   m_period_edit.GetTextBoxPointer().Update(true);
//--- Loading applied price
   if(!m_applied_price.IsLocked())
   {
      m_applied_price.SelectItem(m_signal_set[index].app_price);
      m_applied_price.GetButtonPointer().Update(true);
   }
//--- Loading signal rule
   m_rule_type.SelectItem(m_signal_set[index].rule_type);
   m_rule_type.GetButtonPointer().Update(true);
   m_rule_value.SetValue((string)m_signal_set[index].rule_value);
   m_rule_value.GetTextBoxPointer().Update(true);
//--- Loading a text label
   if(m_signal_set[index].label_type==0)
   {
      m_label_button[0].IsPressed(true);
      m_label_button[0].Update(true);
      m_label_button[1].IsPressed(false);
      m_label_button[1].Update(true);
      m_text_box.IsLocked(true);
   }
   else
   {
      m_label_button[0].IsPressed(false);
      m_label_button[0].Update(true);
      m_label_button[1].IsPressed(true);
      m_label_button[1].Update(true);
      m_text_box.IsLocked(false);
      m_text_box.ClearTextBox();
      m_text_box.AddText(0,CharArrayToString(m_signal_set[index].label_value));
      m_text_box.Update(true);
   }
//--- Loading the color of the text label
   m_color_button[0].CurrentColor(m_signal_set[index].label_color);
   m_color_button[0].Update(true);
//--- Loading the background color
   if(m_signal_set[index].back_color==clrNONE)
   {
      m_set_param[0].IsPressed(false);
      m_set_param[0].Update(true);
      m_color_button[1].IsLocked(true);
      m_color_button[1].GetButtonPointer().Update(true);
   }
   else
   {
      m_set_param[0].IsPressed(true);
      m_set_param[0].Update(true);
      m_color_button[1].IsLocked(false);
      m_color_button[1].CurrentColor(m_signal_set[index].back_color);
      m_color_button[1].GetButtonPointer().Update(true);
   }
//--- Loading the border color
   if(m_signal_set[index].border_color==clrNONE)
   {
      m_set_param[1].IsPressed(false);
      m_set_param[1].Update(true);
      m_color_button[2].IsLocked(true);
      m_color_button[2].GetButtonPointer().Update(true);
   }
   else
   {
      m_set_param[1].IsPressed(true);
      m_set_param[1].Update(true);
      m_color_button[2].IsLocked(false);
      m_color_button[2].CurrentColor(m_signal_set[index].border_color);
      m_color_button[2].GetButtonPointer().Update(true);
   }
//--- Loading the tooltip value
   if(!m_signal_set[index].tooltip)
   {
      m_set_param[2].IsPressed(false);
      m_set_param[2].Update(true);
      m_tooltip_text.IsLocked(true);
      m_tooltip_text.Update(true);
   }
   else
   {
      m_set_param[2].IsPressed(true);
      m_set_param[2].Update(true);
      m_tooltip_text.IsLocked(false);
      m_tooltip_text.ClearTextBox();
      m_tooltip_text.AddText(0,CharArrayToString(m_signal_set[index].tooltip_text));
      m_tooltip_text.Update(true);
   }
//--- Loading the image
   if(!m_signal_set[index].image)
   {
      m_set_param[3].IsPressed(false);
      m_set_param[3].Update(true);
      m_pictures_slider.IsLocked(true);
      m_pictures_slider.GetRadioButtonsPointer().Update(true);
   }
   else
   {
      m_set_param[3].IsPressed(true);
      m_set_param[3].Update(true);
      m_pictures_slider.IsLocked(false);
      m_pictures_slider.GetRadioButtonsPointer().SelectButton(m_signal_set[index].img_index);
      m_pictures_slider.GetRadioButtonsPointer().Update(true);
   }
//--- Loading selected timeframes
   for(int i=0; i<21; i++)
   {
      if(!m_tf_button[i].IsLocked())
      {
         m_tf_button[i].IsPressed(m_signal_set[index].timeframes[i]);
         m_tf_button[i].Update(true);
      }
   }
//---
   FileClose(h);
   return(true);
}

Assim, a primeira ação com o algoritmo de salvar/carregar é concluída. Agora, nós precisamos criar o objeto que servirá como registros dos sinais criados. Ao clicar nesses objetos, nós poderemos editar os parâmetros do sinal de negociação criado anteriormente. Para implementar esses objetos, nós criamos uma matriz das instâncias de classe CButton.

CButton           m_signal_editor[5];

Além disso, adicionamos um método criando os objetos.

bool              CreateSignalEditor(CButton &button,string text,const int x_gap,const int y_gap);

Implementamos esse método no arquivo StepWindow.mqh, pois esses objetos pertencem à janela principal.

//+------------------------------------------------------------------+
//| Creates a button with an image                                   |
//+------------------------------------------------------------------+
#resource "\\Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_light.bmp"

bool CProgram::CreateSignalEditor(CButton &button,string text,const int x_gap,const int y_gap)
{
//---
   color baseclr=C'70,180,70';
   color pressed=C'70,170,70';
//--- Save the window pointer
   button.MainPointer(m_step_window);
//--- Set up properties before creation
   button.XSize(110);
   button.YSize(30);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.IconXGap(3);
   button.IconYGap(7);
   button.IconFile("Images\\EasyAndFastGUI\\Icons\\bmp16\\settings_light.bmp");
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(pressed);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(pressed);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
//--- Create the control
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Add the element pointer to the base
   CWndContainer::AddToElementsArray(0,button);
   return(true);
}

Usando esse método, nós adicionamos cinco objetos ao corpo do CreateStepWindow(), que serão os objetos na lista de sinais.

//---
   for(int i=0; i<5; i++)
   {
      if(!CreateSignalEditor(m_signal_editor[i],"Signal_"+string(i),10,40*i+90))
         return(false);
   }

Para desativar a exibição desses elementos após o lançamento do aplicativo, esconda-o no método CreateGUI().

//+------------------------------------------------------------------+
//| Creates the graphical interface of the program                   |
//+------------------------------------------------------------------+
bool CProgram::CreateGUI(void)
{
//--- Step 1-3. Symbol selection window.
   if(!CreateStepWindow("Signal Monitor Step 1: Choose Symbols"))
      return(false);
//---
   if(!CreateSetWindow("Signal Monitor Edit Signal"))
      return(false);
//--- Creating form 2 for the color picker
   if(!CreateColorWindow("Color Picker"))
      return(false);
//--- Finishing the creation of GUI
   CWndEvents::CompletedGUI();
   m_back_button.Hide();
   m_add_signal.Hide();
   m_signal_header.Hide();
   m_label_button[1].IsPressed(true);
   m_label_button[1].Update(true);
   for(int i=0; i<5; i++)
      m_signal_editor[i].Hide();
   return(true);
}

A próxima coisa a fazer antes da compilação do projeto é criar um método que excluirá todos os dados salvos anteriormente durante a configuração inicial. Para fazer isso, criamos o método ClearSaves() e chamamos ele no construtor da classe CProgram.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::ClearSaves(void)
{
   for(int i=0; i<5; i++)
      FileDelete("Signal Monitor\\signal_"+string(i)+".bin");
   m_total_signals=0;
   return(true);
}

Agora, adicionamos o seguinte ao evento de clique no botão de sinal Add:

//--- Add Signal button click event
      if(lparam==m_add_signal.Id())
      {
         m_set_window.OpenWindow();
         m_number_signal=-1;
         RebuildTimeframes();
         m_new_signal.LabelText("Add");
         m_new_signal.Update(true);
      }

O mecanismo para adicionar um novo sinal de negociação está pronto após a compilação do projeto. O próximo passo é a implementação da edição de um sinal criado anteriormente.

Fig.5 Adicionando um novo sinal de negociação.

Vamos resumir tudo. Como é mostrado na figura 5, nós implementamos a possibilidade de adicionar os sinais com um clique no botão Add Signal. Além disso, um botão com o novo nome do sinal é adicionado a Signal List. Atualmente, ele é um valor predefinido sem a possibilidade de editá-lo. No entanto, nada acontece com o clique em Signal_0, então vamos corrigir isso. Vamos ativar a reabertura da janela de configurações com o carregamento na interface exatamente daquelas configurações que foram salvas anteriormente para o sinal selecionado. Outra ideia é implementar a possibilidade de editar as configurações carregadas e salvá-las.

Abrimos o corpo do OnEvent() na classe base CProgram e localizamos a parte com o evento de clique no botão. Adicionamos o seguinte código a ele:

//---
      for(int i=0; i<5; i++)
      {
         if(lparam==m_signal_editor[i].Id())
         {
            LoadSignalSet(i);
            m_new_signal.LabelText("Save");
            m_new_signal.Update(true);
            m_set_window.OpenWindow();
            m_number_signal=i;
         }
      }

Aqui, nós determinamos qual botão de sinal criado foi pressionado. Sabendo disso, nós carregamos os dados salvos anteriormente na interface da janela de configurações usando o método LoadSignalSet(), alteramos o nome do botão de Add para Save e abrimos a janela de configurações.


Agora que as ferramentas para criar e editar os sinais de negociação estão prontas, é hora de vinculá-lo à parte do aplicativo responsável pela pesquisa e exibição dos sinais. Nós já criamos uma base para o monitoramento de sinais. Ele possui uma exibição tabular com os nomes de linhas (símbolos selecionados na primeira etapa da configuração) e colunas (períodos selecionados na segunda etapa da configuração).

Fig.6 Botão criando um monitor de sinais de negociação.

A sequência de ações após a criação de pelo menos um sinal de negociação é simples. Um clique em Create aciona a formação de um monitor de sinais de negociação com base em todo o array de configurações que foram definidas anteriormente. Antes de prosseguir com a programação deste sistema, nós precisamos complementar o método ToMonitor() que é chamado depois de pressionar Create.

//--- Hide Step 3
   m_add_signal.Hide();

   m_signal_header.Hide();
   m_back_button.Hide();
   m_next_button.Hide();
   for(int i=0; i<5; i++)
      m_signal_editor[i].Hide();

Como nós temos os objetos de botão que permitem exibir e editar os sinais de negociação criados atualmente, esses botões também devem estar ocultos ao pular para a janela do monitor, da mesma forma que todos os controles da Etapa 3 anterior.

No primeiro artigo, quando nós desenvolvemos a estrutura do aplicativo, um dos elementos do monitor era o bloco de indicação mostrado na figura 5 do primeiro artigo. Seu objetivo é exibir em tempo real a presença de um dos sinais de negociação criados anteriormente. Portanto, o primeiro passo é criar um objeto que será usado como um bloco de indicação. Isso pode ser feito implementando o método CreateSignalButton() na classe CProgram

bool              CreateSignalButton(CButton &button,const int x_gap,const int y_gap);

Além disso, adicionamos um array das instâncias de classe CButton necessárias para a criação do conjunto completo de blocos de indicação.

CButton           m_signal_button[];

Agora, abrimos o StepWindow.mqh e adicionamos a implementação do método criado no final do arquivo:

//+------------------------------------------------------------------+
//| Creates an indication block                                      |
//+------------------------------------------------------------------+
bool CProgram::CreateSignalButton(CButton &button,const int x_gap,const int y_gap)
{
//---
   color baseclr=C'220,225,235';
//--- Save the window pointer
   button.MainPointer(m_step_window);
//--- Set up properties before creation
   button.TwoState(false);
   button.XSize(40);
   button.YSize(20);
   button.IconXGap(2);
   button.IconYGap(button.YSize()/2-8);
   button.LabelXGap(19);
   button.LabelYGap(2);
   button.FontSize(m_base_font_size);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(baseclr);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(baseclr);
   button.LabelColor(clrBlack);
   button.LabelColorPressed(clrSlateGray);
   button.IconFile("");
   button.IconFileLocked("");
   button.IsDoubleBorder(true);
//--- Create the control
   if(!button.CreateButton("",x_gap-button.XSize()/2,y_gap))
      return(false);
//--- Add the element pointer to the base
   CWndContainer::AddToElementsArray(0,button);
   return(true);
}

Agora aplicamos-o no método de criação ToMonitor(). Para fazer isso, localizamos a seção Timeframes no corpo do método e adicionamos o código ao método como mostrado abaixo:

//--- Timeframes
   int tf=ArraySize(m_timeframes);
   ArrayResize(m_timeframe_label,tf);
//---
   for(int i=0; i<tf; i++)
   {
      if(!CreateTimeframeLabel(m_timeframe_label[i],110+50*i,m_step_window.CaptionHeight()+3,m_timeframes[i]))
         return;
      m_timeframe_label[i].Update(true);
   }
//-- Signal blocks
   int k=0;
   ArrayResize(m_signal_button,sy*tf);
   for(int j=0; j<sy; j++)
   {
      for(int i=0; i<tf; i++)
      {
         if(!CreateSignalButton(m_signal_button[k],m_timeframe_label[i].XGap()+m_timeframe_label[i].XSize()/2,m_step_window.CaptionHeight()+25+j*25))
            return;
         m_signal_button[k].Update(true);
         k++;
      }
   }
//--- Resize window
   AutoResize(m_timeframe_label[tf-1].XGap()+m_timeframe_label[tf-1].XSize()+5,m_symbol_label[sy-1].YGap()+m_symbol_label[sy-1].YSize()+5);

Compilamos o projeto e obtemos um layout pronto para a exibição futura dos sinais de negociação.


Fig.7 Um layout pronto dos sinais de negociação.

Agora lembre-se de quais elementos do bloco de indicação podem ser configurados para exibir certos sinais.

  • Cor de fundo.
  • A presença e cor da borda do bloco de indicação.
  • A cor e o valor do rótulo do texto.
  • Presença de um ícone.
  • Presença de uma dica de ferramenta.

Para gerenciar essas propriedades, nós definimos os seguintes métodos na seção privada de nossa classe base CProgram:

   void              SetBorderColor(int index, color clr);
   void              SetLabel(int index, string text,color clr=clrBlack);
   void              SetIcon(int index,int number);
   void              SetBackground(int index,color clr);
   void              SetTooltip(int index,string text="\n");

Sua implementação:

//+------------------------------------------------------------------+
//| Set the border color                                             |
//+------------------------------------------------------------------+
void CProgram::SetBorderColor(int index, color clr)
{
   m_signal_button[index].BorderColor(clr);
   m_signal_button[index].BorderColorHover(clr);
   m_signal_button[index].BorderColorPressed(clr);
   m_signal_button[index].Update(true);
}
//+------------------------------------------------------------------+
//| Set the label text                                               |
//+------------------------------------------------------------------+
void CProgram::SetLabel(int index, string text,color clr=clrBlack)
{
   m_signal_button[index].LabelColor(clr);
   m_signal_button[index].LabelColorHover(clr);
   m_signal_button[index].LabelColorPressed(clr);
   m_signal_button[index].LabelText(text);
   m_signal_button[index].Update(true);
}
//+------------------------------------------------------------------+
//| Set the background                                               |
//+------------------------------------------------------------------+
void CProgram::SetBackground(int index,color clr)
{
   m_signal_button[index].BackColor(clr);
   m_signal_button[index].BackColorHover(clr);
   m_signal_button[index].Update(true);
}
//+------------------------------------------------------------------+
//| Set the icon                                                     |
//+------------------------------------------------------------------+
void CProgram::SetIcon(int index,int number)
{
   //---
   string image[]=
   {
      "Images\\EasyAndFastGUI\\Icons\\bmp16\\arrow_up.bmp",
      "Images\\EasyAndFastGUI\\Icons\\bmp16\\arrow_down.bmp"
   };
   string path=(number>=0)?image[number]:"";
   if(number<0)
      m_signal_button[index].IsCenterText(true);
   else
      m_signal_button[index].IsCenterText(false);
   m_signal_button[index].IconFile(path);
   m_signal_button[index].IconFilePressed(path);
   m_signal_button[index].Update(true);
}
//+------------------------------------------------------------------+
//| Set the tooltip                                                  |
//+------------------------------------------------------------------+
void CProgram::SetTooltip(int index,string text="\n")
{
   m_signal_button[index].Tooltip(text);
   m_signal_button[index].ShowTooltip(true);
}

Em seguida, nós precisamos criar alguns métodos auxiliares necessários para os cálculos adicionais, exibição correta e, o mais importante, para a correspondência de cada um dos blocos de indicação criados para uma linha específica (símbolo selecionado) e coluna (período de tempo). Primeiro, criamos os métodos para determinar a linha e a coluna do bloco de indicação com base no índice na tabela.

   int               GetRow(int index,int row_size);
   int               GetCol(int index,int row_size);
//+------------------------------------------------------------------+
//| Determining a row by the index                                   |
//+------------------------------------------------------------------+
int CProgram::GetRow(int index,int row_size)
{
   return(int(MathFloor(index/row_size)+1));
}
//+------------------------------------------------------------------+
//| Determining a column by the index                                |
//+------------------------------------------------------------------+
int CProgram::GetCol(int index,int row_size)
{
   return(int(MathMod(index,row_size)+1));
}

Nós também precisamos obter os dados necessários a partir da interface. Ou seja, nós precisamos converter a exibição de texto dos períodos no tipo de enumeração do período. Nós também precisamos descobrir com base no índice do bloco de indicação, a qual símbolo e período ele corresponde na tabela.

//+------------------------------------------------------------------+
//| Return timeframe by row                                          |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES CProgram::StringToTimeframe(const string timeframe)
{
   if(timeframe=="M1")  return(PERIOD_M1);
   if(timeframe=="M2")  return(PERIOD_M2);
   if(timeframe=="M3")  return(PERIOD_M3);
   if(timeframe=="M4")  return(PERIOD_M4);
   if(timeframe=="M5")  return(PERIOD_M5);
   if(timeframe=="M6")  return(PERIOD_M6);
   if(timeframe=="M10") return(PERIOD_M10);
   if(timeframe=="M12") return(PERIOD_M12);
   if(timeframe=="M15") return(PERIOD_M15);
   if(timeframe=="M20") return(PERIOD_M20);
   if(timeframe=="M30") return(PERIOD_M30);
   if(timeframe=="H1")  return(PERIOD_H1);
   if(timeframe=="H2")  return(PERIOD_H2);
   if(timeframe=="H3")  return(PERIOD_H3);
   if(timeframe=="H4")  return(PERIOD_H4);
   if(timeframe=="H6")  return(PERIOD_H6);
   if(timeframe=="H8")  return(PERIOD_H8);
   if(timeframe=="H12") return(PERIOD_H12);
   if(timeframe=="D1")  return(PERIOD_D1);
   if(timeframe=="W1")  return(PERIOD_W1);
   if(timeframe=="MN")  return(PERIOD_MN1);
//--- The default value
   return(::Period());
}
//+------------------------------------------------------------------+
//| Determine the timeframe                                          |
//+------------------------------------------------------------------+
ENUM_TIMEFRAMES CProgram::GetTimeframe(int index)
{
   int tf=ArraySize(m_timeframes);
   return(StringToTimeframe((m_timeframe_label[GetCol(index,tf)-1].LabelText())));
}
//+------------------------------------------------------------------+
//| Determine the symbol                                             |
//+------------------------------------------------------------------+
string CProgram::GetSymbol(int index)
{
   int tf=ArraySize(m_timeframes);
   return(m_symbol_label[GetRow(index,tf)-1].LabelText());
}

O próximo método está diretamente relacionado ao algoritmo de busca de sinal: ele procura o conjunto de parâmetros dos sinais criados anteriormente no símbolo e período de tempo especificados.

bool              GetSignal(string sy,ENUM_TIMEFRAMES tf,SIGNAL &signal_set);

As configurações são passadas pela estrutura SIGNAL a partir de um conjunto de parâmetros. 

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::GetSignal(string sy,ENUM_TIMEFRAMES tf,SIGNAL &signal_set)
{
//--- Getting the indicator handle
   int h=INVALID_HANDLE;
   ENUM_APPLIED_PRICE app_price;
   switch(signal_set.app_price)
   {
   case  0:
      app_price=PRICE_CLOSE;
      break;
   case  1:
      app_price=PRICE_OPEN;
      break;
   case  2:
      app_price=PRICE_HIGH;
      break;
   case  3:
      app_price=PRICE_LOW;
      break;
   case  4:
      app_price=PRICE_MEDIAN;
      break;
   case  5:
      app_price=PRICE_TYPICAL;
      break;
   case  6:
      app_price=PRICE_WEIGHTED;
      break;
   default:
      app_price=PRICE_CLOSE;
      break;
   }
//---
   switch(signal_set.ind_type)
   {
   case  0:
      h=iATR(sy,tf,signal_set.ind_period);
      break;
   case  1:
      h=iCCI(sy,tf,signal_set.ind_period,app_price);
      break;
   case  2:
      h=iDeMarker(sy,tf,signal_set.ind_period);
      break;
   case  3:
      h=iForce(sy,tf,signal_set.ind_period,MODE_SMA,VOLUME_TICK);
      break;
   case  4:
      h=iWPR(sy,tf,signal_set.ind_period);
      break;
   case  5:
      h=iRSI(sy,tf,signal_set.ind_period,app_price);
      break;
   case  6:
      h=iMomentum(sy,tf,signal_set.ind_period,app_price);
      break;
   default:
      break;
   }
   if(h==INVALID_HANDLE)
   {
      Print(sy+". Failed to get handle");
      Print("Handle = ",h,"  error = ",GetLastError());
      return(false);
   }
   //---
   double arr[1];
   if(CopyBuffer(h,0,
    0,1,arr)!=1)
   {
      Print("sy= ",sy,"tf= ",EnumToString(tf)," Failed to get handle data ",GetLastError());
      return(false);
   }
   IndicatorRelease(h);
//--- Check the condition
   double r_value=signal_set.rule_value;
   double c_value=arr[0];
   m_ind_value=c_value;
   int s=0;
   switch(signal_set.rule_type)
   {
   case  0:
      if(c_value>r_value)
         s=1;
      break;
   case  1:
      if(c_value>=r_value)
         s=1;
      break;
   case  2:
      if(c_value==r_value)
         s=1;
      break;
   case  3:
      if(c_value<r_value)
         s=1;
      break;
   case  4:
      if(c_value<=r_value)
         s=1;
      break;
   default:
      s=0;
      break;
   }
//---
   if(s>0)
      return(true);
   return(false);
}

O método GetSignal() recebe da estrutura SIGNAL as informações sobre quais indicadores disponíveis foram selecionados para gerar os sinais de negociação, quais configurações foram selecionadas para o indicador e qual regra de busca foi ela definida. Não esqueça que a filtragem pelos períodos pode ser realizada duas vezes para cada sinal. A primeira vez que ela é realizada na segunda etapa de configuração, é possível filtrar os valores selecionados na janela de criação do sinal de negociação, conforme mostrado na figura 8 abaixo.

Fig.8 Selecionando os períodos para o sinal criado.

Para o nosso algoritmo considerar esse filtro e não procurar por sinais fora dos períodos especificados, a especificação dos períodos deve ser verificada para cada um dos sinais de negociação criados. Então, criamos o método CheckTimeframe() na classe base. O método servirá como um filtro.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::CheckTimeframe(ENUM_TIMEFRAMES tf,SIGNAL &signal_set)
{
   for(int i=0; i<21; i++)
   {
      if(StringToTimeframe(CharArrayToString(signal_set.tf_name[i].tf))==tf)
         return(true);
   }
   return(false);
}

Agora, é hora de criar o mecanismo de busca do sinal de negociação. Para fazer isso, adicionamos um método à seção public da classe CProgram: SearchSignal().

bool              SearchSignals(void);

Vamos analisar sua implementação passo a passo com mais detalhes e ver o objetivo dos métodos auxiliares criados anteriormente.

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CProgram::SearchSignals(void)
{
//--- Search for set signals
   SIGNAL signal_set[];
   int cnt=0;
   for(int i=0; i<5; i++)
   {
      if(FileIsExist("Signal Monitor\\signal_"+string(i)+".bin"))
         cnt++;
   }
//---
   ArrayResize(signal_set,cnt);
   ZeroMemory(signal_set);
//---
   for(int i=0; i<cnt; i++)
   {
      int h=FileOpen("Signal Monitor\\signal_"+string(i)+".bin",FILE_READ|FILE_BIN);
      if(h==INVALID_HANDLE)
      {
         MessageBox("Configuration not found","Signal Monitor");
         return(false);
      }
      FileReadStruct(h,signal_set[i]);
      FileClose(h);
      for(int j=0; j<ArraySize(m_signal_button); j++)
      {
         //---
         string sy=GetSymbol(j);
         ENUM_TIMEFRAMES tf=GetTimeframe(j);
         //---
         if(!CheckTimeframe(tf,signal_set[i]))
            continue;
         //---
         if(GetSignal(sy,tf,signal_set[i]))
         {
            //---
            if(signal_set[i].label_type==1)
               SetLabel(j,CharArrayToString(signal_set[i].label_value),signal_set[i].label_color);
            else
               SetLabel(j,DoubleToString(m_ind_value,3),signal_set[i].label_color);
            //---
            if(signal_set[i].back_color!=clrNONE)
               SetBackground(j,signal_set[i].back_color);
            //---
            if(signal_set[i].border_color!=clrNONE)
               SetBorderColor(j,signal_set[i].border_color);
            else
               SetBorderColor(j,signal_set[i].back_color);
            //---
            if(signal_set[i].tooltip)
               SetTooltip(j,CharArrayToString(signal_set[i].tooltip_text));
            //---
            if(signal_set[i].image)
               SetIcon(j,signal_set[i].img_index);
            else
               SetIcon(j,-1);
         }
      }
   }
   return(true);
}

Na primeira etapa da operação, o método de busca coleta os dados sobre o número total de sinais de negociação criados e configurados. Em seguida, o método executa um loop através dos arquivos que conectam as informações sobre as configurações de sinal e lê esses dados em uma estrutura. O mecanismo determina para cada bloco de indicação o símbolo e o período apropriado aos quais o bloco corresponde na forma de tabela. Com base nesses dados, verificamos se um sinal de negociação precisa ser pesquisado no período selecionado. Se o período corresponder, buscamos um sinal. Se um sinal for encontrado, colorimos o bloco de indicação de acordo com a configuração do sinal. Agora, o método criado pode ser aplicado. O método deve ser chamado no final do corpo do método ToMonitor().

...
//--- Resize window
   AutoResize(m_timeframe_label[tf-1].XGap()+m_timeframe_label[tf-1].XSize()+5,m_symbol_label[sy-1].YGap()+m_symbol_label[sy-1].YSize()+5);
//---
   SearchSignals();
}

Agora, vamos tentar ativar uma pesquisa repetida após um determinado intervalo de tempo. Abrimos o arquivo SignalMonitor.mq5 e criamos uma enumeração no início do arquivo:

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
enum UPDATE
{
   MINUTE,        // 1 Minute
   MINUTE_15,     // 15 Minutes
   MINUTE_30,     // 30 Minutes
   HOUR,          // 1 Hour
   HOUR_4         // 4 Hours
};

Uma nova configuração agora pode ser facilmente adicionada às entradas:

input UPDATE               Update            =  HOUR;                // Update interval

Criamos duas variáveis para os cálculos.

int cnts=0;
datetime update;

Adicionamos as seguintes linhas na inicialização do expert:

//---
   switch(Update)
   {
   case MINUTE:
      cnts=60;
      break;
   case MINUTE_15:
      cnts=60*15;
      break;
   case MINUTE_30:
      cnts=60*30;
      break;
   case HOUR:
      cnts=3600;
      break;
   case HOUR_4:
      cnts=3600*4;
      break;
   default:
      cnts=1;
      break;
   }
   update=TimeLocal()+cnts;

Assim, nós determinamos o intervalo de atualização e definimos o próximo tempo de atualização. No corpo da função OnTick(), adicionamos a verificação de tempo: se o intervalo de tempo especificado tiver passado, buscamos os sinais de negociação novamente.

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
   if(TimeLocal()>update)
   {
      program.SearchSignals();
      update=TimeLocal()+cnts;
   }
}

Compilamos o projeto e criamos um conjunto de seus próprios símbolos. Nós podemos adicionar um sinal para demonstrar a operação do monitor.

 

Na próxima parte desta série de artigos, nós continuaremos expandindo a funcionalidade atual para uma configuração mais flexível dos sinais de negociação, e também melhoraremos alguns dos recursos existentes.


Conclusão

O arquivo anexado abaixo contém todos os arquivos descritos adequadamente organizados em pastas. Para uma operação correta, você deve salvar a pasta MQL5 na pasta raiz da plataforma. Para abrir o diretório raiz da plataforma, no qual a pasta MQL5 está localizada, pressione a combinação de teclas Ctrl+Shift+D na plataforma MetaTrader 5 ou use o menu de contexto como é mostrado na Fig. 9 abaixo.


Fig. 9. Abrindo a pasta MQL5 no diretório raiz da plataforma MetaTrader 5


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

Arquivos anexados |
MQL5.zip (1706.81 KB)
Últimos Comentários | Ir para discussão (5)
alextradesignal
alextradesignal | 8 mar. 2020 em 21:37

111

É possível adicionar uma rolagem vertical ou como superar o problema com o número de tickers?

e, depois de salvar, o Expert Advisor trava com um erro.

Alexander Fedosov
Alexander Fedosov | 9 mar. 2020 em 07:43
alextradesignal:

É possível adicionar uma rolagem vertical ou como superar o problema com o número de tickers?

e, depois de salvar, o Expert Advisor trava com um erro.

Na próxima parte, apenas para contas de negociação com um grande número de símbolos, alterarei a exibição da seleção de símbolos.

Sobre exceder o limite:

- Encontre o número total de símbolos no Market Watch.


- Vá para o arquivo Program.mqh no código-fonte e altere esse número para o número de símbolos no Market Watch

struct SAVE
{
   bool              tf[72];
};
Stanislav Korotky
Stanislav Korotky | 9 mar. 2020 em 12:03
Alexander Fedosov:

- Vá para o arquivo Program.mqh no código-fonte e altere esse número para o número de caracteres na Visão geral do mercado

Gênio.

Kwan Tuck
Kwan Tuck | 23 jul. 2020 em 08:16
kwancheetuck.Gold Level Product Specialist Benefits2 Seus benefícios %20 Silver Level Product Specialist estão incluídos com %20 user.compahy atingir o preço de reserva +60 11-3346 1063 Pular navegação
Perguntas frequentesFaça uma pergunta
Você já é um usuário Sedo?
Se quiser enviar uma pergunta, recomendamos enfaticamente que use o prompt de login no canto superior direito para primeiro fazer login em sua conta Sedo e depois enviar sua pergunta. Ao fazer isso, você terá a oportunidade de verificar o status do seu problema a qualquer momento e receber mais suporte do Serviço de Atendimento ao Cliente da China! Se você ainda não é um usuário Sedo, pode abrir uma conta gratuita agora. Clique em "Informações de login" no canto superior direito para obter mais detalhes. Caso queira apenas encaminhar sua dúvida, preencha o formulário abaixo com todas as informações solicitadas e, em seguida, envie sua pergunta.

*Necessário

Sobrenome*Requerido

Primeiro nome*Preciso

Endereço de e-mail*Preciso

O usuário de leitor de tela pressiona Enter para substituir o produto. Valor substituto: Outro
Exibição do produto
Este botão não funciona em leitores de tela. Em vez disso, use o link anterior. Outro
O usuário do leitor de tela pressiona a tecla Enter em vez do assunto. Valores substituídos: Termos de uso
Assunto
Este botão não funciona em leitores de tela. Em vez disso, use um link anterior. Termos do usuário
Seleção de idioma *Requerido

Nome do domínio

Detalhes da pergunta*necessário

Anexar arquivo
Selecione o arquivo a ser carregado para concluir
Benefícios de estacionar nomes de domínio e configuração de estacionar nomes de domínio em SEDO.pdf (231.58KB) Excluir Benefícios de estacionar nomes de domínio e configuração de estacionar nomes de domínio em SEDO.pdf
Quando posso receber comissões de estacionamento_(4).pdf (191.69KB)Excluir Quando posso receber comissões de estacionamento_(4).pdf
Como otimizar os domínios estacionados? (2).pdf (296,98KB) Excluir Como otimizar os domínios estacionados? (2).pdf
.
Como faço para adicionar um nome de domínio para venda ou estacionamento? .pdf (237,57KB) Excluir Como adicionar um nome de domínio para venda ou estacionamento? .pdf
Sedo GmbH - Perguntas frequentes e sistema de tickets (161.31KB)Excluir Sedo GmbH - Perguntas frequentes e sistema de tickets
FunClub Terms Conditions Named Forms.pdf (73.9KB) 刪除請發送電子郵件至my_sms@xlwinmarketing.net. FunClub Terms Conditions Named_Forms... .Sereenshot_20200226-02224%20100%contldential%20 of%20quota tag has'attachmeht%20Please email mym_sms@ chee Terms Conditions. Formulários de nomeação. Benefícios para especialistas Estacionamento de nomes de domínio. Caça-níqueis de cassino na Internet. Ajuda . Cracking . Vulnerabilidades. Internet Global .2020KWANCHEETUCK SOLUTIONS . Responder perguntas. Perguntas sobre produtos. Problemas com nossos serviços. Melhorias. Nossos serviços. Maneiras de ajudar o Google a resolver seus problemas.

Google Chrome
Conta do Google
YouTube
Gmail
Google Play
Pesquisa do Google
AdSense
Telefone Pixel
Google Maps
Google Cloud Drive
Google Ads
Álbuns do Google
Google para famílias
Google Fi
Google Nest
Google Pay
Google Store
Google Domains
Google Shopping
Centro de Acessibilidade do Google
Consumidores
Blogger
Google Finance
Google Earth
Google Maps
Picasa
Barra de ferramentas do Google
Pesquisa do Google
Calendário
Editor de documentos
Livros
Fóruns do Google
YouTube
Tendências de pesquisa do Google
Android
Plataformas de colaboração
Google Chrome
Google Cloud Drive
Google Voice
Google Translate
Google Chrome
Google+
Google TV
Google Play
Impressão na nuvem
Meus mapas
Loja de aplicativos on-line do Chrome
Loja de aplicativos on-line do Chrome
Google Fiber
Nexus
Anuncie conosco
Hangouts
Pacote de edição de fotos Nik
Chromecast
Chromecast
Google Keep
Starbucks WiFi
Google Fi
Waze
Wear OS do Google
Google Fit
Guia para pais do YouTube Kids
Loja do Google
Google Cast
Álbuns do Google
Android Auto
Android TV
Google para famílias
Câmera do Google
Google Wifi
Assistente local
YouTube Music
Central de ajuda do YouTube Studio
Google Duo
Dados
YouTube Go
Google Nest
YouTube TV
Google Clips
Telefone Pixel
Prêmios de opinião
Daydream
Assistente pessoal do Google
Arquivos do Google
CS First
Pixelbook
Mensagens
Reserva
"Aplicativos de telefone
Gboard
Contatos
Google One
Google...Free%20Basic%20Internet%20(FBI)%20*02224
Kwan Tuck
Kwan Tuck | 23 jul. 2020 em 08:37
kwancheetuck.Gold Level Product Specialist Benefits2 Your %20 Silver Level Product Specialist Benefits Included There are %20 Users Reach Reserve Price +60 11-3346 1063 Please email kwancheetuck Terms Conditions. Informe o nome do formulário KWANCHEETUCK e solicite o que você precisa. Copyright © 2020 ® kwan chee tuck © "Got" Auto ® de Crack . Vulnerabilidades. Internet global. Direitos autorais © 2020® KWANCHEETUCK Solutions. Responda às perguntas. Perguntas sobre produtos. Problemas com nossos serviços. Melhorias. Nossos serviços. Criar uma Internet limpa. Responsabilidade de todos. Esse assunto é importante.

Linguagem MQL como um meio de marcação da interface gráfica de programas MQL. Parte 1 Linguagem MQL como um meio de marcação da interface gráfica de programas MQL. Parte 1
O artigo propõe uma nova ideia para descrever a interface de programas MQL com ajuda das construções da linguagem MQL. As classes especiais transformam o esquema visual MQL em elementos da GUI, permitem gerenciá-los de maneira unificada, configurar propriedades e processar eventos. Além disso, apresenta exemplos de uso de layouts para caixas de diálogo e elementos da biblioteca padrão.
Trabalhando com séries temporais na biblioteca DoEasy (Parte 38): coleção de séries temporais - atualização em tempo real e acesso aos dados do programa Trabalhando com séries temporais na biblioteca DoEasy (Parte 38): coleção de séries temporais - atualização em tempo real e acesso aos dados do programa
No artigo, consideraremos a atualização em tempo real dos dados das séries temporais, bem como o envio de mensagens sobre o evento "Nova Barra" para o gráfico do programa de controle, a partir de todas as séries temporais de todos os símbolos, a fim de processar estes eventos nos programa. Para determinar se necessário atualizar séries temporais para símbolos e períodos inativos, usaremos a classe "Novo tick".
Trabalhando com séries temporais na biblioteca DoEasy (Parte 39): indicadores com base na biblioteca - preparação de dados e eventos das séries temporais Trabalhando com séries temporais na biblioteca DoEasy (Parte 39): indicadores com base na biblioteca - preparação de dados e eventos das séries temporais
No artigo, consideramos o uso da biblioteca DoEasy para criar indicadores multissímbolos e multiperíodos. Prepararemos as classes da biblioteca, para trabalhar como parte dos indicadores, e testaremos a criação correta de séries temporais para usá-los como fontes de dados em indicadores. Realizaremos a criação e o envio de eventos de séries temporais.
Otimização Walk Forward Contínua (parte 5): Panorama do Projeto Otimizador Automático e Criação da Interface Gráfica Otimização Walk Forward Contínua (parte 5): Panorama do Projeto Otimizador Automático e Criação da Interface Gráfica
Este artigo fornece uma descrição mais detalhada da otimização walk-forward na plataforma MetaTrader 5. Nos artigos anteriores, nós consideramos os métodos para gerar e filtrar o relatório de otimização e começar a analisar a estrutura interna do aplicativo responsável pelo processo de otimização. O Otimizador Automático é implementado como uma aplicação em C# e possui sua própria interface gráfica. O quinto artigo é dedicado à criação dessa interface gráfica.