English Русский 中文 Deutsch 日本語 Português
preview
Cómo construir un EA que opere automáticamente (Parte 14): Automatización (VI)

Cómo construir un EA que opere automáticamente (Parte 14): Automatización (VI)

MetaTrader 5Trading | 17 mayo 2023, 09:44
413 0
Daniel Jose
Daniel Jose

Introducción

En el artículo anterior, Cómo construir un EA que opere automáticamente (Parte 13): Automatización (V), expliqué cómo tú, incluso sin conocimientos en programación, puedes llegar a crear las bases necesarias, para poder convertir el EA, que estoy mostrando en esta secuencia, en un EA automático. Estos conceptos e información se aplican a cualquier EA, incluidos los que tú puedas crear. En este artículo, estoy enseñando una de las muchas maneras de llevar a cabo esta tarea.

Es fundamental comprender completamente el contenido del artículo anterior para entender realmente lo que se tratará aquí. Sin ese conocimiento, el contenido de este artículo puede llegar a ser confuso y difícil de entender. Si no estás familiarizado con el artículo anterior, te recomiendo que lo leas antes de continuar. Dicho esto, vayamos al punto central: cómo transformar un EA inicialmente manual en un EA automático.


El nacimiento de la clase C_Automaton

En el artículo anterior se mostraba la siguiente figura:

Figura 01

Figura 01 - Modo de funcionamiento manual.

Esta figura representa la interacción del operador con la plataforma para abrir o cerrar posiciones en el servidor comercial. Para automatizar este proceso, es necesario realizar algunos cambios en esta figura. Así, la figura 01, que representa el modelo manual, se convertirá en la figura 02. Esta figura representa un EA operando automáticamente con base en una operación definida durante la programación.

Figura 02

Figura 02 - Modo de funcionamiento automático.

Es importante destacar que en la figura 02 aparece la imagen de un ser humano como supervisor del sistema. Un sistema automático nunca debe dejarse funcionando sin supervisión. Es esencial que un operador humano esté siempre supervisando, aunque sólo esté observando sin hacer nada.

En la misma figura, se puede notar la presencia de una clase adicional entre el EA y la clase C_Manager, llamada C_Automaton. Este artículo tratará principalmente de esta clase y su relación con el EA y la clase C_Manager, sustituyendo al operador a la hora de abrir y cerrar posiciones o enviar órdenes pendientes al libro.

Una vez más, es importante destacar que no se realizará ninguna modificación en el sistema existente, que debe estar funcionando correctamente, seguro, robusto, estable y fiable antes de la introducción de la clase C_Automaton. Por lo tanto, si hay modificaciones en el sistema presentado, la clase C_Automaton debe ser eliminada, la clase C_Mouse debe ser restaurada y el sistema debe ser probado con los cambios realizados. Sólo cuando el sistema esté funcionando perfectamente es que la clase C_Automaton puede ser reintroducida para que el EA funcione sin intervención humana. Sin embargo, recuerda siempre la necesidad de supervisión. La intervención humana debe ser el último recurso, pero la supervisión debe ser constante.

Antes de examinar cómo se programa la clase C_Automaton, echaremos un breve vistazo al código del EA, que ya ha sido modificado para su uso automatizado. El código COMPLETO para el EA puede verse a continuación en su totalidad:

#property copyright "Daniel Jose"
#property description "This one is an automatic Expert Advisor"
#property description "for demonstration. To understand how to"
#property description "develop yours in order to use a particular"
#property description "operational, see the articles where there"
#property description "is an explanation of how to proceed."
#property version   "1.14"
#property link      "https://www.mql5.com/pt/articles/11318"
//+------------------------------------------------------------------+
#include <Generic Auto Trader\C_Automaton.mqh>
//+------------------------------------------------------------------+
C_Automaton *automaton;
//+------------------------------------------------------------------+
input int       user01   = 1;           //Leverage Factor
input double    user02   = 100;         //Take Profit ( FINANCE )
input double    user03   = 75;          //Stop Loss ( FINANCE )
input bool      user04   = true;        //Day Trade ?
input double    user08   = 35;          //BreakEven ( FINANCE )
//+------------------------------------------------------------------+
input string    user90  = "00:00 - 00:00";      //Sunday
input string    user91  = "09:05 - 17:35";      //Monday
input string    user92  = "10:05 - 16:50";      //Tuesday
input string    user93  = "09:45 - 13:38";      //Wednesday
input string    user94  = "11:07 - 15:00";      //Thursday
input string    user95  = "12:55 - 16:25";      //Friday
input string    user96  = "00:00 - 00:00";      //Saturday
//+------------------------------------------------------------------+
#define def_MAGIC_NUMBER 987654321
//+------------------------------------------------------------------+
int OnInit()
{
        string szInfo;
        
        automaton = new C_Automaton(def_MAGIC_NUMBER, user03, user02, user01, user04, user08, PERIOD_M5);
        for (ENUM_DAY_OF_WEEK c0 = SUNDAY; c0 <= SATURDAY; c0++)
        {
                switch (c0)
                {
                        case SUNDAY     : szInfo = user90; break;
                        case MONDAY     : szInfo = user91; break;
                        case TUESDAY    : szInfo = user92; break;
                        case WEDNESDAY  : szInfo = user93; break;
                        case THURSDAY   : szInfo = user94; break;
                        case FRIDAY     : szInfo = user95; break;
                        case SATURDAY   : szInfo = user96; break;
                }
                (*automaton).SetInfoCtrl(c0, szInfo);
        }
        (*automaton).CheckToleranceLevel();
        EventSetMillisecondTimer(100);

        return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
        delete automaton;
        EventKillTimer();
}
//+------------------------------------------------------------------+
void OnTick() { }
//+------------------------------------------------------------------+
void OnTimer()
{
        (*automaton).Triggers();
}
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result)
{
        switch (trans.type)
        {
                case TRADE_TRANSACTION_POSITION:
                        (*automaton).UpdatePosition(trans.position);
                        break;
                case TRADE_TRANSACTION_ORDER_DELETE:
                        if (trans.order == trans.position) (*automaton).PendingToPosition();
                        else
                        {
                                (*automaton).UpdatePosition(trans.position);
                                (*automaton).EraseTicketPending(trans.order);
                        }
                        break;
                case TRADE_TRANSACTION_ORDER_UPDATE:
                        (*automaton).UpdatePending(trans.order);
                        break;
                case TRADE_TRANSACTION_REQUEST: if ((request.symbol == _Symbol) && (result.retcode == TRADE_RETCODE_DONE) && (request.magic == def_MAGIC_NUMBER)) switch (request.action)
                        {
                                case TRADE_ACTION_DEAL:
                                        (*automaton).UpdatePosition(request.order);
                                        break;
                                case TRADE_ACTION_SLTP:
                                        (*automaton).UpdatePosition(trans.position);
                                        break;
                                case TRADE_ACTION_REMOVE:
                                        (*automaton).EraseTicketPending(request.order);
                                        break;
                        }
                        break;
        }
}
//+------------------------------------------------------------------+

Noten que sólo hubo unos pocos cambios en este código. El manejador del evento OnChartEvent ha sido eliminado, pues ya no es necesario, y una nueva función ha aparecido en el evento OnTime. Más adelante se presentarán más detalles sobre esta función. Por lo demás, el código sigue siendo el mismo que el anterior cuando EA se operaba manualmente. Es extremadamente importante enfatizar que cuando se hace un EA automático, no se debe modificar todo el código. Sólo se deben hacer los cambios necesarios, y en este caso, la única modificación fue la inclusión de la nueva función en el evento temporal; por lo demás, el código sigue siendo idéntico.

No obstante, este código EA no es, subrayo, NO ES, un código definitivo e inmutable. Dependiendo del sistema que se vaya a utilizar, puede haber más o menos definiciones a realizar por el usuario, que se reflejarán aquí, y puede haber variaciones en el constructor de la clase C_Automaton. Por lo tanto, puede ser necesario tener más o menos parámetros aquí. Por lo tanto, no considere este código como una solución para todos los casos.

