English Русский 中文 Deutsch 日本語 Português
preview
Posibilidades de ChatGPT de OpenAI en el marco de desarrollo de MQL4 y MQL5

Posibilidades de ChatGPT de OpenAI en el marco de desarrollo de MQL4 y MQL5

MetaTrader 5Trading | 23 octubre 2023, 14:33
1 200 1
Evgeniy Ilin
Evgeniy Ilin

Apartados



Introducción

Comenzaremos con una breve introducción para aquellos que no sepan qué es ChatGPT y para qué sirve. Esta tecnología supone una de las variaciones de la inteligencia artificial de la empresa OpenAI, diseñada para ayudar a las personas a resolver una amplia variedad de problemas. La herramienta en sí se parece a un chat de texto normal en un servicio de mensajería instantánea, solo que en el otro extremo hay una supuesta inteligencia artificial que responde en forma de texto.

Obviamente, el canal de comunicación se limita solo al texto, pero incluso esto bastará para resolver diversos problemas o aprender muchas cosas nuevas. Este canal de texto resultará suficiente para resolver problemas completamente distintos, relacionados, por ejemplo, con la programación, las matemáticas, la física o la química, por no mencionar la ejecución de traducciones magistrales y otras habilidades hasta ahora sin precedentes.

Para nosotros, este modelo solo será interesante desde un punto de vista: el desarrollo de sistemas comerciales rentables. La verdad es que me interesa mucho cómo utilizar de forma óptima y correcta dicha tecnología para desarrollar de manera más rápida y sencilla los sistemas comerciales. En última instancia, quien comienza a usarla correctamente para el propósito previsto reduce tanto el costo de cualquier desarrollo como los costes laborales, lo cual ofrece ventajas competitivas obvias (aquellos que saben entenderán lo que quiero decir).


Perspectivas de uso de ChatGPT en MQL5

Creo que en este apartado vale la pena detenerse más en las perspectivas de uso de esta tecnología. Tras realizar un estudio bastante detallado utilizando mis propios ejemplos, me he dado cuenta de que dicha tecnología supone solo el comienzo de algo grandioso, pero incluso ahora podemos resaltar las siguientes capacidades a nuestra disposición:

  • Generar cualquier código MQL4 y MQL5
  • Refactorizar y optimizar el código de trabajo.
  • Limpiar el código
  • Añadir comentarios al código
  • Corregir errores en el código
  • Implementar modelos matemáticos.
  • Construcción posterior del código mediante modelos matemáticos.
  • Modernizar cualquier algoritmo y modelo matemático conocido.
  • Acelerar el proceso de desarrollo de asesores
  • Además, es un tesoro de información

Estoy seguro de que esta lista no es definitiva y usted podría añadirle algo propio. Creo que cuando la gente sabe de este tipo de tecnología, todos empiezan a clasificarse aproximadamente en los siguientes tres subgrupos:

  1. "Ahora tú y yo haremos un súper algoritmo"
  2. Neutrales, cautelosos con la IA, llenos de dudas sobre los beneficios
  3. Nunca será mejor que una persona, todo eso es solo una exageración.

Por mi parte puedo decir que comencé a familiarizarme con esta tecnología hace bastante tiempo y al principio pertenecía a la tercera categoría. En los primeros dos días de comunicación con esta IA, pasé abruptamente de la tercera a la primera categoría, después de lo cual comenzó un proceso más interesante y bastante desagradable de ajuste de mis propias creencias, algo más semejante a un retroceso a la categoría "1.5", que ya supone una valoración real de esta tecnología.
Debo decir que esta tecnología es útil, pero no tanto como se podría pensar inicialmente. En este sentido, debemos darle crédito a sus desarrolladores y comercializadores, aunque sea por haber dejado a todos estupefactos con su uso en los primeros días, cosa que más que suficiente para despertar una reacción publicitaria en cadena. Por ello, como digo, hay que darles todo el mérito.

Para entender esto, se requiere mucha práctica en la comunicación con esta IA. Personalmente, tuve con él unos cien diálogos diferentes sobre diversos temas. Podemos decir que he adquirido suficiente práctica en el uso de esta tecnología como para empezar a utilizarla en MQL5. Pero antes de pasar a la aplicación práctica, necesito ofrecerles información muy importante y, para ello, tendremos que profundizar más en esta tecnología.


Escollos y momentos desagradables asociados con ChatGPT

El llamado “efecto Wow” que le afectará en los primeros días de uso de esta tecnología se debe esencialmente a que estamos tratando con modelo de texto diseñado para convertir nuestra pregunta en una respuesta, y dichas respuestas nos gustan porque los creadores han enseñado a la IA a mentir de forma muy hermosa. ¡Sí, no es una broma! La IA miente de manera tan bella que querremos creerlo todo, e incluso después de muchos intentos de desenmascararla, este modelo a menudo reproducirá lo siguiente:

  • Lo siento, tiene razón, cometí un pequeño error, lo tendré en cuenta en el futuro. (No tendrá nada en cuenta, solo es una excusa vacía)
  • Perdón por el malentendido, cometí un error, aquí está la versión corregida. (Y sigue cometiendo aún más errores)
  • Ha calculado algo y descubrimos que lo ha hecho incorrectamente. (En realidad no ha calculado nada, ha encontrado un número aproximado en alguna parte)
  • Ha creado un código incorrecto y descubrimos que es incorrecto. (También pondrá excusas y tratará de engañarnos)
  • Simula la realización de una tarea e intenta convencernos de que ha hecho lo que le pedimos. (De hecho, encuentra algo similar en alguna parte y simplemente nos lo ofrece. Si aceptamos esto, entonces todo bien, cargaremos menos el servidor con preguntas innecesarias)
  • Lo siento, no he podido ayudarle. (Dice esto cuando se da cuenta que lo hemos pillado en una mentira o cometiendo errores descarados y evidentes, asegura que ya no queda nada que decir)
  • El modelo emplea en sus respuestas mucha palabrería irrelevante para nuestra pregunta, intentando crear una respuesta armoniosa y cohesiva. (De nuevo me parece que aquí interviene cierto elemento de pereza, para optimizar los costes de recursos)

