English Русский 中文 Deutsch 日本語 Português
preview
Desarrollo de un EA comercial desde cero (Parte 29): Plataforma parlante

Desarrollo de un EA comercial desde cero (Parte 29): Plataforma parlante

MetaTrader 5Ejemplos | 17 octubre 2022, 09:33
426 0
Daniel Jose
Daniel Jose

1.0 - Introducción

¿Qué tal si hacemos que el EA sea más divertido? Operar en los mercados financieros suele ser una actividad extremadamente aburrida y monótona, pero podemos hacerla un poco menos tediosa. Este proyecto podría ser peligroso en caso de que tengas un problema que te haga adicto, pero en realidad con las modificaciones todo el escenario podría ser más entretenido, menos aburrido.

Así que aquí va una advertencia: NO utilicen las modificaciones presentes en este artículo si están viendo el mercado como un juego, porque hay un riesgo real de pérdidas muy grandes.

Aunque la advertencia anterior parece una broma, lo cierto es que algunas modificaciones del EA lo hacen peligroso para algunas personas propensas a la ludopatía en general.

Algunos de los cambios que se harán aquí tienen como objetivo aumentar la estabilidad y el rendimiento general del EA, pero si quieren mantenerlos, no hay problema. Ahora bien, con el sistema de órdenes que se ha creado y que está presente en EA, algunas cosas pueden eliminarse sin que ello suponga un perjuicio para un operador más experimentado. Así que siéntanse libres de quitar o mantener cosas, o incluso de modificarlas.


2.0 - Eliminación del Chart Trade

El Chart Trade es algo que en un sistema de órdenes menos complejo que el existente en nuestro EA sigue teniendo sentido. Pero en el caso del EA que se está elaborando y en la etapa actual de desarrollo, no tiene sentido tener un Chart Trade en el gráfico, podemos quitarlo. Si lo desean, pueden mantenerlo, esto se logra con la edición de un solo comando. Sí, así es, me gusta dejar las cosas muy sencillas, para luego poder cambiarlas (o no) de forma muy rápida y sin generar ningún tipo de estrés durante el proceso, como cuando surgen problemas en el código o se producen fallos catastróficos en puntos críticos.

Pues bien, para controlar lo más rápidamente posible y al mismo tiempo con seguridad, dentro del código EA, hemos añadido la siguiente definición:

#define def_INTEGRATION_CHART_TRADER            // Integra o chart trader ao EA ...

Si esta definición no existe o se convierte en un comentario, el CHART TRADE no se compilará con el EA. Veamos cuales son los puntos afectados por esta definición, el primero y más obvio es los includes:

#ifdef def_INTEGRATION_CHART_TRADER
        #include <NanoEA-SIMD\SubWindow\C_TemplateChart.mqh>
#endif 

Aunque el código anterior no está dentro del archivo del EA, sino del archivo C_IndicatorTradeView.mqh, para el compilador la definición se verá en todos los puntos del código, por lo que no tenemos que preocuparnos de reajustar el código. Para eso, simplemente creamos la definición en un punto fácil de encontrar, en este caso dentro del código del EA y lo utilizamos donde sea necesario.

Pero continuemos un rato dentro del archivo C_IndicatorTradeView.mqh. Dado que podemos compilar un EA sin Chart Trade, tenemos que organizarnos para acceder a los datos definidos en el cuadro de mensajes de inicialización del EA, los cuales se pueden ver en la siguiente imagen:

Recuerden que tenemos que acceder a estos datos. Antes los transferíamos al Chart Trade y cuando había necesidad de consultarlos, entrábamos en el Chart Trade y los obteníamos. Pero ahora sin el Chart Trade tendremos que seguir otro camino para acceder a estos mismos datos.

En el archivo C_IndicatorTradeView.mqh estos valores son necesarios en un solo lugar, y es cuando crearemos el indicador 0 que se utiliza para mostrar dónde se posicionará la orden pendiente, este punto está dentro de la rutina DispatchMessage, y se puede ver en el fragmento de abajo:

// ... Código anterior ...

                                        case CHARTEVENT_MOUSE_MOVE:
                                                Mouse.GetPositionDP(dt, price);
                                                mKeys   = Mouse.GetButtonStatus();
                                                bEClick  = (mKeys & 0x01) == 0x01;    //Clique esquerdo
                                                bKeyBuy  = (mKeys & 0x04) == 0x04;    //SHIFT Pressionada
                                                bKeySell = (mKeys & 0x08) == 0x08;    //CTRL Pressionada
                                                if (bKeyBuy != bKeySell)
                                                {
                                                        if (!bMounting)
                                                        {
#ifdef def_INTEGRATION_CHART_TRADER
                                                                m_Selection.bIsDayTrade = Chart.GetBaseFinance(m_Selection.vol, valueTp, valueSl);
#else 
                                                                m_Selection.vol = EA_user20 * Terminal.GetVolumeMinimal();
                                                                valueTp = EA_user21;
                                                                valueSl = EA_user22;
                                                                m_Selection.bIsDayTrade = EA_user23;
#endif 
                                                                valueTp = Terminal.AdjustPrice(valueTp * Terminal.GetAdjustToTrade() / m_Selection.vol);
                                                                valueSl = Terminal.AdjustPrice(valueSl * Terminal.GetAdjustToTrade() / m_Selection.vol);
                                                                m_Selection.it = IT_PENDING;
                                                                m_Selection.pr = price;
                                                        }

// ... Restante do código ...

Fíjense en las líneas resaltadas, no tiene sentido buscar estos valores EA_userXX dentro de este archivo, no están aquí, porque ellos vienen del código del EA y se pueden ver en el fragmento de abajo:

#ifdef def_INTEGRATION_CHART_TRADER
        input group "Chart Trader"
#else 
        input group "Base Operacional do EA"
#endif 
input int       EA_user20   = 1;     //Fator de alavancagem
input double    EA_user21   = 100;   //Take Profit ( FINANCEIRO )
input double    EA_user22   = 81.74; //Stop Loss ( FINANCEIRO )
input bool      EA_user23   = true;  //Day Trade ?

Con esto ya tenemos un control de la manera cómo se haría si el Chart Trade estuviera en el gráfico. Fíjense que prácticamente no cambiamos en nada el código, solo llevamos los datos necesarios que son definidos por el usuario al interior del lugar correcto. Algunas personas pueden encontrar innecesaria esta configuración por parte del operador durante la operación de carga del EA, y esto es cierto en cierto modo, ya que el sistema de órdenes nos permite ajustar todas las variables sin ninguna dificultad, de esta manera ustedes podrían definir un valor mínimo como factor de apalancamiento y mantener tanto el STOP como el TAKE a 0, y las operaciones iniciales como Day Trade, y hacerlo en la función DispatchMessage de la clase C_IndicatorTradeView, ya que esto no afectaría para nada al sistema, puesto que el operador puede modificar la orden que está en el gráfico y luego enviarla al servidor. Cabe destacar que este tipo de modificación queda a criterio del operador, ya que es algo muy personal.


2.0.1 - Ajuste de algunas cosas

Antes de volver a la parte en la que eliminamos Chart Trade, hay otra cosa que tenemos que hacer, y esto mejorará la estabilidad del EA en general.

Hagamos lo siguiente, en la clase C_IndicatorTradeView definiremos una estructura de datos privada, que se puede ver a continuación:

struct st01
{
        bool    ExistOpenPosition,
                SystemInitilized;
}m_InfoSystem;

Ella se inicializará en el siguiente código:

void Initilize(void)
{
        static int ot = 0, pt = 0;
                                
        m_InfoSystem.ExistOpenPosition = false;
        m_InfoSystem.SystemInitilized = false;
        ChartSetInteger(Terminal.Get_ID(), CHART_SHOW_TRADE_LEVELS, false);
        ChartSetInteger(Terminal.Get_ID(), CHART_DRAG_TRADE_LEVELS, false);                             
        if ((ot != OrdersTotal()) || (pt != PositionsTotal()))
        {
                ObjectsDeleteAll(Terminal.Get_ID(), def_NameObjectsTrade);
                ChartRedraw();
                for (int c0 = ot = OrdersTotal(); c0 >= 0; c0--)  IndicatorAdd(OrderGetTicket(c0));
                for (int c0 = pt = PositionsTotal(); c0 >= 0; c0--) IndicatorAdd(PositionGetTicket(c0));
        }
        m_InfoSystem.SystemInitilized = true;
}

¡¿Por qué estamos creando e inicializando estos datos aquí?! Recuerden que MetaTrader 5 envía EVENTOS al EA, y uno de estos eventos es el OnTick. En sistemas sencillos no hay muchos problemas, pero a medida que el sistema se vuelve más y más complejo, tenemos que asegurarnos de que las cosas funcionan correctamente. Y puede ocurrir que MetaTrader 5 envíe eventos al EA antes de que el mismo esté realmente preparado para manejar dichos eventos. Por esta razón, nos debemos asegurar de que el EA está preparado mediante la creación de ciertas variables que pueden indicar el nivel de funcionamiento del propio EA, y si éste no está totalmente preparado, se deben ignorar los eventos desencadenados por MetaTrader 5 hasta que el EA pueda responder adecuadamente a dichos eventos.

El punto más crítico de todos se ve en el código justo debajo:

inline double SecureChannelPosition(void)
                        {
                                static int nPositions = 0;
                                double Res = 0;
                                ulong ticket;
                                int iPos = PositionsTotal();
                                
                                if (!m_InfoSystem.SystemInitilized) return 0;
                                if ((iPos != nPositions) || (m_InfoSystem.ExistOpenPosition))
                                {
                                        m_InfoSystem.ExistOpenPosition = false;
                                        for (int i0 = iPos - 1; i0 >= 0; i0--) if (PositionGetSymbol(i0) == Terminal.GetSymbol())
                                        {
                                                m_InfoSystem.ExistOpenPosition = true;
                                                ticket = PositionGetInteger(POSITION_TICKET);
                                                if (iPos != nPositions) IndicatorAdd(ticket);
                                                SetTextValue(ticket, IT_RESULT, PositionGetDouble(POSITION_VOLUME), Res += PositionGetDouble(POSITION_PROFIT), PositionGetDouble(POSITION_PRICE_OPEN));
                                        }
                                        nPositions = iPos;
                                }
                                return Res;
                        };

Los puntos resaltados no existían antes, por lo que en algunos momentos podían ocurrir cosas extrañas, pero ahora tenemos las pruebas necesarias para que nada anormal pase desapercibido.

Este tema de probar todo y todas las posibilidades es algo bastante complicado, ya que muchas pruebas ayudan a que el sistema sea muy estable, pero también puede complicar a la hora de hacer mantenimiento o cambios en el código, ya que algunas de ellas tienen que hacerse manteniendo una determinada secuencia lógica para que sean efectivas, y esto es algo bastante costoso de realizar.

Pero vean que con la realización de la prueba de si hay o no una posición en el activo que el EA está siguiendo podemos darle cierta agilidad a este último, más aún cuando MetaTrader 5 está con varios activos abiertos y cada uno tiene cierta cantidad de posiciones que le aparecerán al EA. Con nosotros filtrando esto aquí, eliminamos el bucle para que el EA sólo ejecute el código si es realmente necesario, de lo contrario reduciremos un poco el tiempo de procesamiento que consumirá el EA, es poco, pero ya hace alguna diferencia en casos muy extremos.


2.0.2 - «Extirpación» del Chart Trade del EA

Bien, ahora que hemos hecho la modificación a la clase C_IndicatorTradeView, podemos volver a centrarnos en el código del EA, y retirar el Chart Trade del código. Lo primero que hay que hacer es quitarlo del código OnInit, veamos cómo hacerlo:

int OnInit()
{       
        Terminal.Init();

#ifdef def_INTEGRATION_WITH_EA
        WallPaper.Init(user10, user12, user11);
        VolumeAtPrice.Init(user32, user33, user30, user31);
        TimesAndTrade.Init(user41);
        EventSetTimer(1);
#endif 

        Mouse.Init(user50, user51, user52);
        
#ifdef def_INTEGRATION_CHART_TRADER
        static string   memSzUser01 = "";
        if (memSzUser01 != user01)
        {
                Chart.ClearTemplateChart();
                Chart.AddThese(memSzUser01 = user01);
        }
        Chart.InitilizeChartTrade(EA_user20 * Terminal.GetVolumeMinimal(), EA_user21, EA_user22, EA_user23);
        TradeView.Initilize();
        OnTrade();
#else 
        TradeView.Initilize();
#endif 
   
        return INIT_SUCCEEDED;
}

Todo el código en verde será sustituido por el código en azul. En el caso de que no utilicemos Chart Trade, puede parecer que no hay mucha diferencia, que solo fue un cambio en el tamaño del ejecutable. Pero no es solo esto, observen que junto con el código de Chart Trade también quitamos un evento OnTrade, ahora este evento ya no será necesario para el EA y éste no manejará este evento.

¡¿Pero estás loco?! ¿Cómo se puede retirar el evento OnTrade del EA? ¿Y ahora cómo vamos a manejar los eventos comerciales? Estos eventos serán manejados por el evento OnTradeTransaction, y serán manejados de una manera más eficiente que el evento OnTrade, lo que significa que el EA será más simple y consecuentemente más robusto.

Otro punto que también sufre cambios es la rutina que se puede ver justo debajo:

void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
        Mouse.DispatchMessage(id, lparam, dparam, sparam);
#ifdef def_INTEGRATION_WITH_EA
        switch (id)
        {
                case CHARTEVENT_CHART_CHANGE:
                        Terminal.Resize();
                        WallPaper.Resize();
                        TimesAndTrade.Resize();
        break;
        }
        VolumeAtPrice.DispatchMessage(id, sparam);
#endif 

#ifdef def_INTEGRATION_CHART_TRADER
        Chart.DispatchMessage(id, lparam, dparam, sparam);
#endif 

        TradeView.DispatchMessage(id, lparam, dparam, sparam);  
}

