English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Crear y Publicar Informes de Trading y Notificaciones SMS

Crear y Publicar Informes de Trading y Notificaciones SMS

MetaTrader 5Ejemplos | 7 febrero 2014, 14:19
1 387 0
Denis Zyatkevich
Denis Zyatkevich

Introducción

Este artículo describe cómo generar un informe de resultados de trading (usando un Asesor Experto, Indicador o Script) como archivo HTML y subirlo por FTP a un servidor WWW. También explicaremos cómo enviar notificaciones de eventos de trading como mensajes SMS a teléfonos móviles.

Para sentirse más cómodo con el material descrito en este artículo, se recomienda al lector que se familiarice con el lenguaje HTML.

Para implementar los informes necesitamos un servidor WWW (puede ser cualquier ordenador) que pueda acceder a datos por FTP. Para implementar la posibilidad de recibir notificaciones sobre eventos de trading por SMS, necesitaremos una puerta de enlace EMAIL-SMS (la mayoría de compañías telefónicas prestan este servicio).

1. Crear un informe y enviarlo por FTP

Creemos un programa MQL5 que generará un informe de trading y lo enviará por protocolo FTP. Primero lo crearemos como un Script. En el futuro, lo podremos usar como un bloque terminado que se podrá insertar en cualquier Asesor Experto o Indicador. Por ejemplo, en un Asesor Experto puede usar este bloque como el controlador de eventos Trade o Timer para ejecutar este bloque tras la solicitud de trading, o para establecer acciones para el evento ChartEvent. En un Indicador, puede incluir este bloque en el controlador de eventos Timer o ChartEvent.

Puede ver un ejemplo de informe creado por un programa en las Figuras 1, 2 y 3. O puede descargarse este informe yendo al enlace que se encuentra al final de este artículo.

Figura 1. Ejemplo de informe: Tabla de Transacciones y Posiciones.

Figura 1. Ejemplo de informe: Tabla de Transacciones y Posiciones.

Figura 2. Ejemplo de informe: Gráfico de Saldo.

Figura 2. Ejemplo de informe: Gráfico de Saldo.

 Figura 3. Ejemplo de informe: Gráfico de Precio en el Instrumento Actual.

Figura 3. Ejemplo de informe: Gráfico de Precio en el Instrumento Actual.

En la tabla de Transacciones y Posiciones (Deals and Positions) (Figura 1), todas las transacciones se dividen en posiciones por motivos de conveniencia. El lado izquierdo de la tabla muestra el volumen, hora y precio de introducción en el mercado (de apertura de posiciones y adiciones). El lado derecho de la tabla muestra los mismos parámetros para salir del mercado (cierre parcial o completo de posición). En in/out, la transacción se divide en dos partes: el cierre de una posición y la apertura de la siguiente.

Bajo la tabla de Transacciones y Posiciones se muestra el gráfico de Saldo (Balance chart) (eje horizontal - hora), y al final, el gráfico de Precio (Price chart) en el Instrumento Actual.

El programa crea los archivos "report.html", "picture1.gif" y "picture2.gif" (archivos html del informe, de las imágenes del gráfico de saldo y del de precio) en la carpeta MetaTarder5_istall_dir\MQL5\Files. Y la publicación FTP se activa en la configuración del terminal: envía estos tres archivos al servidor especificado. Además, necesitaremos dos archivos de imagen con flechas apuntando a la dirección de la posición abierta: Buy (Compra) o Sell (Venta) ("buy.gif" and "sell.gif"). Puede tomar estas imágenes (el enlace de descarga está al final del artículo) o dibujarlas usted mismo en cualquier editor de gráficos. Estos dos archivos se deberían colocar en la misma carpeta del servidor WWW con el archivo "report.html".

Como parámetros de entrada, el programa acepta el momento de comienzo y final del período para las que se generó el informe. En nuestro ejemplo, el final del informe es el momento actual, y el usuario selecciona la variante de período del informe: un período entero, el último día, la última semana, el último mes, o el último año.

Otros aspectos a tener en consideración sobre cómo se crea un informe: Se requiere un servidor de trading para todo el historial de transacciones disponible. Las transacciones obtenidas se procesan una tras otra. El array deal_status[] almacena información sobre si la transacción se ha procesado o no. Los índices de elemento de este array son los números de transacciones recibidos de la lista de transacciones del servidor de trading. Y los valores de los elementos se interpretan de la siguiente manera: 0 - la transacción aún no se ha procesado, 1 - la transacción se ha procesado parcialmente (in/out), 127 - la transacción se ha procesado (otros valores no se usarán y se reservarán para su futuro uso).

El array symb_list[] contiene la lista de nombres de instrumentos financieros con la que se llevó a cabo la operación de trading, y el array lots_list[] contiene los volúmenes de las posiciones abiertas para cada instrumento en el momento de procesamiento de una transacción. Los valores positivos de volumen se corresponden con posiciones largas, mientras que valores negativos se corresponden con posiciones cortas. Si el volumen es igual a cero, significa que esta herramienta no tiene posiciones abiertas. Si durante una transacción aparece un instrumento financiero que no está en la lista (en el array symb_list[]), se añade allí, y el número de instrumentos financieros (la variable symb_total) aumenta en 1.

En cada procesamiento de transacción, cada transacción subsiguiente se analiza con el mismo instrumento financiero hasta que la posición se cierra o queda en estado in/out. Solo se analizan las transacciones cuyo valor en el array deal_status[] es menor de 127. Tras el procesamiento de la transacción, el elemento correspondiente del array deal_status[] se asigna con un valor de 127, y si la transacción está en estado in/out de posición, el valor será 1. Si el momento en el que se abrió la posición coincide con el período del informe (definido por las variables StartTime y EndTime), esta posición se registrará en el informe (con todas sus entradas y salidas).

Además de la tabla de transacciones, se abre un nuevo gráfico para el instrumento financiero actual. Para este gráfico se facilitan todas las propiedades necesarias, y se hace una captura de pantalla usando la función ChartScreenShot() para obtener un archivo de imagen con el gráfico de precio para el instrumento actual. A continuación, en este gráfico se oculta el gráfico de precio y se dibuja el gráfico de cambios de saldo, y después se hace otra captura de pantalla.

Cuando se han creado dos archivos de imagen con gráficos y un archivo HTMl con informe, se comrpueva si se pueden enviar archivos por FTP. Si está permitido, los archivos "report.html", "picture1.gif" y "picture2.gif" se enviarán usando la función SendFTP(), según la configuración especificada en MetaTrader 5.

Ejecute el Language Editor (Editor de Lenguaje) de MetaQuotes y comience a crear un script. Defina las constantes: la frecuencia de actualización del gráfico (en segundos), la anchura y altura del gráfico de precio, y la anchura máxima del gráfico de saldo. El período del gráfico que mostrará la curva de cambios de saldo se elegirá dependiendo de la duración del período del informe y de la anchura máxima del gráfico. La anchura del gráfico se ajusta al tamaño que se necesita para el gráfico de saldo.

La altura del gráfico se calcula automáticamente como la mitad de la anchura. Asimismo, especificaremos la anchura del eje vertical como constante: es el número de píxeles por los que se reducen los gráficos en comparación a la anchura de la imagen a causa del eje vertical.

#define timeout 10           // chart refresh timeout
#define Picture1_width 800   // max width of chart in report
#define Picture2_width 800   // width of price chart in report
#define Picture2_height 600  // height of price chart in report
#define Axis_Width 59        // width of vertical axis (in pixels)

Especifique que los parámetros de entrada se solicitarán al usuario.

// request input parameters
#property script_show_inputs

Cree una enumeración de períodos de informe.

// enumeration of report periods
enum report_periods
  {
   All_periods,
   Last_day,
   Last_week,
   Last_month,
   Last_year
  };

Solicite un período del informe al usuario (la opción por defecto es el período entero).

// ask for report period
input report_periods ReportPeriod=0;

Escriba el cuerpo de la función OnStart().

