Gráficos e diagramas em HTML
Introdução
Provavelmente, o MetaTrader 5 é um produto totalmente auto suficiente e não precisa de extensões adicionais. O MetaTrader 5 fornece conexão com o corretor, exibe cotas, permite que usemos uma variedade de indicadores para análise de mercado e, é claro, dá ao negociador uma oportunidade de fazer operações de negócios. é bem claro que já que o MetaTrader 5 foca primariamente em tornar a negociação confortável, ele não pode e, tecnicamente, não deve ser uma ferramenta universal absoluta, projetada para pesquisa, análise de métodos matemáticos, criação de conteúdo multimídia e assim por diante.
Além disso, a universalidade excessiva de um produto de software leva à diminuição da sua eficiência, confiabilidade e segurança. Por outro lado, em alguns casos, o usuário pode precisar de alguns recursos adicionais, negociadores em especial são pessoas com várias áreas de especialidade e conhecimentos educacionais. Então, quaisquer recursos adicionais podem aumentar a atratividade da plataforma de negociação, se eles, é claro, são alcançados de uma maneira razoavelmente simples e não com o custo de sua confiabilidade e segurança.
Neste artigo consideraremos um dos tais suplementos, que fornece a oportunidade de criar e exibir os gráficos e diagramas baseado nos dados, obtidos a partir do terminal.
Cada programa deve fazer o que faz de melhor. Se aderirmos a esse principio, então, vamos fazer com que o MetaTrader 5 seja responsável por negociações com o corretor, coleta e processamento de entrada de informações e use um programa diferente destinado a esses propósitos, para a exibição gráfica destas informações.
WEB-browser
Hoje é difícil encontrar um computador que não tenha um WEB-browser instalado. Por um longo tempo os browsers têm evoluído e melhorado. Os browsers modernos são bem confiáveis, estáveis em seu trabalho e o mais importante, grátis. Levando em consideração que um WEB-browser é praticamente a ferramenta básica para o acesso à internet, a maioria dos usuários são familiarizados com eles, e têm poucas dificuldades em seu uso.
As capacidades dos browsers modernos são tão amplas que nós os usamos para assistir vídeos, ouvir música, jogar games e fazer várias outras atividades através do WEB-browser. Então, hoje o WEB-browser é uma ferramenta bem desenvolvida para a exibição de tipos diferentes de informações que podem ser apresentadas em vários formatos.
Não pode-se deixar de mencionar que existem atualmente vários WEB-browsers populares: InternetExplorer, Mozilla Firefox, Google Chrome e Opera. Estes browsers podem diferir significativamente entre eles no aspecto de implementação de software e interfaces de usuários. Entretanto, teoricamente, eles devem suportar totalmente os padrões básicos adotados na rede para a troca de informações, que primariamente pertence aos padrões da linguagem HTML.
Na prática, não importando os esforços dos desenvolvedores, os browsers ainda têm algumas características individuais em termos de implementação de certos protocolos ou tecnologias. Se decidirmos que um browser em particular, devido aos seus recursos individuais, não nos satisfaz, esse problema é então resolvido facilmente instalando um ou vários outros WEB-browsers em nosso computador. Mesmo defensores ardorosos de tais browsers como o Firefox assim mesmo têm pelo menos o Internet Explorer instalado em seus sistemas.
Apesar do fato de que os WEB-browsers foram desenvolvidos como a parte do cliente, fornecendo interação com um servidor remoto, eles também são usados para exibir informações locais em seu computador. Um exemplo disso pode ser visualizado em páginas da WEB, previamente salvas em seu computador. O browser não precisa do acesso à internet para trabalhar com páginas locais.
Então, um WEB-browser, sendo executado em modo offline é um candidato muito atraente para o papel de um programa usado para expandir as capacidades gráficas do terminal de cliente do MetaTrader 5. Para usá-lo você não precisa fazer compras caras, instalações inconvenientes e compridas nem aprender a usar um novo produto de software.
Além disso, mais adiante neste artigo consideraremos as possibilidades do uso de WEB-browsers para a construção de gráficos e diagramas baseados nos dados obtidos no MetaTrader 5.
HTML e JavaScript
Ao escolher usar um WEB-browser como sua extensão, vamos definir para nós mesmos uma regra básica, que vamos aderir estritamente de agora em diante - a exibição das páginas HTML criadas devem ser realizadas sem o servidor da WEB local ou remoto. Ou seja, não instalaremos em nosso computador nenhum software servidor, e a exibição de nossas páginas não necessitará de um acesso à rede. As páginas HTML que criarmos devem ser exibidas somente por meio do WEB-browser e devem estar localizadas em nosso computador. Esta regra minimizará o risco associado com a possível redução de segurança devido ao acesso à uma rede externa.
Usando somente os recursos do HTML 4 para exibição de informações podemos criar páginas da WEB com tabelas, texto formatado e imagens, mas essas oportunidades podem não nos satisfazer completamente, já que a nossa meta é construir gráficos e diagramas completos baseados em dados recebidos do MetaTrader 5.
Na maioria dos casos, o que vemos no browser quando navegamos em sites diferentes é criado usando as extensões de HTML. Em geral, essas extensões são executadas no lado do servidor e, por essa razão, inadequadas para os nossos propósitos. Tecnologias capazes de trabalhar no lado do browser e que não necessitem de software de servidor, por exemplo, Macromedia Flash, JavaScript e Java podem ser de nosso interesse.
Se para a execução, no lado do browser, de aplicações Macromedia Flash e Java, vamos, no mínimo precisar da instalação de plug-ins adicionais, então os programas de usuário, criados em JavaScript são executados diretamente pelo browser. Todos os WEB-browsers comuns têm seu próprio intérprete de JavaScript integrado. Para evitar a instalação de quaisquer softwares adicionais ou plug-ins, vamos escolher o JavaScript.
Então, no que segue, usaremos somente o MetaTrader 5 com MQL5 e um WEB-browser com HTML e JavaScript. Nenhum software adicional será necessário. Deve-se lembrar que uma página HTML é nada mais que um arquivo de texto. Então, para criar um documento HTML podemos usar um editor de texto. Por exemplo, podemos criar e editar códigos HTML no MetaEditor 5. No momento da criação deste artigo, a edição do código HTML foi feita no browser Opera @ USB v10.63, que permite que você edite o conteúdo da página, salve a página modificada e faça uma pré-visualização da maneira que ela será visualizada.
Uma pessoa, não familiarizada com as linguagens HTML e JavaScript pode estar razoavelmente apreensiva com as possíveis dificuldades associadas ao aprendizado delas. Para facilitar a sua tarefa e evitar um estudo aprofundado de HTML e JavaScript, tentaremos usar soluções práticas baseadas nesta tecnologia. Devido ao escopo deste artigo, nossa meta está limitada somente na construção de gráficos e diagramas, usaremos bibliotecas JavaScript prontas e criadas especialmente para este propósito.
A Emprise JavaScript Charts é uma biblioteca de gráficos bem avançada. Talvez o leitor se interesse em conhecer mais dela através do link fornecido, entretanto esta biblioteca não é grátis. Assim, vamos mudar para bibliotecas grátis, por exemplo, Dygraphs JavaScript Visualization Library e Highcharts charting library. A Dygraphs é atrativa devido ao seu tamanho reduzido e simplicidade e a biblioteca Highcharts, por sua vez, inclui uma quantidade maior de recursos e parece mais universal. Apesar do fato de a biblioteca Highcharts ter aproximadamente 75 KB e necessite da biblioteca adicional jQuery, que tem aproximadamente outros 70 KB, ainda assim vamos escolhê-la como nossa biblioteca.
Você pode se familiarizar com a biblioteca Highcharts em nosso site http://www.highcharts.com/ na seção "Demo Gallery". Para cada um dos exemplos, clicando em "view options" você pode ver o seu código fonte JavaScript. A documentação detalhada sobre a biblioteca está localizada na seção "Documentation/Options Reference", nesta seção você pode achar também muitos exemplos de usos de opções diferentes. à primeira vista, por causa da abundância do código JavaScript, e, incomum para uma sintaxe de um programador MQL o uso desta biblioteca pode parecer um pouco complicado. Mas não é. Considere o primeiro exemplo de um arquivo HTML simples, que, através dos meios da biblioteca exibirá o gráfico.
Como um exemplo, vamos criar um arquivo de texto chamado Test_01.htm no editor Notepad e copiar o seguinte exemplo simples para o uso da biblioteca.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Example</title> <!-- - --> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js" type="text/javascript"></script> <script src="/js/highcharts.js" type="text/javascript"></script> <!-- - --> <script type="text/javascript"> var chart1; $(document).ready(function(){ chart1 = new Highcharts.Chart({ chart: {renderTo: 'container1'}, series: [{data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]}] }); }); </script> <!-- - --> </head> <body> <div id="container1" style="width: 700px; height: 400px "></div> </body> </html>
O código de amostra está separado em quatro seções pelos comentários.
A primeira, parte superior do código, contém as tags comuns da página HTML. Esta parte do código não é de interesse especial para nós agora.
Ela é seguida por outra parte, que contém duas tags . No primeiro caso, damos ao browser um comando para baixar o código de biblioteca jquery.min.js do site ajax.googleapis.com. O segundo caso supõe que no lado do servidor, o catálogo /js/ contenha a biblioteca highcharts.js, que o browser precisa baixar. Tendo decidido previamente que no processo de exibição nossas páginas não deveriam ter nenhum acesso feito por fontes externas esta parte do código terá que ser modificada.
Depois de fazer as modificações, esta parte do código se parecerá com isso
<script src="jquery.min.js" type="text/javascript"></script> <script src="highcharts.js" type="text/javascript"></script>
Neste caso, damos o comando para baixar ambas as bibliotecas do catálogo que mantém o nosso arquivo HTML, ou seja, a partir do catálogo atual. Para que as bibliotecas sejam baixadas pelo browser, elas precisam primeiro ser baixadas dos sites ajax.googleapis.com and http://www.highcharts.com respectivamente e copiadas no mesmo catálogo em que o nosso arquivo HTML está localizado. Ambas as bibliotecas podem também ser encontradas no final deste artigo nos anexos.
Na próxima seção do código um objeto de classe Highcharts.Chart é criado. O parâmetro "renderTo: 'container1" indica que o gráfico será exibido no elemento HTML chamado "container1" e o parâmetro "data" define os dados que serão exibidos no gráfico. Como podemos ver neste exemplo, os dados são definidos da mesma forma que os parâmetros - durante a criação de um objeto da classe Highcharts.Class. Fazendo modificações, nós localizamos a definição dos dados exibidos em uma parte separada do código, isso nos permitirá, em um caso que precisemos exibir gráficos múltiplos para agrupar os seus dados.
Na última parte do nosso exemplo, a tag
Levando em conta as modificações feitas, o código do nosso exemplo se parecerá com o seguinte:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Example</title> <!-- - --> <script src="jquery.min.js" type="text/javascript"></script> <script src="highcharts.js" type="text/javascript"></script> <!-- - --> <script type="text/javascript"> var dat1 = [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]; </script> <!-- - --> <script type="text/javascript"> var chart1; $(document).ready(function(){ chart1 = new Highcharts.Chart({ chart: {renderTo: 'container1'}, series: [{data: dat1}] }); }); </script> <!-- - --> </head> <body> <div id="container1" style="width: 700px; height: 400px "></div> </body> </html>
Este caso de teste e todas as bibliotecas podem ser copiados dos anexos no final deste artigo. O arquivo exemplo Test_01.htm e os arquivos das bibliotecas estão localizados na mesma pasta \Test, assim, nós simplesmente damos um clique duplo no arquivo HTML Test_01.htm para ver os resultados do nosso trabalho.
Deve ser mantido em mente que uma exibição normal desta página teste, a execução do JavaScript, deve ser permitida no WEB-browser. Já que os browsers, por motivos de segurança, permitem que você desabilite essa opção, pode ser que ela esteja desativada. Como resultado, devemos ver o seguinte:
Figura 1. Test_01.htm
Este é o nosso primeiro gráfico de teste e apesar da complexidade aparente desta tecnologia, a sua criação não levou muito tempo.
Devemos notar alguns recursos dos gráficos exibidos criados desta maneira. No catálogo copiado, abra o arquivo Test_01.htm e se o WEB-browser permitir que você faça um zoom nas páginas visualizadas você notará que mesmo com um aumento substancial, a qualidade do gráfico não piora.
Isto acontece pois este gráfico não é uma imagem estática como arquivos PNG ou JPEG e é retraçado depois de um zoom na área designada para o seu desenho. Então, a imagem não pode ser salva em disco da maneira que normalmente salvamos uma foto que gostamos. Já que o gráfico foi construído com o JavaScript, não devemos deixar de mencionar o fato de que browsers diferentes, tendo seus intérpretes integrados próprios desta linguagem, podem nem sempre executá-los da mesma maneira.
Os gráficos criados usando JavaScript podem, às vezes, parecer diferentes usando browsers diferentes. Na maioria das vezes, estas diferenças, comparadas com outros browsers ocorrem no Internet Explorer.
Mas esperamos que os criadores de bibliotecas JavaScript cuidem da compatibilidade o máximo possível em seu código com os WEB-browsers mais populares.
MetaTrader 5 e MQL5
No exemplo acima, os dados, destinados a serem exibidos no gráfico, foram ajustados manualmente durante a criação da página HTML. Para dispor a transferência de dados do MetaTrader 5 para o gráfico criado usaremos o método mais simples. Permita que o MetaTrader 5 grave os dados em um arquivo separado no qual ele será carregado no browser quando exibir o gráfico. Vamos criar um exemplo que inclua uma página HTML, que exibirá o gráfico, fazendo o download dos dados de um arquivo um script no MQL5, que criará esse arquivo.
Como o arquivo HTML, usaremos o arquivo Test_01.htm criado previamente, depois de fazer algumas pequenas modificações nele. Chamaremos o arquivo modificado de example1.htm. Todas as modificações feitas serão reduzidas ao fato de que as linhas:
<script type="text/javascript"> var dat1 = [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]; </script>serão substituídas por
<script type="text/javascript"> var dat1=[0]; </script> <script src="exdat.txt" type="text/javascript"></script>
Agora o browser, ao baixas a página HTML, também precisará carregar o arquivo de texto exdat.txt, no qual, os valores destinados a serem exibidos no gráfico serão designados para o banco de dados dat1. Este arquivo deve conter um fragmento do código JavaScript. Este arquivo pode ser criado no MetaTrader 5 usando o script correspondente.
Um exemplo de tal script é fornecido abaixo.
//+------------------------------------------------------------------+ //| Example1.mq5 | //| Copyright 2010, MetaQuotes Software Corp. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2010, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ void OnStart() { int i,n,fhandle; double gr[25]; string str; n=ArraySize(gr); for(i=0;i<n;i++) { gr[i]=NormalizeDouble(MathSin(i*3*2*M_PI/n),4); } str=DoubleToString(gr[0],4); for(i=1;i<n;i++) { str+=","+DoubleToString(gr[i],4); } ResetLastError(); fhandle=FileOpen("exdat.txt",FILE_WRITE|FILE_TXT|FILE_ANSI); if(fhandle<0){Print("File open failed, error ",GetLastError());return;} FileWriteString(fhandle,"dat1=["+str+"];\n"); FileClose(fhandle); } //+------------------------------------------------------------------+
Para gravar os dados exibidos este script usa o banco de dados gr[] que contém 25 itens. Este banco de dados, como exemplo, é preenchido com valores da função sinus, com arredondamento feito em até quatro casas decimais. Este banco de dados, é claro, pode ser preenchido com qualquer outro, dado mais útil.
Mais tarde, estes dados são formatados e combinados em uma série de texto simples. Para reduzir o volume do arquivo de texto gerado, os valores dos elementos do banco de dados gr[] com apenas quatro casas decimais são posicionados na série. Para este fim usamos a função DoubleToString().
Depois que a série de texto str é formada, ela é gravada no arquivo exdat.txt. No caso de uma execução bem sucedida do script, o arquivo de texto texdat.txt será criado na subpasta \MQL5\Files do terminal do cliente; se o arquivo já existir ele será substituído.
Os arquivos jquery.min.js, highcharts.js, Example1.mq5, Example1.htm e exdat.txt são apresentados no fim deste artigo na seção de anexos. Estes cinco arquivos estão localizados no catálogo \Example1. Para simplificar a visualização dos resultados, simplesmente copie este exemplo no catálogo \Example1 e abra o arquivo Example1.htm. O gráfico será construído de acordo com os dados do arquivo exdat.txt.
Figura 2. Example1.htm
é claro, para ser executado o script Example1.mq5 deve estar na pasta \MQL5\Scripts do terminal de cliente e estar compilado.
Conforme mencionado antes, depois do lançamento do script, o arquivo exdat.txt será criado na pasta \MQL5\Files, mas em nosso exemplo, o arquivo HTML, os arquivos das bibliotecas e os arquivos de dados devem estar todos localizados na mesma pasta. Então, temos que copiar os arquivos jquery.min.js, highcharts.js e Example1.htm para a pasta \MQL5\Files ou copiar o arquivo exdat.txt para a pasta onde esses arquivos estão.
Neste exemplo, a página HTML e as bibliotecas são gravadas em arquivos diferentes. No estágio de criação, pode ser útil que partes diferentes do projeto estejam localizadas em arquivos separados. Isso ajuda a evitar, por exemplo, mudanças aleatórias do código das bibliotecas quando da edição do arquivo HTML. Mas depois da página HTML ter sido completamente editada e nenhuma modificação futura seja esperada, as bibliotecas podem ser integradas diretamente no arquivo de código HTML.
Isto é possível porque as bibliotecas JavaScript são nada mais que arquivos de texto simples. Se abrirmos o jquery.min.js ou o highcharts.js com um editor de texto, não veremos nada compreensível, pois o código-fonte das bibliotecas foi comprimido em sua capacidade máxima.
A compressão é feita removendo os símbolos de serviço, por exemplo, uma linha de alimentação ou uma série de espaços vazios. Depois de tal compressão qualquer formatação é perdida, mas o texto permanece como texto, desde que o tipo de arquivo não mude. Então, não faz diferença se o browser se conecta com o código da biblioteca a partir de um arquivo externo com a extensão .js, ou se ele o lê a partir do arquivo HTML atual, que por sua vez também está em um formato de texto.
Para combinar esses arquivos, substitua as linhas do Example1.htm
<script src="jquery.min.js" type="text/javascript"></script> <script src="highcharts.js" type="text/javascript"></script>
com
<script type="text/javascript"> </script>
Então, usando um editor de texto como o Notepad, abrimos o arquivo da biblioteca jquery.min.js e ao escolhermos o comando "Select all" copiamos o conteúdo do arquivo. Então, abra o arquivo Example1.htm, cole o texto copiado da biblioteca entre as tags e . Salve o arquivo obtido comoExample2.htm. Da mesma maneira, copie o conteúdo da biblioteca highcharts.js neste arquivo, o colocando entre o texto da biblioteca copiada previamente e a tag .
Como resultado da cópia, o arquivo HTML aumenta em tamanho, entretanto, agora não precisamos separar os arquivos das bibliotecas para a sua exibição correta. é suficiente ter o arquivo de dados exdat.txt na Folder\Example2, que inclui os arquivos Example2.htm e o exdat.txt está localizado no final deste artigo na seção de anexos.
Um relatório do histórico de negociação em uma forma gráfica
Para uma demonstração mais completa do método proposto de exibição de informações gráficas, criaremos um relatório que mostra o histórico da conta de negociação em um intervalo de tempo especificado. O relatório baseado em HTML, que é criado no MetaTrader 5 quando você seleciona o comando "Report" no menu de contexto da aba "History" servirá de protótipo. Este relatório inclui um grande número de características diferentes, resumidas na tabela. Supondo que essas características serão melhor visualizadas quando apresentadas na forma de gráficos e diagramas, vamos exibí-las usando a biblioteca gráfica highcharts.js.
No exemplo acima, para a construção do gráfico, usamos os parâmetros de exibição padrão, ajustados nesta versão da biblioteca highcharts.js.
Para fins práticos, esta opção não será bem sucedida, já que em cada caso teremos que ajustar a visualização do gráfico para se ajustar a requerimentos específicos individuais. Para este fim, a biblioteca highcharts.js fornece uma ampla gama de oportunidades, tendo um grande número de opções que podem ser aplicadas ao gráfico ou diagrama. Como já mencionado, a lista de opções, juntamente com as suas descrições detalhadas e exemplos, pode ser encontrada em http://www.highcharts.com.
Não vamos nos estender na descrição das opções da biblioteca de gráficos e nas especificações do seu uso pois esse artigo destina-se somente a sugerir e demonstrar a habilidade do uso de um WEB-browser para a exibição de informações recebidas do MetaTrader 5. Especialmente já que dependendo dos requisitos específicos para a criação de uma página da WEB, algumas outras bibliotecas de JavaScript podem ser usadas. O leitor pode selecionar de maneira independente a biblioteca mais adequada e estudar de forma mais aprofundada a prática requerida em seu uso.
Para exibir o histórico da conta de negociação nós criamos o arquivo ProfitReport.htm. Ele pode ser encontrado nos anexos. A pasta \Report contém o data.txt com os dados para exibir. O arquivo data.txt é colocado na pasta como um exemplo.
Quando copiamos a pasta \Report e abrimos o ProftReport.htm, vemos as características de negociação da conta teste, criada para esse exemplo de forma gráfica.
Figura 3. ProfitReport.htm
Quando criamos o ProfitReport.htm, fizemos primeiro um layout de página grosseiro e determinamos aproximadamente onde e quais tipos de informações serão posicionadas.
Então colocamos os gráficos, com suas opções padrão na página.
Depois da criação desse modelo, escolhemos as opções que melhor se encaixam para cada gráfico em particular. Depois de concluir a edição nós simplesmente copiamos os textos e bibliotecas para a página. Como já foi mencionado, para uma exibição correta da página, ela deve estar localizada no mesmo catálogo do arquivo data.txt que contém os dados destinados a sua exibição.
O arquivo data.txt foi criado no MetaTrader 5, usando o script ProfitReport.htm. No caso de uma execução bem sucedida deste script, o arquivo data.txt é criado na pasta \MQL5\Files, contendo as características de negociação da conta ativa atual.
Não devemos esquecer que o script deve ser colocado na pasta \MQL5\Scripts e compilado.
//----------------------------------------------------------------------------------- // ProfitReport.mq5 // Copyright 2011, MetaQuotes Software Corp. // https://www.mql5.com //----------------------------------------------------------------------------------- #property copyright "Copyright 2011, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property script_show_inputs #include <Arrays\ArrayLong.mqh> #include <Arrays\ArrayDouble.mqh> #include <Arrays\ArrayString.mqh> #include <Arrays\ArrayInt.mqh> //--- input parameters input int nD=30; // Number of days //--- global double balabce_cur=0; // balance double initbalance_cur=0; // Initial balance (not including deposits to the account) int days_num; // number of days in the report (including the current day) datetime tfrom_tim; // Date from datetime tend_tim; // Date to double netprofit_cur=0; // Total Net Profit double grossprofit_cur=0; // Gross Profit double grossloss_cur=0; // Gross Loss int totaltrades_num=0; // Total Trades int longtrades_num=0; // Number of Long Trades double longtrades_perc=0; // % of Long Trades int shorttrades_num=0; // Number of Short Trades double shorttrades_perc=0; // % of Short Trades int proftrad_num=0; // Number of All Profit Trades double proftrad_perc=0; // % of All Profit Trades int losstrad_num=0; // Number of All Loss Trades double losstrad_perc=0; // % of All Loss Trades int shortprof_num=0; // Number of Short Profit Trades double shortprof_perc=0; // % of Short Profit Trades double shortloss_perc=0; // % of Short Loss Trades int longprof_num=0; // Number of Long Profit Trades double longprof_perc=0; // % of Long Profit Trades double longloss_perc=0; // % of Long Loss Trades int maxconswins_num=0; // Number of Maximum consecutive wins double maxconswins_cur=0; // Maximum consecutive wins ($) int maxconsloss_num=0; // Number of Maximum consecutive losses double maxconsloss_cur=0; // Maximum consecutive losses ($) int aveconswins_num=0; // Number of Average consecutive wins double aveconswins_cur=0; // Average consecutive wins ($) int aveconsloss_num=0; // Number of Average consecutive losses double aveconsloss_cur=0; // Average consecutive losses ($) double largproftrad_cur=0; // Largest profit trade double averproftrad_cur=0; // Average profit trade double larglosstrad_cur=0; // Largest loss trade double averlosstrad_cur=0; // Average loss trade double profitfactor=0; // Profit Factor double expectpayoff=0; // Expected Payoff double recovfactor=0; // Recovery Factor double sharperatio=0; // Sharpe Ratio double ddownabs_cur=0; // Balance Drawdown Absolute double ddownmax_cur=0; // Balance Drawdown Maximal double ddownmax_perc=0; // % of Balance Drawdown Maximal int symbols_num=0; // Numbre of Symbols string Band=""; double Probab[33],Normal[33]; CArrayLong TimTrad; CArrayDouble ValTrad; CArrayString SymNam; CArrayInt nSymb; //----------------------------------------------------------------------------------- // Script program start function //----------------------------------------------------------------------------------- void OnStart() { int i,n,m,k,nwins=0,nloss=0,naverw=0,naverl=0,nw=0,nl=0; double bal,sum,val,p,stdev,vwins=0,vloss=0,averwin=0,averlos=0,pmax=0; MqlDateTime dt; datetime ttmp,it; string symb,br; ulong ticket; long dtype,entry; if(!TerminalInfoInteger(TERMINAL_CONNECTED)){printf("Terminal not connected.");return;} days_num=nD; if(days_num<1)days_num=1; // number of days in the report (including the current day) tend_tim=TimeCurrent(); // date to tfrom_tim=tend_tim-(days_num-1)*86400; TimeToStruct(tfrom_tim,dt); dt.sec=0; dt.min=0; dt.hour=0; tfrom_tim=StructToTime(dt); // date from //---------------------------------------- Bands ttmp=tfrom_tim; br=""; if(dt.day_of_week==6||dt.day_of_week==0) { Band+=(string)(ulong)(ttmp*1000)+","; br=",";ttmp+=86400; } for(it=ttmp;it<tend_tim;it+=86400) { TimeToStruct(it,dt); if(dt.day_of_week==6){Band+=br+(string)(ulong)(it*1000)+","; br=",";} if(dt.day_of_week==1&&br==",") Band+=(string)(ulong)(it*1000); } if(dt.day_of_week==6||dt.day_of_week==0) Band+=(string)(ulong)(tend_tim*1000); //---------------------------------------- balabce_cur=AccountInfoDouble(ACCOUNT_BALANCE); // Balance if(!HistorySelect(tfrom_tim,tend_tim)){Print("HistorySelect failed");return;} n=HistoryDealsTotal(); // Number of Deals for(i=0;i<n;i++) { ticket=HistoryDealGetTicket(i); entry=HistoryDealGetInteger(ticket,DEAL_ENTRY); if(ticket>=0&&(entry==DEAL_ENTRY_OUT||entry==DEAL_ENTRY_INOUT)) { dtype=HistoryDealGetInteger(ticket,DEAL_TYPE); if(dtype==DEAL_TYPE_BUY||dtype==DEAL_TYPE_SELL) { totaltrades_num++; // Total Trades val=HistoryDealGetDouble(ticket,DEAL_PROFIT); val+=HistoryDealGetDouble(ticket,DEAL_COMMISSION); val+=HistoryDealGetDouble(ticket,DEAL_SWAP); netprofit_cur+=val; // Total Net Profit if(-netprofit_cur>ddownabs_cur)ddownabs_cur=-netprofit_cur; // Balance Drawdown Absolute if(netprofit_cur>pmax)pmax=netprofit_cur; p=pmax-netprofit_cur; if(p>ddownmax_cur) { ddownmax_cur=p; // Balance Drawdown Maximal ddownmax_perc=pmax; } if(val>=0) //win { grossprofit_cur+=val; // Gross Profit proftrad_num++; // Number of Profit Trades if(val>largproftrad_cur)largproftrad_cur=val; // Largest profit trade nwins++;vwins+=val; if(nwins>=maxconswins_num) { maxconswins_num=nwins; if(vwins>maxconswins_cur)maxconswins_cur=vwins; } if(vloss>0){averlos+=vloss; nl+=nloss; naverl++;} nloss=0;vloss=0; } else //loss { grossloss_cur-=val; // Gross Loss if(-val>larglosstrad_cur)larglosstrad_cur=-val; // Largest loss trade nloss++;vloss-=val; if(nloss>=maxconsloss_num) { maxconsloss_num=nloss; if(vloss>maxconsloss_cur)maxconsloss_cur=vloss; } if(vwins>0){averwin+=vwins; nw+=nwins; naverw++;} nwins=0;vwins=0; } if(dtype==DEAL_TYPE_SELL) { longtrades_num++; // Number of Long Trades if(val>=0)longprof_num++; // Number of Long Profit Trades } else if(val>=0)shortprof_num++; // Number of Short Profit Trades symb=HistoryDealGetString(ticket,DEAL_SYMBOL); // Symbols k=1; for(m=0;m<SymNam.Total();m++) { if(SymNam.At(m)==symb) { k=0; nSymb.Update(m,nSymb.At(m)+1); } } if(k==1) { SymNam.Add(symb); nSymb.Add(1); } ValTrad.Add(val); TimTrad.Add(HistoryDealGetInteger(ticket,DEAL_TIME)); } } } if(vloss>0){averlos+=vloss; nl+=nloss; naverl++;} if(vwins>0){averwin+=vwins; nw+=nwins; naverw++;} initbalance_cur=balabce_cur-netprofit_cur; if(totaltrades_num>0) { longtrades_perc=NormalizeDouble((double)longtrades_num/totaltrades_num*100,1); // % of Long Trades shorttrades_num=totaltrades_num-longtrades_num; // Number of Short Trades shorttrades_perc=100-longtrades_perc; // % of Short Trades proftrad_perc=NormalizeDouble((double)proftrad_num/totaltrades_num*100,1); // % of Profit Trades losstrad_num=totaltrades_num-proftrad_num; // Number of Loss Trades losstrad_perc=100-proftrad_perc; // % of All Loss Trades if(shorttrades_num>0) { shortprof_perc=NormalizeDouble((double)shortprof_num/shorttrades_num*100,1); // % of Short Profit Trades shortloss_perc=100-shortprof_perc; // % of Short Loss Trades } if(longtrades_num>0) { longprof_perc=NormalizeDouble((double)longprof_num/longtrades_num*100,1); // % of Long Profit Trades longloss_perc=100-longprof_perc; // % of Long Loss Trades } if(grossloss_cur>0)profitfactor=NormalizeDouble(grossprofit_cur/grossloss_cur,2); // Profit Factor if(proftrad_num>0)averproftrad_cur=NormalizeDouble(grossprofit_cur/proftrad_num,2);// Average profit trade if(losstrad_num>0)averlosstrad_cur=NormalizeDouble(grossloss_cur/losstrad_num,2); // Average loss trade if(naverw>0) { aveconswins_num=(int)NormalizeDouble((double)nw/naverw,0); aveconswins_cur=NormalizeDouble(averwin/naverw,2); } if(naverl>0) { aveconsloss_num=(int)NormalizeDouble((double)nl/naverl,0); aveconsloss_cur=NormalizeDouble(averlos/naverl,2); } p=initbalance_cur+ddownmax_perc; if(p!=0) { ddownmax_perc=NormalizeDouble(ddownmax_cur/p*100,1); // % of Balance Drawdown Maximal } if(ddownmax_cur>0)recovfactor=NormalizeDouble(netprofit_cur/ddownmax_cur,2); // Recovery Factor expectpayoff=netprofit_cur/totaltrades_num; // Expected Payoff sum=0; val=balabce_cur; for(m=ValTrad.Total()-1;m>=0;m--) { bal=val-ValTrad.At(m); p=val/bal; sum+=p; val=bal; } sum=sum/ValTrad.Total(); stdev=0; val=balabce_cur; for(m=ValTrad.Total()-1;m>=0;m--) { bal=val-ValTrad.At(m); p=val/bal-sum; stdev+=p*p; val=bal; } stdev=MathSqrt(stdev/ValTrad.Total()); if(stdev>0)sharperatio=NormalizeDouble((sum-1)/stdev,2); // Sharpe Ratio stdev=0; for(m=0;m<ValTrad.Total();m++) { p=ValTrad.At(m)-expectpayoff; stdev+=p*p; } stdev=MathSqrt(stdev/ValTrad.Total()); // Standard deviation if(stdev>0) { ArrayInitialize(Probab,0.0); for(m=0;m<ValTrad.Total();m++) // Histogram { i=16+(int)NormalizeDouble((ValTrad.At(m)-expectpayoff)/stdev,0); if(i>=0 && i<ArraySize(Probab))Probab[i]++; } for(m=0;m<ArraySize(Probab);m++) Probab[m]=NormalizeDouble(Probab[m]/totaltrades_num,5); } expectpayoff=NormalizeDouble(expectpayoff,2); // Expected Payoff k=0; symbols_num=SymNam.Total(); // Symbols for(m=0;m<(6-symbols_num);m++) { if(k==0) { k=1; SymNam.Insert("",0); nSymb.Insert(0,0); } else { k=1; SymNam.Add(""); nSymb.Add(0); } } } p=1.0/MathSqrt(2*M_PI)/4.0; for(m=0;m<ArraySize(Normal);m++) // Normal distribution { val=(double)m/4.0-4; Normal[m]=NormalizeDouble(p*MathExp(-val*val/2),5); } filesave(); } //----------------------------------------------------------------------------------- // Save file //----------------------------------------------------------------------------------- void filesave() { int n,fhandle; string loginame,str="",br=""; double sum; ResetLastError(); fhandle=FileOpen("data.txt",FILE_WRITE|FILE_TXT|FILE_ANSI); if(fhandle<0){Print("File open failed, error ",GetLastError());return;} loginame="\""+(string)AccountInfoInteger(ACCOUNT_LOGIN)+", "+ TerminalInfoString(TERMINAL_COMPANY)+"\""; str+="var PName="+loginame+";\n"; str+="var Currency=\""+AccountInfoString(ACCOUNT_CURRENCY)+"\";\n"; str+="var Balance="+(string)balabce_cur+";\n"; str+="var IniBalance="+(string)initbalance_cur+";\n"; str+="var nDays="+(string)days_num+";\n"; str+="var T1="+(string)(ulong)(tfrom_tim*1000)+";\n"; str+="var T2="+(string)(ulong)(tend_tim*1000)+";\n"; str+="var NetProf="+DoubleToString(netprofit_cur,2)+";\n"; str+="var GrossProf="+DoubleToString(grossprofit_cur,2)+";\n"; str+="var GrossLoss="+DoubleToString(grossloss_cur,2)+";\n"; str+="var TotalTrad="+(string)totaltrades_num+";\n"; str+="var NProfTrad="+(string)proftrad_num+";\n"; str+="var ProfTrad="+DoubleToString(proftrad_perc,1)+";\n"; str+="var NLossTrad="+(string)losstrad_num+";\n"; str+="var LossTrad="+DoubleToString(losstrad_perc,1)+";\n"; str+="var NLongTrad="+(string)longtrades_num+";\n"; str+="var LongTrad="+DoubleToString(longtrades_perc,1)+";\n"; str+="var NShortTrad="+(string)shorttrades_num+";\n"; str+="var ShortTrad="+DoubleToString(shorttrades_perc,1)+";\n"; str+="var ProfLong ="+DoubleToString(longprof_perc,1)+";\n"; str+="var LossLong ="+DoubleToString(longloss_perc,1)+";\n"; FileWriteString(fhandle,str); str=""; str+="var ProfShort="+DoubleToString(shortprof_perc,1)+";\n"; str+="var LossShort="+DoubleToString(shortloss_perc,1)+";\n"; str+="var ProfFact="+DoubleToString(profitfactor,2)+";\n"; str+="var LargProfTrad="+DoubleToString(largproftrad_cur,2)+";\n"; str+="var AverProfTrad="+DoubleToString(averproftrad_cur,2)+";\n"; str+="var LargLosTrad="+DoubleToString(larglosstrad_cur,2)+";\n"; str+="var AverLosTrad="+DoubleToString(averlosstrad_cur,2)+";\n"; str+="var NMaxConsWin="+(string)maxconswins_num+";\n"; str+="var MaxConsWin="+DoubleToString(maxconswins_cur,2)+";\n"; str+="var NMaxConsLos="+(string)maxconsloss_num+";\n"; str+="var MaxConsLos="+DoubleToString(maxconsloss_cur,2)+";\n"; str+="var NAveConsWin="+(string)aveconswins_num+";\n"; str+="var AveConsWin="+DoubleToString(aveconswins_cur,2)+";\n"; str+="var NAveConsLos="+(string)aveconsloss_num+";\n"; str+="var AveConsLos="+DoubleToString(aveconsloss_cur,2)+";\n"; str+="var ExpPayoff="+DoubleToString(expectpayoff,2)+";\n"; str+="var AbsDD="+DoubleToString(ddownabs_cur,2)+";\n"; str+="var MaxDD="+DoubleToString(ddownmax_cur,2)+";\n"; str+="var RelDD="+DoubleToString(ddownmax_perc,1)+";\n"; str+="var RecFact="+DoubleToString(recovfactor,2)+";\n"; str+="var Sharpe="+DoubleToString(sharperatio,2)+";\n"; str+="var nSymbols="+(string)symbols_num+";\n"; FileWriteString(fhandle,str); str="";br=""; for(n=0;n<ArraySize(Normal);n++) { str+=br+"["+DoubleToString(((double)n-16)/4.0,2)+","+DoubleToString(Normal[n],5)+"]"; br=","; } FileWriteString(fhandle,"var Normal=["+str+"];\n"); str=""; str="[-4.25,0]"; for(n=0;n<ArraySize(Probab);n++) { if(Probab[n]>0) { str+=",["+DoubleToString(((double)n-16)/4.0,2)+","+DoubleToString(Probab[n],5)+"]"; } } str+=",[4.25,0]"; FileWriteString(fhandle,"var Probab=["+str+"];\n"); str=""; sum=0; if(ValTrad.Total()>0) { sum+=ValTrad.At(0); str+="["+(string)(ulong)(TimTrad.At(0)*1000)+","+DoubleToString(sum,2)+"]"; for(n=1;n<ValTrad.Total();n++) { sum+=ValTrad.At(n); str+=",["+(string)(ulong)(TimTrad.At(n)*1000)+","+DoubleToString(sum,2)+"]"; } } FileWriteString(fhandle,"var Prof=["+str+"];\n"); FileWriteString(fhandle,"var Band=["+Band+"];\n"); str="";br=""; for(n=0;n<SymNam.Total();n++) { str+=br+"{name:\'"+SymNam.At(n)+"\',data:["+(string)nSymb.At(n)+"]}"; br=","; } FileWriteString(fhandle,"var Sym=["+str+"];\n"); FileClose(fhandle); }
Como podemos ver, o código do script é particularmente inconveniente, mas isto não se dá devido à complexidade da tarefa, especialmente devido ao grande número de características de negociação, o valor que deve ser determinado. Para a gravação desses valores, o início do script declara as variáveis globais, fornecidas com os comentários relevantes.
A função OnStart() verifica se o terminal está conectado ao servidor de negociação e, se não, o script termina o seu trabalho. Na ausência de conexão com o servidor, não conseguiremos definir uma conta ativa e obter informações sobre ela.
O próximo passo é o cálculo dos dados, a partir dos quais os dados de negociação para a conta ativa atual serão inclusos no relatório. Com data final, usamos o valor da data atual e hora atual no momento da execução do script. O número de dias, inclusos no relatório, podem ser ajustados no momento do carregamento do script mudando o parâmetro de entrada "Número de dias" que por padrão é igual a 30 dias. Uma vez que definimos o tempo de início e de fim do relatório, na variável da série Band, um par de valores de tempo, correspondendo com o início e o final do fim de semana será formado. Esta informação é usada para que no gráfico de equilíbrio os intervalos de tempo que correspondam a sábado e domingo, possam ser marcados em amarelo.
Em seguida, usando a função HistorySelect(), o histórico de acordos e pedidos para um intervalo específico fica disponível e chamando a função HistoryDealsTotal() determinamos o número de acordos no histórico. Depois disto, baseado no número de acordos, um ciclo é formado, que reúne as estatísticas, necessárias para o cálculo das características de negociação e no final do ciclo os seus valores são determinados.
Quando criamos o script, nossa tarefa foi preservar o significado das características de negociação de acordo com o relatório gerado no MetaTrader 5. Supõe-se que as características, calculadas pelo script, devem corresponder com a descrição que é dada no arquivo Ajuda do terminal.
A informação de acesso ao histórico da conta e os cálculos de características de negociação podem ser encontrados nos seguintes artigos:
- Ordens, posições e negócios no MetaTrader 5;
- Criação de quadro de informações usando as Classes de biblioteca padrão e Google Chart API;
- O que significam os números no Relatório de teste Expert;
- Matemática na negociação; Como estimar resultados de negociação.
A maioria das características são calculadas bem fácil, então, neste artigo, não consideraremos as operações associadas com o cálculo de cada característica e consideraremos, mais tarde, somente as diferenças existentes do relatório padrão e seus suplementos.
No relatório, que é gerado pelo terminal, o gráfico de equilíbrio é construído por uma exibição sequencial de valores para cada vez que eles mudam e a escala X reflete o número de tais mudanças. Em nosso caso, para a construção do gráfico usamos uma escala de tempo.
Então, o gráfico de lucro é bem diferente do gráfico gerado pelo terminal. Escolhemos essa opção de uma construção de gráfico para exibir o momento do fechamento das posições em uma escala de tempo real. Podemos, então, ver quando a atividade de negociação aumentou ou diminuiu no período do relatório.
Quando construir um gráfico, deve ser mantido em mente que o MQL5 opera com o valor de data apresentado como o número de segundos passados desde 1º de janeiro de 1970, enquanto a biblioteca de gráficos requer este valor como o número de milissegundos desde 1º de janeiro de 1970. Então os valores de datas recebidos no script devem ser multiplicados por mil para serem exibidos corretamente.
Para gravar o valor do lucro e o momento do fechamento do acordo, o script usa as classes CArrayDouble e CArrayLong a partir da Biblioteca padrão. Toda vez que um acordo resultante for detectado no loop, as informações sobre ele são posicionadas usando o método Add(), no elemento, que é adicionado no final do banco de dados. Isto permite que nós desviemos a necessidade de determinar com antecedência o número de elementos necessários. O tamanho do banco de dados simplesmente aumenta com o número de acordos encontrados no histórico de acordos.
Para cada acordo uma verificação é executada em qual símbolo foi executado, enquanto retém o nome do símbolo e o número de acordos executados nele. Assim como para o gráfico de lucro, estes dados, quando visualizados no histórico, se acumulam fazendo um registro em um elemento que é adicionado no final do banco de dados. Para gravar o nome do símbolo e o número de acordos, usamos as classes CArrayString e CArrayInt da biblioteca padrão.
A única coluna no gráfico será muito larga para o caso de os acordos serem executados no único símbolo. Para evitar isso, o banco de dados sempre contém pelo menos 7 elementos. Elementos não usados não são exibidos no diagrama, já que eles tem valores zero e, então, não permitem que a coluna fique muito larga. Para certificar que quando houver um número pequeno de símbolos, as colunas são posicionadas aproximadamente no meio do eixo X, os elementos insignificantes do banco de dados são inseridos sequencialmente no início ou no fim do banco de dados.
A próxima diferença do relatório padrão é a tentativa de construir o gráfico de distribuição de probabilidade para a sequência de valores de lucro para cada acordo.
Figura 4. Densidade de probabilidade
Este tipo de gráfico é quase sempre apresentado na forma de histogramas. Em nosso caso, o gráfico de probabilidade é criado construindo uma ranhura, baseada nos valores existentes da coluna de tal histograma. Os valores calculados da densidade de probabilidade são complementados na esquerda e na direita, fora do gráfico com valores zero. Isto é necessário para que o for construído pelo gráfico de ranhura não seja interrompido no último valor conhecido e continuado além do gráfico, declinando de zero.
Para comparação, no gráfico de densidade de probabilidade, a cor cinza é usada para destacar o gráfico da distribuição normal, normalizado de tal forma que a soma das suas leituras seja igual a um, assim como o gráfico, que foi construído com os valores do histograma. No relatório de exemplo fornecido, o número de acordos não é suficiente para dar uma estimativa aproximada confiável da distribuição de probabilidade dos valores de negociações de lucro. Podemos supor que quando há um grande número de acordos no histórico, este gráfico parecerá mais autêntico.
Assim que todas as características de negociação sejam calculadas, a função filesave() é chamada no final do script. Esta função abre o arquivo data.txt, no qual os nomes e valores das variáveis são registrados em um formato de texto. Os valores dessas variáveis correspondem com os parâmetros calculados e os seus nomes correspondem com os nomes, que são usados no arquivo HTML durante a transferência de parâmetros para as funções da biblioteca de gráficos.
Para reduzir o número de acessos ao disco durante a criação do arquivo, linhas curtas são consolidadas em uma linha mais longa e somente então é gravado no arquivo. O arquivo data.txt, como de costume no MetaTrader 5, é criado no catálogo MQL5\Files; se este arquivo já existir, ele será substituído. Para conveniência, você pode copiar o arquivo ProfitReport.htm neste catálogo e executá-lo de lá.
No terminal do MetaTrader 5, quando salvar um relatório no formato HTML, ele será aberto automaticamente por um browser, que está registrado como browser padrão. Esta possibilidade não foi implementada no exemplo fornecido neste artigo.
Para adicionar um auto-executável, insira as seguintes linhas no início do script ProfitReport.mq5
#import "shell32.dll" int ShellExecuteW(int hwnd,string lpOperation,string lpFile,string lpParameters, string lpDirectory,int nShowCmd); #import
e no final, depois de uma chamada à função filesave(), adicione
string path=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\ProfitReport.htm"; ShellExecuteW(NULL,"open",path,NULL,NULL,1);
Se o arquivo ProfitReport.htm existir no caminho de variável especificado, então quando a função ShellExecuteW() for chamada, ele será aberto pelo browser. A função ShellExecuteW() está localizada na biblioteca do sistema shell32.dll, a declaração desta função será adicionada no início do arquivo para dar acesso a ele.
Conclusão
O uso de WEB-browsers nos permite exibir várias informações diferentes ao mesmo tempo que podem ser úteis para, por exemplo, a organização de controle visual sobre o estado interno de módulos individuais do Expert Advisor, rodando no terminal de cliente.
Os dados de gerenciamento principal, os sinais de negociação, o delimitador de parada e outros dados de módulos podem ser exibidos convenientemente e simultaneamente. Os relatórios de páginas múltiplas HTML podem ser usados se for necessário exibir muita informação.
Deve-se notar que as capacidades da linguagem JavaScript são muito maiores que somente desenhar gráficos. Usando esta linguagem podemos criar páginas da web verdadeiramente interativas. Na internet você pode encontrar um grande número de códigos JavaScript prontos inclusos na página da web e vários exemplos do uso desta linguagem.
Por exemplo, o terminal pode ser gerenciado diretamente da janela do browser se for organizada uma troca de dados de mão dupla entre o terminal e o browser.
Esperamos que o método descrito neste artigo seja útil.
Arquivos
JS_Lib.zip - highcharts.js and jquery.min.js
librariesTest.zip - highcharts.js, jquery.min.js and Test_01.htm
Example1.zip - highcharts.js, jquery.min.js, Example1.htm, Example1.mq5 and exdat.txt
Example2.zip - Example2.htm and exdat.txt
Report.zip - ProfitReport.htm and data.txt
ProfitReport.mq5 - Script for the collection of statistics and the creation of the data.txt file
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/244
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso