English Русский 中文 Deutsch 日本語 Português
preview
Funciones en las aplicaciones MQL5

Funciones en las aplicaciones MQL5

MetaTrader 5Trading | 8 diciembre 2023, 15:32
1 249 1
Mohamed Abdelmaaboud
Mohamed Abdelmaaboud

Introducción

En el mundo de la programación existe un término muy popular que usamos y escuchamos con frecuencia debido a su importancia en cualquier software: hablamos de la función. Precisamente sobre ella discutiremos en este artículo, aprendiendo además a crear software funcional y de alta calidad. Asimismo, veremos qué son las funciones, por qué necesitamos usarlas y cómo podemos utilizarlas en nuestras aplicaciones. Después de ello, veremos algunas funciones simples que se pueden utilizar en cualquier sistema comercial. A lo largo del artículo abarcaremos los siguientes temas:

¡Atención! Toda la información del presente artículo se ofrece «tal cual», únicamente con fines ilustrativos, y no supone ningún tipo de recomendación. El artículo no garantiza ningún resultado en absoluto. Todo lo que ponga en práctica usando este artículo como base, lo hará bajo su propia cuenta y riesgo; el autor no garantiza resultado alguno.


Definición de una función

En esta parte, definiremos las funciones en programación y también veremos sus tipos y ventajas. Una función es un bloque de código declarado con un nombre significativo específico, que puede utilizarse en cualquier otra parte del programa, llamado una y otra vez para realizar una tarea específica. Si tenemos una tarea específica que un programa debe realizar en muchas de sus partes o en muchos programas, crearemos una función o bloque de código para realizar dicha tarea y luego la llamaremos solo en esas partes, sin reescribir todo el código. Entonces podremos decir que una función es un método para abstraer nuestro código. Existen funciones integradas y personalizadas. Una función integrada es una función lista para usar del propio lenguaje de programación, mientras que una función personalizada es una función creada por el usuario según sus necesidades o tareas. En este artículo nos centraremos en las funciones personalizadas.

Supongamos que necesitamos que el programa cierre todas las órdenes abiertas cuando la equidad alcance la reducción máxima, y que dicha tarea deberá realizarse en muchas partes del programa. En este caso, será mejor crear una función e incluir el código o la lógica necesaria para realizar la tarea, y luego llamarla en otras partes, en lugar de repetir el mismo código en todos los lugares necesarios.

Para responder a la pregunta de por qué necesitamos usar este tipo de función, deberemos observar los detalles del uso de funciones personalizadas:

  • Las funciones personalizadas permiten utilizar el método DRY (No te repitas): Crearemos una función que pueda realizar nuestra tarea una vez y luego la llamaremos en cualquier software adecuado.
  • Reutilización: Una vez creada una función, podremos reutilizarla en cualquier momento.
  • "Divide y vencerás": Usando funciones, también podemos dividir un problema grande en otros pequeños y resolver cada uno de ellos.
  • El código se vuelve más legible y comprensible: Cada elemento del código resolverá un problema específico.
  • Abstracción: Sin las funciones, necesitaríamos más líneas de código.
  • Encapsulación: Las funciones ayudan a proteger nuestro código y nuestros datos, haciendo además su gestión más sencilla.
  • Simplificación de la depuración: Las funciones hacen que sea mucho más fácil encontrar y corregir errores.


Estructura de la función

En esta sección veremos:

  • Declaración o definición de una función.
  • Llamada de una función

En primer lugar, necesitaremos definir o declarar una nueva función, por lo que deberemos hacer algo como esto:

returnedDataType functionName(param1, param2)
{
        bodyOfFunction
}
  • (returnedDataType) - tipo de datos que la función deberá retornar tras la ejecución.
  • (functionName) - nombre de la función (se corresponde con la tarea realizada).
  • (param1, param2) - variables o marcadores de posición (si fueran necesarios).
  • (bodyOfFunction) - código completo que realizará la tarea. 