void OnStart()
  {

Determine el inicio y el final del período del informe.

  datetime StartTime=0;           // beginning of report period
  datetime EndTime=TimeCurrent(); // end of report period

  // calculating the beginning of report period
  switch(ReportPeriod)
    {
     case 1:
        StartTime=EndTime-86400;    // day
        break;
     case 2:
        StartTime=EndTime-604800;   // week
        break;
     case 3:
        StartTime=EndTime-2592000;  // month
        break;
     case 4:
        StartTime=EndTime-31536000; // year
        break;
    }
  // if none of the options is executed, then StartTime=0 (entire period)

Declare las variables que se usarán en el programa. El propósito de las variables se describe en los comentarios.

   int total_deals_number;  // number of deals for history data
   int file_handle;         // file handle
   int i,j;                 // loop counters 
   int symb_total;          // number of instruments, that were traded
   int symb_pointer;        // pointer to current instrument
   char deal_status[];      // state of deal (processed/not processed)
   ulong ticket;            // ticket of deal
   long hChart;             // chart id

   double balance;           // current balance value
   double balance_prev;      // previous balance value
   double lot_current;       // volume of current deal
   double lots_list[];       // list of open volumes by instruments
   double current_swap;      // swap of current deal
   double current_profit;    // profit of current deal
   double max_val,min_val;   // maximal and minimal value
   
   string symb_list[];       // list of instruments, that were traded
   string in_table_volume;   // volume of entering position
   string in_table_time;     // time of entering position
   string in_table_price;    // price of entering position
   string out_table_volume;  // volume of exiting position
   string out_table_time;    // time of exiting position
   string out_table_price;   // price of exiting position
   string out_table_swap;    // swap of exiting position
   string out_table_profit;  // profit of exiting position

   bool symb_flag;           // flag that instrument is in the list

   datetime time_prev;           // previous value of time
   datetime time_curr;           // current value of time
   datetime position_StartTime;  // time of first enter to position
   datetime position_EndTime;    // time of last exit from position
   
   ENUM_TIMEFRAMES Picture1_period;  // period of balance chart

Abra un nuevo gráfico y configure sus propiedades: este es el gráfico de precio que se imprimirá al final del informe.

 // open a new chart and set its properties
hChart=ChartOpen(Symbol(),0);
ChartSetInteger(hChart,CHART_MODE,CHART_BARS);            // bars chart
ChartSetInteger(hChart,CHART_AUTOSCROLL,true);            // autoscroll enabled
ChartSetInteger(hChart,CHART_COLOR_BACKGROUND,White);     // white background
ChartSetInteger(hChart,CHART_COLOR_FOREGROUND,Black);     // axes and labels are black
ChartSetInteger(hChart,CHART_SHOW_OHLC,false);            // OHLC are not shown
ChartSetInteger(hChart,CHART_SHOW_BID_LINE,true);         // show BID line
ChartSetInteger(hChart,CHART_SHOW_ASK_LINE,false);        // hide ASK line
ChartSetInteger(hChart,CHART_SHOW_LAST_LINE,false);       // hide LAST line
ChartSetInteger(hChart,CHART_SHOW_GRID,true);             // show grid
ChartSetInteger(hChart,CHART_SHOW_PERIOD_SEP,true);       // show period separators
ChartSetInteger(hChart,CHART_COLOR_GRID,LightGray);       // grid is light-gray
ChartSetInteger(hChart,CHART_COLOR_CHART_LINE,Black);     // chart lines are black
ChartSetInteger(hChart,CHART_COLOR_CHART_UP,Black);       // up bars are black
ChartSetInteger(hChart,CHART_COLOR_CHART_DOWN,Black);     // down bars are black
ChartSetInteger(hChart,CHART_COLOR_BID,Gray);             // BID line is gray
ChartSetInteger(hChart,CHART_COLOR_VOLUME,Green);         // volumes and orders levels are green
ChartSetInteger(hChart,CHART_COLOR_STOP_LEVEL,Red);       // SL and TP levels are red
ChartSetString(hChart,CHART_COMMENT,ChartSymbol(hChart)); // comment contains instrument <end segm

Haga una captura de pantalla a un gráfico y guarde la imagen como "picture2.gif".

// save chart as image file
ChartScreenShot(hChart,"picture2.gif",Picture2_width,Picture2_height);

Solicite el historial de transacciones para todo el tiempo de existencia de la cuenta.

// request deals history for entire period
HistorySelect(0,TimeCurrent());

Abra el archivo "report.html", en el que escribiremos una página HTML con el informe (codificación ANSI).

// open report file
file_handle=FileOpen("report.html",FILE_WRITE|FILE_ANSI);

Escriba la primera parte del documento HTML:

  • inicio del documento html (<html>)
  • título que se mostrará en la parte de arriba de su ventana de navegador (<head><title>Informe de Trading del Expert</title></head>)
  • comienzo de la parte principal del documento html con color de fondo (<body bgcolor='#EFEFEF'>)
  • alineamiento central (<center>)
  • título de la tabla de transacciones y posiciones (<h2>Informe de Tradingt</h2>)
  • comienzo de la tabla de transacciones y posiciones con alineamiento, anchura de borde, color de fondo, color de borde, espaciado de celda y margen de celda (<table align='center' border='1' bgcolor='#FFFFFF' bordercolor='#7F7FFF' cellspacing='0' cellpadding='0'>)
  • encabezado de tabla  
// write the beginning of HTML
   FileWrite(file_handle,"<html>"+
                           "<head>"+
                              "<title>Expert Trade Report</title>"+
                           "</head>"+
                              "<body bgcolor='#EFEFEF'>"+
                              "<center>"+
                              "<h2>Trade Report</h2>"+
                              "<table align='center' border='1' bgcolor='#FFFFFF' bordercolor='#7F7FFF' cellspacing='0' cellpadding='0'>"+
                                 "<tr>"+
                                    "<th rowspan=2>SYMBOL</th>"+
                                    "<th rowspan=2>Direction</th>"+
                                    "<th colspan=3>Open</th>"+
                                    "<th colspan=3>Close</th>"+
                                    "<th rowspan=2>Swap</th>"+
                                    "<th rowspan=2>Profit</th>"+
                                 "</tr>"+
                                 "<tr>"+
                                    "<th>Volume</th>"+
                                    "<th>Time</th>"+
                                    "<th>Price</th>"+
                                    "<th>Volume</th>"+
                                    "<th>Time</th>"+
                                    "<th>Price</th>"+
                                 "</tr>");

Obtenga número de transacciones en la lista.

// number of deals in history
total_deals_number=HistoryDealsTotal();

Configure las dimensiones para los arrays symb_list[], lots_list[] y deal_status[].

// setting dimensions for the instruments list, the volumes list and the deals state arrays
ArrayResize(symb_list,total_deals_number);
ArrayResize(lots_list,total_deals_number);
ArrayResize(deal_status,total_deals_number);

Inicialice los elementos del array deal_status[] con valor 0: todas las transacciones están sin procesar.

// setting all elements of array with value 0 - deals are not processed
ArrayInitialize(deal_status,0);

Configure los valores iniciales de saldo y variable usados para almacenar el anterior valor de saldo.

balance=0;       // initial balance
balance_prev=0;  // previous balance

Configure el valor inicial de variable usado para almacenar el número de instrumentos financieros en la lista.

// number of instruments in the list
symb_total=0;

Cree un bucle que procesa secuencialmente cada transacción de la lista.

// processing all deals in history
for(i=0;i<total_deals_number;i++)
  {

Seleccione la transacción actual y obtener su ticket.

//select deal, get ticket
ticket=HistoryDealGetTicket(i);

Cambie el saldo por la cantidad de beneficio en la transacción actual.

// changing balance
balance+=HistoryDealGetDouble(ticket,DEAL_PROFIT);

Obtenga la hora de la transacción - esta opción se usará de forma frecuente.

// reading the time of deal
time_curr=HistoryDealGetInteger(ticket,DEAL_TIME);

Si se trata de la primera transacción de la lista, debemos ajustar los límites del período del informe y seleccionar el período para el gráfico de saldo dependiendo de la duración del período del informe y la anchura de la región en la que se representará el gráfico. Configurar los valores iniciales de saldo máximo y mínimo (estas variables se usarán para establecer un máximo y mínimo en el gráfico).

// if this is the first deal
if(i==0)
  {
   // if the report period starts before the first deal,
   // then the report period will start from the first deal
   if(StartTime<time_curr) StartTime=time_curr;
   // if report period ends before the current time,
   // then the end of report period corresponds to the current time
   if(EndTime>TimeCurrent()) EndTime=TimeCurrent();
   // initial values of maximal and minimal balances
   // are equal to the current balance
   max_val=balance;
   min_val=balance;
   // calculating the period of balance chart depending on the duration of
   // report period
   Picture1_period=PERIOD_M1;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)) Picture1_period=PERIOD_M2;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*120) Picture1_period=PERIOD_M3;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*180) Picture1_period=PERIOD_M4;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*240) Picture1_period=PERIOD_M5;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*300) Picture1_period=PERIOD_M6;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*360) Picture1_period=PERIOD_M10;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*600) Picture1_period=PERIOD_M12;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*720) Picture1_period=PERIOD_M15;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*900) Picture1_period=PERIOD_M20;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*1200) Picture1_period=PERIOD_M30;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*1800) Picture1_period=PERIOD_H1;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*3600) Picture1_period=PERIOD_H2;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*7200) Picture1_period=PERIOD_H3;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*10800) Picture1_period=PERIOD_H4;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*14400) Picture1_period=PERIOD_H6;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*21600) Picture1_period=PERIOD_H8;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*28800) Picture1_period=PERIOD_H12;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*43200) Picture1_period=PERIOD_D1;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*86400) Picture1_period=PERIOD_W1;
   if(EndTime-StartTime>(Picture1_width-Axis_Width)*604800) Picture1_period=PERIOD_MN1;
   // changing the period of opened chart
   ChartSetSymbolPeriod(hChart,Symbol(),Picture1_period);
  }

Si esta transacción no es la primera, cree el objeto "line" usando la línea en la que se representa el gráfico de cambio de saldo. La línea se representa solo si al menos uno de sus extremos está dentro del período del informe. Si ambos extremos se encuentran dentro del período del informe, la línea será "ancha". El color de la línea de saldo es verde. Si el saldo está más allá del margen de saldo mínimo y máximo, este margen se ajusta.

