Gráficos y diagramas en HTML

Victor | 21 marzo, 2014


Introducción

Generalmente, MetaTrader 5 es un producto autosuficiente y no necesita extensiones adicionales. MetaTrader 5 ofrece una conexión con el broker, muestra cuotas, nos permite usar una gran variedad de indicadores para análisis de mercado y, por supuesto, le da al trader la oportunidad de realizar operaciones de trading. Es evidente que MetaTrader 5 está diseñado para hacer el proceso de trading más cómodo; no puede ser, y técnicamente no debería ser, una herramienta universal hecha para llevar a cabo investigaciones, análisis de métodos matemáticos, creación de contenido multimedia, etcétera.

Además, la universalidad excesiva en un producto de software lleva, en última instancia, a una disminución de su eficiencia, fiabilidad y seguridad. Por otro lado, en ciertos casos, el usuario podría requerir elementos adicionales, especialmente en el caso de traders con varias áreas de especialización en currículos educativos. Por tanto, cualquier elemento adicional podría aumentar el atractivo de la plataforma de trading, si estos, por supuesto, se consiguen de forma relativamente fácil y no a expensas de su fiabilidad y seguridad.

En este artículo consideraremos uno de tales suplementos, que nos permitirá crear y mostrar los gráficos y diagramas basándonos en los datos obtenidos del terminal.

Cada programa debería hacer lo que mejor se le dé. Siguiendo este principio, hagamos a MetaTrader 5 responsable para la realización de operaciones de trading con el broker, recopilando y procesando información entrante, y para mostrar esta información gráficamente usemos otro programa diferente, diseñado específicamente para ello.


Navegador web

Hoy día es difícil encontrar un ordenador que no tenga instalado un navegador de web. Los navegadores han ido evolucionado y mejorando durante mucho tiempo. Los navegadores modernos son bastante fiables, estables para trabajar y, lo más importante, gratuitos. Puesto que un navegador web es prácticamente la herramienta básica para acceder a internet, la mayoría de los usuarios están muy familiarizados con ellos, y tienen pocas dificultades para utilizarlos.

Las capacidades de los navegadores modernos son tan amplias que nos hemos acostumbrado a ver vídeos, escuchar música, jugar a juegos y hacer un buen número de otras actividades diversas a través de un navegador web. Por tanto, hoy día un navegador web es una herramienta sólida para mostrar diferentes tipos de información que se pueden presentar en varios formatos.

No podemos dejar de mencionar que actualmente hay varios navegadores web populares: InternetExplorer, Mozilla Firefox, Google Chrome, y Opera. Estos navegadores pueden tener diferencias significativas entre ellos en aspectos de implementación de software e interfaces de usuario. No obstante, en teoría, todos ellos deberían soportar los estándares básicos adoptados en la red para el intercambio de información, lo que principalmente concierne a los estándares del lenguaje HTML.

En la práctica, a pesar de los esfuerzos de los desarrolladores, los navegadores siguen teniendo características individuales de implementación en ciertos protocolos o tecnologías. Si decidimos que un navegador particular, a causa de sus cualidades particulares, no satisface nuestras demandas, este problema se puede solucionar fácilmente instalando otro o varios otros navegadores web en nuestro ordenador. Incluso seguidores fieles de navegadores como Firefox tienen al mismo tiempo al menos el Internet Explorer instalado en sus sistemas.

A pesar del hecho de que los navegadores web se desarrollaron de forma que facilitaran interacción entre el cliente y un servidor remoto, también se pueden usar para mostrar información local guardada en nuestro ordenador. Un ejemplo de esto se puede ver en las páginas web guardadas previamente en su ordenador. El navegador no necesita acceso a internet para trabajar con páginas locales.

Por tanto, un navegador web que funcione en modo offline es un atractivo candidato para el papel de programa usado para expandir las capacidades gráficas del terminal de cliente MetaTrader 5. Para usarlo, no debe hacer costosas compras, instalaciones lentas y pesadas, ni aprender a usar software nuevo alguno.