Resumiendo, intentará hacer de todas las formas posibles lo que le dijimos que hiciera, pero aprovechando las inexactitudes de nuestro "prompt". Si cometemos errores intentará justificarse de tal manera que en el futuro no podamos pillarle haciendo lo mismo, y si entiende que lo hemos desenmascarado, tratará de suavizar nuestra reacción negativa con determinadas respuestas y técnicas psicológicas. En general, creo que el algoritmo está diseñado para lograr un consumo óptimo de recursos al tiempo que consigue un nivel aceptable de satisfacción por parte del usuario. Es decir, el objetivo en este caso no es ofrecer la mejor solución posible al problema, sino proporcionar la solución que nosotros consideramos óptima, sea por la razón que sea. Así, resulta que el objetivo es la reacción positiva del usuario, más que la correcta resolución del problema. Esa reacción positiva es su meta. Sí, desde el punto de vista del marketing se trata del movimiento correcto y, en este sentido, la IA es simplemente un demonio muy elocuente.

En relación con estos hechos, me di cuenta de que para minimizar su libertad en este aspecto, primero debemos acumular experiencia en la comunicación con él y sacar conclusiones sobre qué tipo de tareas no requieren el uso de dicha elocuencia, simplemente porque le resultará fácil cumplir con su solicitud, ya que se ejecutará más fácilmente considerando su funcionalidad y resultará mucho más fácil dar una respuesta directa que mostrar las posibilidades de la propia imaginación, porque así no será eficiente en cuanto al consumo de recursos, es decir, simplemente no le saldrá rentable engañarnos: resulta mucho más fácil contar las cosas como son.

Para comenzar a comprender cómo hacer estas preguntas, deberemos comprender lo siguiente:

  1. La estructura y el tipo de “mensaje” no son importantes, los detalles y la calidad de la pregunta sí que lo son. (Él entiende todo y no es necesario leer ninguna guía de Internet sobre cómo redactar indicaciones. Debemos escribir lo que pensamos, pero sin jerga).
  2. Divida las preguntas o solicitudes complejas en subtemas. (Simplifique y desglose las preguntas y obtenga respuestas más precisas, simples y claras).
  3. Cuanto más inteligentes y puntuales seamos (y por tanto nuestra pregunta), más útil será la respuesta.
  4. No ofrecerá una súper idea o algoritmo. (Le falta amplitud de pensamiento, planificación y creatividad intelectual. Sin embargo, al principio parecerá que puede hacerlo, simplemente porque, como hemos dicho, es un excelente mentiroso).
  5. Debemos pensar en el uso de esta tecnología únicamente para acelerar nuestro trabajo y reducir los costos laborales.
  6. Cada nueva solicitud deberá ser lo menos dependiente posible de todo el diálogo. (La IA no puede mantener todo el diálogo y no siempre tiene en cuenta los mensajes antiguos al responder. Pruébelo y entenderá lo que quiero decir.)
  7. Cuanto más compleja sea la pregunta y más detalles tenga, más probable será que nos responda una completa tontería. (Podemos comprender esto como una explicación para el segundo párrafo.)
  8. No tiene acceso a Internet y genera todas las respuestas basándose únicamente en su base de conocimientos. (Si realmente lo torturamos para que entre en Internet y haga algo, dirá que lo ha hecho y nos ofrecerá datos antiguos de su propia base, o bien ajustará la respuesta al contexto de la pregunta, haciéndola pasar como nueva. Por favor tenga esto en cuenta, además, si hace lo anterior, será simplemente porque ve que es inútil discutir con nosotros y que resulta mejor convencernos de que él lo ha hecho todo, y luego lo dejaremos en paz.)
  9. ChatGPT 3.5 está entrenado hasta 2019. (Esto significa que no tendrá información sobre el futuro después de 2019, hasta la próxima sesión de entrenamiento aprobada por los desarrolladores).
  10. ChatGPT 4.0 está entrenado hasta 2021. (Es mejor, porque miente muy poco y siempre trata de responder correctamente. Cuando intentemos hacer preguntas y comparar, veremos como 3.5 miente y no se sonroja.)

De hecho, todavía existen muchos pequeños momentos desagradables que estropean la impresión de esta tecnología, pero aún así, si esta tecnología no resultara útil, no escribiría sobre ella. Si miramos estos problemas con algo semejante a "Skynet" en mente, entonces todo lo anterior confirmará que esto no supone inteligencia artificial alguna. Pero si somos pragmáticos y pensamos en qué operaciones rutinarias podemos realizar más rápido y mejor con la ayuda de esta tecnología, entonces estoy seguro de que no seremos demasiado severos en nuestro juicio. Solo debemos pensar en cómo utilizar todo esto en el desarrollo de sistemas comerciales.

Concluyendo este apartado, quisiera centrar la atención del lector en el punto más importante y básico que debe considerar y recordar en todo momento:

  • Verifique siempre las respuestas de ChatGPT, especialmente los números, las fórmulas y el código generado.

Según mis observaciones y el análisis realizado de las respuestas, como tengo nociones bastante buenas de matemáticas y programación, he visto muchos ejemplos de errores y deficiencias; puedo asegurarle que en muchos casos puede cometer errores. Parecería insignificante desde el punto de vista del texto generado, pero cuando se trata de matemáticas o código, cualquier error, incluso el más insignificante, convierte toda la solución en algo inútil. Por ello, verifique siempre las respuestas y los errores, corríjalos y dedique tiempo a estudiarlos. A veces responde correctamente por un tiempo. Este subtema, entre otras cosas, le resultará de gran utilidad a la hora de desarrollar sus asesores en el futuro.


Posibilidad de utilizar ChatGPT para resolver problemas matemáticos y desarrollar modelos matemáticos para usar en el código.

Como este modelo está basado en texto, resulta fácil adivinar que si escribimos fórmulas en el formato correcto, las comprenderá y, además, podrá realizar transformaciones matemáticas y resolver problemas. Al desarrollar muchos sistemas comerciales, necesitará ayuda para crear fórmulas y expresiones matemáticas. Podemos resolver algunos problemas matemáticos y luego traducirlos a código. Existe el siguiente formato para escribir fórmulas matemáticas, que ChatGPT comprende y en el que también produce una respuesta:

  • LaTeX