else
  // if this is not the first deal
  {
   // plotting the balance line, if the deal is in the report period,
   // and setting properties of the balance line
   if(time_curr>=StartTime && time_prev<=EndTime)
     {
      ObjectCreate(hChart,IntegerToString(i),OBJ_TREND,0,time_prev,balance_prev,time_curr,balance);
      ObjectSetInteger(hChart,IntegerToString(i),OBJPROP_COLOR,Green);
      // if both ends of line are in the report period,
      // it will be "thick"
      if(time_prev>=StartTime && time_curr<=EndTime)
        ObjectSetInteger(hChart,IntegerToString(i),OBJPROP_WIDTH,2);
     }
   // if new value of balance exceeds the range
   // of minimal and maximal values, it must be adjusted
   if(balance<min_val) min_val=balance;
   if(balance>max_val) max_val=balance;
  }

Asigne el valor temporal anterior a la variable correspondiente.

// changing the previous time value
time_prev=time_curr;

Si la transacción no se ha procesado todavía, procésela.

// if the deal has not been processed yet
if(deal_status[i]<127)
  {

Si esta transacción supone un cambio en el saldo y está dentro del período del informe, la cadena de caracteres correspondiente se añade al informe. La transacción se marca como procesada.

// If this deal is balance charge
if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BALANCE)
  {
   // if it's in the report period - write the corresponding string to report.
   if(time_curr>=StartTime && time_curr<=EndTime)
     FileWrite(file_handle,"<tr><td colspan='9'>Balance:</td><td align='right'>",HistoryDealGetDouble(ticket,DEAL_PROFIT),
     "</td></tr>");
   // mark deal as processed
   deal_status[i]=127;
  }

Si esta transacción es de Compra o Venta, compruebe si este instrumento está en la lista (el array symb_list[]). Si no, añádalo. La variable symb_pointer apunta a los elementos del array symb_list[], que contiene el nombre del instrumento de la transacción actual.

