English Русский 中文 Deutsch 日本語 Português 한국어 Français Italiano Türkçe
preview
Desarrollando un EA comercial desde cero (Parte 20): Un nuevo sistema de órdenes (III)

Desarrollando un EA comercial desde cero (Parte 20): Un nuevo sistema de órdenes (III)

MetaTrader 5Sistemas comerciales | 15 julio 2022, 16:31
576 0
Daniel Jose
Daniel Jose

1.0 - Introducción

En el artículo anterior, Desarrollando un EA comercial desde cero (Parte 19), me centré más en mostrar los cambios que se produjeron en el código para potenciar el nuevo sistema de órdenes, una vez implementados esos cambios, puedo centrarme al 100% en el verdadero problema, que es implementar un sistema de órdenes que sea 100% visual y fácil de entender para los que están operando, sin necesidad de saber ni cuánto vale un tick, ni dónde se debe colocar la orden para ganar X cantidad o dónde está el stop para anticipar una pérdida de Y.

La creación de este sistema es algo que exige un buen dominio de MQL5, así como entender cómo funciona en realidad la plataforma MetaTrader 5 y qué recursos nos proporciona.


2.0 - Planificación

2.0.1 - Diseño de los indicadores

Bueno, la idea aquí, y no sólo la idea, porque lo que voy a hacer de hecho es mostrar cómo implementar el sistema en este artículo, es crear algo que en el gráfico se presenta como la figura de abajo:

Mira que es bastante sencillo saber de qué se trata, incluso sin que yo lo explique conseguimos darnos cuenta de que hay un botón para cerrar, un valor y un punto para facilitar el arrastre de la orden. Pero eso no es todo, cuando el Stop Loss se convierte en un Stop Gain, el sistema se encargará de mostrarlo, y será como se ve a continuación:

Es decir, será muy sencillo saber cuándo, con cuánto, dónde y si vale la pena o no mantener una determinada posición.

Las imágenes anteriores muestran sólo los objetos de los límites de la orden OCO o de la posición OCO, pero no olvidé la parte relacionada con el precio de apertura, porque esto también es importante.

En el caso de la orden pendiente tendrá la siguiente apariencia:

Mientras que para una posición el aspecto será ligeramente diferente, como puede verse a continuación:

Bueno las proporciones no son muy alentadoras.... Pero esta es la idea que se llevará a cabo, en cuanto al tema de los colores, utilizaré estos, pero puedes modificarlos si lo deseas para que sean más de tu gusto.

Siguiendo con la parte de planificación, podemos notar que básicamente tendremos 5 objetos en cada indicador, lo que significa que tendremos que hacer que MetaTrader 5 maneje 5 objetos al mismo tiempo, para cada indicador. En el caso de una orden OCO pendiente, MetaTrader 5 tendrá que lidiar con 15 objetos, así como en el caso de una posición OCO, MetaTrader 5 tendrá que lidiar con 15 objetos, y esto por orden o posición, lo que significa que si tienes 4 órdenes OCO pendientes y 1 posición OCO abierta, MetaTrader 5 tendrá que lidiar con 25 objetos, sin contar con los otros que también estarán en el gráfico del activo, y eso si estás usando un solo activo en la plataforma.

Digo esto porque es importante saber cómo será el consumo de memoria, así como el procesamiento por cada orden que vayas a poner en el activo, no es que esto sea un problema para los ordenadores modernos, pero es necesario saber lo que en realidad le estás exigiendo al equipo, porque hasta entonces se trataba de un solo objeto en la pantalla que por punto de orden, pero ahora cada uno de los puntos tendrá 5 objetos y estos tendrán que permanecer conectados de alguna manera, y quien hará esta conexión será la plataforma, nosotros solo informaremos de cómo deben estar conectados, y lo que ocurre cuando se dispara un evento en cada uno de los objetos.


2.0.2 - Elección de los objetos

La siguiente cuestión es elegir qué objetos utilizaremos, aunque parezca sencillo, es una cuestión muy importante, porque esto definirá cómo se hará en realidad la implementación, la primera elección se basará en la forma de posicionar los objetos en la pantalla.

Pues bien, para ello tenemos 2 tipos o formas de hacerlo, y afortunadamente MetaTrader 5 cubre ambas: la primera es utilizando la posición por coordenadas de tiempo y precio, y la segunda es utilizando las coordenadas cartesianas X e Y.

Bien, pero antes de intentar hacer cualquier tipo de profundización entre una y otra, ya descarto inmediatamente el modelo por coordenadas de tiempo y precio, que a pesar de ser a primera vista ideal, no será nada útil cuando tratemos con muchos objetos que estarán enlazados y que deberán permanecer juntos, por lo que tendremos que utilizar el sistema cartesiano.

En otro artículo ya exploré este sistema y mostré cómo seleccionar los objetos, para más detalles ve Múltiples Indicadores en un Gráfico (Parte 05).

Una vez realizada esta planificación, por fin podemos pasar a la parte de codificación propiamente dicha, es hora de poner las cosas en práctica.


3.0 - Implementación

Como no quiero simplemente implementar un sistema, de hecho quiero que entiendas lo que pasa, para que también puedas hacer tu propio sistema sobre este que te estoy mostrando, te mostraré las cosas poco a poco para que entiendas de hecho cómo se está creando, recordándote que todo lo que vemos en el caso de las órdenes pendientes también funcionará para las posiciones, ya que el sistema sigue los mismos principios y comparte un código común.


3.0.1 - Creación de la base de la interfaz

El resultado de esta primera etapa se puede ver a continuación, esta es mi forma de hacerlo atractivo para que te entusiasmes como lo hice yo cuando desarrollé y decidí compartir este código con todos ustedes. Espero que esto sirva de motivación para aquellos que quieran aprender a programar o en desarrollar un conocimiento más avanzado en la materia.


Mirando la imagen de arriba puedes estar pensando que esto se construyó de manera convencional, abandonando todo el código creado hasta ahora, pero no, vamos a utilizar exactamente lo que se construyó hasta ahora.

Así que partiendo del código del artículo anterior, vamos a hacer algunas modificaciones, como había dicho allí lo que sí necesitábamos hacer, y vamos a añadir algunas clases, en este primer momento vamos a añadir 3 nuevas clases.


3.0.1.1 - La clase C_Object_Base

Comenzaremos creando una nueva clase, la C_Object_Base, esta es la clase más baja de nuestro sistema, los primeros códigos de esta clase se pueden ver a continuación:

class C_Object_Base
{
        public  :
//+------------------------------------------------------------------+
void Create(string szObjectName, ENUM_OBJECT typeObj)
{
        ObjectCreate(Terminal.Get_ID(), szObjectName, typeObj, 0, 0, 0);
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_SELECTABLE, false);
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_SELECTED, false);
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_BACK, true);
        ObjectSetString(Terminal.Get_ID(), szObjectName, OBJPROP_TOOLTIP, "\n");
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_BACK, false);
        ObjectSetString(Terminal.Get_ID(), szObjectName, OBJPROP_TOOLTIP, "\n");
        PositionAxleY(szObjectName, 9999);
};

// ... Resto del código de la clase

Observa que tenemos un código de creación genérico, esto nos facilitará mucho la vida. Siguiendo dentro de esta misma clase tenemos los códigos de posicionamiento estándar en los ejes X e Y.

void PositionAxleX(string szObjectName, int X)
{
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_XDISTANCE, X);
};
//+------------------------------------------------------------------+
virtual void PositionAxleY(string szObjectName, int Y)
{
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_YDISTANCE, Y);
};

El código de posicionamiento en el eje Y dependerá de cada objeto concreto, pero aunque el objeto no tenga uno específico, la clase proporciona uno genérico. También tenemos una forma genérica de indicar el color del objeto, que se realiza mediante el código.

virtual void SetColor(string szObjectName, color cor)
{
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_COLOR, cor);
}

Y también tenemos una forma de definir las dimensiones de los objetos.

void Size(string szObjectName, int Width, int Height)
{
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_XSIZE, Width);
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_YSIZE, Height);
};

De esta manera tenemos la clase C_Object_Base terminada por ahora, luego volveremos a ella.


3.0.1.2 - La clase C_Object_BackGround

Ahora crearemos otras dos clases para soportar nuestros objetos gráficos, la primera es la clase C_Object_BackGround, esta clase creará una caja de fondo para recibir otros elementos posteriormente. Su código es bastante sencillo y puede verse completo a continuación:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
#include "C_Object_Base.mqh"
//+------------------------------------------------------------------+
class C_Object_BackGround : public C_Object_Base
{
        public:
//+------------------------------------------------------------------+
		void Create(string szObjectName, color cor)
                        {
                                C_Object_Base::Create(szObjectName, OBJ_RECTANGLE_LABEL);
                                ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_BORDER_TYPE, BORDER_FLAT);
                                ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_CORNER, CORNER_LEFT_UPPER);
                                ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_COLOR, clrNONE);
                                ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_BGCOLOR, cor);
                        }
//+------------------------------------------------------------------+
virtual void PositionAxleY(string szObjectName, int Y)
                        {
                                int desl = (int)(ObjectGetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_YSIZE) / 2);
                                ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_YDISTANCE, Y - desl);
                        }
//+------------------------------------------------------------------+
};

Fíjate que utilizamos la herencia para poder montar el objeto con un mínimo de código, de esta manera, sólo hacemos que la clase se modifique y se modifique a sí misma según sea necesario, para que luego no tengamos que seguir haciendo estos ajustes. Esto se puede ver en el código resaltado, donde la clase se posicionará automáticamente en la ubicación correcta, simplemente introduciendo el valor del eje Y, comprobará su dimensión y se posicionará para estar en el centro del eje que le estamos pasando.


3.0.1.3 - La clase C_Object_TradeLine

La clase C_Object_TradeLine es la encargada de sustituir esa línea horizontal que se utilizaba antes para informar donde estaba la línea de precio de las órdenes, esta clase es muy curiosa, así que presta atención a su código, en primer lugar tendremos una variable estática privada en ella, se puede ver en el fragmento de abajo.

#property copyright "Daniel Jose"
#include "C_Object_BackGround.mqh"
//+------------------------------------------------------------------+
class C_Object_TradeLine : public C_Object_BackGround
{
        private :
                static string m_MemNameObj;
        public  :
//+------------------------------------------------------------------+

// ... Código interno de la clase

//+------------------------------------------------------------------+
};
//+------------------------------------------------------------------+
string C_Object_TradeLine::m_MemNameObj = NULL;
//+------------------------------------------------------------------+

Está resaltada para que puedas ver cómo debe ser declarada y la forma correcta de inicializarla. En cierto modo se podría crear una variable global para reemplazar lo que hará esta variable estática, pero quiero mantener las cosas dentro del control, así cada objeto tendrá lo que necesita, y la información será guardada por los mismos, así si quiero cambiar un objeto por otro no tendré un gran sobreesfuerzo para hacerlo.

Lo siguiente que hay que ver es el código de creación de objetos.

void Create(string szObjectName, color cor)
{
        C_Object_BackGround::Create(szObjectName, cor);
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_XSIZE, TerminalInfoInteger(TERMINAL_SCREEN_WIDTH));
        SpotLight(szObjectName);
};

Para hacer esto correctamente usamos la clase C_Object_BackGround donde de hecho crearemos una caja que servirá de línea, de nuevo esto es porque si se usara otro tipo de objeto no tendríamos el mismo comportamiento que tendremos, y el único objeto que hace la cosa como se desea es el que está presente en la clase C_Object_Background, así que lo modificaremos para que se adapte a nuestras necesidades, y así crear una línea.

Después de esto vemos el código que se encarga de resaltar una línea.

void SpotLight(string szObjectName = NULL)
{
        if (szObjectName != NULL) ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_YSIZE, (szObjectName != NULL ? 4 : 3));
        if (m_MemNameObj != NULL) ObjectSetInteger(Terminal.Get_ID(), m_MemNameObj, OBJPROP_YSIZE, 3);
        m_MemNameObj = szObjectName;
};

Ahora este código es muy interesante, ya que cuando resaltamos una línea no necesitamos saber cuál fue resaltada, el propio objeto lo hace por nosotros, y cuando una nueva línea merece ser resaltada, automáticamente la línea que estaba resaltada pierde este estatus y la nueva línea toma su lugar, ahora si ninguna línea debe ser resaltada, sólo llamamos a la función, y ésta se encargará de quitar el resaltado de cualquier línea, sin importar cuál sea.

Sabiendo esto, el código anterior junto con el siguiente hace desaparecer el antiguo código de selección, de esta manera MetaTrader 5 nos dirá qué indicador estamos manipulando.

string GetObjectSelected(void) const { return m_MemNameObj; }

Pero aún queda una rutina más por ver, la que produce el posicionamiento de la línea en el eje Y, y esta rutina se ve justo debajo.

virtual void PositionAxleY(string szObjectName, int Y)
{
        int desly = (m_MemNameObj == szObjectName ? 2 : 1);
        ObjectSetInteger(Terminal.Get_ID(), szObjectName, OBJPROP_YDISTANCE, Y - desly);
};

Al igual que la rutina vista en el objeto BackGround, ésta también se ajustará automáticamente al punto correcto dependiendo de si la línea está resaltada o no.

Y así tenemos nuestros dos objetos ahora enteramente completados, pero antes de que podamos realmente verlos en la pantalla como se muestra antes, tenemos que hacer algunas cosas en la clase C_ObjectsTrade.


3.0.2 - Modificación de la clase C_ObjectsTrade

Las modificaciones a realizar no son muy complicadas a primera vista, pero la cantidad de veces que tenemos que repetir el mismo código puede llegar a ser un poco desalentador a veces, así que traté de encontrar una manera de evitar esto, y la manera fue usando macros, pero si usted encuentra confuso seguir un código lleno de macros, siéntase libre de cambiar las macros a funciones o procedimientos, y en casos extremos reemplazar las macros por su propio código interno, pero yo prefiero usar macros por la costumbre de ya hacer esto durante muchos años.

Lo primero que haremos será crear una enumeración de eventos.

enum eEventType {EV_GROUND = 65, EV_LINE};

A medida que se crean los objetos, se deben añadir aquí nuevos eventos, y tienen que ser algo relevante, pero cada objeto tendrá un único tipo de evento, y este evento será generado por MetaTrader 5, nuestro código sólo se encargará de que el evento sea manejado correctamente.

Una vez hecho esto vamos a crear las variables que nos darán acceso a cada uno de los objetos.

C_Object_BackGround     m_BackGround;
C_Object_TradeLine      m_TradeLine;

Estas están en el ámbito global de la clase, pero son privadas, podríamos declararlas en cada función que las utilice, pero eso no tiene mucho sentido, ya que toda la clase se encargará de los objetos.

Ahora, de hecho, tenemos el primer cambio del código del artículo anterior.

inline string MountName(ulong ticket, eIndicatorTrade it, eEventType ev)
{
        return StringFormat("%s%c%c%c%d%c%c", def_NameObjectsTrade, def_SeparatorInfo, (char)it, def_SeparatorInfo, ticket, def_SeparatorInfo, (char)ev);
}

Los puntos destacados no existían antes, pero ahora ayudarán a MetaTrader 5 y a mantenernos informados de lo que ocurre.

Y ha aparecido una nueva rutina.

void SetPositionMinimalAxleX(void)
{
        m_PositionMinimalAlxeX = (int)(ChartGetInteger(ChartID(), CHART_WIDTH_IN_PIXELS) * 0.2);
}

Esta generará un punto de inicio en el eje X para los objetos, cada uno tendrá un punto específico, pero aquí les damos una referencia de inicio, puedes modificar eso para cambiar esa posición de inicio, solo modifica el punto en este fragmento de arriba.

La rutina de selección sufrió un gran cambio, pero cambiará un poco más adelante, por ahora se mantendrá como se ve a continuación.

inline void Select(const string &sparam)
{
        ulong tick;
        double price;
        eIndicatorTrade it;
        eEventType ev;
        string sz = sparam;
                                
        if (!GetInfosOrder(sparam, tick, price, it, ev)) sz = NULL;
        m_TradeLine.SpotLight(sz);
}

Otra rutina que también sufrió cambios fue la que crea el indicador.

inline void CreateIndicatorTrade(ulong ticket, double price, eIndicatorTrade it, bool select)
{
        if (price <= 0) RemoveIndicatorTrade(ticket, it); else
        {
                CreateIndicatorTrade(ticket, it, select);
                PositionAxlePrice(price, ticket, it, -1, -1, 0, false);
        }
}

Pero el fragmento anterior no es lo principal, lo que realmente hace todo el trabajo pesado es lo que vemos a continuación.

inline void CreateIndicatorTrade(ulong ticket, eIndicatorTrade it)
{
        color cor1, cor2;
        string sz0;
                                
        switch (it)
        {
                case IT_TAKE    :
                        cor1 = clrPaleGreen;
                        cor2 = clrDarkGreen;
                        break;
                case IT_STOP    :
                        cor1 = clrCoral;
                        cor2 = clrMaroon;
                        break;
                case IT_PENDING:
                default:
                        cor1 = clrGold;
                        cor2 = clrDarkGoldenrod;
                        break;
        }                               
        m_TradeLine.Create(MountName(ticket, it, EV_LINE), cor2);
        if (ticket == def_IndicatorTicket0) m_TradeLine.SpotLight(MountName(ticket, IT_PENDING, EV_LINE));
        m_BackGround.Create(sz0 = MountName(ticket, it, EV_GROUND), cor1);
        switch (it)
        {
                case IT_TAKE:
                case IT_STOP:
                        m_BackGround.Size(sz0, 92, 22);
                        break;
                case IT_PENDING:
                        m_BackGround.Size(sz0, 110, 22);
                        break;
        }
}

En esta rutina definimos los colores y la secuencia de creación de los objetos, también definimos sus dimensiones, cualquier objeto que se añada al indicador debe ser colocado usando esta rutina para tener todo centrado y siempre siendo probado. Si te pones a crear rutinas para crear los indicadores acabarás creando un tipo de código difícil de mantener y lo que es peor, no se probará en algunos momentos, sólo se probará de hecho cuando creas que todo está bien y lo pongas en una cuenta real, entonces te darás cuenta tarde de que algunas cosas no funcionan como se esperaba. Así que este es el consejo, siempre trate de reunir funciones dentro de las cosas que hacen el mismo trabajo, incluso si no tiene sentido al principio, tendrá sentido con el tiempo, ya que siempre estará probando lo que se está cambiando.

La siguiente rutina que fue modificada y que merece ser destacada se ve a continuación.

#define macroDelete(A)  {                                                               \
                ObjectDelete(Terminal.Get_ID(), MountName(ticket, A, EV_GROUND));       \
                ObjectDelete(Terminal.Get_ID(), MountName(ticket, A, EV_LINE));         \
                        }
                                        
inline void RemoveIndicatorTrade(ulong ticket, eIndicatorTrade it = IT_NULL)
                        {
                                ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, false);
                                if ((it != NULL) && (it != IT_PENDING) && (it != IT_RESULT)) macroDelete(it)
                                else
                                {
                                        macroDelete(IT_PENDING);
                                        macroDelete(IT_RESULT);
                                        macroDelete(IT_TAKE);
                                        macroDelete(IT_STOP);
                                }
                                ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, true);
                        }
#undef macroDelete

Esta rutina, al igual que la siguiente, es un poco aburrida, porque tiene que funcionar a nivel de que seas tú quien seleccione cada uno de los objetos que se crearon, uno por uno, y esto para cada uno de los indicadores. Piensa en ello. Si no fuera por el uso de una macro para facilitar las cosas, el asunto sería una pesadilla, sería extremadamente agotador codificar esta rutina, ya que cada indicador, al terminar el código, tendrá 5 objetos, y sabiendo que cada conjunto en una orden OCO tendrá 3 indicadores, esto nos llevaría a tener que codificar con 15 objetos, y en este caso las posibilidades de equivocarnos, ya que la diferencia entre ellos es sólo el nombre, serían enormes. De esta manera utilizando la macro el código se reduce a lo que se resalta, es decir, codificaremos solo 5 objetos al final, pero esto aquí es la primera fase, para tener el resultado que se muestra detrás.

Y para terminar esta primera fase tenemos otra rutina igual de tediosa que hacer si no hubiera macros, es cierto que podríamos usar procedimientos en lugar de macros, pero, gustos son gustos y no hay discusión.

#define macroSetAxleY(A)        {                                               \
                m_BackGround.PositionAxleY(MountName(ticket, A, EV_GROUND), y); \
                m_TradeLine.PositionAxleY(MountName(ticket, A, EV_LINE), y);    \
                                }
                                                                        
#define macroSetAxleX(A, B)     {                                               \
                m_BackGround.PositionAxleX(MountName(ticket, A, EV_GROUND), B); \
                m_TradeLine.PositionAxleX(MountName(ticket, A, EV_LINE), B);    \
                                }

inline void PositionAxlePrice(double price, ulong ticket, eIndicatorTrade it, int FinanceTake, int FinanceStop, int Leverange, bool isBuy)
                        {
                                double ad;
                                int x, y;
                                
                                ChartTimePriceToXY(Terminal.Get_ID(), 0, 0, price, x, y);
                                macroSetAxleY(it);
                                macroSetAxleX(it, m_PositionMinimalAlxeX);
                                if (Leverange == 0) return;
                                if (it == IT_PENDING)
                                {
                                        ad = Terminal.GetAdjustToTrade() / (Leverange * Terminal.GetVolumeMinimal());
                                        ChartTimePriceToXY(Terminal.Get_ID(), 0, 0, price + Terminal.AdjustPrice(FinanceTake * (isBuy ? ad : (-ad))), x, y);
                                        macroSetAxleY(IT_TAKE);
                                        macroSetAxleX(IT_TAKE, m_PositionMinimalAlxeX + 120);
                                        ChartTimePriceToXY(Terminal.Get_ID(), 0, 0, price + Terminal.AdjustPrice(FinanceStop * (isBuy ? (-ad) : ad)), x, y);
                                        macroSetAxleY(IT_STOP);
                                        macroSetAxleX(IT_STOP, m_PositionMinimalAlxeX + 220);
                                }
                        }
#undef macroSetAxleX
#undef macroSetAxleY

Si crees que la rutina anterior era un tedio, piensa en esta, aquí el trabajo se duplicaría, y gracias a los códigos resaltados la cosa se vuelve aceptable.

Bueno hay otros pequeños cambios que tuvieron que ocurrir, pero no merecen tanta atención, así que cuando ejecutamos este código, obtenemos exactamente lo que esperamos, es decir, los indicadores comenzaron a aparecer en la pantalla.


4.0 - Conclusión

Ahora falta un poco para que el sistema esté realmente completo, en cuanto a la forma de visualizar las órdenes directamente en el gráfico, pero ahora hay que hacerlo en un solo paso, ya que es necesario hacer cambios muy significativos en otros puntos del código.

De esta manera se dejará para el siguiente artículo, ya que los cambios serán muy profundos, y en caso de que algo salga mal, tendrás que retroceder un paso y volver a intentarlo hasta que puedas modificar el sistema de la manera que quieras, de esta manera podrás personalizarlo dejándolo de la manera que te convenga, pero en el siguiente artículo dejaremos el sistema como se muestra a continuación:


Parece que es algo sencillo de conseguir, ¿verdad? Pero créanme, hay que hacer muchos cambios para lograr realmente esto y de una manera que funcione, así que será para el próximo artículo, nos vemos allí.

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

Archivos adjuntos |
Indicadores con control interactivo en el gráfico. Indicadores con control interactivo en el gráfico.
Una nueva mirada a la interfaz del indicador. Lo más importante es la comodidad. Tras probar docenas de estrategias comerciales diferentes a lo largo de los años, además de probar cientos de indicadores diferentes, he llegado a algunas conclusiones propias que quiero compartir con ustedes en este artículo.
Vídeo: Comercio automatizado simple: cómo crear un asesor comercial sencillo usando MQL5 Vídeo: Comercio automatizado simple: cómo crear un asesor comercial sencillo usando MQL5
La mayoría de los estudiantes de mis cursos consideraban que el lenguaje MQL5 era difícil de entender. Asimismo, buscaban formas sencillas de automatizar algunos procesos. En este artículo, el lector aprenderá cómo comenzar a trabajar directamente en MQL5 incluso sin conocimientos de programación y habiendo tenido incluso intentos fallidos de dominar este tema en el pasado.
Desarrollando un EA comercial desde cero (Parte 21): Un nuevo sistema de órdenes (IV) Desarrollando un EA comercial desde cero (Parte 21): Un nuevo sistema de órdenes (IV)
Finalmente el sistema visual funcionará... aún no del todo. Aquí terminaremos de hacer los cambios básicos, y no serán pocos, serán muchos, y todos ellos necesarios, y todo el trabajo será bastante interesante.
Redes neuronales: así de sencillo (Parte 14): Clusterización de datos Redes neuronales: así de sencillo (Parte 14): Clusterización de datos
Lo confieso: ha pasado más de un año desde que publiqué el último artículo. En tanto tiempo, me ha sido posible repensar mucho, desarrollar nuevos enfoques. Y en este nuevo artículo, me gustaría alejarme un poco del método anteriormente usado de aprendizaje supervisado, y sugerir una pequeña inmersión en los algoritmos de aprendizaje no supervisado. En particular, vamos a analizar uno de los algoritmos de clusterización, las k-medias.