Mostraremos un ejemplo simple. Si necesitamos crear una función simple para realizar la tarea de sumar dos valores, podremos implementarla con el siguiente bloque de código:

//addition function
// returned data type is an integer - the name of the function is add - parameters or arguments are two int variables val1 and val2
int add(int val1, int val2)
  {
   //body of function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of val1 and val2 addition
   int result = val1+val2;
   //Print result in the experts tab
   Print(result);
   //returning value
   return result;
  }

Tras definir nuestra función, deberemos llamarla. Esto se puede hacer llamando al nombre de la función e indicando los parámetros necesarios según nuestra función en la parte deseada del código del programa. En nuestro ejemplo, la llamada a la función tendrá el aspecto que sigue:

   //calling our defined function by its name and specifying arguments
   add(5,15);

Al realizar la llamada, podremos obtener el resultado del valor 20 en la pestaña de expertos según nuestra función y los argumentos especificados, como se muestra en la siguiente imagen.

añadir el resultado de la función

El ejemplo anterior demuestra lo que podemos hacer con una función, pero hay muchas características disponibles que se pueden usar en las funciones. A continuación veremos algunas de ellas.

Función con argumentos

En el último ejemplo hemos utilizado dos variables enteras: val1 y val2. Estas variables se tratan como argumentos de nuestra función. Dichos argumentos pueden ser números enteros, líneas, etc. En nuestro último ejemplo, estas eran variables enteras. Veamos un ejemplo similar con argumentos string:

//sayHello function
// returned data type is string - name of function is sayHello - parameters or arguments are two string variables greeting and name
string sayHello(string greeting, string name)
  {
   //body of function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of greeting and name addition
   string result = greeting+name;
   //Print result in the experts tab
   Print(result);
   //returning value
   return result;
  }

Podemos llamar a esta función de la forma mencionada y encontrar su resultado después de la ejecución, como mostramos a continuación:

resultado de la función sayhello

También pueden ser una combinación de estos tipos de datos dependiendo de lo que necesitemos en nuestra función como parámetros o argumentos para ejecutar el cuerpo de la misma. Estos argumentos también podrán ser el número requerido.

Función sin argumentos

Una función se puede declarar o definir sin especificar sus parámetros o argumentos; también podemos simplemente darle un nombre significativo, luego dejar los argumentos vacíos y rellenarlos completando el cuerpo de la función para realizar la tarea, y después llamar a la función sin especificar argumentos:

//sayHello function
// returned data type is a string - the name of the function is sayHello - no parameters
string sayHello()
  {
   //body of the function that we need the function to perform when calling it
   //create a result new variable to be assigned by the result of greeting and name addition
   string greeting= "Hello, ";
   string name= "World!";
   string result = greeting+name;
   //Print the result in the experts' tab
   Print(result);
   //returning value
   return result;
  }

Cuando llamemos a la función, esta se verá así:

sayHello();

El resultado será el mismo que hemos mencionado antes en la función con argumentos, ya que el cuerpo de la función es el mismo.

Función con valores predeterminados

También definiremos una función y estableceremos valores iniciales o predeterminados para los parámetros, pero aún podemos cambiarlos o actualizarlos a los valores deseados.

//defining function with default values
string sayHello(string greeting= "Hello, ", string name="World!")
  {
   string result = greeting+name;
   Print(result);
   return result;
  }

Luego podremos llamar a la función dos veces para determinar la diferencia entre los valores predeterminados. Si no especificamos parámetros, la función retornará los valores predeterminados:

   sayHello();
   sayHello("Hi, ", "Developer!");

Resultado:

resultado de la función sayhello

Transmisión de parámetros

Como ya hemos mencionado, podemos transmitir a la función datos de cualquier tipo: entero, string, array, etc. Al transmitir los parámetros por valores, las variables de origen en la función permanecerán sin cambios, como al transmitir los valores de los parámetros de la función. También podremos transmitir parámetros de función por referencia si necesitamos actualizar las variables de origen.