// if this deal is buy or sell
if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BUY || HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_SELL)
  {
   // check if there is instrument of this deal in the list
   symb_flag=false;
   for(j=0;j<symb_total;j++)
     {
      if(symb_list[j]==HistoryDealGetString(ticket,DEAL_SYMBOL))
        {
         symb_flag=true;
         symb_pointer=j;
        }
     }
   // if there is no instrument of this deal in the list
   if(symb_flag==false)
     {
      symb_list[symb_total]=HistoryDealGetString(ticket,DEAL_SYMBOL);
      lots_list[symb_total]=0;
      symb_pointer=symb_total;
      symb_total++;
     }

Configure los valores iniciales de las variables position_StartTime y position_EndTime, que almacenan el tiempo de vida inicial y final de la posición.

// set the initial value for the beginning time of deal
position_StartTime=time_curr;
// set the initial value for the end time of deal
position_EndTime=time_curr;

Las variables in_table_volume, in_table_time, in_table_price, out_table_volume, out_table_time, out_table_price, out_table_swap y out_table_profit almacenarán tablas que estarán dentro de celdas de una tabla más grande: volumen, hora y precio de apertura de mercado; volumen, hora, precio, cambio y beneficio de salida de mercado. La variable in_table_volume también almacenarán el nombre del instrumento financiero y el enlace a una imagen que se corresponde con la dirección de una posición abierta. Asignar todas estas variables con valores iniciales.

// creating the string in report - instrument, position direction, beginning of table for volumes to enter the market
if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BUY) StringConcatenate(in_table_volume,"<tr><td align='left'>",
symb_list[symb_pointer],"</td><td align='center'><img src='buy.gif'></td><td><table border='1' width='100%' bgcolor='#FFFFFF'
bordercolor='#DFDFFF'>");
if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_SELL) StringConcatenate(in_table_volume,"<tr><td align='left'>",
symb_list[symb_pointer],"</td><td align='center'><img src='sell.gif'></td><td><table border='1' width='100%' bgcolor='#FFFFFF'
bordercolor='#DFDFFF'>");
// creating the beginning of time table to enter the market
in_table_time="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>";
// creating the beginning of price table to enter the market
in_table_price="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>";
// creating the beginning of volume table to exit the market
out_table_volume="<td><table border='1' width='100%' bgcolor=#FFFFFF bordercolor='#DFDFFF'>";
// creating the beginning of time table to exit the market
out_table_time="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>";
// creating the beginning of price table to exit the market
out_table_price="<td><table border='1' width='100%' bgcolor='#FFFFFF' bordercolor='#DFDFFF'>";
// creating the beginning of swap table to exit the market
out_table_swap="<td><table border='1' width='100%' bgcolor=#FFFFFF bordercolor='#DFDFFF'>";
// creating the beginning of profit table to exit the market
out_table_profit="<td><table border='1' width='100%' bgcolor=#FFFFFF bordercolor='#DFDFFF'>";

Procese todas las transacciones con la posición actual hasta que se cierre. Procesarlas todas ahora si no lo había hecho antes.

// process all deals for this position starting with the current(until position is closed)
for(j=i;j<total_deals_number;j++)
  {
   // if the deal has not been processed yet - process it
   if(deal_status[j]<127)
     {

Seleccione una transacción y obtener su ticket.

// select deal, get ticket
ticket=HistoryDealGetTicket(j);

Si la transacción está en el mismo instrumento que la posición abierta, procésela. Obtenga la hora de la transacción. Si el momento de la transacción está más allá del margen temporal de la posición, extienda este margen. Obtener el volumen de la transacción.

// if the instrument of deal matches the instrument of position, that is processed
if(symb_list[symb_pointer]==HistoryDealGetString(ticket,DEAL_SYMBOL))
  {
   // get the deal time
   time_curr=HistoryDealGetInteger(ticket,DEAL_TIME);
   // If the deal time goes beyond the range of position time
   // - extend position time
   if(time_curr<position_StartTime) position_StartTime=time_curr;
   if(time_curr>position_EndTime) position_EndTime=time_curr;
   // get the volume of deal
   lot_current=HistoryDealGetDouble(ticket,DEAL_VOLUME);

Las transacciones de Compra y Venta se procesan por separado. Comience con las transacciones de Compra.

// if this deal is buy
if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_BUY)
  {

Si ya ha abierto una posición para venta, esta transacción de Compra supondrá una salida del mercado. Y si el volumen de la transacción es mayor que el volumen de la posición corta abierta, pasará a in/out. Asigne variables de cadena de caracteres con los valores requeridos. Asigne un valor de 127 al array deal_status[] si la transacción se ha procesado completamente, o un valor de 1 si está en in/out, y esta transacción debe analizarse para otra posición.

// if position is opened for sell - this will be exit from market
if(NormalizeDouble(lots_list[symb_pointer],2)<0)
  {
   // if buy volume is greater than volume of opened short position - then this is in/out
   if(NormalizeDouble(lot_current+lots_list[symb_pointer],2)>0)
     {
      // creating table of volumes to exit the market - indicate only volume of opened short position
      StringConcatenate(out_table_volume,out_table_volume,"<tr><td align='right'>",DoubleToString(-lots_list[symb_pointer],2),"</td></tr>");
      // mark position as partially processed
      deal_status[j]=1;
     }
   else
     {
      // if buy volume is equal or less than volume of opened short position - then this is partial or full close
      // creating the volume table to exit the market
      StringConcatenate(out_table_volume,out_table_volume,"<tr><td align='right'>",DoubleToString(lot_current,2),"</td></tr>");
      // mark deal as processed
      deal_status[j]=127;
     }

   // creating the time table to exit the market
   StringConcatenate(out_table_time,out_table_time,"<tr><td align='center'>",TimeToString(time_curr,TIME_DATE|TIME_SECONDS),"</td></tr>");

   // creating the price table to exit the market
   StringConcatenate(out_table_price,out_table_price,"<tr><td align='center'>",DoubleToString(HistoryDealGetDouble(ticket,DEAL_PRICE),
   (int)SymbolInfoInteger(symb_list[symb_pointer],SYMBOL_DIGITS)),"</td></tr>");

   // get the swap of current deal
   current_swap=HistoryDealGetDouble(ticket,DEAL_SWAP);

   // if swap is equal to zero - create empty string of the swap table to exit the market
   if(NormalizeDouble(current_swap,2)==0) StringConcatenate(out_table_swap,out_table_swap,"<tr></tr>");
   // else create the swap string in the swap table to exit the market
   else StringConcatenate(out_table_swap,out_table_swap,"<tr><td align='right'>",DoubleToString(current_swap,2),"</td></tr>");

   // get the profit of current deal
   current_profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);

   // if profit is negative (loss) - it is displayed as red in the profit table to exit the market
   if(NormalizeDouble(current_profit,2)<0) StringConcatenate(out_table_profit,out_table_profit,"<tr><td align=right><SPAN style='COLOR: #EF0000'>",
   DoubleToString(current_profit,2),"</SPAN></td></tr>");
   // else - it is displayed as green
   else StringConcatenate(out_table_profit,out_table_profit,"<tr><td align='right'><SPAN style='COLOR: #00EF00'>",
        DoubleToString(current_profit,2),"</SPAN></td></tr>");
  }

Si ya ha abierto una posición larga, la compra en esta transacción será la entrada al mercado (la primera, o una adición). Si el elemento del array deal_status[] que se corresponde con esta transacción tiene un valor de 1, significa que está en estado in/out. Asigne variables de cadena de caracteres con los valores requeridos y marque la transacción como procesada (asigne el elemento correspondiente del array deal_status[] con un valor de127).

else
   // if position is opened for buy - this will be the enter to the market
   {
    // if this deal has been already partially processed (in/out)
    if(deal_status[j]==1)
      {
       // create the volume table of entering the market (volume, formed after in/out, is put here)
       StringConcatenate(in_table_volume,in_table_volume,"<tr><td align='right'>",DoubleToString(lots_list[symb_pointer],2),"</td></tr>");
       // indemnity of volume change, which will be produced (the volume of this deal is already taken into account)
       lots_list[symb_pointer]-=lot_current;
      }
    // if this deal has not been processed yet, create the volume table to enter the market
    else StringConcatenate(in_table_volume,in_table_volume,"<tr><td align='right'>",DoubleToString(lot_current,2),"</td></tr>");

    // creating the time table of entering the market
    StringConcatenate(in_table_time,in_table_time,"<tr><td align center>",TimeToString(time_curr,TIME_DATE|TIME_SECONDS),"</td></tr>");

    // creating the price table of entering the market
    StringConcatenate(in_table_price,in_table_price,"<tr><td align='center'>",DoubleToString(HistoryDealGetDouble(ticket,DEAL_PRICE),
    (int)SymbolInfoInteger(symb_list[symb_pointer],SYMBOL_DIGITS)),"</td></tr>");

    // mark deal as processed
    deal_status[j]=127;
   }

Cambie el volumen de la posición al volumen de la transacción actual. Si la posición está cerrada (el volumen es equivalente a 0), deje de procesar esta posición (salga del bucle con la variable j) y busque la siguiente posición no procesada (en el bucle con la variable i).

 // change of position volume by the current instrument, taking into account the volume of current deal
 lots_list[symb_pointer]+=lot_current;
 // if the volume of opened position by the current instrument became equal to zero - position is closed
 if(NormalizeDouble(lots_list[symb_pointer],2)==0 || deal_status[j]==1) break;
}

Las transacciones de venta se procesan de forma similar, y después salimos de bucle con la variable j.

       // if this deal is sell
       if(HistoryDealGetInteger(ticket,DEAL_TYPE)==DEAL_TYPE_SELL)
         {
          // if position has been already opened for buy - this will be the exit from market
          if(NormalizeDouble(lots_list[symb_pointer],2)>0)
            {
             // if sell volume is greater than volume of opened long position - then this is in/out
             if(NormalizeDouble(lot_current-lots_list[symb_pointer],2)>0)
               {
                // creating table of volumes to exit the market - indicate only volume of opened long position
                StringConcatenate(out_table_volume,out_table_volume,"<tr><td align='right'>",DoubleToString(lots_list[symb_pointer],2),"</td></tr>");
                // mark position as partially processed
                deal_status[j]=1;
               }
             else
               {
                // if sell volume is equal or greater than volume of opened short position - then this is partial or full close
                // creating the volume table to exit the market
                StringConcatenate(out_table_volume,out_table_volume,"<tr><td align='right'>",DoubleToString(lot_current,2),"</td></tr>");
                // mark deal as processed
                deal_status[j]=127;
               }

             // creating the time table to exit the market
             StringConcatenate(out_table_time,out_table_time,"<tr><td align='center'>",TimeToString(time_curr,TIME_DATE|TIME_SECONDS),"</td></tr>");

             // creating the price table to exit the market
             StringConcatenate(out_table_price,out_table_price,"<tr><td align='center'>",DoubleToString(HistoryDealGetDouble(ticket,DEAL_PRICE),
             (int)SymbolInfoInteger(symb_list[symb_pointer],SYMBOL_DIGITS)),"</td></tr>");

             // get the swap of current deal
             current_swap=HistoryDealGetDouble(ticket,DEAL_SWAP);

             // if swap is equal to zero - create empty string of the swap table to exit the market
             if(NormalizeDouble(current_swap,2)==0) StringConcatenate(out_table_swap,out_table_swap,"<tr></tr>");
             // else create the swap string in the swap table to exit the market
             else StringConcatenate(out_table_swap,out_table_swap,"<tr><td align='right'>",DoubleToString(current_swap,2),"</td></tr>");

             // get the profit of current deal
             current_profit=HistoryDealGetDouble(ticket,DEAL_PROFIT);

             // if profit is negative (loss) - it is displayed as red in the profit table to exit the market
             if(NormalizeDouble(current_profit,2)<0) StringConcatenate(out_table_profit,out_table_profit,"<tr><td align='right'>
             <SPAN style='COLOR: #EF0000'>",DoubleToString(current_profit,2),"</SPAN></td></tr>");
             // else - it is displayed as green
             else StringConcatenate(out_table_profit,out_table_profit,"<tr><td align='right'><SPAN style='COLOR: #00EF00'>",
                  DoubleToString(current_profit,2),"</SPAN></td></tr>");
            }
          else
            // if position is opened for sell - this will be the enter to the market
            {
             // if this deal has been already partially processed (in/out)
             if(deal_status[j]==1)
               {
                // create the volume table of entering the market (volume, formed after in/out, is put here)
                StringConcatenate(in_table_volume,in_table_volume,"<tr><td align='right'>",DoubleToString(-lots_list[symb_pointer],2),"</td></tr>");

                // indemnity of volume change, which will be produced (the volume of this deal is already taken into account)
                lots_list[symb_pointer]+=lot_current;
               }
             // if this deal has not been processed yet, create the volume table to enter the market
             else StringConcatenate(in_table_volume,in_table_volume,"<tr><td align='right'>",DoubleToString(lot_current,2),"</td></tr>");

             // creating the time table of entering the market
             StringConcatenate(in_table_time,in_table_time,"<tr><td align='center'>",TimeToString(time_curr,TIME_DATE|TIME_SECONDS),"</td></tr>");

             // creating the price table of entering the market
             StringConcatenate(in_table_price,in_table_price,"<tr><td align='center'>",DoubleToString(HistoryDealGetDouble(ticket,DEAL_PRICE),
             (int)SymbolInfoInteger(symb_list[symb_pointer],SYMBOL_DIGITS)),"</td></tr>");

             // mark deal as processed
             deal_status[j]=127;
            }
          // change of position volume by the current instrument, taking into account the volume of current deal
          lots_list[symb_pointer]-=lot_current;
          // if the volume of opened position by the current instrument became equal to zero - position is closed
          if(NormalizeDouble(lots_list[symb_pointer],2)==0 || deal_status[j]==1) break;
         }
      }
   }
}