En caso de que no haya integración dentro del EA, las únicas líneas que realmente se compilarán son las resaltadas. Como estos eventos tienden a ser bastante constantes (cuanto más eficiente sea el manejo de estos eventos mejor), a menudo competirán con otro evento que MetaTrader 5 activará para que el EA lo maneje, y este otro evento se ve a continuación:

void OnTick()
{
#ifdef def_INTEGRATION_CHART_TRADER
        Chart.DispatchMessage(CHARTEVENT_CHART_CHANGE, 0, TradeView.SecureChannelPosition(), C_Chart_IDE::szMsgIDE[C_Chart_IDE::eRESULT]);
#else 
        TradeView.SecureChannelPosition();
#endif 

#ifdef def_INTEGRATION_WITH_EA
        TimesAndTrade.Update();
#endif 
}

Este evento es una verdadera PESADILLA, porque suele ser llamado varias veces, y en algunos casos varias veces en menos de 1 segundo. Pero con los cambios realizados en el código de la clase C_IndicatorTradeView, el manejo de este evento es ligeramente más eficiente. En el futuro mejoraremos un poco más esta eficiencia, pero por ahora será suficiente.

Pues bien, después de todos estos cambios, el Chart Trade no se integrará en el EA. Claro, podemos convertir el Chart Trade en un indicador, y esto tendrá algunos beneficios, mientras mantenemos el sistema del EA centrado sólo en su trabajo principal: tratar, posicionar y mantener el sistema de órdenes dentro de una gestión adecuada. Aunque el transporte de Chart Trade al interior de un indicador implica algunos cambios extra, no mostraré ahora cómo hacerlo, esta transferencia se verá en otro momento. Pero la verdad es que sí tenemos cómo llevar el Chart Trade dentro de un indicador y poder enviar órdenes a través de él.