A continuación le mostramos un ejemplo sencillo para entender lo que hemos hablado sobre la transmisión por referencia.

//passing by reference
void updateNums(int &val1, int &val2)
  {
   val1*=2;
   val2/=2;
  }

Luego crearemos nuevas variables, imprimiremos sus valores, llamaremos a nuestra función con estas nuevas variables como parámetros e imprimiremos sus valores después de la llamada para ver la diferencia:

//new variables
   int firstNum = 10;
   int secondNum = 20;
   
//before calling function
   Print("before calling: ");
   Print(firstNum, " - " ,secondNum, "\n"); 
   
// calling   
   updateNums(firstNum, secondNum);

// after calling  
   Print("after calling: ");
   Print(firstNum, " - " ,secondNum, "\n"); 

Como resultado, obtendremos los valores de las nuevas variables 10 y 20, y después de la llamada cambiarán a 20 y 10 de acuerdo con el cuerpo de la función. Resultado:

transmisión por referencia

Operador return

Si tenemos una función que retorna un valor, deberemos tener una declaración de retorno. Dependiendo del propósito de la función, podremos tener más de una declaración de retorno en la función, pero si la función retorna un valor, entonces deberá haber al menos una declaración de retorno en la última línea de la función. Puede ser de cualquier tipo, pero no podrá ser un array. Sin embargo, podemos retornar un elemento de un array. Si queremos que la función retorne un array, podremos transmitir un array a la función por referencia como mencionamos anteriormente.

A continuación le mostramos un ejemplo con una declaración return.

string sayHello(string greeting= "Hello, ", string name="World!")
  {
   string result = greeting+name;
   Print(result);
   return result;
  }

Función de tipo void

Si tenemos una función que no retorna un valor, usaremos una función de tipo void, porque este tipo no retorna un valor. Normalmente podemos transmitir los parámetros a una función de este tipo, pero no requiere una declaración return. A continuación le mostramos un ejemplo de dichas funciones.

void add(int val1, int val2)
  {
   int result= val1+val2;
  }

Sobrecarga de funciones

En algunos casos, las funciones tendrán el mismo nombre para realizar la misma tarea, pero con diferentes parámetros. Por ejemplo, si tenemos una tarea de suma, pero necesitamos realizar esa suma para dos valores, y también necesitamos realizar la misma tarea para tres valores, crearemos dos funciones con el mismo nombre, pero cambiando los parámetros según a la tarea. Y esto significará que tendremos una función de sobrecarga que realizará la misma tarea, pero con diferentes parámetros.

Estos parámetros distintos pueden ser parámetros de diferentes tipos, números del mismo tipo de datos o ambos. A continuación le mostramos un ejemplo de una función de sobrecarga con el mismo tipo de datos pero con un número diferente de parámetros:

void overloadingFun(int val1, int val2)
{
   int result=val1+val2;
}

void overloadingFun(int val1, int val2, int val3)
{
   int result=val1+val2+val3;
}

Como podemos ver, tendremos la misma función, pero los parámetros serán diferentes. Al llamar a una función, encontraremos que estas dos funciones aparecen cuando introducimos el nombre de la función, luego podremos seleccionar lo que necesitemos según los detalles de nuestra tarea. A continuación le mostramos un ejemplo de una función de sobrecarga con diferentes parámetros según el tipo de datos:

void overloadingFun(int val1, int val2)
{
   int result=val1+val2;
}

void overloadingFun(string message, int val1, int val2)
{
   int result=message+val1+val2;
}

También podremos seleccionar la función que necesitemos usando los parámetros al llamar a la función.


Aplicaciones

En esta sección, crearemos aplicaciones simples utilizando funciones. Una vez creadas las aplicaciones, podremos llamarlas en diferentes partes del software o incluso en otro software.

Notificaciones sobre noticias