Más adelante en este artículo consideraremos las posibilidades de usar navegadores web para construir gráficos y diagramas basándonos en los datos obtenidos en MetaTrader 5.


HTML y JavaScript

Al elegir usar un navegador web como nuestra extensión, definamos para nosotros mismos las reglas básicas que seguiremos rigurosamente de ahora en adelante: siempre mostraremos las páginas HTML creadas sin los servidores local ni remoto. Es decir, que no instalaremos en nuestro ordenador ningún software de servidor, y no necesitaremos acceso a la red para mostrar nuestras páginas. Las páginas HTML que creemos se mostrarán solo por medio del navegador web, y deberán estar localizadas en nuestro ordenador. Esta regla minimizará los riesgos derivados de la posible reducción de seguridad que supone acceder a la red exterior.

Usando solo los elementos de HTML 4 para mostrar información, podemos crear páginas web con tablas, texto con formato e imágenes, pero con estas oportunidades no tendremos suficiente, ya que nuestro objetivo es construir gráficos y diagramas completos basándonos en los datos recibidos de MetaTrader 5.

En la mayoría de los casos, lo que vemos en nuestro navegador al entrar en diferentes páginas se crea usando las extensiones de HTML. En general, estas extensiones se ejecutan en el lado del servidor, y por esta razón no se corresponde con nuestro propósito. Las tecnologías que pueden trabajar en el lado del servidor y no requieren software de servidor nos pueden resultar de interés. Ejemplos de esto son Macromedia Flash, JavaScript, y Java.

Para la ejecución en el lado del servidor de las aplicaciones Macromedia Flash y Java necesitaremos como mínimo la instalación de plug-ins adicionales; los programas de usuario escritos en JavaScript se ejecutarán directamente en el navegador. Todos los navegadores web más comunes vienen con lectores de JavaScript incorporados. Para evitar tener que instalar software adicional o plug-ins, elijamos JavaScript.

Por tanto, de ahora en adelante solo usaremos MetaTrader 5 con MQL5 y un navegador web con HTML y JavaScript. No necesitaremos más software. Recordemos que una página HTML no es nada más que un archivo de texto. Por tanto, para crear un documento HTML podemos usar cualquier editor de texto. Por ejemplo, podemos crear y editar código HTML en MetaEditor 5. Al escribir este artículo, la edición del código HTML se hizo en el navegador Opera @ USB v10.63, que nos permite editar el contenido de la página, guardar la página modificada y obtener una vista previa de cómo se mostrará en pantalla.

Una persona que no esté familiarizada con los lenguajes HTML y JavaScript podría enfrentarse a dificultades asociadas con el control de estas herramientas. Para facilitar nuestra tarea y evitar un estudio avanzado de HTML y JavaScript, trataremos de usar soluciones ya hechas en esta tecnología. Puesto que en este artículo nuestro objetivo se limita a construir gráficos y diagramas, usaremos bibliotecas de JavaScript listas y escritas especialmente para este propósito.

Emprise JavaScript Charts es una biblioteca de gráficos avanzados. Quizás el lector esté interesado en familiarizarse más con el enlace que le hemos facilitado, aunque sebe saber que esta biblioteca no es gratuita. Por tanto, recurramos a las bibliotecas gratuitas. Por ejemplo, las bibliotecas Dygraphs JavaScript Visualization y Highcharts charting. Dygraphs resulta atractiva por su compacidad y sencillez, y la biblioteca Highcharts, por su parte, incluye una cantidad de elementos mayor, y tiene un aspecto más universal. A pesar de que la biblioteca Highcharts tiene un tamaño aproximado de 75 KB y requiere una biblioteca jQuery adicional que supone aproximadamente otros 70 KB, la elegiremos igualmente como nuestra biblioteca.