3.0 - Adición de sonidos

Muchas veces no miramos el gráfico, pero aun así queremos saber qué está pasando. Una de las formas de ser alertado sobre algo es a través del sonido, y este es uno de los mejores tipos de alertas, porque realmente llama nuestra atención inmediatamente y muchas veces, gracias a él, ya sabemos cómo actuar sin necesidad de ningún otro mensaje.

Así que vamos a aprender a poner unas cuantas alertas sonoras básicas, en algunos casos una frase que nos diga algo concreto. Aunque lo que les mostraré aquí y pondré a su disposición en el apéndice es algo muy básico, tal vez esto los motive a aumentar la cantidad de esas alertas y avisos, al punto de no tener que perder tiempo leyendo mensajes, ya que un sonido muchas veces puede indicar algún evento específico, y esto les dará una ganancia de agilidad en momentos específicos de negociación, créanme, esto hace mucha diferencia.

Lo primero que hay que hacer es crear un nuevo archivo que contendrá una nueva clase, y ésta soportará y aislará nuestro sistema de sonido. Una vez hecho esto, podremos empezar a producir cosas de forma muy sostenible. La clase a crear se puede ver en su totalidad en el siguiente código:

class C_Sounds
{
        protected:
                enum eTypeSound {TRADE_ALLOWED, OPERATION_BEGIN, OPERATION_END};
        public  :
//+------------------------------------------------------------------+
inline bool PlayAlert(const int arg)
                {
                        return PlaySound(StringFormat("NanoEA-SIMD\\RET_CODE\\%d.wav", arg));
                }
//+------------------------------------------------------------------+
inline bool PlayAlert(const eTypeSound arg)
                {
                        string str1;
        
                        switch (arg)
                        {
                                case TRADE_ALLOWED   : str1 = def_Sound00; break;
                                case OPERATION_BEGIN : str1 = def_Sound01; break;
                                case OPERATION_END   : str1 = def_Sound02; break;
                                defaultreturn false;
                        }
                        PlaySound("::" + str1);
                        
                        return true;
                }
//+------------------------------------------------------------------+
};