El trading durante las noticias económicas se considera muy arriesgado e indeseable. El calendario económico contiene noticias e indicadores macroeconómicos con su descripción, fecha, hora e importancia, además del significado de dichos eventos económicos. Existen muchas fuentes para actualizar estos importantes valores. El calendario económico también está disponible en el terminal comercial MetaTrader 5. Podrá encontrar su pestaña en la ventana "Herramientas" y configurar exactamente lo que necesite ver según la importancia, las divisas y los países. También hay funciones integradas para trabajar con el calendario económico. Las encontrará en la documentación de MQL5:

Funciones del calendario económico

Por lo tanto, deberemos consultar manualmente el calendario económico para evitar comerciar durante las noticias, o crear una aplicación que nos avise cuando se acerquen noticias. Esta es una tarea continua que necesitaremos en cualquier sistema comercial o en muchos programas de software. Podemos crear la función necesaria y luego llamarla fácilmente. Precisamente a ello vamos a dedicarnos ahora:

Esta aplicación será un asesor. En el ámbito global, crearemos un tipo bool para el nombre de nuestra función (isNewsComing), sin añadir parámetros.

bool isNewsComing()

El cuerpo de la función crearemos un array con el nombre del valor, y su tipo será (MqlCalendarValue), que representará los valores nuevos, en particular el valor real.

MqlCalendarValue values[];

Necesitaremos determinar el día actual definiendo la hora de inicio del día usando (iTime) para retornar la hora de apertura de la barra tras declarar una nueva variable datetime llamada (startTime), así como la hora de finalización del día, que será igual a la hora de inicio específica y el número de segundos del día usando la función (PeriodoSeconds), después de declarar una nueva variable datetime para (endTime)

   datetime startTime=iTime(_Symbol,PERIOD_D1,0);
   datetime endTime=startTime+PeriodSeconds(PERIOD_D1);

Luego obtendremos una serie de valores para todos los eventos del día, utilizando una hora de inicio y una hora de finalización específicas para definir un rango de tiempo y realizar una clasificación según el país y la divisa actuales usando la función CalendarValueHistory. Los parámetros serán un array de valores, la hora de inicio, la hora de finalización, el país y la divisa.

CalendarValueHistory(values,startTime,endTime,NULL,NULL);

Ahora crearemos un ciclo comenzando con el valor (0) para la variable int creada (i), y continuaremos el ciclo si (i) es menor que el tamaño del array de valores del array, y también aumentaremos (i) en un valor

for(int i=0; i<ArraySize(values); i++)

El cuerpo del ciclo for creará una variable de evento y su tipo (MqlCalendarEvent) para las descripciones de los eventos. Podemos utilizarlo en (CalendarEventById).

MqlCalendarEvent event;

Después obtendremos la descripción del evento según su identificador usando (CalendarEventById): sus parámetros serán event_id y event.

CalendarEventById(values[i].event_id,event);

Luego crearemos la variable de país: su tipo será (MqlCalendarCountry) para describir países, y se podrá usar con (CalendarCountryById).

MqlCalendarCountry country;

A continuación obtendremos las descripciones de un país según su identificador usando la función (MqlCalendarCountry). Sus parámetros serán Country_id y el país.

CalendarCountryById(event.country_id,country);

Después estableceremos las condiciones para filtrar los eventos según el símbolo actual o las noticias sobre divisas. La importancia de las noticias es media o alta.

      if(StringFind(_Symbol,country.currency)<0)
         continue;

      if(event.importance==CALENDAR_IMPORTANCE_NONE)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_LOW)
         continue;

Asimismo, estableceremos una condición con un rango de tiempo de notificación (30 segundos antes de que se publique la noticia).

      if(TimeCurrent()>=values[i].time-30*PeriodSeconds(PERIOD_M1) &&
         TimeCurrent()<values[i].time+30*PeriodSeconds(PERIOD_M1))