Si el momento en el que se abrió una posición se encuentra dentro del período del informe (al menos parcialmente), la entrada correspondiente es una salida al archivo "report.html".

// if the position period is in the the report period - the position is printed to report
if(position_EndTime>=StartTime && position_StartTime<=EndTime) FileWrite(file_handle,
in_table_volume,"</table></td>",
in_table_time,"</table></td>",
in_table_price,"</table></td>",
out_table_volume,"</table></td>",
out_table_time,"</table></td>",
out_table_price,"</table></td>",
out_table_swap,"</table></td>",
out_table_profit,"</table></td></tr>");

Asigne la variable balance_prev con el valor de saldo. Salga del bucle con la variable i.

   }
 // changing balance
 balance_prev=balance;
}

Escriba el final del archivo HTML (enlaces a imágenes, el final del alineamiento central, el final de la parte principal, el final del documento HTML). Cierre el archivo "report.html".

// create the end of html-file
FileWrite(file_handle,"</table><br><br><h2>Balance Chart</h2><img src='picture1.gif'><br><br><br><h2>Price Chart</h2><img src='picture2.gif'></center></body></html>");
// close file
FileClose(file_handle);

No espere a la actualización del gráfico más del tiempo especificado en la constante de frecuencia.

// get current time
time_curr=TimeCurrent();
// waiting for chart update
while(SeriesInfoInteger(Symbol(),Picture1_period,SERIES_BARS_COUNT)==0 && TimeCurrent()-time_curr<timeout) Sleep(1000);

Configure el máximo y mínimo en el gráfico.

// setting maximal and minimal values for the balance chart (10% indent from upper and lower boundaries)
ChartSetDouble(hChart,CHART_FIXED_MAX,max_val+(max_val-min_val)/10);
ChartSetDouble(hChart,CHART_FIXED_MIN,min_val-(max_val-min_val)/10);

Configure las propiedades de un gráfico de saldo.

// setting properties of the balance chart
ChartSetInteger(hChart,CHART_MODE,CHART_LINE);                // chart as line
ChartSetInteger(hChart,CHART_FOREGROUND,false);               // chart on foreground
ChartSetInteger(hChart,CHART_SHOW_BID_LINE,false);            // hide BID line
ChartSetInteger(hChart,CHART_COLOR_VOLUME,White);             // volumes and orders levels are white
ChartSetInteger(hChart,CHART_COLOR_STOP_LEVEL,White);         // SL and TP levels are white
ChartSetInteger(hChart,CHART_SHOW_GRID,true);                 // show grid
ChartSetInteger(hChart,CHART_COLOR_GRID,LightGray);           // grid is light-gray
ChartSetInteger(hChart,CHART_SHOW_PERIOD_SEP,false);          // hide period separators
ChartSetInteger(hChart,CHART_SHOW_VOLUMES,CHART_VOLUME_HIDE); // hide volumes
ChartSetInteger(hChart,CHART_COLOR_CHART_LINE,White);         // chart is white
ChartSetInteger(hChart,CHART_SCALE,0);                        // minimal scale
ChartSetInteger(hChart,CHART_SCALEFIX,true);                  // fixed scale on vertical axis
ChartSetInteger(hChart,CHART_SHIFT,false);                    // no chart shift
ChartSetInteger(hChart,CHART_AUTOSCROLL,true);                // autoscroll enabled
ChartSetString(hChart,CHART_COMMENT,"BALANCE");               // comment on chart

