English Русский 中文 Español Deutsch 日本語
Interação entre o MetaTrader 4 e o Matlab através de arquivos CSV

Interação entre o MetaTrader 4 e o Matlab através de arquivos CSV

MetaTrader 4Exemplos | 22 fevereiro 2016, 12:26
906 0
Dmitriy
Dmitriy

Introdução

O ambiente de energia computacional do Matlab é conhecido por ser consideravelmente superior à de qualquer linguagem de programação incluindo MQL4. A ampla variedade de funções matemáticas fornecidas pelo Matlab permite realizar cálculos computacionais complexos negligenciando totalmente a base teórica das operações realizadas.

No entanto, a interação em tempo real entre um terminal de trading e o Matlab representa uma tarefa não trivial. Neste artigo, sugiro uma forma de organizar a troca de dados entre o MetaTrader 4 e o Matlab através de arquivos CSV.


1. Interfuncionamento

Suponha que, na entrada de cada nova barra, o MetaTrader 4 deve enviar dados sobre as últimas 100 barras para o Matlab e ser respondido com seus resultados de processamento.

Para resolver este problema, vamos precisar criar um indicador no MetaTrader 4 que iria escrever dados em um arquivo de texto e ler os resultados do processamento de outro arquivo de texto criado pelo Matlab.

O MetaTrader 4 deve formar seu próprio arquivo de dados na entrada de cada nova barra. O MetaTrader 4 também deve tentar ler os resultados em cada crédito. A fim de não ler o resultado antes do Matlab atualiza-lo, teremos excluído o arquivo que contém o resultado antes de formar o nosso arquivo de saída. Neste caso, a tentativa de leitura terá sucesso somente após o Matlab terminar seu cálculo e formar um novo arquivo.

O Matlab deve analisar os atributos do arquivo criados no MetaTrader 4 a cada segundo e iniciar o processamento quando seu tempo de criação mudar. Após o processamento tiver terminado, o arquivo excluído pelo MetaTrader 4 antes do início da gravação de dados é recriado. O MetaTrader 4 o exclui com êxito, carrega novos dados e aguarda resposta.


2. Formação de um arquivo de dados de saída

Há muitos artigos dedicados a salvar dados como arquivos, por isso, neste artigo, não vou focar neste ponto. Apenas vou deixar claro que escrevemos dados em 7 colunas: “DATA”, “TEMPO”, “ALTA”, “BAIXA”, “FECHAMENTO”, “ABERTURA”, “VOLUME”. O caractere de separação é “;”. A prioridade da barra é das mais antigas para as posteriores, isto é, a linha que contém as características da barra de zero deve ser registrada por último. O arquivo será fornecido com uma linha contendo os nomes das colunas. O nome do arquivo será composto do nome do símbolo e do período de tempo.

#property indicator_chart_window
extern int length = 100;   // The amount of bars sent to be processed
double ExtMap[];           // Chart buffer
string nameData;
int init()
{
   nameData = Symbol()+".txt";         // name of the data file to be sent
   return(0);
}
int start()
{
   static int old_bars = 0;   // remember the amount of bars already known   
   if (old_bars != Bars)      // if a new bar is received 
   {
      write_data();                             // write the data file                              
   }      
   old_bars = Bars;              // remember how many bars are known
   return(0);
}
//+------------------------------------------------------------------+
void write_data()
{
  int handle;
  handle = FileOpen(nameData, FILE_CSV|FILE_WRITE,';');
  if(handle < 1)
  {
    Comment("Creation of "+nameData+" failed. Error #", GetLastError());
    return(0);
  }
  FileWrite(handle, ServerAddress(), Symbol(), Period());                  // heading
  FileWrite(handle, "DATE","TIME","HIGH","LOW","CLOSE","OPEN","VOLUME");   // heading
  int i;
  for (i=length-1; i>=0; i--)
  {
    FileWrite(handle, TimeToStr(Time[i], TIME_DATE), TimeToStr(Time[i], TIME_SECONDS),
                      High[i], Low[i], Close[i], Open[i], Volume[i]);
  }
  FileClose(handle);
  Comment("File "+nameData+" has been created. "+TimeToStr(TimeCurrent(), TIME_SECONDS) );
  return(0);
}

Não vamos precisar de todos estes dados, é claro, mas é sempre melhor ter um arquivo significativo do que apenas um conjunto de colunas com valores desconhecidos.


3. Criação da Interface Gráfica do Usuário (GUI)

O arquivo está pronto. Vamos iniciar o Matlab.