Luego deberemos imprimir un mensaje en la pestaña Expertos con el nombre del evento y el texto (is coming! Stop Trading...)

Print(event.name, " is coming! Stop Trading...");

Valor de retorno: true

return true;

Si las condiciones no son verdaderas, finalizaremos el ciclo y retornaremos false para finalizar la función.

return false;

Luego podremos llamar a la función en la función OnTick, y si retorna true, necesitaremos imprimir un mensaje (News is coming...!)

   if(isNewsComing())
     {
      Print("News is comming...!");
     }

Ahora hemos creado una función, la hemos llamado y podemos usarla en cualquier parte de nuestro programa según nuestras necesidades. Nuestro siguiente paso tendrá como objetivo garantizar que el código completo de un bloque se pueda volver a leer fácilmente. Los archivos con el código fuente de todas las aplicaciones se adjuntan al artículo.

//+------------------------------------------------------------------+
//| News Alert Function                                              |
//+------------------------------------------------------------------+ 
void OnTick()
  {
   if(isNewsComing())
     {
      Print("News is comming...!");
     }
  }
//+------------------------------------------------------------------+
bool isNewsComing()
  {
   MqlCalendarValue values[];
   datetime startTime=iTime(_Symbol,PERIOD_D1,0);
   datetime endTime=startTime+PeriodSeconds(PERIOD_D1);
   CalendarValueHistory(values,startTime,endTime,NULL,NULL);
   for(int i=0; i<ArraySize(values); i++)
     {
      MqlCalendarEvent event;
      CalendarEventById(values[i].event_id,event);
      MqlCalendarCountry country;
      CalendarCountryById(event.country_id,country);
      if(StringFind(_Symbol,country.currency)<0)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_NONE)
         continue;
      if(event.importance==CALENDAR_IMPORTANCE_LOW)
         continue;
      if(TimeCurrent()>=values[i].time-30*PeriodSeconds(PERIOD_M1) &&
         TimeCurrent()<values[i].time+30*PeriodSeconds(PERIOD_M1))
        {
         Print(event.name, " is coming! Stop Trading...");
         return true;
        }
     }
   return false;
  }
//+------------------------------------------------------------------+

Cálculo del tamaño del lote

Ahora necesitaremos crear una aplicación que pueda calcular el tamaño de lote óptimo después de determinar el porcentaje de riesgo y la pérdida máxima en puntos. También necesitaremos crear una función sobrecargada para calcular el tamaño de lote óptimo después de determinar el porcentaje de riesgo, el precio de entrada y el precio del stop-loss. Crearemos esta aplicación como un script:

Así, crearemos una función llamada OptimalLotSize como double. La primera función tendrá dos parámetros: una variable double del porcentaje de riesgo máximo y una variable double con la pérdida máxima en puntos.

double OptimalLotSize(double maxRiskPrc, double maxLossInPips)

Luego indicaremos lo que deberemos hacer con esos parámetros. Primero, determinaremos el valor de la equidad de la cuenta usando una función (AccountInfoDouble) que retornará el valor de la propiedad de la cuenta correspondiente. En nuestro caso, este será el identificador de la equidad de la cuenta (ENUM_ACCOUNT_INFO_DOUBLE). Después crearemos una notificación con el valor requerido,

   double accEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   Alert("accEquity: ", accEquity);

y determinaremos el tamaño del contrato de un símbolo usando la función (SymbolInfoDouble), que retornará la propiedad correspondiente del símbolo especificado con una variante del nombre del símbolo (_Symbol) para retornar el símbolo actual, y una prop_id igual a (SYMBOL_TRADE_CONTRACT_SIZE) como uno de los valores (ENUM_SYMBOL_INFO_DOUBLE). A continuación, crearemos una notificación con este valor de retorno

   double lotSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   Alert("lotSize: ", lotSize);

Después calcularemos el valor del punto y recibiremos una notificación con el valor requerido

   double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
   Alert("tickValue: ", tickValue);