Redibuje el gráfico de saldo.

// redraw the balance chart
ChartRedraw(hChart);
Sleep(8000);

Haga una captura de pantalla del gráfico (guarde la imagen "picture1.gif"). La anchura del gráfico se ajusta a la anchura del período del informe (aunque, a causa de las fiestas, se dan a menudo errores, y el gráfico se hace más ancho que la curva de cambio de saldo), y la altura se calcula como la mitad de la anchura.

// screen shooting the balance chart
ChartScreenShot(hChart,"picture1.gif",(int)(EndTime-StartTime)/PeriodSeconds(Picture1_period),
(int)(EndTime-StartTime)/PeriodSeconds(Picture1_period)/2,ALIGN_RIGHT);

Elimine todos los objetos del gráfico y cerrarlo.

// delete all objects from the balance chart
ObjectsDeleteAll(hChart);
// close chart
ChartClose(hChart);

Si se permite el envío de archivos por FTP, enviar tres archivos: "report.html", picture1.gif " y " picture2.gif ".

// if report publication is enabled - send via FTP
// HTML-file and two images - price chart and balance chart
if(TerminalInfoInteger(TERMINAL_FTP_ENABLED))
   {
    SendFTP("report.html");
    SendFTP("picture1.gif");
    SendFTP("picture2.gif");
   }
}

Por ahora, la descripción del programa está completa. Para enviar archivos por FTP, deberá ajustar su configuración de MetaTrader 5: vaya al menú Tools (Herramientas), después Options (Opciones) y después abra la pestaña Publisher (Publicador) (Figura 4).

Figura 4. Opciones para publicar un informe por FTP.

Figura 4. Opciones para publicar un informe por FTP.

En el cuadro de diálogo deberá asegurarse de activar la opción "Enable" ("Permitir"), especificar el número de cuenta, dirección FTP, ruta nombre de usuario y contraseña de acceso. La periodicidad de actualización no tiene importancia.

Ahora puede ejecutar el script. Tras la ejecución, aparece en pantalla el gráfico de saldo durante unos segundos, y después desaparece. En el Journal (Diario) puede encontrar posibles errores y ver si los archivos se enviaron por FTP. Si todo funciona bien, tres nuevos archivos aparecerán en el servidor, en la carpeta especificada. Si coloca allí dos archivos de imagen en forma de flecha, y si el servidor WWW está configurado y funciona correctamente, puede abrir un informe en su navegador web.

2. Enviar notificaciones como mensaje SMS a un teléfono móvil

Hay ocasiones en las que se encuentra lejos de su ordenador y otros aparatos electrónicos, y solo tiene su teléfono móvil a mano. Pero usted siempre querrá tener control sobre las operaciones de trading en su cuenta o monitorizar las cuotas para el instrumento financiero. En este caso, puede configurar el envío de notificaciones por mensaje SMS a un teléfono móvil. Muchas compañías telefónicas ofrecen un servicio de EMAIL-SMS que le permitirá recibir mensajes como cartas enviadas a una dirección de correo electrónico especificada.

Para ello, debe tener un buzón de correo electrónico (particularmente, debe conocer su servidor SMTP). Ajuste su configuración de MetaTrader 5: vaya al menú Tools (Herramientas), después Options (Opciones) y abra la pestaña Email (Correo Electrónico) (Figura 5).

Figura 5. Configurar el envío de notificaciones por correo electrónico

Figura 5. Configurar el envío de notificaciones por correo electrónico

Active la opción "Enable" ("Permitir"), especifique una dirección de servidor SMTP, nombre de usuario y contraseña, dirección del remitente (su correo electrónico) y la del recipiente, es decir, la dirección de correo electrónico usada para enviar mensajes como SMS (compruebe el servicio con su compañía telefónica). Si todo está correcto, entonces al hacer click en el botón "Test" se enviará un mensaje de verificación (vea información adicional en el Diario).

La forma más fácil de recibir una notificación cuando el precio llega a un nivel determinado es crear una alerta. Para hacer esto, abra la pestaña Toolbox (Caja de Herramientas) correspondiente y seleccione Create (Crear) (Figura 6).

Figura 6. Crear una alerta

Figura 6. Crear una alerta

En esta ventana, active la opción "Enable" ("Permitir"), seleccione la acción "Mail", seleccione el instrumento financiero, introduzca el valor para la condición y escriba el texto del mensaje. En "Maximum iterations" ("Máximo de iteraciones"), introduzca el valor 1 si no quiere que el mensaje aparezca repetidamente. Tras completar todos los campos, haga click en OK.

Si enviamos un mensaje desde un programa MQL5, tendremos más posibilidades. Usaremos la función SendMail(). Tiene dos parámetros. Primero, el título; segundo, el cuerpo del mensaje.

Puede llamar a la función SendMail() después de la solicitud de trading (función OrderSend()), o en el controlador de eventos Trade. Así tendremos notificaciones de eventos de trading: entrada al mercado, establecimiento de órdenes, cierre de posiciones. O puede colocar la función SendMail() dentro de OnTimer(): recibiremos notificaciones periódicas sobre las cuotas actuales. Puede configurar el envío de notificaciones cuando aparecen determinadas señales de trading: cuando las líneas del indicador se cruzan, cuando el precio alcanza algunas líneas y niveles, etc.

Pongamos algunos ejemplos.

Si en un Asesor Experto o en un script sustituye

OrderSend(request,result};

 con lo siguiente