Pero excluyendo estos puntos que mencioné, básicamente se mantendrá sin mayores cambios. Así que el consejo es estudiar lo que realmente será necesario para el sistema que se va a utilizar. Se deben configurar las partes que no necesitan ser ajustadas por el operador y permitirle ajustar sólo las partes realmente necesarias, dependiendo del tipo de escenario utilizado. En función del tipo de escenario utilizado.

Otra cosa que habrás notado es que la clase C_Automaton hereda de la clase C_Manager. Por eso el código prácticamente no cambia. Como pudiste notar, todo sucederá dentro de la clase C_Automaton.

Así que si quieres usar esta misma estructura de EA y las clases que estoy demostrando, simplemente modifica la clase C_Automaton para que tu sistema operativo se desarrolle dentro de ella. De esta forma, la creación de nuevos EAs utilizando diferentes sistemas operativos será considerablemente más rápida, segura y consistente, ya que la única diferencia entre ellos será la propia clase C_Automaton. Al crear la clase a través del constructor, puedes informar algunas características específicas del sistema operativo, lo que aumentará significativamente el nivel de flexibilidad, usabilidad, robustez y reusabilidad del software.

Así, tu EA siempre cumplirá con los estándares de calidad requeridos por los usuarios. Sin embargo, se pueden hacer algunas modificaciones para hacer las cosas más interesantes. Quizá en el futuro comparta públicamente algunas de estas modificaciones. En cualquier caso, no dudes en modificar y adaptar el sistema a tu modo de funcionamiento. Después de todo, para eso escribo estos artículos y permito el libre acceso al código.

Mi única petición es que, si utilizas cualquier parte de este contenido, se mencione su origen. No es ninguna vergüenza hacerlo, pero es una falta de ética utilizar o distribuir algo sin informar de la fuente.

Ahora, echemos un vistazo a lo que hay dentro de la caja negra de la clase llamada C_Automaton.


Análisis del código de la clase C_Automaton

Como se ha mencionado anteriormente, tanto el código del EA como el código de la clase C_Automaton dependen de cómo se va a operar, cuándo se va a operar y qué se va a operar. Sin embargo, independientemente de estos factores, la clase C_Automaton tiene esencialmente tres funciones internas: un constructor, una función disparada por el evento de tiempo EA, y otra función interna y privada de la clase.

Es importante destacar que serán exactamente estas tres funciones, y sólo ellas. En algunas situaciones, puede que necesites añadir o quitar funciones para ayudar a estas tres, pero la base siempre serán estas tres funciones.

Para no quedarse sólo en la teoría, vean el vídeo a continuación, que puede ser largo para muchos. Sin embargo, quiero enfatizar que no importa qué sistema esté operando, todos, sin excepción, tendrán algún tipo de pérdida, ya sea mayor o menor. Vean el vídeo para entender lo que se explicará más adelante.


Vídeo 01 - Demostración de AE automático (duración +/- 25 min)

En el video, estoy utilizando un sistema operativo donde el EA utiliza una media móvil exponencial de 9 para generar las entradas al inicio de cada nueva barra. La creación de este sistema fue cubierta en un artículo anterior, así que léelo para entender el proceso detrás de lo que se verá aquí. Sin embargo, para hacer las cosas menos teóricas y permitirte, como entusiasta, entender cómo la clase C_Automaton permite al EA crear, gestionar y cerrar una operación, veremos algunos ejemplos de código para crear configuraciones específicas.

Sigue con nosotros mientras explicamos cada uno de los métodos y vemos cómo fueron desarrollados y codificados. De esta manera, podrás desarrollar casi cualquier "setup", aunque hay casos muy específicos que pueden requerir un poco más de código. Sin embargo, como estos casos son poco frecuentes y la mayoría de la gente utiliza indicadores, estos ejemplos le serán bastante útiles para crear su modelo operativo totalmente automatizado. Antes de sumergirnos en el código en sí, veamos algunos pequeños detalles sobre el mismo.