Asimismo, calcularemos el valor de pérdida máxima según una equidad de cuenta determinada y recibiremos una notificación con este valor

   double maxLossDollar = accEquity * maxRiskPrc;
   Alert("maxLossDollar: ", maxLossDollar);

Luego calcularemos el valor máximo en la divisa cotizada según el valor de pérdida máxima calculado y retornaremos una notificación con este valor

   double maxLossInQuoteCurr = maxLossDollar / tickValue;
   Alert("maxLossInQuoteCurr: ", maxLossInQuoteCurr);

Además calcularemos el tamaño de lote óptimo y retornaremos una notificación con el valor requerido

   double OptimalLotSize = NormalizeDouble(maxLossInQuoteCurr / (maxLossInPips * 0.0001)/ lotSize,2);
   Alert("OptimalLotSize: ", OptimalLotSize);

La declaración return devuelve OptimalLotSize como un valor double.

return OptimalLotSize;

Después de esto, crearemos una función de sobrecarga transmitiendo tres parámetros double para el porcentaje de riesgo máximo, el precio de entrada y el precio del stop-loss.

double OptimalLotSize(double maxRiskPrc, double entryPrice, double stopLoss)

A continuación, determinaremos la pérdida máxima en pips como un valor absoluto basado en los parámetros de entrada del precio de entrada y el precio de stop-loss con la posterior divisón por 0,0001.

double maxLossInPips = MathAbs(entryPrice - stopLoss)/0.0001;

El operador return será la función OptimalLotSize creada con los parámetros de porcentaje de riesgo máximo y pérdida máxima en puntos.

return OptimalLotSize(maxRiskPrc,maxLossInPips);

Luego podremos llamar a cualquiera de las dos funciones en la parte OnStart() según lo que necesitemos.

OptimalLotSize(0.01, 1.12303, 1.11920);

A continuación le mostramos el código completo para crear este tipo de función.

//+------------------------------------------------------------------+
//| lotSize Calc Function                                            |
//+------------------------------------------------------------------+
void OnStart()
  {
   OptimalLotSize(0.01, 1.12303, 1.11920);
  }
//+------------------------------------------------------------------+
double OptimalLotSize(double maxRiskPrc, double maxLossInPips)
  {
   double accEquity = AccountInfoDouble(ACCOUNT_EQUITY);
   Alert("accEquity: ", accEquity);
   double lotSize = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_CONTRACT_SIZE);
   Alert("lotSize: ", lotSize);
   double tickValue = SymbolInfoDouble(_Symbol,SYMBOL_TRADE_TICK_VALUE);
   Alert("tickValue: ", tickValue);
   double maxLossDollar = accEquity * maxRiskPrc;
   Alert("maxLossDollar: ", maxLossDollar);
   double maxLossInQuoteCurr = maxLossDollar / tickValue;
   Alert("maxLossInQuoteCurr: ", maxLossInQuoteCurr);
   double OptimalLotSize = NormalizeDouble(maxLossInQuoteCurr / (maxLossInPips * 0.0001)/ lotSize,2);
   Alert("OptimalLotSize: ", OptimalLotSize);
   return OptimalLotSize;
  }
//+------------------------------------------------------------------+
double OptimalLotSize(double maxRiskPrc, double entryPrice, double stopLoss)
  {
   double maxLossInPips = MathAbs(entryPrice - stopLoss)/0.0001;
   return OptimalLotSize(maxRiskPrc,maxLossInPips);
  }
//+------------------------------------------------------------------+

Tras ejecutar este script, recibiremos la siguiente advertencia

 lotSize

Al igual que sucede con la aplicación anterior, tendremos una función lotSize Calc que podremos usar y llamar fácilmente en diferentes partes del programa para completar la tarea sin tener que reescribir el código.

Cierre de todas las aplicaciones

Aquí necesitaremos crear un script que pueda cerrar las órdenes abiertas y pendientes, implementando para ello una función que pueda usarse o invocarse en cualquier parte del programa que corresponda.