Deveríamos desenvolver uma aplicação que iria ler dados de texto do arquivo, processar e gravar os resultados em outro arquivo. Teremos que criar uma GUI para especificar o nome do arquivo, visualizar gráficos e iniciar o processamento. Vamos começar agora.

Para criar a GUI, vamos iniciar o "Guia de Início Rápido", digitando "guia" no console ou pressionando no painel principal do Matlab. Na caixa de diálogo exibida, selecione "Criar Nova GUI" -> "GUI em branco (padrão)". Agora podemos ver a interface para a criação de uma GUI com um formulário vazio. Neste formulário, vamos colocar os seguintes objetos: "Editar Texto", "Pressionar Botão", "Texto estático", "Eixos", "Pressionar Botão". O resultado é mais ou menos assim:

Agora devemos chamar o construtor de propriedade visual para cada objeto e definir as propriedades da seguinte forma:

Texto estático: Alinhamento Horizontal - esquerda, Tag - textinfo, String - Info.
Editar texto: Alinhamento Horizontal - esquerda, Tag - editarCaminho, String - Selecionar caminho.
Pressionar botão: Tag - pressionarNavegação, String - Navegação.
Eixos: Caixa - ligada, NomedaFonte - MS Sans Serif, Tamanho da fonte - 8, Tag - eixosdoGráfico.
Pressionar botão: Tag - pressionarIniciar, String - Iniciar.

Ao alterar a propriedade da Tag, selecionamos um nome exclusivo para cada objeto. Ao alterar outros, modificamos a aparência da Tag.

Quando tudo estiver pronto, vamos iniciar a interface pressionando "Executar", confirme o salvamento da interface e do arquivo-M, dê um nome (por exemplo, "De Para"), e pressione "Salvar". Depois disso, GUI será lançada e aparece como aparece durante seu trabalho. O Matlab gera o arquivo-M para ser a base do nosso programa futuro e o abre no editor incorporado.

Se a aparência não lhe adapta por algum motivo, feche a GUI e corrija o arranjo do objeto usando o editor. Meu distributivo, por exemplo, não exibiu MS Sans Serif corretamente. Então eu tive que mudar para "Sans Serif".


4. Construção da Interface do Usuário

O comportamento da interface pode ser programado no Editor do arquivo-M utilizando a linguagem Matlab. O programa esqueleto gerado pelo Matlab representa uma lista de funções a serem chamadas pelo usuário ao trabalhar com os objetos de interface. As funções estão vazias, então a GUI ainda não faz nada. É nossa tarefa preencher as funções com os conteúdos necessários.


4.1 Programação do Botão de Navegação


Primeiramente, precisamos de acesso a um arquivo gerado pelo MetaTrader 4, por isso vamos começar chamando a função pressionando "Navegação".

O nome da função chamada pressionando o botão consiste no nome do botão (definido pela propriedade "Tag") e pós-fixado "_Callback". Vamos encontrar a função "pushBrowse_Callback" no arquivo de texto ou apenar pressionar "Mostrar funções" na barra de ferramentas e selecionar "pushBrowse_Callback" na lista.

A sintaxe da linguagem de programação Matlab difere das regras convencionais de codificação nas linguagens C e similares. Particularmente, não há necessidade de marcar o corpo da função com chaves ou especificar o tipo de dados a serem passados para a função, índices da matriz (vetor) iniciam com um, e o caractere de comentário é "%". Assim, todo o texto verde acima não é um programa, mas um comentário feito pelos desenvolvedores do Matlab para sermos capazes de compreender o caso.

Teremos de criar um diálogo para introduzir o nome completo do arquivo. Para isso, vamos usar a função "uigetfile":

% --- Executes on button press in pushBrowse.
function pushBrowse_Callback(hObject, eventdata, handles)
[fileName, filePath] = uigetfile('*.txt'); % receive and the path from the user
if fileName==0          % if it is canceled
    fileName='';        % create an empty name
    filePath='';        % create an empty path
end
fullname = [filePath fileName] % form a new name
set(handles.editPath,'String', fullname); % write in the editPath

"puxadores" aqui é uma estrutura que armazena descritores de todos os objetos na nossa GUI incluindo o do formulário em que o colocamos. A estrutura é passada de uma função para outra e permite o acesso aos objetos.
"hObject" é uma descrição do objeto que chamou a função.
"Set" ajuda a definir o valor do objeto por um determinado valor e tem a seguinte sintaxe: set(object_descriptor, object_property_name, property_value).

