Discusión sobre el artículo "Desarrollamos un asesor experto multidivisa (Parte 17): preparación adicional para el trading real"

 

Artículo publicado Desarrollamos un asesor experto multidivisa (Parte 17): preparación adicional para el trading real:

Ahora nuestro EA utiliza una base de datos para recuperar las cadenas de inicialización de instancias individuales de estrategias comerciales. Sin embargo, la base de datos es bastante voluminosa y contiene mucha información innecesaria para el funcionamiento real del asesor experto. Vamos a intentar que el EA funcione sin conexión obligatoria a la base de datos.

En uno de los artículos anteriores, ya hemos llamado su atención sobre las modificaciones del EA necesarias para trabajar en cuentas reales. Antes de esto, nuestros esfuerzos se centraban principalmente en obtener resultados aceptables de los EA en el simulador de estrategias. Pero el trabajo para avanzar hacia el comercio real no ha finalizado, aún queda mucho por hacer.

Además de la restauración del trabajo del asesor experto tras reiniciar el terminal, la posibilidad de utilizar nombres ligeramente diferentes de los instrumentos comerciales y la finalización automática de la negociación al alcanzarse los indicadores especificados, también nos enfrentamos al siguiente problema: para formar la cadena de inicialización, utilizamos la información obtenida directamente de la base de datos, que almacena todos los resultados de la optimización de las instancias de estrategias comerciales y sus grupos.

Para ejecutar el asesor experto, deberemos tener un archivo con la base de datos en la carpeta común de los terminales. El tamaño de la base de datos ya es de varios gigabytes y no hará sino crecer en el futuro. Por consiguiente, no sería racional hacer que la base de datos forme parte del EA, ya que solo se necesitará una parte muy pequeña de la información almacenada en ella para ejecutarlo. Por ello, deberemos implementar un mecanismo para extraer y utilizar esta información en el asesor experto.

Разрабатываем мультивалютный советник (Часть 17): Дальнейшая подготовка к реальной торговле

Autor: Yuriy Bykov

 

Yuri hola! Estoy estudiando tu código y no entiendo un poco.... En el archivo SimpleVolumesStrategy.mqh en el constructor tienes un parámetro:

         // Registrar el manejador de eventos de nueva barra en el marco de tiempo mínimo
         IsNewBar(m_symbol, PERIOD_M1);

¿Por qué haces esto? ¿Por qué exactamente el periodo M1, y no el actual, sobre el que se lanza esta instancia de estrategia? Según entiendo en este caso, el Asesor Experto trabajará no por aperturas de barras de un determinado TF, sino simplemente por m1. ¿O he entendido algo mal?

Y el segundo punto - en la función SignalForOpen() aquí:

      // Si el volumen actual supera el nivel establecido, entonces
      if(m_volumes[0] > avrVolume * (1 + m_signalDeviation + m_ordersTotal * m_signaAddlDeviation)) {
         // si el precio de apertura de la vela es menor que el precio actual (cierre), entonces
         if(iOpen(m_symbol, m_timeframe, 0) < iClose(m_symbol, m_timeframe, 0)) {
            signal = 1; // señal de compra
         } else {
            signal = -1; // en caso contrario, señal de venta
         }
      }

Has indicado la barra 0 (actual) en los cálculos, aunque me parece que debería estar la barra 1 (última cerrada). Es que la barra 0 en el primer tick (si trabajamos sobre precios de apertura) no tiene cuerpo, y por tanto el precio de apertura es siempre igual al precio de cierre. Y no puede tener volumen porque aún no se ha formado. Puede que esté entendiendo algo mal, pero de alguna manera funciona.... Me gustaría entender por qué es así?

Y también si quiero lanzar algún parámetro (nuevo) en esta estrategia, tengo que crearlo en el SimpleVolumesStage1.mq5 Expert Advisor en la configuración y pasarlo a una variable de cadena allí, y luego en esta clase (SimpleVolumesStrategy.mqh) en el constructor para analizar en el orden correcto y eso es todo? ¿O tengo que prescribir en otro lugar?

 

Hola Victor.

Зачем Вы это делаете? Почему именно период М1, а не текущий на котором запускается этот экземпляр стратегии? Как я понимаю в этом случае советник будет работать не по открытиям баров заданного ТФ а просто по м1. Или я что-то не правильно понимаю?

El trabajo del Asesor Experto consta de dos partes: apertura de posiciones virtuales y sincronización de las posiciones virtuales abiertas con las reales. El conjunto TF se utiliza sólo en la primera parte para determinar la señal de apertura. Y la sincronización debería realizarse idealmente en cada tick o al menos en cada nueva barra del timeframe mínimo M1, porque en cualquier momento una posición virtual puede alcanzar TP o SL.