Incluiremos la clase Trade en el código usando el preprocesamiento o #include para incluir todas las funciones comerciales en el archivo (Trade.mqh).

#include <Trade/Trade.mqh>

Luego crearemos un objeto con el tipo de clase CTrade que se utilizará en el programa.

CTrade trade;

En el ámbito global, también necesitaremos crear una función closeAll vacía sin argumentos.

void closeAll()

El cuerpo de la función creará un ciclo for para comprobar las órdenes abiertas.

for(int i=PositionsTotal()-1; i>=0; i--)

 Cuerpo del ciclo, creación de la variable ulong posTicket y asignación del ticket de órdenes abiertas a la misma

ulong posTicket=PositionGetTicket(i);

Luego cerraremos una operación abierta usando trade.PositionClose(posTicket)

trade.PositionClose(posTicket);

Asimismo, eliminaremos las órdenes pendientes creando otro ciclo for para detectar dichas órdenes, asignando sus tickets a la variable ulong posTicket y eliminando la orden pendiente según su ticket detectado.

   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      ulong posTicket=OrderGetTicket(i);
      trade.OrderDelete(posTicket);
     }

Después de esto podremos llamar a esta función en OnStart().

closeAll();

El script cerrará y eliminará todas las órdenes. A continuación le mostramos el código completo de closeAllApp:

//+------------------------------------------------------------------+
//| closeAll Function                                                |
//+------------------------------------------------------------------+ 
#include <Trade/Trade.mqh>
CTrade trade;
//+------------------------------------------------------------------+
void OnStart()
  {
   closeAll();
  }
//+------------------------------------------------------------------+
void closeAll()
  {
//close all open positions
   for(int i=PositionsTotal()-1; i>=0; i--)
     {
      ulong posTicket=PositionGetTicket(i);
      trade.PositionClose(posTicket);
     }
//delete all pending orders
   for(int i=OrdersTotal()-1; i>=0; i--)
     {
      ulong posTicket=OrderGetTicket(i);
      trade.OrderDelete(posTicket);
     }
  }
//+------------------------------------------------------------------+

Las aplicaciones analizadas son solo ejemplos de lo que podemos crear usando funciones personalizadas. Podrá crear cualquier otra aplicación o función según sus necesidades, como trailing stops, gestión comercial, aplicaciones de reducción, etc.


Conclusión

El uso de funciones posee una serie de ventajas innegables:

  • Las funciones permiten utilizar el método DRY.
  • Esto nos ayudará a simplificar la solución de cualquier tarea voluminosa dividiéndola en tareas pequeñas.
  • Hace que el código sea más legible.
  • Permite la reutilización.
  • Posibilita la abstracción del código.
  • Permite encapsular el código.
  • Mejora la depuración.

También hemos analizado los tipos de funciones (integradas y definidas por el usuario) y cómo crear y definir estas; asimismo, hemos analizado la estructura y las características de las funciones, incluidas las funciones con argumentos, la transmisión de esos argumentos o parámetros sin argumentos y las funciones con valores predeterminados. Esto supone que podemos definir una función utilizando cualquier tipo de datos y trabajar con el operador return. También hemos aprendido a crear múltiples funciones de sobrecarga con el mismo nombre pero diferentes argumentos para realizar la misma tarea.

Espero que los ejemplos de las aplicaciones le hayan ayudado a comprender mejor el tema:

  • New Alert App - notificaciones sobre noticias importantes. Puede usarse o llamarse en cualquier parte del programa. El código fuente de newsAlertApp se adjunta a continuación.
  • Lot size Calc App - obtener el tamaño de lote óptimo para abrir una operación según un determinado porcentaje de riesgo, precio de entrada y precio de stop-loss. O bien usando como base un cierto porcentaje de riesgo y una pérdida máxima en puntos, lo cual significará que hemos creado una función de sobrecarga en esta aplicación. También podemos utilizarla o llamarla en cualquier parte del programa. El código fuente de lotSizeCalcApp se adjunta a continuación.
  • Close All App - cerrar todas las órdenes abiertas y pendientes. El código fuente de closeAllApp se adjunta a continuación.