Você pode encontrar o valor das propriedades do objeto usando a seguinte função: property_value = get(object_descriptor, object_descriptor_name).
Mas não se esqueça que o nome é um valor do tipo string, por isso deve ser entre aspas simples.

Há uma última coisa que temos que saber sobre objetos e suas propriedades. O formulário, onde colocamos os elementos da GUI, é em si um objeto colocado no objeto "raiz" (é seu descendente). Ele também tem um conjunto de propriedades que podem ser modificadas. As propriedades podem ser visualizadas usando a ferramenta chamada "Editor de objeto" para ser chamada a partir da barra de ferramentas principal do editor de interface. Objeto "raiz", como o termo sugere, é a raiz da hierarquia dos objetos gráficos e não tem ascendência.

Agora vamos verificar o que temos como resultado. Vamos agora começar a nossa GUI pressionando Executar na barra de ferramentas principal do Editor de arquivo-M. Tente clicar no Navegador e selecionar nosso arquivo. Está funcionando? Em seguida, feche a GUI que está em operação e prossiga.


4.2 Programação do Botão Iniciar, Desenho Gráfico


Agora vamos atribuir o botão Iniciar com a chamada da função que iria ler os dados do arquivo e mostrá-los em um gráfico.

Primeiramente, vamos criar a função. Vamos precisar da estrutura dos descritores dos objetos "puxadores'' como entradas. Tendo acesso aos objetos, seremos capazes de lê-los e definir suas propriedades.

% data reading, chart drawing, processing, storage
function process(handles)
fullname = get(handles.editPath, 'String'); % read the name from editPath
data = dlmread(fullname, ';', 2, 2);    % read the matrix from file
info = ['Last update: ' datestr(now)];  % form an informative message
set(handles.textInfo, 'String',info);   % write info into the status bar
 
high = data(:,1);   % it is now high where the first column of the data matrix is
low = data(:,2);    % d low -- the second
close = data(:,3);  % --/--
open = data(:,4);   %
len = length(open); % the amount of elements in open
 
axes(handles.axesChart); % make the axes active
hold off; % clean axes off before adding a new chart
candle(high, low, close, open); % draw candlesticks (in the current axes)
set(handles.axesChart,'XLim',[1 len]); % set limits for charting

Algumas explicações:

“dlmread” lê os dados do arquivo de texto com separadores e possui a seguinte sintaxe: dlmread(full_file_name, separator, skip_strings, skip_columns);
“comprimento(qqq)” – o lado maior da matriz qqq;
”agora” - hora e data atual;
“datestr(now)” - transforma data e hora em um texto;

Você também deve saber que o Matlab fornece uma informação útil enorme de ajuda com a teoria e com os exemplos.

Vamos colocar a nossa função no final do programa (será mais fácil de encontrá-la) e adicionar sua chamada na “pushStart_Callback”:

% --- Executes on button press in pushStart.
function pushStart_Callback(hObject, eventdata, handles)
process(handles);

Lance isto usando "Executar", selecione um arquivo, pressione "Iniciar" e aprecie o resultado.


4.3 Salvando o Caminho em um Arquivo


Tudo está bem agora, mas é um pouco irritante clicar permanentemente com o mouse para selecionar um arquivo depois de ter pressionado "Navegação". Vamos tentar salvar o caminho uma vez selecionado.
Vamos começar lendo. O nome de um arquivo que armazena o caminho será composto pelo nome da GUI e sufixo “_saveparam” e terá extensão ".mat".
A função “FromTo_OpeningFcn” é executada diretamente após a criação do formulário da GUI. Nós vamos adicionar lá a tentativa de ler o caminho do arquivo. Se a tentativa falhar, será utilizado o valor padrão.

% --- Executes just before FromTo is made visible.
function FromTo_OpeningFcn(hObject, eventdata, handles, varargin)
guiName = get(handles.figure1, 'Name'); % get the name of our GUI
name = [guiName '_saveparam.mat']       % define the file name
h=fopen(name);                          % try to open the file
if h==-1                                % if the file does not open
    path='D:\';                         % the default value
else
    load(name);                         % read the file    
    fclose(h);                          % close the file
end
set(handles.editPath,'String', path);   % write the name into object "editPath"

Outras strings da função “FromTo_OpeningFcn” serão mantidas inalteradas.


Vamos modificar a função “pushBrowse_Callback” como se segue:

% --- Executes on button press in pushBrowse.
function pushBrowse_Callback(hObject, eventdata, handles)
path = get(handles.editPath,'String'); % read the path from object editPath 
[partPath, partName, partExt] = fileparts(path);    % divide the path into parts
template = [partPath '\*.txt'];                     % create a template of parts
[userName, userPath] = uigetfile(template);         % get the user name and the path from the user
if userName~=0                                      % if "Cancel" is not pressed        
    path = [userPath userName];                     % reassemble the path
end
set(handles.editPath,'String', path);               % write the path into object "editPath"
guiName = get(handles.figure1, 'Name');             % get to know the name of our GUI
save([guiName '_saveparam.mat'], 'path');           % save the path

4.4 Processamento de dados


Como um processo exemplar, vamos interpolar a coluna "ABERTURA" por uma função polinomial de quarta ordem.
Vamos adicionar o seguinte código no final da nossa função, "process":

fitPoly2 = fit((1:len)',open,'poly4'); % get the polynomial formula
fresult = fitPoly2(1:len); % calculate Y values for X=(from 1 to len)
hold on; % a new chart has been added to the old one
stairs(fresult,'r'); % plot stepwise by color - 'r'- red


Vamos tentar lançar e pressionar "Iniciar".


Se você tem aproximadamente o mesmo resultado como mostrado acima, é hora de começar a salvar os dados como um arquivo.


4.5 Salvar dados como um arquivo


Salvar dados não é mais complicado que lê-los. A única "sutileza" é que o vetor "fResult" deve ser contado para baixo, isto é, a partir do mais recente para o primeiro. Isto é feito para simplificar a leitura do arquivo no MetaTrader 4, a partir da barra zero até o final do arquivo.

Vamos complementar a função "process" com o seguinte código:

[pathstr,name,ext,versn] = fileparts(fullname); % divide the full name
                                                % of the file into parts
newName = [pathstr '\' name '_result' ext];     % re-compose the new file name
fresult = flipud(fresult);  % turn vector fresult
dlmwrite(newName, fresult);    % write in t
% function called by the timer
function checktime(obj, event, handles)
set(handles.textInfo,'String',datestr(now));
he file

Agora, por favor, certifique-se de que o arquivo que contém o resultado foi criado, localizado no mesmo lugar onde há o arquivo inicial e possui o mesmo nome complementado pelo sufixo "_result".


4.6 Controle do temporizador


Esta é a parte mais difícil do trabalho. Teremos que criar um temporizador que verifique o arquivo de formação do tempo do MetaTrader 4 a cada segundo. Se o tempo mudar, a função "process" deve ser lançada. O temporizador para-inicia será executado utilizando "Iniciar". Quando a GUI abrir, eliminaremos todos os temporizadores criados anteriormente.

Vamos criar um temporizador colocando o seguinte código na função “FromTo_OpeningFcn”:

timers = timerfind; % find timers
if ~isempty(timers) % if timers are available
    delete(timers); % delete all timers
end
handles.t = timer('TimerFcn',{@checktime, handles},'ExecutionMode','fixedRate','Period',1.0,'UserData', 'NONE');

O código acima deve ser inserido imediatamente após a nossa inserção anterior nesta função, isto é, antes das strings “handles.output = hObject;” e “guidata(hObject, handles);”.

Ao executar este código, o Matlab, imediatamente após a criação da GUI, irá verificar se há disponibilidade de temporizadores, eliminando os já existentes e criando um novo. O temporizador irá chamar a função “checktime” cada segundo e passará a lista de descritores "alças" na função. Além das "alças", o temporizador passará seu próprio descritor para a função, bem como a estrutura que contém a duração da chamada e da razão. Não podemos influenciar isto, mas temos que considerar quando a codificação da função for chamada pelo temporizador.

Você pode localizar a própria função quando quiser. Deixe que ela própria escreva na barra de status do Matlab o momento em que foi chamada:

Na sua criação, o temporizador é parado, agora devemos lançá-lo. Vamos encontrar a função “pushStart_Callback”. Vamos comentar chamando de 'process(handles)' colocado nele e escrever a gestão do temporizador para ele:

% --- Executes on button press in pushStart.
function pushStart_Callback(hObject, eventdata, handles)
% process(handles);
statusT = get(handles.t, 'Running'); % Get to know the timer status
if strcmp(statusT,'on')     % If it is enabled - 
    stop(handles.t);        % disable it
    set(hObject,'ForegroundColor','b'); % change color of pushStart marking
    set(hObject,'String',['Start' datestr(now)]); % change the button top marking
end     
if strcmp(statusT,'off')    % If it is disabled - 
    start(handles.t);       % enable it
    set(hObject,'ForegroundColor','r');% change color of pushStart marking
    set(hObject,'String',['Stop' datestr(now)]); % change the button top marking
end 

Agora vamos verificar como tudo funciona. Vamos tentar ativar e desativar o temporizador utilizando "Iniciar". Se o temporizador estiver ativado, o relógio acima do caminho do campo de entrada deve funcionar.

Seria mais correto eliminar o temporizador utilizando o botão "X" no fechamento da GUI. Se você quiser fazer isso, adicione-o

stop(handles.t) ; % stop the timer
delete(handles.t); % delete the timer

no início da função “figure1_CloseRequestFcn”. Esta função será chamada no fechamento da GUI. Você pode acessá-la a partir do editor da GUI:

Mas, por favor, levar em consideração que, agora, se você pressionar "Executar" do editor sem ter fechado a GUI operacional, o temporizador antigo não será excluído ao criar o novo. E da próxima vez vai haver mais um criado, etc. Você pode lidar com temporizadores "desestabilizados" usando o comando "delete(timerfind)" do console Matlab.


Agora, se tudo estiver funcionando bem, criaremos uma função para verificar o tempo da última modificação do arquivo do MetaTrader 4:

% function to be called by the timer
function checktime(obj, event, handles)
filename = get(handles.editPath, 'String'); % get to know the file name 
fileInfo = dir(filename);        % get info about the file
oldTime = get(obj, 'UserData');  % recall the time
if ~strcmp(fileInfo.date, oldTime) % if the time has changed
    process(handles);
end
set(obj,'UserData',fileInfo.date); % save the time
set(handles.pushStart,'String',['Stop ' datestr(now)]); % override the time

A função "dir(full_file_name)" retorna uma estrutura que contém as informações do arquivo (nome, data, bytes, isDir). As informações sobre o tempo de criação do arquivo anterior serão armazenadas na propriedade "Userdata" do objeto do temporizador. Seu descritor é passado para a função "checktime" nomeada como obj.

Agora, ao mudar um arquivo criado por MetaTrader 4, nosso programa irá substituir o resultado. Você pode verificar isso, modificando o arquivo manualmente (por exemplo, deletando as últimas strings) e rastreando as alterações no gráfico ou arquivo resultante. Claro que, o botão "Iniciar" deve ser pressionado para isso.

Se uma janela extra contendo a cópia do gráfico for criada durante o funcionamento do programa, adicione a seguinte string no início da função "process":

set(handles.figure1,'HandleVisibility','on');


5. Desenhando os resultados no MetaTrader 4


Agora vamos retornar ao MetaTrader 4. Temos que complementar nosso indicador com uma função que lê o resultado do arquivo e o desenha em um gráfico. O comportamento do programa será descrito da seguinte forma:

1. Se uma nova barra for recebida: Exclua o arquivo do resultado anterior, apague o gráfico e salve o arquivo de dados.
2. Se o resultado do arquivo for legível: Leia o arquivo, desenhe um gráfico e exclua o arquivo do resultado.

Não vou descrever aqui como o código abaixo funciona já que a leitura de dados do arquivo e a elaboração de indicadores podem ser encontrados em outros artigos. Aqui, o arquivo do resultado é eliminado imediatamente depois de ter sido colocado no gráfico. Sendo assim, não se preocupe se você ver várias mensagens de erro de leitura.

Erros de leitura ocorrem em dois casos:
1. Imediatamente após uma nova barra ter rendimentos, uma vez que o arquivo do resultado não foi criado ainda.
2. Imediatamente após o resultado ser lido e o gráfico ser desenhado, já que o arquivo foi excluído a fim de não voltar a ler os mesmos dados.

Assim, o programa mantém seu status de "erro de leitura" praticamente o tempo todo. :)

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_width1 2
#property indicator_color1 Tomato
extern int length = 100;   // The amount of bars to be sent for processing
double ExtMap[];           // Chart buffer
string nameData;
string nameResult;

int init()
{
   nameData = Symbol()+".txt";         // the name of the data file to be sent
   nameResult = Symbol()+"_result.txt";// the name of the received file containing results
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, ExtMap);
   return(0);
}
int deinit()
  {
   Comment("");
   return(0);
  }