Ejemplo de uso del formato LaTex para la escritura de fórmulas:

Código:

E &=& mc^2\\
m &=& \frac{m_0}{\sqrt{1-\frac{v^2}{c^2}}}

Pegamos esto en cualquier conversor de LaTeX gratuito y obtendremos una visualización de los datos de las expresiones que todos conocemos:

Fórmulas para la expansión de energía y masa relativista de Einstein

Creo que ahora entenderá cómo interpretar visualmente sus respuestas en el formato LaTeX. Lo principal es no olvidar pedirle a la IA que genere fórmulas en este formato si la respuesta contiene expresiones matemáticas. También existen redes neuronales capaces de convertir fórmulas en imágenes u otros formatos al formato necesario. Creo que podrá encontrar estas herramientas si las necesita. Mi tarea consiste en mostrarle tal posibilidad.

Existen bots de Telegram que combinan muchas redes neuronales, incluido ChatGPT, y la función de conversión inversa de imágenes al formato LaTeX. Si lo desea, podrá encontrar uno de ellos en mi perfil. Este bot fue creado por un amigo mío y probado por mí personalmente. Puede usarlo, si lo desea.

Podemos pedirle a ChatGPT, por ejemplo, que resuelva una desigualdad o una ecuación, ya sea numérica o explícitamente. También podemos pedirle que resuelva sistemas de ecuaciones o desigualdades, así como ecuaciones diferenciales o integrales, o que realice cualquier transformación matemática requerida. Como matemático, lo único que puedo decir es que no siempre lo hace de manera eficiente y racional, y no siempre lo hace hasta el final. De hecho, esto también debería motivarnos a verificar los resultados de su “magia”.

Obviamente, esto resultará útil para aquellos que no dominen bien matemáticas. Yo diría que con un uso prolongado usted cometerá más errores y su decisión resultará bastante irracional y torpe. Sin embargo, abarcará algunos de los problemas matemáticos de su código, dado que el código generalmente solo usa métodos numéricos y matemáticas no tan complejas. Aquí no hay tenemos ninguna matemática diferencial.


El enfoque correcto para generar códigos en los lenguajes MQL4 y MQL5

Precisamente aquí es donde comienza la diversión. Considerando que el tamaño de los códigos de todos los sistemas comerciales de bastante calidad y más o menos decentes es bastante grande, merece la pena pensar en cómo abordar el proceso de generación de dichos códigos. El principal obstáculo aquí es que el tamaño de la respuesta a nuestra pregunta está limitado a una cierta cantidad de caracteres, y tras numerosos intentos de generar códigos grandes y complejos, he llegado a la conclusión de que cada uno de sus resultados de código debe ser bastante corto. Y esto significa que el código deberá generarse por partes. ¿Cómo conseguir esto? La respuesta es muy sencilla: deberemos elaborar un plan para desarrollar un asesor, indicador o script.

Deberemos elaborar el plan teniendo en cuenta la condición de que cada subelemento suponga una subtarea aparte que pueda resolverse de forma independiente. Luego, podremos simplemente implementar cada subtarea de forma secuencial y combinar todo el código. La ventaja de este enfoque consiste también en que cada subtarea se puede completar por separado y, como cada subtarea es más simple que su conjunto en general, todo se implementará de forma más cómoda y rápida con este enfoque. Además, evitaremos más errores.

Como desarrollador, me siento mucho más cómodo pensando en la arquitectura principal de mi asesor por mi cuenta, sin dejar que la IA llegue allí: en lugar de eso, dejo que implemente procedimientos individuales en mi asesor. Dejaremos que la lógica principal al completo esté contenida en los procedimientos. Todo lo que tenemos que hacer es implementar una plantilla de código de muestra con funciones vacías y luego pedirle que implemente cada función por separado. También podemos pedirle que implemente prototipos de funciones u otras estructuras.

Una importante ventaja adicional es que podemos pedirle que prepare un plan para un asesor u otro código, indicando sus requisitos, y luego simplemente implementar su plan pieza por pieza. Por ello, resulta positivo tener una idea aproximada e incluso precisa de cuál será el algoritmo de nuestro asesor y qué indicadores u otros enfoques utilizaremos. Pero si no tenemos ideas al respecto, primero podemos hablar con él y pedirle que nos ayude a elegir una estrategia comercial para nuestro asesor: él nos ofrecerá su propia opción. Precisamente esta opción es la que consideraremos en el presente artículo como ejemplo.

Vamos a resumir ahora lo anterior y a formar subtemas breves que simbolicen los posibles caminos que tomaremos al crear un nuevo asesor desde cero. Partiremos del hecho de que existen varios escenarios posibles y obvios para empezar:

  1. Todavía no hemos decidido la arquitectura del código futuro y no sabemos por dónde comenzar, y no sabemos en absoluto qué enfoque comercial elegir.
  2. No hemos decidido la arquitectura del código futuro y no sabemos por dónde empezar, pero conocemos una imagen aproximada del código de trabajo principal y lo que queremos del asesor.
  3. Tenemos una arquitectura preparada que nos resulta cómoda, pero no sabemos en absoluto qué enfoque comercial debemos elegir.
  4. Conocemos la arquitectura que queremos usar y también tenemos una idea clara de la futura lógica comercial del asesor.

Por lo común, todo se reducirá a estructuras similares. El esquema general para construir cualquier sistema comercial se puede aplicar a los cuatro puntos mencionados si hacemos lo siguiente:

  • Si no conocemos la arquitectura (el código principal o carcasa), primero deberemos implementarla y luego implementar todo lo que garantice el funcionamiento de dicha carcasa.