El mundo de las funciones es muy interesante y debemos prestarle atención para poder crear fragmentos de código útiles de forma fácil y eficiente. Espero que el artículo le haya resultado útil y haya ampliado su arsenal de herramientas comerciales. Si quiere aprender más sobre programación o cómo crear sistemas comerciales basados ​​en los indicadores técnicos más populares como la media móvil, RSI, MACD, Estocástico, Bandas de Bollinger, Parabolic Sar y otros, puede leer mis artículos anteriores y tal vez encuentre algo útil.

Traducción del inglés realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/en/articles/12970

Archivos adjuntos |
newsAlertApp.mq5 (1.37 KB)
lotSizeCalcApp.mq5 (1.45 KB)
closeAllApp.mq5 (0.86 KB)
Hilario Miguel Ofarril Gonzalez
Hilario Miguel Ofarril Gonzalez | 9 dic. 2023 en 16:43
Sumarle al conocimiento.para enceñar el punto expesifico.donde aprendemos de otros . estrategias.muy concretas .y continuar de manera precisa.es como estar en una batalla dónde los números son infinitos .de ello es como digo yo sentirce satisfechos .cuando ganamos la güera .el programa.de las defensas en el tradi.es tratar de cobertice en ganadores .sin afectar.nuestras inversiones.sin dejar pasar .ke existiendo el esfuerzo.nos hace más útiles .a la hora .de poner a prueba nuestro sacrificio.me dedico a leer cada adticulo de cada maestro .y de ello aprendo .llevando a práctica el deceo de convertirme en un gran maestro .como ellos y trasmitir .enceñasmzas .para ke el mundo del tradi ..sea más fuerte .eso es lo ke nos define entre todos .. voluntad.y sacrificio....vale
Transformada discreta de Hartley Transformada discreta de Hartley
En este artículo nos familiarizaremos con uno de los métodos de análisis espectral y de procesamiento de señales: la transformada discreta de Hartley. Con ella podremos filtrar señales, analizar su espectro y mucho más. Las capacidades de la DHT no son inferiores a las de la transformada discreta de Fourier. Sin embargo, a diferencia de este, la DHT utiliza solo números reales, lo cual la hace más cómoda de implementar en la práctica y los resultados de su aplicación resultan más visuales.
StringFormat(). Panorámica, ejemplos de uso listos para aplicar StringFormat(). Panorámica, ejemplos de uso listos para aplicar
El artículo supone una continuación de la revisión de la función PrintFormat(). Hoy veremos brevemente cómo formatear líneas utilizando StringFormat() y su uso posterior en el programa. Asimismo, escribiremos plantillas para mostrar información sobre un símbolo en el registro del terminal. El presente artículo resultará útil tanto a principiantes como a desarrolladores experimentados.
El modelo de movimiento de precios y sus principales disposiciones (Parte 3): Cálculo de parámetros óptimos en el juego bursátil El modelo de movimiento de precios y sus principales disposiciones (Parte 3): Cálculo de parámetros óptimos en el juego bursátil
En el marco del presente enfoque de ingeniería desarrollado por el autor, basado en la teoría de la probabilidad, se encuentran las condiciones para abrir una posición rentable, y también se calculan los valores óptimos (que maximizan las ganancias) para el stop loss y el take profit.
Analizamos PrintFormat() y tomamos ejemplos listos para usar Analizamos PrintFormat() y tomamos ejemplos listos para usar
El presente artículo resultará útil tanto a principiantes como a desarrolladores experimentados. En él veremos el funcionamiento de la función PrintFormat(), analizaremos ejemplos de formato string y escribiremos plantillas para enviar información diversa al registro del terminal.