Partes comunes, partes dependientes

Para que no te pierdas en la explicación del código de la clase C_Automaton cuando veas los ejemplos, vamos a aclarar una cuestión inicial.

El código de la clase C_Automaton es peculiar, pero para los programadores experimentados es algo común. Hay partes comunes en todas las operaciones y partes que dependen de la operación específica. Es importante que te des cuenta de esto cuando describas tu método, como se muestra en el artículo anterior. Si no entiendes que hay elementos comunes en todos los modelos, puedes pensar que la clase C_Automaton no puede cubrir tu modelo, cuando en realidad puede cubrir cualquier modelo. A veces necesitarás añadir algunas variables, pero te mostraré cómo hacerlo para que puedas cubrir cualquier tipo de modelo.

Las partes comunes del código siempre se repetirán, independientemente del modelo que quieras utilizar. Las partes dependientes son las que hacen que tu modelo sea único y no se repetirán en otro modelo.

Veamos a continuación el código común para cualquier modelo:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_Manager.mqh"
//+------------------------------------------------------------------+
class C_Automaton : public C_Manager

{
        protected:
                enum eTrigger {TRIGGER_NONE, TRIGGER_BUY, TRIGGER_SELL};
        private :
                struct st00
                {
                        int     Shift,
                                nBars;
                        double  OverBought,
                                OverSold;
                }m_Infos;
                double  m_Buff[];
                int     m_nBars,
                        m_Handle;
                ENUM_TIMEFRAMES m_TF;
//+------------------------------------------------------------------+
static eTrigger m_Memory;
//+------------------------------------------------------------------+  
inline eTrigger CheckTrigger(void)
                        {
                               int iRet;

                               if (((iRet = iBars(NULL, m_TF)) > m_nBars) && (m_Handle != INVALID_HANDLE))
			       {
			       }

                               return TRIGGER_NONE;
                        }
//+------------------------------------------------------------------+  
        public  :
//+------------------------------------------------------------------+
                C_Automaton(const ulong magic, double FinanceStop, double FinanceTake, uint Leverage,
                                                bool IsDayTrade, double Trailing, const ENUM_TIMEFRAMES iPeriod,
                                                const double OverBought = 70, const double OverSold = 30, const int iShift = 1)
                        :C_Manager(magic, FinanceStop, FinanceTake, Leverage, IsDayTrade, Trailing, true, 10),
                         m_TF(iPeriod),
                         m_Handle(INVALID_HANDLE)
                        {
                                m_Infos.Shift      = iShift;
                                m_Infos.OverBought = OverBought;
                                m_Infos.OverSold   = OverSold;
                                ArraySetAsSeries(m_Buff, true);
                                m_nBars = iBars(NULL, m_TF);
                        }
//+------------------------------------------------------------------+
inline virtual void Triggers(void) final
                        {
                                if (!CtrlTimeIsPassed()) ClosePosition(); else switch (CheckTrigger())
                                {
                                        case TRIGGER_BUY:
                                                if (m_Memory == TRIGGER_SELL) ClosePosition();
                                                if (m_Memory != TRIGGER_BUY) ToMarket(ORDER_TYPE_BUY);
                                                m_Memory = TRIGGER_BUY;
                                                break;
                                        case TRIGGER_SELL:
                                                if (m_Memory == TRIGGER_BUY) ClosePosition();
                                                if (m_Memory != TRIGGER_SELL) ToMarket(ORDER_TYPE_SELL);
                                                m_Memory = TRIGGER_SELL;
                                                break;
                                }
                        };
//+------------------------------------------------------------------+  
};
//+------------------------------------------------------------------+
static C_Automaton::eTrigger C_Automaton::m_Memory = TRIGGER_NONE;
//+------------------------------------------------------------------+

Todo lo que ves en el código anterior forma parte del código común presente en cualquier modelo. No importa cuál sea el modelo, este código siempre estará presente. Es cierto que pueden aparecer algunas nuevas variables y llamadas a la clase C_Manager, como verás en los ejemplos de código. Pero esencialmente, el código anterior permanecerá prácticamente intacto.