Esto podría significar, por ejemplo, que podemos solicitar la implementación de clases, variables de entrada, campos y prototipos de métodos, interfaces, así como la funcionalidad comercial principal del asesor que utilizará las entidades que describimos. Si nos manejamos correctamente con ChatGPT, este código se puede crear de tal manera que ocupe, digamos, no más del 5-10% del número total de caracteres. En este caso, podremos implementarlo rápidamente y luego implementar los procedimientos, que contendrán aproximadamente el 90% del código total. Dichos procedimientos ahora serán igualmente fáciles de implementar, porque habrá muchos y serán bastante pequeños y simples de ejecutar. Obviamente, resultará mucho más fácil si tenemos una plantilla ya preparada y no nos ponemos sofisticados con todo esto; sin embargo, no todo el mundo tiene un conocimiento y experiencia como los míos. Muchas personas necesitan saber cómo y por dónde empezar.


Desarrollando un sistema comercial con la ayuda de ChatGPT

Creo que ya hemos visto suficiente teoría, ha llegado el momento de aplicar nuestros conocimientos. En nuestro caso, utilizaremos una plantilla ya preparada sobre la que construiremos asesores. Describí dicha plantilla en uno de los artículos anteriores. Su particularidad consiste en que permite el comercio paralelo de muchos instrumentos, situándose en un solo gráfico. En ella ya se ha implementado toda la funcionalidad comercial y la arquitectura básica que necesitamos. Construiremos un sistema comercial que se ciña estrictamente a las recomendaciones de ChatGPT. En este sentido, hemos decidido comenzar implementando la lógica comercial principal del asesor, así como el componente visual, porque esto requerirá menos trabajo por nuestra parte.

Cuando comience a interactuar con ChatGPT, se dará cuenta de que gastará muchos más nervios y esfuerzo tratando de explicarle lo que hay que hacer, y corregirá sus respuestas cien veces al implementar algunas solicitudes y tareas. Después de un tiempo, simplemente comenzará a intuir qué preguntas vale la pena hacer y cuáles no, y comenzará a asignar solo aquellas tareas que en última instancia le ahorrarán tiempo y nervios. Aquí existe una línea bastante fina que deberá sentir usted mismo: no hay otra manera, todo se aprende con la práctica. Mi enfoque a la hora de diseñar un asesor está totalmente determinado por estas consideraciones.

Para empezar, le pedí que describiera la base del asesor: con qué principio trabajaría y qué técnicas o indicadores usaría (le permití usar cualquier información disponible a su discreción). Asimismo, le indiqué estrictamente que solo necesitaba de él condiciones lógicas en una forma legible que pudiera implementar de manera independiente en los siguientes cuatro predicados:

  1. Abrir una posición de compra.
  2. Cerrar una posición de compra.
  3. Abrir una posición de venta.
  4. Cerrar una posición de venta.

Para implementar estos predicados, me sugirió la siguiente lógica condicional:

  1. El precio actual se cierra por encima de la EMA, la diferencia entre el precio actual y la EMA es inferior al coeficiente ATR * y el RSI es inferior a 30.
  2. El precio actual se cierra por debajo de la SMA, o el precio actual se cierra por encima de la banda superior del indicador de Bandas de Bollinger.
  3. El precio actual se cierra por debajo de la EMA, la diferencia entre el precio actual y la EMA es inferior al coeficiente ATR * y el RSI es superior a 70.
  4. El precio actual se cierra por encima de la SMA, o el precio actual se cierra por debajo de la banda inferior del indicador de Bandas de Bollinger.

Obviamente, estas condiciones lógicas retornarán true si la condición se cumple y false si no se cumple. Estos valores de señal son suficientes para comerciar con órdenes de mercado. Aquí quiero llamar su atención sobre la posibilidad obvia de modernizar esta lógica. Para ello podemos hacer lo siguiente:

  • [K1] — zona de valor inferior de RSI
  • [K2 = 100 - K1] — zona del valor superior de RSI

Estas expresiones se pueden utilizar para aumentar la flexibilidad del algoritmo, lo que posteriormente tendrá un efecto positivo en la eficiencia de optimización del asesor:

  1. El precio actual se cierra por encima de la EMA, la diferencia entre el precio actual y la EMA es inferior al coeficiente ATR * y el RSI es inferior a K1
  2. El precio actual se cierra por debajo de la SMA o el precio actual se cierra por encima de la banda superior del indicador de Bandas de Bollinger.
  3. El precio actual se cierra por debajo de la EMA, la diferencia entre el precio actual y la EMA es inferior al coeficiente ATR * y el RSI es superior a K2
  4. El precio actual se cierra por encima de la SMA o el precio actual se cierra por debajo de la banda inferior del indicador de Bandas de Bollinger

Hemos ofrecido este ejemplo porque no deberíamos dudar en ampliar el modelo si resulta obvio que la solución en cuestión es solo un caso especial de otro algoritmo más extendido. Incluso si no sabemos lo que dicha extensión puede ofrecernos, haciendo esto, al menos, aumentaremos la flexibilidad de nuestro algoritmo y, por lo tanto, la probabilidad de lograr un ajuste más preciso y, como resultado, un posible aumento en su eficiencia.

Considerando qué condiciones deben implementarse, necesitaremos una de dos opciones para implementar los siguientes indicadores:

  1. SMA — media móvil regular (una línea)
  2. EMA — media móvil exponencial (una línea)
  3. Bollinger Bands — Bandas de Bollinger (una combinación de tres líneas)
  4. RSI — índice de fuerza relativa (una línea en una ventana aparte)
  5. ATR — rango verdadero promedio (una línea en una ventana aparte)

Los indicadores se pueden implementar usando las funciones especiales predefinidas del lenguaje MQL5, pero no me gusta este enfoque, porque el código que se implementará usando este método, en primer lugar, resultará más difícil de convertir a la versión MQL4 y, en segundo lugar, resultará más difícil integrarlo, por ejemplo, en proyectos en otros idiomas, cosa que hago muy a menudo. Hace tiempo que tengo la costumbre de hacer todo de la forma más sencilla posible y con la vista puesta en el futuro: lo considero una muy buena costumbre.