Puede familiarizarse con la biblioteca Highcharts en la página web http://www.highcharts.com/, en la sección "Demo Gallery" ("Galería de demostración"). En cada uno de los ejemplos, al pulsar en "View options" ("Ver opciones") podrá ver el código fuente de JavaScript. Podrá encontrar documentación detallada sobre la biblioteca en la sección "Documentation/Options Reference" ("Referencia de documentación/Opciones"). En esta sección también podrá encontrar varios ejemplos del uso de diferentes opciones. A primera vista, a causa de la abundancia del código de JavaScript y la sintaxis poco conocida para un programador de MQL, el uso de esta biblioteca puede parecer bastante complicado. Pero este no es el caso. Observe el primer ejemplo de un archivo HTML sencillo que, por medio de la biblioteca, mostrará el gráfico.

Como ejemplo, creemos un archivo de texto con el nombre Test_01.htm en el editor de Bloc de Notas, y copiemos el siguiente ejemplo sencillo del uso de la 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>

El código de ejemplo se separa en cuatro secciones por los comentarios.

La primera parte del código contiene las tags de HTML comunes. Esta parte del código no nos interesa especialmente ahora mismo.

Le sigue otra parte que contiene dos tags <script>. En el primer caso, damos al navegador un comando para descargar de la página web ajax.googleapis.com la biblioteca jquery.min.js. El segundo caso asume que, en el lado del servidor, el catálogo /js/ contiene la biblioteca highcharts.js, que el navegador debe descargar. Puesto que anteriormente ya decidimos que en el proceso de mostrar nuestras páginas no debería haber acceso alguno a fuentes externas, hay que cambiar esta parte del código.

Tras hacer los cambios, esta parte del código tendrá este aspecto:

<script src="jquery.min.js" type="text/javascript"></script>
<script src="highcharts.js" type="text/javascript"></script>

En este caso, damos el comando para descargar ambas bibliotecas del catálogo que contiene nuestro archivo HTML, es decir, del catálogo actual. Para que el navegador descargue las bibliotecas, deben descargarse primero de ajax.googleapis.com y http://www.highcharts.com respectivamente, y ser copiadas en el mismo catálogo en el que se encuentra nuestro archivo HTML. Ambas bibliotecas se pueden encontrar al final de este artículo, en los archivos adjuntos.

En la siguiente sección del código se crea un objeto de la clase Highcharts.Chart. El parámetro "renderTo: 'container1'" indica que el gráfico se mostrará en el elemento HTML llamado "container1", y el parámetro "data" definirá los datos que se mostrarán en el gráfico. Como podemos ver en este ejemplo, los datos se definen de la misma forma que los parámetros: durante la creación de un objeto de la clase Highcharts.Chart. Haciendo estos pequeños cambios encontraremos la definición de los datos mostrados en una parte del código separada, lo que nos permitirá agrupar sus datos en caso de que necesitemos mostrar gráficos múltiples.

En la última parte de nuestro ejemplo, la tag <div> declara un elemento HTML llamado "container1", y se indican las dimensiones de este objeto. Tal y como se mencionó antes, este es el elemento HTML que se usará para construir el gráfico, cuyo tamaño se determinará por el tamaño del elemento "container1", especificado en la tag <div>.

Una vez aplicados los cambios, el código de nuestro ejemplo tendrá el siguiente aspecto:

<!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 ejemplo y todas las bibliotecas se pueden copiar de los archivos adjuntos al final de este artículo. El archivo de ejemplo Test_01.htm y los archivos de las bibliotecas se encuentran en la misma carpeta \Test, por tanto simplemente debemos hacer doble click en el archivo Test_01.htm para comprobar los resultados de nuestro trabajo.

Debe tener en cuenta que, para mostrar esta página de prueba de modo normal, se debe permitir la ejecución de JavaScript en nuestro navegador web. Puesto que los navegadores, por motivos de seguridad, permiten desactivar esta opción, puede que esté desactivada. Como resultado, veríamos lo siguiente:

Test_01.htm

Figura 1. Test_01.htm 

Este es nuestro primer gráfico de prueba, y a pesar de la aparente complejidad de esta tecnología, su creación no nos llevó mucho tiempo.

Debemos tener en cuenta algunos elementos de los gráficos mostrados que hemos creado de esta forma. En el catálogo copiado, abra el archivo Test_01.htm, y si su navegador web le permite ampliar las páginas mostradas, notará que, aún con una ampliación sustancial, la calidad del gráfico no empeora.

Esto se debe a que este gráfico no es una imagen estática, como lo serían archivos PNG o JPEG, y se redibuja tras ampliar o reducir el área de dibujo. Por tanto, una imagen así no se puede guardar en un disco del mismo modo que lo haríamos con una imagen que nos ha gustado. Puesto que el gráfico se creo con JavaScript, no debemos olvidarnos de mencionar el hecho de que navegadores diferentes, con sus lectores de este lenguaje incorporados, puede que no siempre lo ejecuten de la misma forma.

Los gráficos creados usando JavaScript pueden tener un aspecto diferente al mostrarse en diferentes navegadores. Estas diferencias suelen ocurrir sobre todo en Internet Explorer, en comparación con otros navegadores.

Pero esperamos que los creadores de las bibliotecas JavaScript se ocupen de conseguir la máxima compatibilidad en sus códigos con los navegadores web más populares.


MetaTrader 5 y MQL5

En el ejemplo de arriba, los datos destinados a mostrarse en el gráfico se configuraron manualmente durante la creación de la página HTML. Para llevar a cabo la transferencia de datos de MetaTrader 5 al gráfico creado, usaremos el método más sencillo. Dejemos que MetaTrader 5 grabe los datos en un archivo separado que se cargará en el navegador al mostrar el gráfico. Escribamos un ejemplo que incluya una página HTML que mostrará el gráfico descargando datos desde un archivo y un script en MQL5 que creará este archivo.

Al igual que en el caso del archivo HTML, usaremos el archivo Test_01.htm que ya creamos antes tras hacer algunos cambios en él. Llamaremos al archivo modificado example1.htm. Todos los cambios hechos se reducen al hecho de que las líneas

<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án reemplazadas por
<script type="text/javascript">
var dat1=[0];
</script>
<script src="exdat.txt" type="text/javascript"></script>

Ahora, el navegador, al descargar la página HTML, necesitará también cargar el archivo de texto exdat.txt, en el que los valores que deben mostrarse en el gráfico se asignarán al array dat1. Este archivo debería contener un fragmento de código JavaScript, y se puede crear fácilmente en MetaTrader 5 usando el script correspondiente.

Abajo puede ver un ejemplo de este script.

//+------------------------------------------------------------------+
//|                                                     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 guardar los datos mostrados, este script usa el array gr[], que contiene 25 objetos. Este array, como ejemplo, se llena con valores de la función sinus, con un redondeo en la cuarta cifra decimal. Este array, por supuesto, se puede llenar con otros datos más útiles.

Además, se les da formato a estos datos y se combinan en una sola cadena de caracteres. Para reducir los valores del archivo de texto generado, los valores de los elementos del array gr[] se colocan en la cadena de caracteres con cuatro cifras decimales. Por este propósito usamos la función DoubleToString().

Tras formarse la cadena de caracteres str, se guarda en el archivo exdat.txt. En caso de que el script se ejecute sin éxito, el archivo de texto texdat.txt se creará en la subcarpeta \MQL5\Files del terminal de cliente. Si el archivo ya existe, se sobreescribirá.

Los archivos jquery.min.js, highcharts.js, Example1.mq5, Example1.htm y exdat.txt se presentan al final de este artículo, en la sección de archivos adjuntos. Estos cinco archivos se encuentran en el catálogo \Example1. Para ver los resultados, simplemente copie este ejemplo, y abra el archivo Example1.htm en el catálogo \Example1. El gráfico se construirá de acuerdo con los datos del archivo exdat.txt.