A pesar de la extrema simplicidad de este código, tenemos algo bastante interesante aquí. Observe que estamos sobrescribiendo la función PlayAlert, por lo tanto tenemos dos versiones de la misma función. ¡¿Y por qué así?! La razón es que, por la forma en que funcionará nuestro sistema de sonido, debemos tener estas dos variaciones. En el caso de la primera versión de la función, reproduciremos un sonido que está en el archivo, y en la segunda versión reproduciremos el sonido que forma parte del EA, siendo una característica del mismo. Ahora bien, hay una cosa que quizá muchos no sepan hacer, que es reproducir sonidos directamente desde archivos de audio. Pero no se preocupen, les mostraré cómo deben proceder para hacerlo. La razón de la primera versión es que algunas personas pueden querer poner su propia voz o algún otro sonido como alerta, y cambiarlo en cualquier momento, y para hacer esto no es necesario recompilar el EA, de hecho se pueden cambiar estos sonidos incluso con el EA estando en ejecución dentro de MetaTrader 5, que desde el momento en que el sonido tiene que ser reproducido, el EA utilizará la versión más reciente que ustedes pusieron, por lo que sólo tienen que cambiar el archivo de audio por otro que quieran, y el EA ni siquiera notará la diferencia o el cambio, y esto ayuda mucho. Pero hay otra razón, que se verá al mirar el código del EA.

De hecho, la primera versión se utiliza en un lugar bastante específico, y esto se puede ver en el fragmento de clase que se destaca a continuación:

class C_Router
{
        protected:
        private  :
                MqlTradeRequest TradeRequest;
                MqlTradeResult  TradeResult;
//+------------------------------------------------------------------+
inline bool Send(void)
        {
                if (!OrderSend(TradeRequest, TradeResult))
                {
                        if (!Sound.PlayAlert(TradeResult.retcode))Terminal.MsgError(C_Terminal::FAILED_ORDER, StringFormat("Error Number: %d", TradeResult.retcode));
                        
                        return false;
                }
                return true;
        }

// ... Restante da classe ....

Sólo piense en la cantidad de trabajo que se requeriría para manejar todos los posibles errores devueltos por el servidor de comercio, sería casi una locura, pero grabando un archivo de audio, y poniendo su nombre para reflejar el valor que está siendo devuelto por el servidor de comercio, el EA sabrá qué archivo debe reproducir su audio, esto nos facilita mucho la vida, ya que sólo tendremos que indicar qué archivo es en base al valor de retorno del servidor, y el EA buscaría y reproduciría este mismo archivo, dándonos una alerta sonora, o un mensaje de voz para que podamos saber exactamente qué ha pasado. Maravilloso, ¡¿no es así?! Pues ahora la plataforma nos informará de forma muy clara de lo que ha ocurrido o de lo que está fallando para que las órdenes sean rechazadas. Y lo hará de una forma muy adecuada y que representa algo específico para nosotros, algo que puede ser exclusivo y único para nuestra forma de operar y actuar en los mercados. Veremos cuánta agilidad ganaremos, porque en el mismo archivo de audio podemos dejar claro cómo resolver el problema.

Pero también tenemos un segundo modo de funcionamiento de la función, que es que los sonidos se almacenan dentro del ejecutable del EA, esta es la segunda versión de la misma función, y se utilizará en esta etapa actual, en 3 lugares diferentes, para indicar 3 tipos diferentes de eventos. La primera ubicación puede verse en el siguiente fragmento de código: La primera ubicación puede verse en el fragmento de código que aparece a continuación:

int OnInit()
{
        if (!TerminalInfoInteger(TERMINAL_TRADE_ALLOWED))
        {
                Sound.PlayAlert(C_Sounds::TRADE_ALLOWED);
                return INIT_FAILED;
        }
        
        Terminal.Init();

// ... Restante do código ...

Lo que hace este código es verificar si AlgoTrading está habilitado o no en la plataforma, en caso de que nos hayamos olvidado de habilitarlo, el EA nos informará que no estará disponible para ninguna operación. Para comprobar si está habilitado o no, basta con observar el indicador presente en la plataforma, y que se ve en el punto que se muestra en la imagen siguiente:


El segundo punto en el que utilizaremos un sonido auxiliar, se ve en el fragmento siguiente:

void CreateIndicator(ulong ticket, eIndicatorTrade it)
{
        string sz0;
                                
        switch (it)
        {
                case IT_TAKE    : macroCreateIndicator(it, clrForestGreen, clrDarkGreen, clrNONE); break;
                case IT_STOP    : macroCreateIndicator(it, clrFireBrick, clrMaroon, clrNONE); break;
                case IT_PENDING:
                        macroCreateIndicator(it, clrCornflowerBlue, clrDarkGoldenrod, def_ColorVolumeEdit);
                        m_BtnCheck.Create(ticket, sz0 = macroMountName(ticket, it, EV_CHECK), def_BtnCheckEnabled, def_BtnCheckDisabled);
                        m_BtnCheck.SetStateButton(sz0, true);
                        macroInfoBase(IT_PENDING);
                        break;
                case IT_RESULT  :
                        macroCreateIndicator(it, clrSlateBlue, clrSlateBlue, def_ColorVolumeResult);
                        macroInfoBase(IT_RESULT);
                        Sound.PlayAlert(C_Sounds::OPERATION_BEGIN);
                        m_InfoSystem.ExistOpenPosition = true;
                        break;
        }
        m_BtnClose.Create(ticket, macroMountName(ticket, it, EV_CLOSE), def_BtnClose);
}

Cada vez que se cree un indicador de posición, se reproducirá un sonido. Esto nos facilita mucho la vida, ya que sabremos que una orden pendiente se ha convertido en una posición, y que debemos empezar a prestarle atención.

El tercer y último punto donde tenemos un sonido auxiliar es cuando una posición se está cerrando por cualquier razón. Esto se hace en un punto muy específico que es el código de abajo:

inline void RemoveIndicator(ulong ticket, eIndicatorTrade it = IT_NULL)
{
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, false);
        if ((it == IT_NULL) || (it == IT_PENDING) || (it == IT_RESULT))
        {
                if (macroGetPrice(ticket, IT_RESULT, EV_LINE) > 0) Sound.PlayAlert(C_Sounds::OPERATION_END);
                ObjectsDeleteAll(Terminal.Get_ID(), StringFormat("%s%c%llu%c", def_NameObjectsTrade, def_SeparatorInfo, ticket, (ticket > 1 ? '*' : def_SeparatorInfo)));
        } else ObjectsDeleteAll(Terminal.Get_ID(), StringFormat("%s%c%llu%c%c", def_NameObjectsTrade, def_SeparatorInfo, ticket, def_SeparatorInfo, (char)it));
        ChartSetInteger(Terminal.Get_ID(), CHART_EVENT_OBJECT_DELETE, true);
        m_Selection.ticket = 0;
        Mouse.Show();
        ChartRedraw();
}

Ustedes pueden pensar que al quitar el EA, éste emitirá el sonido de cierre, pero no, esto no sucederá, porque la línea de precios seguirá estando presente en el sistema. Pero cuando la posición se cierre, ocurrirá algo diferente, y la línea de precio de la posición estará en la posición de precio 0, y en este momento se emitirá el sonido, con lo cual se nos indica que la posición se cerró.

Recordando que estos sonidos que son recursos del EA irán con él a donde vaya el ejecutable, y no podrán ser modificados sin que el código sea recompilado, debido a esto son más limitados, pero al mismo tiempo ayudan a portar el EA a otros lugares sin tener que llevar archivos de audio.

Con todo, en el caso de los sonidos utilizados para alertarnos de fallos o errores, estos son diferentes, y deben transportarse por separado, y colocarse en un lugar predeterminado para que puedan funcionar cuando se necesiten.

En el código adjunto, tendremos una carpeta llamada SOUNDS. No tiene sentido dejar esta carpeta en la misma carpeta donde estará el código, porque los sonidos contenidos en esta carpeta no se reproducirán, hay que transportarla a otra ubicación, esta ubicación se puede encontrar fácilmente, en caso de que no sepamos dónde está, no se preocupen, estará junto con el resto del código:

#property copyright "Daniel Jose"
//+------------------------------------------------------------------+
void OnStart()
{
        Print(TerminalInfoString(TERMINAL_PATH));
}
//+------------------------------------------------------------------+

Cuando se ejecuta este script se obtiene una información en la caja de herramientas, esta indica la ubicación que vamos a utilizar, un ejemplo del resultado de la ejecución se puede ver en la imagen de abajo:

Lo que haremos será lo siguiente:

  1. Abrimos el adjunto al artículo;
  2. Abrimos el Explorador de archivos;
  3. Accedemos a la carpeta indicada en la imagen anterior;
  4. Copiamos el contenido de la carpeta SOUNDS del archivo adjunto en la carpeta anterior;
  5. Si lo deseamos, eliminamos los 3 archivos (WARRING, BEGIN, END) porque serán compilados junto con el EA;
  6. Cambiamos el contenido de los archivos .WAV si lo deseamos por algo más agradable, pero teniendo cuidado de dejarlo con el mismo nombre;
  7. Utilizamos el EA en el terminal MetaTrader 5 y somos felices...
Pero recuerden que para que los sonidos (WARRING, BEGIN, END) se compilen en el EA, debemos tener en el directorio de códigos del MQL5 la carpeta SOUNDS con estos mismos sonidos, de lo contrario, no se integrarán en el código del EA.


4.0 - Conclusión

En este artículo hemos aprendido a añadir sonidos personalizados en el sistema del EA.  Es muy cierto que aquí hemos hecho uso de un sistema muy sencillo para demostrar cómo hacer esto, pero no estamos limitados sólo al EA, podemos utilizarlo también en indicadores o incluso en scripts.

El gran detalle es que si utilizamos los mismos conceptos e ideas propuestos aquí, podemos grabar mensajes de voz diciendo o advirtiendo sobre algo. Y cuando el EA o cualquier otro proceso que esté siendo ejecutado por MetaTrader 5 y que utilice el sistema de sonido llegue a activarse a través de los disparadores mostrados en el artículo, usted u otro operador recibirá dicho mensaje sonoro diciéndole o alertándole sobre algún tipo de medida que ya había previsto y que debería ser adoptada.

Y no se trata de un mensaje de texto, sino de un mensaje de voz, lo que lo hace mucho más efectivo, ya que se puede explicar rápidamente a los usuarios del sistema lo que se debe hacer, o cuál fue la causa que generó dicho mensaje.

Pero este sistema no se queda solo en este esquema, podemos ir más allá de lo que se demostró aquí, la idea es exactamente esta, permitirnos tener en la plataforma un aliado, ya que al tener una interacción vocal con el operador podemos pasar un mensaje que puede ser mejor entendido que un simple texto. Así que lo que nos limitará es sólo nuestra creatividad...
   


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

Archivos adjuntos |
EA_-_h_Parte_29_6.zip (14465.62 KB)
Desarrollo de un EA comercial desde cero (Parte 30): ¿¡El CHART TRADE ahora como indicador?! Desarrollo de un EA comercial desde cero (Parte 30): ¿¡El CHART TRADE ahora como indicador?!
Vamos a hacer uso del Chart Trade nuevamente... pero ahora será un indicador y podrá o no estar presente en el gráfico.
Desarrollo de un EA comercial desde cero (Parte 28): Rumbo al futuro (III) Desarrollo de un EA comercial desde cero (Parte 28): Rumbo al futuro (III)
Nuestro sistema de órdenes todavía falla en hacer una cosa, pero FINALMENTE lo resolveremos...
Desarrollo de un EA comercial desde cero (Parte 31): Rumbo al futuro (IV) Desarrollo de un EA comercial desde cero (Parte 31): Rumbo al futuro (IV)
Seguiremos eliminando cosas del interior del EA. Sin embargo, este será el último artículo de esta serie. Lo último que se removerá en esta serie de artículos es el sistema de sonido. Tal vez esto los confunda si no han seguido estos artículos.
Desarrollo de un EA comercial desde cero (Parte 27): Rumbo al futuro (II) Desarrollo de un EA comercial desde cero (Parte 27): Rumbo al futuro (II)
Sigamos avanzando hacia un sistema de órdenes más completo directamente en el gráfico. En este artículo les mostraré una forma de corregir o, más bien, de hacer que el sistema de órdenes sea más intuitivo.