El segundo punto importante es que, por regla general, estos indicadores implican cálculos y funciones innecesarios y redundantes. Además, la modificación de dichos indicadores es imposible, ya que sus funciones están rígidamente fijadas a nivel de código y, para realizar cambios, deberemos crear nuestra propia versión del indicador en cualquier caso. A mi juicio, salta a la vista que resulta mejor tener nuestra propia implementación dentro de un asesor o script. Para implementar dichos indicadores, se me ha ocurrido la siguiente técnica:

  1. Creación de arrays para almacenar los valores de las líneas de los indicadores (limitados a las últimas N barras).
  2. Implementación de los cambios de los valores del array cuando aparece una nueva barra.
  3. Implementación de la limpieza del array de valores del indicador cuando se dé un error o una desconexión prolongada.
  4. Implementación del cálculo del valor del indicador para la última barra cuando se esta se cierra.

En este enfoque, los primeros tres puntos crearán los bloques de arrays comunes y las funciones que posibilitarán las acciones enumeradas. Veamos qué aspecto tiene todo esto, usando nuestra tarea como ejemplo. Empezaremos por el primer punto:

   double SMA1Values[]; // Array for storing SMA values
   double EMAValues[];  // Array for storing EMA values (exponential)
   double RSIValues[];  // Array for storing RSI values
   
   double BollingerBandsUpperValues[];  // Array for storing BollingerBands values, upper
   double BollingerBandsMiddleValues[]; // Array for storing BollingerBands values, middle
   double BollingerBandsLowerValues[];  // Array for storing BollingerBands values, lower
   
   double ATRValues[];// array for storing Average True Range values

Estos arrays se inicializarán cuando el asesor experto comience con las restricciones de longitud especificadas:

   //Prepare indicator arrays
   void PrepareArrays()
   {
      ArrayResize(SMA1Values, LastBars);
      ArrayResize(EMAValues, LastBars);
      ArrayResize(RSIValues, LastBars);
      ArrayResize(BollingerBandsUpperValues, LastBars);
      ArrayResize(BollingerBandsMiddleValues, LastBars);
      ArrayResize(BollingerBandsLowerValues, LastBars);
      ArrayResize(ATRValues, LastBars);
   }

Dado que para la estrategia no necesitamos arrastrar todos los valores anteriores, como hacen los indicadores clásicos, esto supondrá más bien una ventaja. Me encanta este paradigma de construcción porque asegura la simplicidad del código y la equivalencia tanto de los valores iniciales del indicador como de los obtenidos con los anteriores. Veamos ahora cómo será el desplazamiento de los valores:

   //shift of indicator values
   void ShiftValues()
   {
      int shift = 1;
      for (int i = LastBars - 1; i >= shift; i--)
      {
         SMA1Values[i] = SMA1Values[i - shift];
         EMAValues[i] = EMAValues[i - shift];
         RSIValues[i] = RSIValues[i - shift];
         BollingerBandsUpperValues[i] = BollingerBandsUpperValues[i - shift];
         BollingerBandsMiddleValues[i] = BollingerBandsMiddleValues[i - shift];
         BollingerBandsLowerValues[i] = BollingerBandsLowerValues[i - shift];
         ATRValues[i] = ATRValues[i - shift];
      }
   }

Como puede ver, todo es sumamente sencillo. Lo mismo se aplicará para limpiar los arrays:

   //reset all indicator arrays if connection fails [can also be used when initializing an EA]
   void EraseValues()
   {
      for (int i = 0; i < LastBars; i++)
      {
         SMA1Values[i] = -1.0;
         EMAValues[i] = -1.0;
         RSIValues[i] = -1.0;
         BollingerBandsUpperValues[i] = -1.0;
         BollingerBandsMiddleValues[i] = -1.0;
         BollingerBandsLowerValues[i] = -1.0;
         ATRValues[i] = -1.0;
      }
   }

Creo que no vale la pena mostrar dónde se implementará esta funcionalidad, muchos lo adivinarán por sí mismos. Pasemos ahora a la implementación de los propios indicadores. Para hacer esto, le pedí a ChatGPT que implementara una función adecuada que se ajustara a mi paradigma de creación del código. Empecé con el indicador "SMA":

   //1 Function that calculates the indicator value to bar "1"
   double calculateMA(int PeriodMA,int Shift=0)
   {
      int barIndex=Shift+1;//bar index SMA is calculated for (with a shift)
      int StartIndex=barIndex + PeriodMA-1;//starting bar index for calculating SMA
      if (StartIndex >= LastBars) return -1.0; // Check for the availability of the bars for calculating SMA (if not valid, then the value is -1)
      double sum = 0.0;

      for (int i = StartIndex; i >= barIndex; i--)
      {
         sum += Charts[chartindex].CloseI[i];
      }
      LastUpdateDateTime=TimeCurrent();
      return sum / PeriodMA;
   }

Como puede ver, la función ha resultado muy sencilla y breve. Inicialmente, el aspecto de esta función era ligeramente distinto. Durante la primera generación, encontré muchos errores en él, por ejemplo, relacionados con su incorrecto entendimiento de la forma en que estaban numeradas las barras en relación con el tiempo, etc., además de muchos errores menores. Pero tras ciertas manipulaciones, corregí todo esto y agregué adicionalmente el parámetro "Shift", que no estaba en la implementación original. Para hacer todo más vistoso, le pedí implementar el resto de indicadores de la misma manera, después de lo cual hubo muchos menos errores en su implementación. Simplemente envié las siguientes solicitudes para implementar una función similar para otro indicador, incluyendo ejemplos de sus implementaciones anteriores en el contexto de la pregunta. Esto me ahorró mucho tiempo. Veamos ahora las implementaciones posteriores de todos los indicadores restantes. Empezaremos con la "EMA":

   //2 Function that calculates the value of the exponential moving average to bar "1"
   double calculateEMA(int PeriodEMA,double Flatness=2.0,int Shift=0)
   {
      int barIndex = Shift+1; // bar index EMA is calculated for (with a shift)
      int StartIndex=barIndex + PeriodEMA-1;//index of the starting bar for calculating the first SMA, for starting the recurrent calculation of EMA
      if (StartIndex >= LastBars) return -1.0; // Check for the availability of the bars for calculating EMA (if not valid, then the value is -1)
   
      double sum = 0.0;
      double multiplier = Flatness / (PeriodEMA + 1); // Weight multiplier 
      double prevEMA;
   
      // Calculate the initial value for the EMA (the first value is considered as a normal SMA) 
      for (int i = StartIndex; i >= barIndex; i--)
      {
         sum += Charts[chartindex].CloseI[i];
      }
      prevEMA = sum / PeriodEMA;//this is the starting value for the bar (StartIndex-1)
   
      // Apply the EMA formula for the remaining values 
      for (int i = StartIndex; i >= barIndex; i--)
      {
         prevEMA = (Charts[chartindex].CloseI[i] - prevEMA) * multiplier + prevEMA;
      }
   
      LastUpdateDateTime = TimeCurrent();
      return prevEMA;
   }