int start()
{
   static int attempt = 0;    // the amount of attempts to read the result
   static int old_bars = 0;   // remember the amount of the known bars
   
   if (old_bars != Bars)      // if a new bar has income 
   {
      FileDelete(nameResult);                   // delete the result file
      ArrayInitialize( ExtMap, EMPTY_VALUE);    // empty the chart
      write_data();                             // save the data file
      
      old_bars = Bars; return(0);               // nothing should be done this time                           
   }
   //
   int handle_read = FileOpen(nameResult,
                              FILE_CSV|FILE_READ,
                              ';'); // try to open the result file
   attempt++;                       // count the attempt to open
   
   if(handle_read >= 0)             // if the file has opened for reading
   { 
      Comment(nameResult+". Opened with attempt #"+ attempt); // opening report
      read_n_draw(handle_read);  // read the result and draw a chart
      FileClose(handle_read);    // close the file
      FileDelete(nameResult);    // delete the result file
      attempt=0;                 // zeroize the amount of attempts to read
   }
   else                          // if we cannot open the result file
   {
      Comment( "Failed reading "+nameResult+
               ". Amount of attempts: "+attempt+
               ". Error #"+GetLastError()); //Report about failed reading
   }
   old_bars = Bars;              // remember how many bars are known
   return(0);
}
//+------------------------------------------------------------------+
void read_n_draw(int handle_read)
{
   int i=0;
   while ( !FileIsEnding(handle_read)) 
   {
      ExtMap[i] = FileReadNumber(handle_read);
      i++;     
   }
   ExtMap[i-1] = EMPTY_VALUE;
}

 
void write_data()
{
  int handle;
  handle = FileOpen(nameData, FILE_CSV|FILE_WRITE,';');
  if(handle < 1)
  {
    Comment("Failed creating "+nameData+". Error #", GetLastError());
    return(0);
  }
  FileWrite(handle, ServerAddress(), Symbol(), Period());                  // header
  FileWrite(handle, "DATE","TIME","HIGH","LOW","CLOSE","OPEN","VOLUME");   // header
  int i;
  for (i=length-1; i>=0; i--)
  {
    FileWrite(handle, TimeToStr(Time[i], TIME_DATE), TimeToStr(Time[i], TIME_SECONDS),
                      High[i], Low[i], Close[i], Open[i], Volume[i]);
  }
  FileClose(handle);
  Comment("File "+nameData+" has been created. "+TimeToStr(TimeCurrent(), TIME_SECONDS) );
  return(0);
}