En el método VirtualAdvisor::Tick(), al principio se comprueba si se ha producido una nueva barra en todos los símbolos y plazos supervisados, incluido M1. Si no se ha producido, el Asesor Experto no realiza más acciones. Sólo hará algo más cuando se produzca una nueva barra en M1. En este caso, puede optimizar en modo OHLC en M1 y obtener casi los mismos resultados cuando el EA trabaja en el gráfico (donde hay todos los ticks). Y la optimización es mucho más rápida de esta manera. La línea de código que mencionas es sólo una red de seguridad en caso de que no necesitemos rastrear una nueva barra en M1 en la estrategia. De esta manera se garantiza que se rastrea al menos en un símbolo.

Si lo desea, puede, por supuesto, desactivar este modo de funcionamiento a través de la variable useOnlyNewBars_ = false. Entonces el Asesor Experto comprobará y sincronizará las posiciones en cada tick disponible.

Sólo que la barra 0 del primer tick (si trabajamos sobreprecios de apertura) no tiene cuerpo, por lo que el precio de apertura siempre es igual al precio de cierre. Y no puede tener volumen porque aún no se ha formado. Puede que esté malinterpretando algo, pero de alguna manera funciona...

La apertura de una nueva barra M1 puede ocurrir dentro de una barra de un timeframe superior. Tenga en cuenta que SignalForOpen() utiliza el marco temporal actual, que suele ser H1, M30 o M15. Por lo tanto, ya no habrá coincidencia de los precios de apertura y cierre del timeframe actual. Además, esta comprobación sólo se produce cuando el volumen de ticks de la barra actual en el marco temporal actual ha superado significativamente el volumen de ticks típico de una barra. Esto no puede ocurrir en el primer tick, cuando el volumen del tick es sólo 1.

Y también si quiero lanzar algún parámetro (nuevo) en esta estrategia, tengo que crearlo en el SimpleVolumesStage1.mq5 Expert Advisor en la configuración y pasarlo a una variable de cadena allí, y luego en esta clase (SimpleVolumesStrategy.mqh) en el constructor para analizar en el orden correcto y eso es todo? ¿O hay que explicarlo en algún otro sitio?

Por supuesto.

 
Yuriy Bykov #:

El trabajo del Asesor Experto consta de dos partes: apertura de posiciones virtuales y sincronización de las posiciones virtuales abiertas con las reales. El conjunto TF se utiliza sólo en la primera parte para determinar la señal de apertura. Y la sincronización debería realizarse idealmente en cada tick o al menos en cada nueva barra del timeframe mínimo M1, porque en cualquier momento la posición virtual puede alcanzar TP o SL.

En el método VirtualAdvisor::Tick(), al principio se comprueba si se ha producido una nueva barra en todos los símbolos y plazos supervisados, incluido M1. Si no se ha producido, el Asesor Experto no realiza más acciones. Sólo hará algo más cuando se produzca una nueva barra en M1. En este caso, puede optimizar en modo OHLC en M1 y obtener casi los mismos resultados cuando el EA trabaja en el gráfico (donde hay todos los ticks). Y la optimización es mucho más rápida de esta manera. La línea de código que mencionas es sólo una red de seguridad en caso de que no necesitemos rastrear una nueva barra en M1 en la estrategia. De esta forma se garantiza que se rastrea al menos en un símbolo.

Si lo desea, puede, por supuesto, desactivar este modo de funcionamiento a través de la variable useOnlyNewBars_ = false. Entonces el Asesor Experto comprobará y sincronizará las posiciones en cada tick disponible.

Entiendo. Pero, por ejemplo, ¿podemos hacer que la sincronización de posiciones funcione en cada tick, y que la apertura de posiciones virtuales (nuevas) se produzca cuando se produzca una nueva barra en el TF especificado en la estrategia (m15,m30,h1)?

Yuriy Bykov #:
La apertura de una nueva barra M1 puede ocurrir dentro de una barra de un marco de tiempo superior. Tenga en cuenta que SignalForOpen() utiliza el marco de tiempo actual, que suele ser H1, M30 o M15. Por lo tanto, ya no habrá coincidencia de los precios de apertura y cierre del timeframe actual. Además, esta comprobación sólo se produce cuando el volumen de ticks de la barra actual en el marco temporal actual ha superado significativamente el volumen de ticks típico de una barra. Esto no puede ocurrir en el primer tick, cuando el volumen del tick es sólo 1.