string msg_subj,msg_text;
if(OrderSend(request,result))
  {
   switch(request.action)
     {
      case TRADE_ACTION_DEAL:
         switch(request.type)
           {
            case ORDER_TYPE_BUY:
               StringConcatenate(msg_text,"Buy ",result.volume," ",request.symbol," at price ",result.price,", SL=",request.sl,", TP=",request.tp);
               break;
            case ORDER_TYPE_SELL:
               StringConcatenate(msg_text,"Sell ",result.volume," ",request.symbol," at price ",result.price,", SL=",request.sl,", TP=",request.tp);
               break;
           }
         break;
      case TRADE_ACTION_PENDING:
         switch(request.type)
           {
            case ORDER_TYPE_BUY_LIMIT:
               StringConcatenate(msg_text,"Set BuyLimit ",result.volume," ",request.symbol," at price ",request.price,", SL=",request.sl,", TP=",request.tp);
               break;
            case ORDER_TYPE_SELL_LIMIT:
               StringConcatenate(msg_text,"Set SellLimit ",result.volume," ",request.symbol," at price ",request.price,", SL=",request.sl,", TP=",request.tp);
               break;
            case ORDER_TYPE_BUY_STOP:
               StringConcatenate(msg_text,"Set BuyStop ",result.volume," ",request.symbol," at price ",request.price,", SL=",request.sl,", TP=",request.tp);
               break;
            case ORDER_TYPE_SELL_STOP:
               StringConcatenate(msg_text,"Set SellStop ",result.volume," ",request.symbol," at price ",request.price,", SL=",request.sl,", TP=",request.tp);
               break;
            case ORDER_TYPE_BUY_STOP_LIMIT:
               StringConcatenate(msg_text,"Set BuyStopLimit ",result.volume," ",request.symbol," at price ",request.price,", stoplimit=",request.stoplimit,
               ", SL=",request.sl,", TP=",request.tp);
               break;
            case ORDER_TYPE_SELL_STOP_LIMIT:
               StringConcatenate(msg_text,"Set SellStop ",result.volume," ",request.symbol," at price ",request.price,", stoplimit=",request.stoplimit,
               ", SL=",request.sl,", TP=",request.tp);
               break;
           }
         break;
       case TRADE_ACTION_SLTP:
          StringConcatenate(msg_text,"Modify SL&TP. SL=",request.sl,", TP=",request.tp);
          break;
       case TRADE_ACTION_MODIFY:
          StringConcatenate(msg_text,"Modify Order",result.price,", SL=",request.sl,", TP=",request.tp);
          break;
       case TRADE_ACTION_REMOVE:
          msg_text="Delete Order";
          break;
     }
  }
  else msg_text="Error!";
StringConcatenate(msg_subj,AccountInfoInteger(ACCOUNT_LOGIN),"-",AccountInfoString(ACCOUNT_COMPANY));
SendMail(msg_subj,msg_text);

entonces, tras la solicitud de trading, la función OrderSend() enviará un mensaje usando la función SendMail(). Incluirá información sobre el número de cuenta de trading, el nombre de un broker y las acciones llevadas a cabo (compra, venta, realización de orden pendiente, modificación o eliminación de orden), tal y como se muestra a continuación:

59181-MetaQuotes Software Corp. Compra de 0.1 EURUSD a un precio d e1.23809, SL=1.2345, TP=1.2415

Y si en cualquier Asesor Experto o Indicador dentro del cuerpo de la función OnInit() comienza el temporizador usando la función EventSetTimer() (solo tiene un parámetro, el período del temporizador en segundos):

void OnInit()
  {
   EventSetTimer(3600);
  }

 en la función OnDeinit() no se olvide de detenerlo usando EventKillTimer():

void OnDeinit(const int reason)
  {
   EventKillTimer();
  }

y en OnTimer() para mandar mensajes usando la función SendMail():

void OnTimer()
  {
   SendMail(Symbol(),DoubleToString(SymbolInfoDouble(Symbol(),SYMBOL_BID),_Digits));
  }

entonces recibirá mensajes sobre el precio del instrumento financiero actual en el período especificado.

Conclusión

Este artículo describe cómo usar el programa MQL5 para crear un archivo HTML y otro de imagen, y cómo subirlos a un servidor WWW por FTP. También describe cómo configurar el envío de notificaciones a su teléfono móvil como SMS.  

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/61

Archivos adjuntos |
report.zip (33.08 KB)
sendreport_en.mq5 (32.06 KB)
La estrategia "Todo o Nada" en Forex La estrategia "Todo o Nada" en Forex
El objetivo de este artículo es crear una estrategia comercial máximamente sencilla que implemente el principio de juego "Todo o Nada". No se plantea la tarea de crear un Asesor Experto rentable. El objetivo consiste en multiplicar el depósito inicial con la probabilidad máximamente posible. ¿Será posible usar Forex para conseguir grandes beneficios contra la probabilidad de perderlo todo, sin saber nada sobre el análisis técnico y sin usar ningunos indicadores?
Un Ejemplo de Estrategia de Trading Basada en Diferencias de Zona Horaria en Continentes Distintos Un Ejemplo de Estrategia de Trading Basada en Diferencias de Zona Horaria en Continentes Distintos
Navegando por Internet es fácil encontrar muchas estrategias que le darán un buen número de recomendaciones diversas. Tomemos una punto de vista interno y observemos el proceso de la creación de estrategias basado en las diferentes zonas horarias en continentes distintos.
Dr. Tradelove o Cómo dejé de preocuparme y escribí un Asesor Experto Autoenseñable Dr. Tradelove o Cómo dejé de preocuparme y escribí un Asesor Experto Autoenseñable
Hace poco más de un año joo nos ha dado en su artículo "Algoritmos genéticos: ¡Es fácil!" una herramienta para la implementación del Algoritmo Genético en MQL5. Pues, vamos a utilizar esta herramienta y crearemos un Asesor Experto que, al alcanzar unas condiciones extremas, realice la Optimización Genética de sus propios parámetros...
Algoritmos Genéticos: ¡Es fácil! Algoritmos Genéticos: ¡Es fácil!
En este artículo, el autor habla sobre cálculos evolucionarios con el uso de un algoritmo genético personalmente desarrollado. Demuestra el funcionamiento de un algoritmo, usando ejemplos, y facilita recomendaciones prácticas para su uso.