Abaixo está o meu resultado final. Espero não ter cometido nenhum erro e espero que você seja capaz de reproduzi-lo.





Conclusão

Neste artigo, descrevemos uma forma de organizar uma interação entre o MetaTrader 4 e o Matlab através de arquivos CSV. Este método não é único nem otimizado. O valor desta abordagem é que ela auxilia na troca de matrizes de dados sem habilidades especiais de operação com quaisquer ferramentas de programação além do MetaTrader 4 e Matlab.


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

Arquivos anexados |
work.zip (9.98 KB)
Verificador no terminal MetaTrader 4: Deve-se saber Verificador no terminal MetaTrader 4: Deve-se saber
A interface elaborada do terminal MetaTrader4 é de primeira linha, mas além disso, o terminal inclui um verificador de estratégias bem preparado. E enquanto o valor do MetaTrader 4 como sistema de trading é óbvio, a qualidade do verificador de estratégia só pode ser avaliada na prática. Este artigo mostra as vantagens e conveniências de testes no MetaTrader 4.
MT4TerminalSync - Sistema para sincronização de terminais MetaTrader 4 MT4TerminalSync - Sistema para sincronização de terminais MetaTrader 4
Este artigo é dedicado ao tema "Ampliando as possibilidades de programas MQL4 utilizando funções de sistemas operacionais e outros meios de desenvolvimento do programa". O artigo descreve um exemplo de um sistema de programa que implementa a tarefa da sincronização de várias cópias de terminais com base num único molde de origem.
Como cortar um Código de EA para uma vida mais fácil e menos erros Como cortar um Código de EA para uma vida mais fácil e menos erros
Um conceito simples descrito no artigo permite que as pessoas que desenvolvem sistemas de trading automatizados em MQL4 simplifiquem os sistemas de trading existentes, bem como reduzir o tempo necessário para o desenvolvimento de novos sistemas devido a códigos mais curtos.
Teste de Visualização: Gráficos do status da conta Teste de Visualização: Gráficos do status da conta
Aproveite o processo de testes com gráficos exibindo o balanço, agora toda a informação necessária está sendo visualizada!