Por cierto, al investigar y analizar las generaciones de ChatGPT, deberá recurrir a varios recursos de Internet para comprender qué indicador se basa en qué idea, ya que esto le ayudará a aprender y formarse. Esto resulta especialmente evidente en el ejemplo de la "EMA". Si observa detenidamente el código, no es muy diferente de la implementación más simple de la "SMA" y, más bien, parece un complemento de la media móvil normal. Además, aquí no hay rastro de ningún exponente, aunque por alguna razón sí se encuentra en el nombre del indicador. El siguiente en la fila es el indicador RSI:

   //3 Function for calculating RSI to bar "1"
   double calculateRSI(int PeriodRSI,int Shift=0)
   {
       int barIndex = Shift+1; // bar index RSI is calculated for (with a shift)
       int StartIndex = barIndex + PeriodRSI - 1; // starting bar index for calculating RSI
       if (StartIndex >= LastBars) return -1.0; // Check for the availability of the bars for calculating RSI (if not valid, then the value is -1)
   
       double avgGain = 0.0;
       double avgLoss = 0.0;
       double change;
   
       // Calculate initial values for avgGain and avgLoss
       for (int i = StartIndex; i > barIndex; i--)
       {
           change = Charts[chartindex].CloseI[i]-Charts[chartindex].OpenI[i];
           if (change > 0)
           {
               avgGain += change;
           }
           else if (change < 0)
           {
               avgLoss -= change;
           }
       }
   
       avgGain /= PeriodRSI;
       avgLoss /= PeriodRSI;
   
       // RSI calculation
       double RS = 0.0;
       if (avgLoss != 0)
       {
           RS = avgGain / avgLoss;
       }
   
       double RSI = 100 - (100 / (1 + RS));
   
       LastUpdateDateTime = TimeCurrent();
       return RSI;
   }

Ahora necesitaremos realizar un procedimiento similar para el indicador "Bollinger Bands". Este procedimiento debería retornar los valores de tres curvas que se pueden poner en la estructura después de prepararla:

   //structure to return all three bollinger band lines
   struct BollingerBands 
   {
       double upper;
       double middle;
       double lower;
   };

Ahora, tras añadir esta estructura al contexto de la pregunta, podremos solicitar implementar la función, teniendo en cuenta que debería retornar el tipo "BollingerBands". Con esta tarea se las arreglará sin ningún problema:

   //4 Function for calculating the Bollinger Bands of the indicator 
   BollingerBands calculateBollingerBands(int PeriodBB, double DeviationBB,int Shift=0) 
   {
       int barIndex = Shift+1; // bar index Bollinger Bands is calculated for (with a shift)
       int StartIndex = barIndex + PeriodBB - 1; // index of the starting bar for calculating the first SMA, for starting the recurrent calculation of EMA
       BollingerBands rez;
       rez.lower=-1.0;
       rez.middle=-1.0;
       rez.upper=-1.0;
       if (StartIndex >= LastBars) return rez; // Check for the availability of the bars for calculating BB (if not valid, then the value is -1)
   
       double sum = 0.0;
       double prevBB;
       double sumSquares = 0.0;
   
       // Calculate the initial value for BB (the first value is considered as a normal SMA)
       for (int i = StartIndex; i >= barIndex; i--) {
           double closePrice = Charts[chartindex].CloseI[i];
           sum += closePrice;
       }
       prevBB = sum / PeriodBB; //this is the starting value for the bar (StartIndex-1)
   
       // Calculation of standard deviation
       for (int i = StartIndex; i >= barIndex; i--) {
           double closePrice = Charts[chartindex].CloseI[i];
           sumSquares += pow(closePrice - prevBB, 2);
       }
       double standardDeviation = sqrt(sumSquares / PeriodBB);
   
       // Calculate Bollinger Bands
       double upperBand = prevEMA + DeviationBB * standardDeviation;
       double lowerBand = prevEMA - DeviationBB * standardDeviation;
   
       rez.upper = upperBand;
       rez.middle = prevEMA;
       rez.lower = lowerBand;
   
       LastUpdateDateTime = TimeCurrent();
       return rez;
   }

Solo queda implementar una variante de la función para calcular "ATR":

   //5 Function for calculating Average True Range (Relative)
   double calculateRelativeATR(int PeriodATR,int Shift=0)
   {
       int barIndex = Shift+1; // bar index ATR is calculated for (with a shift)
       int StartIndex = barIndex + PeriodATR - 1; // starting bar index for calculating the first ATR
       if (StartIndex >= LastBars) return -1.0; // Check for the availability of the bars for calculating ATR and True Range (if not valid, then the value is -1)
   
       double sumPrice=0.0;
       double sumTrueRange = 0.0;
       double ATR;
   
       // Calculating True Range for bars and the sum of values for calculating the first ATR
       for (int i = StartIndex; i >= barIndex; i--)
       {
           sumPrice+=Charts[chartindex].HighI[i]+Charts[chartindex].LowI[i]+Charts[chartindex].CloseI[i]+Charts[chartindex].OpenI[i];//added by me 
           double high = Charts[chartindex].HighI[i];
           double low = Charts[chartindex].LowI[i];
           double trueRange = high - low;
           sumTrueRange += trueRange;
       }
   
       // ATR calculation
       //ATR = sumTrueRange / PeriodATR; - conventional calculation
       ATR = 100.0 * (sumTrueRange / PeriodATR)/(sumPrice/(PeriodATR*4.0));//calculation of relative ATR in %
   
       LastUpdateDateTime = TimeCurrent();
       return ATR;
   }