Example1.htm 

Figura 2. Example1.htm

Por supuesto, para ejecutar el script Example1.mq5, se debe colocar en la carpeta \MQL5\Scripts del terminal de cliente, y compilarse.

Tal y como se mencionó antes, tras la ejecución del script, el archivo exdat.tx se creará en la carpeta \MQL5\Files, pero en nuestro ejemplo, tanto el archivo HTML como los archivos de las bibliotecas y el archivo de datos se deben colocar en la misma carpeta. Por tanto, debemos copiar los archivos jquery.min.js, highcharts.js y Example1.htm en la carpeta \MQL5\Files o copiar el archivo exdat.txt a la carpeta donde se encuentran estos archivos.

En este ejemplo, la página HTML y las bibliotecas se guardan en archivos diferentes. En la fase de diseño puede que sea útil que las diferentes partes del proyecto se encuentren en archivos separados. Esto nos ayuda a evitar, por ejemplo, cambios aleatorios del código de las bibliotecas al editar el archivo HTML. Pero después de que la página HTML esté completamente editada y no se vayan a realizar más cambios, las bibliotecas se pueden integrar directamente en el archivo de código HTML.

Esto es posible porque las bibliotecas JavaScript no son más que archivos de texto sencillos. Si abrimos jquery.min.js o highcharts.js con un editor de texto, no veremos nada comprensible porque el código fuente de las bibliotecas se comprimió a la máxima capacidad.

La compresión se realiza eliminando los símbolos de servicio, por ejemplo una línea de feed o una serie de espacios. Después de esta compresión se pierde todo formato, pero el texto permanece como texto, puesto que el tipo de archivo no cambia. Por tanto, los resultados no serán diferentes si el servidor se conecta a la biblioteca desde un archivo externo con la extensión .js, o si la lee desde el archivo HTML actual, que a su vez está también en formato de texto.

Para combinar los archivos, sustituya en Example1.htm las líneas

<script src="jquery.min.js" type="text/javascript"></script>
<script src="highcharts.js" type="text/javascript"></script>

con

<script type="text/javascript">

</script>