No te entiendo un poco aquí. Sí, SignalForOpen() utiliza el TF establecido en la configuración de la instancia de estrategia virtual actual, puedo ver eso. Pero por ejemplo, si quiero que el EA trabaje estrictamente en las últimas barras cerradas, entonces aquí tengo que especificar unidades en lugar de ceros.

      if(m_volumes[0] > avrVolume * (1 + m_signalDeviation + m_ordersTotal * m_signaAddlDeviation)) {
         // si el precio de apertura de la vela es menor que el precio actual (cierre), entonces
         if(iOpen(m_symbol, m_timeframe, 0) < iClose(m_symbol, m_timeframe, 0)) {

¿Debo especificar unidades en lugar de ceros? ¿Lo he entendido bien?

 
Viktor Kudriavtsev #:
Por ejemplo, ¿podemos hacer que la sincronización de posiciones funcione en cada tick, y que la apertura de posiciones virtuales (nuevas) se produzca cuando se produzca una nueva barra en el TF especificado en la estrategia (m15,m30,h1)?

Sí, este será el caso si useOnlyNewBars_ = false. Esta variable no es utilizada por las estrategias, ellas mismas determinan cuando comprobar si hay una señal de apertura y cuando abrir posiciones cuando se recibe una señal antes. Por ejemplo, sólo cuando se produce una nueva barra en H1. En este caso, entonces debe modificar el código para que la señal recibida en medio de la barra sobreviva hasta el comienzo de la siguiente barra. Ahora la señal recibida se utiliza inmediatamente (da lugar a la apertura de posiciones virtuales), por lo que no se guarda en ningún sitio.

Aquí no te entiendo un poco. Sí, SignalForOpen() utiliza el TF establecido en la configuración de la instancia actual de la estrategia virtual, puedo ver eso. Pero por ejemplo, si quiero que el EA trabaje estrictamente en las últimas barras cerradas, entonces aquí debería especificar unidades en lugar de ceros ? ¿Lo he entendido bien?

Si con las palabras"EA trabajó estrictamente en las últimas barras cerradas" quiere decir que cuando el volumen de ticks supera el valor umbral en la barra actual para determinar la dirección de la señal de apertura, tomaremos la barra anterior y miraremos su dirección, entonces ha entendido todo correctamente.

 

Hola Yuri. Tengo un error al ejecutar el Asesor Experto SimpleVolumesStage3.mq5 y guardar la información en la base de datos:

2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   database error, FOREIGN KEY constraint failed
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   CDatabase::Execute | ERROR: 5619 in query
2024.09.11 21:02:09.909 Core 1  2024.09.06 23:54:59   INSERT INTO strategy_groups VALUES(0, 'EA_EG_EU (H1, M30, M15, 9x16 items)')
2024.09.11 21:02:09.909 Core 1  final balance 24603.99 USD

¿Qué significa y cómo solucionarlo? La tabla fue añadida a la base de datos usando tu consulta del artículo.

 

Yuri, he estado revisando tu código y veo que el error se produce un poco antes en la función CDatabase::Insert, el log escribe esto:

2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59   CDatabase::Insert | ERROR: Reading row for request 
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59   INSERT INTO passes VALUES (NULL, 0, 0, 10000.00,0.00,11096.20,21542.31,-10446.11,92.51,-63.35,630.89,39.00,444.04,53.00,-376.27,52.00,-376.27,52.00,9430.69,569.31,5.69,5.69,569.31,9325.11,683.96,6.83,6.83,683.96,2.15,2.06,16.22,3.44,3736.76,8435.00,5170.00,3042.00,2128.00,2766.00,2404.00,1706.00,1336.00,6.00,4.00,99.11,8122.90,'class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CVirtualStrategyGroup([
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59           class CSimpleVolumesStrategy("CADCHF",16385,220,1.40,1.70,150,2200.00,200.00,46000,24)
2024.09.12 20:14:11.248 Core 1  2024.09.06 23:54:59          ],66.401062),class CVirtualStrategyGroup([

.....

2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],13.365410),class CVirtualStrategyGroup([
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59           class CSimpleVolumesStrategy("CADJPY",15,132,0.40,1.90,0,7200.00,600.00,45000,27)
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],13.365410),
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],2.970797),
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59          ],1.462074)',
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   '',
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   '2024.09.06 23:54:59') RETURNING rowid;
2024.09.12 20:38:26.905	Core 1	2024.09.06 23:54:59   failed with code 5039

No se puede ejecutar

      if(DatabaseReadBind(request, row)) {

¿Con qué puede estar relacionado? La segunda etapa se pasa y el test en sí se pasa (se cargan las operaciones y pases del Asesor Experto desde la base de datos).

 

Hola Victor.

Volveré pronto para seguir trabajando en este proyecto e intentaré solucionar los errores que he encontrado. Gracias por encontrarlos. He conseguido reproducir algunos de los errores sobre los que escribiste antes. Resultaron estar relacionados con el hecho de que en partes posteriores se hicieron ediciones que iban dirigidas a una cosa, pero que además tenían un impacto en otras cosas que no se tuvieron en cuenta en el siguiente artículo. Esta influencia creó errores. En el próximo artículo volveremos a repasar todos los pasos de la optimización automatizada, eliminando todos los errores detectados.