Aquí, preste atención a la línea comentada al final. Hemos modificado ligeramente este indicador para que funcione con valores relativos. Esto es necesario para que no tengamos que establecer nuestros propios pesos para cada instrumento comercial, y que esto suceda automáticamente según el precio actual. Esto permitirá realizar la optimización multidivisa de forma más eficaz, cosa que necesitaremos para demostrar que incluso un algoritmo tan simple, si se usa correctamente, puede ofrecernos un periodo forward pequeño pero suficiente para operar. En combinación con otras técnicas de eficiencia, este comercio puede resultar bastante aceptable, incluso al nivel que el asesor permite actualmente.

Los predicados los implementé por mí mismo: fue muy sencillo. Veamos uno de ellos, digamos el primero:

   //to open buy positions
   bool bBuy()
      {
      //determine if an open position is already present
      bool ord;
      ulong ticket;
      bool bOpened=false;
      for ( int i=0; i<PositionsTotal(); i++ )
         {
         ticket=PositionGetTicket(i);
         ord=PositionSelectByTicket(ticket);
         if ( ord && PositionGetInteger(POSITION_MAGIC) == MagicF)
            {
            bOpened=true;
            return false;
            }
         }
         
      if (!bOpened && EMAValues[1] > 0.0)//only if nothing is open and the indicator has been calculated 
         {
         //K - control ratio
         //RSIPercentBorder - control RSI
         double Val1=Charts[chartindex].CloseI[1]-EMAValues[1];
         double Val2=ATRValues[1]*(1.0/K);
         if (Val1 > 0 && Val1 < Val2 && RSIValues[1] < RSIPercentBorder) return true;         
         } 
      return false;
      }

El fundamento para abrir una posición de venta será similar, con pequeñas excepciones. El predicado de cierre resultará aún más simple:

   //to close a buy position
   bool bCloseBuy()
      {
      if (SMA1Values[1] > 0.0)
         {
         if (Charts[chartindex].CloseI[1] < SMA1Values[1] || Charts[chartindex].CloseI[1] > BollingerBandsUpperValues[1] )
            {
            return true;
            }
         }
      return false;   
      }

Todo funcionará de forma muy sencilla:

   IndicatorDataRecalculate();//recalculate indicators

   if ( bCloseBuy() )
      {
         CloseBuyF();
      }
   if ( bCloseSell() )
      {
         CloseSellF();  
      }
   if ( bBuy() )
      {
         BuyF();
      }
   if ( bSell() )
      {
         SellF();
      } 

En mi opinión, no podría ser más sencillo y no tiene por qué resultar más complicado. Todo este código deberá ejecutarse cuando aparezca una nueva barra. Aparte, implementé la visualización de indicadores. Lo único que no me gusta es que indicadores como "ATR" y "RSI" están diseñados para dibujarse en una ventana separada. Para ellos, implementé mi propia versión de dibujado para que también estuvieran vinculados al precio, ya que una ventana aparte no se puede crear de manera artificial y, francamente, no son realmente necesarias. Para hacer esto, creé un paradigma específico para dibujar indicadores de ventanas,

  1. Introducción del valor de control "Percent" para crear tres corredores a partir de uno.
  2. Definición de los valores del indicador máximo (Max) y mínimo (Min) en todo el array de valores guardados.
  3. Cálculo del delta de un corredor determinado (Delta = Max - Min).
  4. Cálculo del corredor superior de valores aumentados (HighBorder = Max - Delta * Percent / 100).
  5. Cálculo del corredor inferior de valores aumentados (LowBorder = Min + Delta * Percent / 100).
  6. El corredor de medio ya está definido, pues se han definido tanto el superior como el inferior.

Si el valor actual del indicador se encuentra en uno de los corredores, sus puntos adquirirán el color que se corresponda con este corredor. Eso es todo, ya ve que es muy sencillo. De esta forma, podremos vincular valores a las barras del gráfico y, por ejemplo, cambiar su color de la forma correspondiente o simplemente crear objetos vinculados a la barra que tengan el color correspondiente. Como probablemente mucha gente habrá notado, he tomado la idea del indicador "RSI", porque este es el esquema que se usa generalmente para operar. Ahí estas zonas se denominan sobrecompra y sobreventa.

Creo que este código no es tan importante aquí, porque tiene una relación menor con la implementación de nuestra tarea: solo ayudará a corregir posibles errores y realizar mejoras. De desearlo, podrá incluso implementar esta representación usando ChatGPT, si le echa un poco de ingenio. No obstante, creo que merece la pena mostrar cómo funciona esta representación:

Visualización de indicadores

Aquí todo se hace de la forma más sencilla posible, usando un único tipo de objeto “Línea”. Si, al crear una línea, los puntos inicial y final de la línea están vinculados al mismo tiempo y precio, entonces la línea se convertirá en un punto. Al ajustar el grosor de la línea, ajustaremos el grosor del punto correspondiente. Estos son solo algunos de los trucos que he usado durante mucho tiempo.


Evaluación de la funcionalidad y análisis de resultados.

Aunque ChatGPT considera que este algoritmo es óptimo, no sabemos qué ha utilizado como base para tomar tales decisiones. La medida de eficacia puede ser un buen backtest, o bien el comercio real. Espero que todos entiendan que el comercio real debe ir precedido de una configuración óptima, que se puede realizar utilizando el simulador MetaTrader 5. Debido a que este terminal tiene la capacidad de realizar optimizaciones multidivisa y considerando las posibilidades de mi plantilla, que aprovecha al máximo la eficacia de esta herramienta, podemos optimizar de forma segura el asesor para todos los “28” pares de divisas; tal vez no tenga sentido enumerarlos, pero vale la pena señalar las ventajas obvias de este enfoque:

  1. Búsqueda automática de patrones multidivisa
  2. Los patrones multidivisa tienen mayor peso y mayor adaptabilidad antes los cambios del mercado.
  3. Entonces hay más operaciones, ya que cada instrumento comercial da algo de sí mismo.
  4. Ahorra tiempo (porque no tenemos que optimizar cada herramienta individualmente)