A continuación, usando un editor de texto como por ejemplo el Bloc de Notas, abriremos el archivo de la biblioteca jquery.min.js, y eligiendo el comando "Select all" ("Seleccionar todos), copiaremos los contenidos del archivo. Después, abra el archivo Example1.htm, copie el texto copiad de la biblioteca entre las tags <script type=\"text/javascript\"> y </script>. Guarde el archivo obtenido como Example2.htm. Del mismo modo, copie los contenidos de la biblioteca highcharts.js en este archivo, colocándolo entre el texto de la biblioteca anteriormente copiada y la tag </script>.

Como resultado de ello, el archivo HTML aumentará en tamaño, pero ahora no necesitaremos archivos separados de la biblioteca para su funcionamiento correcto. Basta con tener el archivo de datos exdat.txt en la carpeta \Example2, que incluye los archivos Example2.htm y exdat.txt y se encuentra al final de este artículo en la sección de archivos adjuntos.


Un informe sobre el historial de trading en forma de gráfico

Para una demostración completa del método propuesto para mostrar información gráfica, crearemos un informe que muestre el historial de la cuenta de trading en un intervalo de tiempo específico. El informe de base HTML, que se crea en el MetaTrader 5 al seleccionar el comando "Report" ("Informe") en el menú de contexto de la pestaña "History" ("Historial"), servirá como prototipo. Este informe incluye un gran número de características diferentes, resumidas en una tabla. Suponiendo que estas características serán más visuales al presentarlas en forma de gráficos y diagramas, mostrémoslas usando la biblioteca gráfica highcharts.js.

En el ejemplo de arriba, para la construcción del gráfico usamos los parámetros por defecto configurados en esta versión de la biblioteca highcharts.js.

Por motivos de eficiencia, esta opción no tendrá éxito, puesto que en cada caso tendremos que ajustar la vista del gráfico para que se ajuste a requisitos específicos individuales. Por este motivo, la biblioteca ofrece un gran abanico de oportunidades, puesto que tiene un gran número de opciones que se pueden aplicar al gráfico o diagrama. Como ya se mencionó antes, la lista de opciones, junto con sus descripciones detalladas y ejemplos, se puede encontrar en http://www.highcharts.com.

No insistiremos en la descripción de opciones de la biblioteca de gráficos y en los detalles específicos de su uso porque este artículo está diseñado solo para sugerir y demonstrar la posibilidad de usar un navegador web para mostrar información recibida de MetaTrader 5. Especialmente puesto que, dependiendo de los requisitos específicos para la creación de una página web, podría usarse cualquier otra biblioteca JavaScript. El lector puede seleccionar independientemente la biblioteca que más le convenga y estudiarla a fondo tanto como lo requiera la práctica de su uso.

Para mostrar el historial de la cuenta de trading, creamos el archivo ProfitReport.htm. Se puede encontrar en los archivos adjuntos. La carpeta \Report contiene el archivo data.txt con los datos a mostrar. El archivo data.txt se coloca en la carpeta como ejemplo.

Cuando copiamos la carpeta \Report y abrimos ProfitReport.htm, veremos las características de trading de la cuenta de prueba creada para este ejemplo en forma de gráfico.

ProfitReport.htm

Figura 3. ProfitReport.htm

Al crear ProfitReport.htm, primero hicimos un borrador del esquema de la página y determinamos aproximadamente dónde y qué tipo de información se colocaría.

A continuación colocamos los gráficos con sus opciones por defecto en la página.

Tras crear esta plantilla, elegimos las opciones más adecuadas para cada gráfico individual. Tras completar la edición, simplemente copiamos los textos de las bibliotecas en la página. Como ya mencionamos antes, para una vista de página adecuada se debería colocar en el mismo catálogo que el archivo data.txt, que contiene los datos creados para su diseño.

El archivo data.txt se creó en MetaTrader 5 usando el script ProfitReport.mq5. Si este script se ejecuta con éxito, el archivo data.txt se creará en la carpeta \MQL5\Files con las características de trading de la cuenta activa actual.

No debemos olvidar que el script se debe colocar en la carpeta \MQL5\Scripts y debe compilarse.

//-----------------------------------------------------------------------------------
//                                                                   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, el código del script es bastante pesado, pero esto no se debe a la complejidad de la tarea, sino más bien al gran número de características de trading, cuyo valor se debe determinar. Para el almacenamiento de estos valores, al comienzo del script se declaran las variables globales, facilitadas con comentarios relevantes.

La función OnStart() verifica si un terminal está conectado con el servidor de trading, y si no, el script finaliza su trabajo. En ausencia de conexión con el servidor, no podremos definir una cuenta activa y obtener información sobre ella.

El siguiente paso es el cálculo de la fecha, de la que se incluirán los datos de trading para la cuenta activa actual en el informe. Como fecha de finalización usaremos el valor de la fecha y hora actual en el momento de la ejecución del script. El número de días incluido en el informe se puede configurar al cargar el script cambiando el parámetro de entrada "Number of days" ("Número de días"), que por defecto es igual a 30 días. Una vez que hemos definido las fechas inicial y final del informe, en la variable de la cadena de caracteres Band se forma una pareja de valores temporales correspondientes al comienzo y final del fin de semana. Esta información se usa para que, en el gráfico de saldo, los intervalos temporales correspondientes a los sábados y domingos se marquen en amarillo.

A continuación, usando la función HistorySelect(), el historial de transacciones y órdenes para un intervalo específico pasará a estar disponible, y al llamar a la función HistoryDealsTotal() determinaremos el número de transacciones en el historial. Tras todo esto se distribuye un ciclo basado en el número de transacciones que recopila las estadísticas necesarias para el cálculo de características de trading, y al final del ciclo, se determinan sus valores.

Al crear el script, nuestra tarea era preservar el significado de las características de trading de acuerdo con el informe generado en MetaTrader 5. SE da por hecho que las características calculadas por el script deben corresponderse con la descripción que se da en el archivo "Help" ("Ayuda") del terminal. 

La información sobre el acceso al historial de la cuenta y los cálculos de características de trading se pueden encontrar en los siguientes artículos:

La mayoría de las características se calculan fácilmente, de modo que en este artículo no trataremos las operaciones asociadas con el cálculo de cada característica, y solo consideraremos las diferencias existentes desde el informe estándar y sus suplementos.

En el informe generado por el terminal, el gráfico de saldo se construye con una vista secuencial de valores para cada momento de cambio, y la escala X refleja el número de estos cambios. En nuestro caso, para la construcción del gráfico usamos una escala de tiempo.

Por tanto, el gráfico de beneficios es muy diferente del gráfico generado por el terminal. Elegimos esta opción de construcción de gráfico para mostrar el momento de cierre de posiciones en una escala de tiempo real. Por tanto, podemos ver cuándo aumentó o disminuyó la actividad de trading durante el período que refleja el informe.

Al construir un gráfico, se debe tener en cuenta que MQL5 opera con el valor de fecha presentado como el número de segundos pasados desde el 1 de enero de 1970, mientras que la biblioteca de gráficos requiere este valor como el número de milisegundos desde el 1 de enero de 1970. Por tanto, los valores de fecha recibidos en el script deben multiplicarse por mil para que se muestren correctamente.

Para almacenar el valor de beneficio y el momento de cierre de la transacción, el script usa las clases CArrayDouble y CArrayLong de la Biblioteca estándar. Cada vez que se detecta una transacción resultante en el bucle, se coloca información sobre ella usando el método Add() en el elemento, que se añade al final del array. Esto nos permite superar el obstáculo de tener que determinar por adelantado el número de elementos requerido. El tamaño del array simplemente aumenta con el número de transacciones encontradas en el historial de transacciones.

Para cada transacción se lleva a cabo una comprobación para ver en qué símbolo se ha ejecutado, manteniendo el nombre del símbolo y el número de transacciones realizadas en él. Al igual que para el gráfico de beneficios, estos datos, al ver el historial, se acumulan grabándose dentro de un elemento que se añade al final del array. Para almacenar el nombre del símbolo y el número de transacciones usamos las clases CArrayString y CArrayInt de la Biblioteca Estándar.

Una sola columna en el gráfico será demasiado ancha en casos en los que las transacciones se hayan ejecutado en un símbolo. Para evitar esto, el array de datos siempre contiene al menos 7 elementos. Los elementos no usados no se muestran en el diagrama, puesto que tienen valores de cero y por tanto no permiten que la columna se haga demasiado ancha. Para asegurarnos de que, cuando hay un número pequeño de símbolos, las columnas se colocan aproximadamente en el medio del eje X, los elementos insignificantes del array se insertan secuencialmente al principio o al final del array.

La siguiente diferencia del informe estándar es el intento de construcción de un gráfico de distribución de probabilidad para la secuencia de valores de beneficio para cada transacción.

Densidad de probabilidad

Figura 4. Densidad de probabilidad

En la mayoría de los casos, este tipo de gráficos se presenta en forma de histogramas. En nuestro caso, el gráfico de probabilidad se crea construyendo una ranura basada en la columna existente de valores de este histograma. Los valores calculados de la densidad de probabilidad se complementan a la izquierda y a la derecha, fuera del gráfico, con valores de cero. Esto es necesario para que el gráfico construido por la ranura no se interrumpa en el último valor conocido, y continúe más allá del gráfico, descendiendo hacia cero.

Para comparar, en el gráfico de densidad de probabilidad se usa el color gris para destacar el gráfico de distribución normal, normalizado de modo que la suma de sus lecturas sea igual a uno, al igual que el gráfico que se construyó según los valores del histograma. En el informe de ejemplo facilitado, el número de transacciones no es igual para dar un cálculo más o menos fiable de la distribución de probabilidad de los valores de operaciones rentables. Podemos asumir que, cuando haya un número grande de transacciones en el historial, este gráfico tendrá un aspecto más auténtico.

Una vez que todas las características de trading se hayan calculado, se llama a la función filesave() al final del script. Esta función abre el archivo data.txt, en el cual se graban los nombre y valores de las variables en formato de texto. Los valores de estas variables se corresponden con los parámetros calculados, y sus nombres se corresponden con los nombres usados en el archivo HTML durante la transferencia de parámetros de las funciones de la biblioteca de gráficos.

Para reducir el número de accesos al disco durante la escritura del archivo, se mezclan líneas cortas con líneas más largas, y solo entonces se graba en el archivo. El archivo data.txt, como es habitual en MetaTrader 5, se crea en el catálogo MQL5\Files; si este archivo ya existe, se sobrescribe. Por motivos de conveniencia, puede copiar el archivo ProfitReport.htm dentro del catálogo y ejecutarlo desde ahí.

En el teminal de MetaTrader 5, al guardar un informe en formato HTML, se abre automáticamente por un navegador, que se registra como el navegador por defecto. Esta posibilidad no se implementó en el ejemplo facilitado en este artículo.

Para agregar una autorreproducción, inserte las siguientes líneas al principio del script ProfitReport.mq5

#import "shell32.dll"
int ShellExecuteW(int hwnd,string lpOperation,string lpFile,string lpParameters,
                  string lpDirectory,int nShowCmd);
#import

y, al final, tras una llamada a la función filesave(), añada

string path=TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL5\\Files\\ProfitReport.htm";
ShellExecuteW(NULL,"open",path,NULL,NULL,1);

Si el archivo ProfitReport.htm ya existe en la ruta de la variable especificada, entonces cuando se llame a la función ShellExecuteW() se abrirá enun navegador. La función ShellExecuteW() se encuentra en la biblioteca de sistema shell32.dll, y la declaración de esta función se añade al principio del archivo para facilitar acceso a ella.


Conclusión

El uso de navegadores web nos permite mostrar una buena cantidad de información variada al mismo tiempo que puede ser de gran ayuda, por ejemplo, en la organización de control visual sobre el estado interno de módulos individuales del Asesor Experto que se ejecuta en el terminal de cliente.

Los datos de gestión de capital, las señales de trading, el stop de rastreo y datos de otros módulos se pueden mostrar de forma conveniente y simultánea. Los informes de varias páginas HTML se pueden usar si es necesario mostrar demasiada información.

Debemos señalar que las capacidades del lenguaje JavaScript son mucho más grandes que sencillamente dibujar gráficos. Usando este lenguaje, podemos hacer páginas web verdaderamente interactivas. En internet podrá encontrar un buen número de códigos JavaScript ya hechos, incluidos en la página web, y varios ejemplos del uso de este lenguaje.

Por ejemplo, el terminal se puede gestionar directamente desde la ventana del navegador si se organiza un intercambio de datos bidireccional entre el terminal y el navegador.

Esperamos que el método descrito en este artículo sera de ayuda.


Archivos

JS_Lib.zip            - highcharts.js y jquery.min.js
librariesTest.zip   - highcharts.js, jquery.min.js yTest_01.htm
Example1.zip       - highcharts.js, jquery.min.js, Example1.htm, Example1.mq5 y exdat.txt
Example2.zip       - Example2.htm y exdat.txt
Report.zip           - ProfitReport.htm y data.txt
ProfitReport.mq5 - Script para la recopilación de estadísticas y la creación del archivo data.txt