Todo lo que no está presente en el código anterior forma parte del código dependiente del modelo que estás diseñando. Veamos este código para que entiendas cómo funciona y así sepas qué añadir o no añadir al código para cubrir un modelo más específico.

Empecemos con la declaración de la clase, en el fragmento de abajo:

#include "C_Manager.mqh"
//+------------------------------------------------------------------+
class C_Automaton : public C_Manager
{
        protected:
                enum eTrigger {TRIGGER_NONE, TRIGGER_BUY, TRIGGER_SELL};

Aquí declaramos que la clase C_Automaton hereda públicamente de la clase C_Manager. Esto nos permite, al usar la clase C_Automaton, tener acceso a los procedimientos de la clase C_Manager. Esto es importante para inicializar ciertas cosas relacionadas con la clase de control. Si te fijas en el código EA, te darás cuenta de estos puntos donde se accede a los procedimientos. Aunque no estén declarados en la clase C_Automaton, estos procedimientos provienen de otras clases. Esto ya lo he explicado en otro artículo de esta secuencia.

También creamos un enumerador para tener programación de alto nivel en la clase. Esta enumeración indica qué tipo de disparo se accionó. Un detalle: aunque esta enumeración está declarada en la cláusula protected, no se utilizará fuera de la clase. Sin embargo, fue necesario ponerlo en esta cláusula para inicializar una variable estática de la clase, pero eso será cubierto más adelante.

Lo siguiente es las variables, que se pueden ver en el fragmento de abajo:

        private :
                struct st00
                {
                        int     Shift,
                                nBars;
                        double  OverBought,
                                OverSold;
                }m_Infos;
                double  m_Buff[];
                int     m_nBars,
                        m_Handle;
                ENUM_TIMEFRAMES m_TF;
//+------------------------------------------------------------------+
static eTrigger m_Memory;

En esta estructura rara vez será necesario hacer adiciones, ya que cubre una amplia gama de casos con indicadores. Sin embargo, si utilizas más de un indicador, puede que necesites añadir más estructuras. No será necesario modificar los elementos de la estructura en sí.

Para ilustrar lo que acabo de mencionar, consideremos un ejemplo: la estructura está referenciada por una única variable, lo que permite el uso de un solo indicador, sea cual sea. Pero, ¿y si necesitamos utilizar más de un indicador? ¿Cómo proceder? En ese caso, tendremos que hacer algunas adiciones, y estos cambios se verán en los ejemplos. Por ahora, centrémonos en lo básico y entendamos este sistema más sencillo.

Además, tenemos una variable buffer para recibir los valores del indicadoruna variable para almacenar el número de barras del gráfico , otra para referenciar el indicador , y una más para determinar el periodo del gráfico que se utilizará para el indicador.Por último, hay una variable estática que almacena el último estado de disparo. Esta variable estática se inicializa fuera del cuerpo de la clase, como se muestra en el fragmento siguiente:

static C_Automaton::eTrigger C_Automaton::m_Memory = TRIGGER_NONE;

Por defecto, esta función siempre devolverá un disparador nulo, lo que significa que no se producirá ninguna compra o venta. Por lo tanto, nuestro objetivo es evitar disparos accidentales. Sin embargo, dependiendo del modelo operativo, esta variable estática puede no ser tan útil, ya que el modelo en sí siempre genera disparos cruzados. Sin embargo, al colocar el EA en el gráfico, utilizamos esta variable para garantizar que las cosas no sean aleatorias durante la inicialización o al alternar entre posiciones.

El siguiente punto a observar es la función privada de la clase que se puede ver en el siguiente fragmento:

inline eTrigger CheckTrigger(void)
                        {
                                int iRet;
                                        
                                if (((iRet = iBars(NULL, m_TF)) > m_nBars) && (m_Handle != INVALID_HANDLE))
                                {
                                };
                                return TRIGGER_NONE;
                        }

Por defecto, esta función siempre devolverá un disparador nulo, lo que significa que no compraremos ni venderemos. En esta función, se llevará a cabo el cálculo específico de tu sistema operativo, ya que dicho cálculo depende de la operación en cuestión. Aquí encontrarás diferencias en esta función.

Independientemente del tipo de cálculo a realizar, siempre probaremos el sistema de la siguiente manera: el cálculo sólo se realizará en una nueva barra; si no hay nueva barra, el cálculo será ignorado. Además, el handle debe apuntar a algo válido; de lo contrario, no se calculará nada. Es importante definir claramente estas reglas para evitar problemas al ejecutar el EA.

La siguiente función es el constructor de la clase, que puede verse mejor en el fragmento siguiente:

                C_Automaton(const ulong magic, double FinanceStop, double FinanceTake, uint Leverage,
                            bool IsDayTrade, double Trailing, const ENUM_TIMEFRAMES iPeriod,
                            const double OverBought = 70, const double OverSold = 30, const int iShift = 1)
                        :C_Manager(magic, FinanceStop, FinanceTake, Leverage, IsDayTrade, Trailing, true, 10),
                         m_TF(iPeriod),
                         m_Handle(INVALID_HANDLE)
                        {
                                m_Infos.Shift      = iShift;
                                m_Infos.OverBought = OverBought;
                                m_Infos.OverSold   = OverSold;
                                ArraySetAsSeries(m_Buff, true);
                                m_nBars = iBars(NULL, m_TF);
                        }

Es crucial entender completamente este constructor. Reconozco que su código parece confuso y difícil de entender para aquellos sin experiencia o que están empezando en este campo. Sin embargo, la comprensión de este código es fundamental para sacar el máximo provecho de la clase C_Automaton y hacer que su Expert Advisor sea totalmente automático. Por lo tanto, vamos a empezar por entender lo que este texto aparentemente confuso realmente hace.

Como la clase C_Automaton hereda de la clase C_Manager, es necesario inicializar el constructor C_Manager. Por esta razón, recibe datos de EA, que se pasan completos a la clase C_Manager para inicializarla.

Sin embargo, ten en cuenta que aquí hay dos parámetros extra. Puedes hacer que estos sean pasados de vuelta por el EA si lo deseas, pero pueden depender del tipo de operación que se está creando en la clase C_Automaton. Prefiero mencionar estos parámetros aquí para que entiendas lo que significan. Ve la clase C_Manager para más claridad sobre qué valor usar aquí. El código que describe el constructor de la clase se puede encontrar en artículos anteriores, así que no repetiré la explicación aquí.

El EA también te dirá que periodo del gráfico usar para la clase C_Automaton. Utilizaremos este parámetro para ello.

Es importante que el sistema de automatización se ejecute siempre en un periodo gráfico independiente del que está siendo observado por el supervisor. Si utilizamos el mismo periodo gráfico observado por el supervisor en la clase de automatización, podemos provocar que el EA se dispare accidentalmente en momentos inadecuados. Este es un error común en algunos EAs, donde el programador no tiene la noción adecuada de que el usuario puede cambiar el período del gráfico mientras el EA se está ejecutando. Esto puede causar grandes inconvenientes. Sin embargo, al hacerlo de esta manera, nos aseguramos de que el EA siempre observe el mismo periodo del gráfico, independientemente de lo que esté observando el operador supervisor.

En este punto, tenemos algunos parámetros con valores por defecto. Por lo tanto, pueden o no ser declarados en el código del EA. El uso de valores por defecto no impide declarar un valor diferente en el código del EA

o permitir que el operador establezca estos valores al ejecutar el EA. Sin embargo, dado que en la mayoría de los casos estos valores permanecen prácticamente inalterados, y en otros casos ni siquiera se utilizarán, establezco estos parámetros con un valor por defecto para evitar sobrecargar el constructor. Esto hace que el código sea más compacto y más fácil de analizar y entender. Ten en cuenta que estos valores se almacenan en nuestra estructura interna para su uso posterior.

Un detalle importante: si estás utilizando un sistema en el que estos valores pueden ser modificados por el operador, dependiendo del tipo de indicador utilizado, este código puede cambiar para dar cabida a más variables. En este caso, es adecuado para utilizarlo con un único indicador o con varios, siempre que todos utilicen los mismos datos indicados.

Por último, procedemos a inicializar el valor del handle para que no haga referencia a ningún indicador. Esta medida es crucial para evitar posibles fallos de seguridad en caso de que el identificador apunte a un objeto desconocido. Además, llevamos a cabo la configuración final de las variables del sistema. Es importante destacar que este constructor es el punto de partida fundamental y se le agregarán algunas líneas de código adicionales en función del tipo de sistema que se pretenda implementar. Sin embargo, estos detalles serán abordados en los ejemplos de código correspondientes.

Y para terminar con el código base de la clase C_Automaton, veamos el último fragmento, a continuación:

inline virtual void Triggers(void) final
                        {
                                if (!CtrlTimeIsPassed()) ClosePosition(); else switch (CheckTrigger())
                                {
                                        case TRIGGER_BUY:
                                                if (m_Memory == TRIGGER_SELL) ClosePosition();
                                                if (m_Memory != TRIGGER_BUY) ToMarket(ORDER_TYPE_BUY);
                                                m_Memory = TRIGGER_BUY;
                                                break;
                                        case TRIGGER_SELL:
                                                if (m_Memory == TRIGGER_BUY) ClosePosition();
                                                if (m_Memory != TRIGGER_SELL) ToMarket(ORDER_TYPE_SELL);
                                                m_Memory = TRIGGER_SELL;
                                                break;
                                }
                        };

El procedimiento anterior no es un código finalizado al 100%, ya que puede sufrir pequeños cambios dependiendo del sistema operativo en el que se vaya a implementar. Sin embargo, esencialmente nos muestra lo que ocurrirá en cada llamada proveniente del evento OnTime. Muchos pueden tener la tentación de ponerlo en el evento OnTick, pero en artículos anteriores ya expliqué las razones para no hacerlo. Sugiero leer esos artículos para entender las razones.

En resumen, este código instruye a la clase C_Manager a operar siempre con los requerimientos del mercado. Por esta razón afirmo que el código no está 100% finalizado, ya que dependiendo del modelo que se implemente, el sistema de órdenes puede ser diferente, así como la forma en que se producirá el cambio de posición, lo que afectaría a este código.

Otro punto sobre el código anterior es que no permite que el EA incremente la posición a medida que surgen nuevas señales. Esto se debe al uso de una variable de memoria,

que impide que la posición aumente si se genera una nueva señal de entrada. Sin embargo, aquellos con conocimientos básicos de programación pueden sortear esta restricción que añadí intencionadamente. Si alguien intenta hacer esto sin los conocimientos adecuados, seguramente tendrá serias pérdidas en su cuenta, ya que el EA puede disparar órdenes sin control, agotando todo el saldo disponible en cuestión de segundos. Así que si no tienes una comprensión completa de lo que se está programando, no modifiques este código.

Por esta razón, no profundizaré demasiado en la explicación de este código. Sin embargo, hay algo que me gustaría mencionar antes de pasar a los ejemplos de código. Se trata de la declaración de este procedimiento, que a primera vista puede parecer extraña y sin sentido, por lo que es difícil entender por qué se ha hecho así.

Entendamos la razón detrás de esta declaración. Todo el sistema fue diseñado para utilizar un sistema de clases, lo que hace que el código sea más fiable, seguro y robusto, además de permitir su expansión en el tiempo, haciéndolo mucho más complejo de lo inicialmente diseñado. Sin embargo, este aumento de complejidad no se traduce en un aumento considerable del tamaño del código, ya que el sistema de clases nos permite modularizar el código, reduciendo así el tamaño a la vez que aumenta la complejidad.

La clase C_Automaton no es una clase final en el sistema más amplio, y declarar el procedimiento de esta forma indica al compilador que debe ayudarnos a asegurar que este procedimiento en particular no se modifica en otra clase, asegurando que es único en todo el sistema de clases herederas.

Este tipo de precaución es muy importante cuando se trata de código extremadamente modular y bien estructurado. No importa lo bien organizados que estemos, eventualmente cometemos el error de sobrescribir un procedimiento heredado. Si eso ocurre inadvertidamente, todo el código está en peligro. Afortunadamente, el lenguaje MLQ5 nos proporciona el recurso necesario para evitar este tipo de problemas.

Para entender cómo la clase C_Automaton puede ayudar a automatizar el EA en cuestión, veremos algunos ejemplos de código en los que nos centraremos en explicar cómo implementar el sistema operativo. Antes de empezar, es necesario hacer algunas aclaraciones:

  • Ningún sistema operativo automatizado es 100% seguro.
  • No existe ningún sistema que garantice el beneficio en todas las operaciones.
  • No te dejes engañar por ver el sistema funcionando a la primera; esto se puede ver en el video 01.
  • Sólo opera o automatiza un sistema que ya conozcas. No intentes combinar varias estrategias imaginando que obtendrás mejores resultados. La simplicidad es esencial.
  • Utiliza los modelos aquí presentados bajo tu propia responsabilidad, consciente de que pueden generar tanto beneficios como pérdidas.

Para una mejor comprensión de cómo aplicar el código, cada uno de los modelos irá acompañado de un EA exclusivo, lo que le permitirá comparar los códigos y aprender de ellos.


Conclusión

Sin embargo, debido a la extensión del tema, en este artículo sólo se presentarán tres ejemplos de automatización. Los códigos correspondientes se tratarán en el próximo artículo, que probablemente será el último de esta secuencia. Por lo tanto, es importante no perderse el próximo artículo, porque en él veremos cómo todos estos elementos encajan a la perfección, dando vida al EA de forma totalmente automática, siguiendo la plantilla que usted defina.


Traducción del portugués realizada por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/pt/articles/11318

Cómo construir un EA que opere automáticamente (Parte 15): Automatización (VII) Cómo construir un EA que opere automáticamente (Parte 15): Automatización (VII)
Para coronar esta secuencia sobre automatización vamos a complementar lo visto en el artículo anterior. Este muestra definitivamente cómo todo encajará, haciendo que el Asesor Experto funcione como un reloj.
Perceptrón multicapa y algoritmo de retropropagación (Parte 3): Integración con el simulador de estrategias - Visión general (I) Perceptrón multicapa y algoritmo de retropropagación (Parte 3): Integración con el simulador de estrategias - Visión general (I)
El perceptrón multicapa es una evolución del perceptrón simple, capaz de resolver problemas separables no linealmente. Junto con el algoritmo de retropropagación, es posible entrenar eficientemente esta red neuronal. En la tercera parte de la serie sobre el perceptrón multicapa y la retropropagación, mostraremos cómo integrar esta técnica con el simulador de estrategias. Esta integración permitirá utilizar análisis de datos complejos y tomar mejores decisiones para optimizar las estrategias de negociación. En este resumen, analizaremos las ventajas y los retos de la aplicación de esta técnica.
Ejemplo de creación de la estrategia comercial compleja Owl Ejemplo de creación de la estrategia comercial compleja Owl
Mi estrategia se basa en los fundamentos clásicos del trading y en el perfeccionamiento de indicadores ampliamente usados en todo tipo de mercados. En la práctica, se trata de una herramienta lista para usar que nos permite sacar el máximo rendimiento a la nueva estrategia de negociación rentable propuesta.
Cómo construir un EA que opere automáticamente (Parte 13): Automatización (V) Cómo construir un EA que opere automáticamente (Parte 13): Automatización (V)
¿Sabes lo que es un diagrama de flujo? ¿Sabes cómo utilizarlo? ¿Cree que los diagramas de flujo son sólo cosas de aprendiz de programador? Pues echa un vistazo a este artículo y aprende a trabajar con diagramas de flujo.