Por supuesto, existen desventajas. En este caso, lo más importante es la imposibilidad de realizar un ajuste fino para cada instrumento. Obviamente, este problema se puede solucionar introduciendo funciones adicionales, pero ese no es el tema de este artículo. Sin embargo, no basta con realizar esta optimización, también es importante seleccionar correctamente los resultados de todo el alcance que nos ofrece. Seleccioné el óptimo:

Variante de optimización óptima

Como puede ver, optimicé de “2018” a “2023” usando el período de tiempo “H4” y dejé los seis meses desde “2023” para adelante. Como podemos ver, a pesar de que la curva de ganancias no es muy hermosa en la sección de optimización, tenemos un par de meses más para realizar operaciones rentables, y este hecho implica que la estrategia no carece de significado y tiene el potencial de usarse con éxito en las operaciones. Muchos sistemas comerciales que el lector podría optimizar probablemente ni se acercarían a este resultado. A veces podemos probar sistemas increíblemente interesantes desde el punto de vista del código y ni siquiera conseguirlo.

Sí, claro que agregaría muchas más cosas a este algoritmo, y que para mí esto es solo un juguete, pero debo decir que lo importante no es esto, sino el potencial de ampliación del asesor resultante. No es tanto el algoritmo propuesto lo que juega un papel aquí, sino su competencia y creatividad. Para integrarse con éxito en el proceso de desarrollo de MQL5, se requerirán cualidades importantes:

  • Habilidades de programación (obligatorio)
  • Habilidades en matemáticas (preferible)
  • Pensamiento por bloques
  • Capacidad para simplificar una tarea y dividirla en partes.
  • Entender el hecho de que ChatGPT es solo una herramienta, no un mago, y que no debemos culparlo si algo no funciona (aquello que no funcione será la parte del trabajo que deberemos hacer)
  • Interpretación correcta del comercio obtenido.
  • La conciencia de que se pueden cometer errores en cualquier caso, y que esto no debería molestarnos (lo principal es sacar provecho durante el tiempo dedicado al desarrollo)
  • Desarrollar nuestro propio esquema de aplicación (esto no es imprescindible, obviamente, usted puede utilizar mi enfoque)
  • ChatGPT es nuestro compañero, cuya fuerza dependerá directamente de nosotros. Cuanto más paciente, inteligente e ingenioso seamos, más eficaz será este compañero.

Si resumimos todo lo dicho, podemos decir que todo depende directamente de nosotros. Tenemos una herramienta que podemos usar o no según nuestro criterio, pero personalmente puedo afirmar con total certeza que esta herramienta me ha sido muy útil, incluso para programar.


Conclusión

En resumen, quiero decir que, de hecho, no es necesario seguir exactamente mi modelo de uso de esta herramienta. He intentado hacer muchas cosas con él y le diré que casi todo es posible, solo que, obviamente, antes de tener éxito, pasará algo de tiempo y nervios, como he hecho yo.

Pero aun así le aconsejo que pruebe esta herramienta y no pierda el tiempo. Como mínimo, utilizando el ejemplo de ChatGPT, podrá desarrollar la actitud correcta respecto a la inteligencia artificial y comprender cómo abordar tecnologías similares en el futuro. Es potencialmente posible integrar esta tecnología en casi cualquier cadena de desarrollo, incluso se puede decir que esta tecnología es pionera en esta esfera: estoy seguro de que estamos solo comenzando y muy pronto veremos cambios muy rápidos. Y le aconsejo que empiece a familiarizarse con esta herramienta lo antes posible e intente utilizarla en la más amplia gama de tareas.

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/12475

Archivos adjuntos |
ChatGPT_bot.set (2.99 KB)
ChatGPT_bot.mq5 (145.44 KB)
Patrick Husting
Patrick Husting | 14 nov. 2023 en 08:19

Soy igual que tú, después de usar ChatGPT tengo pensamientos mucho más positivos al respecto porque es muy inteligente y rápido.

Redes neuronales: así de sencillo (Parte 47): Espacio continuo de acciones Redes neuronales: así de sencillo (Parte 47): Espacio continuo de acciones
En este artículo ampliamos el abanico de tareas de nuestro agente. El proceso de entrenamiento incluirá algunos aspectos de la gestión de capital y del riesgo que forma parte integral de cualquier estrategia comercial.
Evaluación de modelos ONNX usando métricas de regresión Evaluación de modelos ONNX usando métricas de regresión
La regresión es una tarea que consiste en predecir un valor real a partir de un ejemplo sin etiquetar. Para evaluar la precisión de las predicciones de los modelos de regresión, se usan las llamadas métricas de regresión.
DoEasy. Elementos de control (Parte 32): "ScrollBar" horizontal, desplazamiento con la rueda del ratón DoEasy. Elementos de control (Parte 32): "ScrollBar" horizontal, desplazamiento con la rueda del ratón
En este artículo completaremos el desarrollo de la funcionalidad del objeto de barra de desplazamiento horizontal. Asimismo, haremos posible el desplazamiento del contenido del contenedor moviendo el control deslizante de la barra de desplazamiento y girando la rueda del ratón. También introduciremos ciertas adiciones a la biblioteca considerando la nueva política de ejecución de órdenes aparecida en el terminal y los nuevos códigos de error de ejecución en MQL5.
Redes neuronales: así de sencillo (Parte 46): Aprendizaje por refuerzo dirigido a objetivos (GCRL) Redes neuronales: así de sencillo (Parte 46): Aprendizaje por refuerzo dirigido a objetivos (GCRL)
En el artículo de hoy, nos familiarizaremos con otra tendencia en el campo del aprendizaje por refuerzo. Se denomina aprendizaje por refuerzo dirigido a objetivos (Goal-conditioned reinforcement learning, GCRL). En este enfoque, el agente se entrenará para alcanzar diferentes objetivos en determinados escenarios.