Português
preview
Del básico al intermedio: Navegando por la SandBox

Del básico al intermedio: Navegando por la SandBox

MetaTrader 5Ejemplos |
33 0
CODE X
CODE X

Introducción

En el artículo anterior, Del básico al intermedio: Acceso aleatorio (II), se mostró cómo podríamos trabajar realmente con archivos para tener acceso aleatorio a los datos o la información que contienen. Se explicó y demostró que un mismo concepto no siempre generaría el mismo tipo de resultado al observar exclusivamente el contenido interno del archivo. Aunque, al observar los resultados impresos en el terminal, no habría diferencias entre una implementación y otra, ya que, básicamente, la propia implementación se encargaría de corregir y adecuar los resultados a lo esperado.

Bien, como la forma de trabajar con archivos básicamente no cambia mucho, y partiendo del supuesto de que entiendes que cada archivo, internamente, es un tipo de registro estructurado, pero sin ningún tipo de declaración explícita del tipo de dato que se verá al observar el contenido de un archivo. En principio, podemos dar por concluida esta primera parte sobre cómo acceder a archivos y trabajar con ellos. En la práctica, tendrás que estudiar la documentación de cada lenguaje específico para poder aprovechar, de la mejor manera posible, las funciones y procedimientos disponibles en ella.

No me malinterpretes, mi estimado lector, por decirte esto. Muy probablemente te gustaría ver cómo se utiliza cada una de las funciones y procedimientos de MQL5. Sin embargo, a mi modo de ver, esto no traería grandes beneficios. Muy al contrario, hacer algo así terminaría por encorsetar el contenido de los artículos, además de hacerlos aburridos y tediosos. El hecho es que, aunque digo que podemos dar por concluido este primer contacto con archivos, aun así no hemos terminado de abordar esta cuestión. Esto ocurre porque lo visto hasta aquí se restringe a las SandBox que MetaTrader 5 mantiene. Básicamente, todavía estamos en el ámbito de lo que podría describirse como acceso de usuario.

Sin embargo, existe otro nivel, que sería el acceso vía aplicación. Esto se tratará en otro momento. Por lo tanto, al establecer esta distinción entre acceso de usuario y acceso vía aplicación, surgen algunas cuestiones un tanto complicadas y que escapan completamente a las reglas impuestas por el uso de las SandBox. Aquí es donde todo empieza a complicarse. Esto, si no has comprendido cómo funciona el sistema de SandBox de MetaTrader 5. Esto ya se abordó en los artículos anteriores.

Antes de entrar en esta cuestión, que complicará mucho las cosas para algunos de ustedes. Existen algunos procedimientos y funciones que, a mi entender, merecen ser explicados. Esto ocurre por la enorme utilidad que tienen, pensando exclusivamente en trabajos con archivos, ya que nos permiten realizar operaciones que, de otro modo, no serían posibles. Para abordar esta cuestión de manera adecuada, pasemos al tema principal de este artículo.


Navegando entre archivos y directorios

Aunque muchos puedan considerar innecesaria esta labor de búsqueda, y esto, en la mayor parte de las aplicaciones, será cierto, existen situaciones muy específicas durante la programación, tanto aquí en la programación para MetaTrader 5 como para otros entornos, donde necesitamos implementar una tarea de búsqueda en un árbol de directorios y archivos. Entender cómo hacer esto quizá sea una de las tareas y actividades más burocráticas que podrás experimentar. Porque, en muchos casos, es algo muy repetitivo y, en cierto modo, aburrido. Sin embargo, aun así, no deja de ser importante que sepas cómo realizar este tipo de tarea.

Debido a ciertas características, al programar para MetaTrader 5, podemos realizar la búsqueda de dos maneras diferentes. Una, de forma interactiva, y la otra, de forma automática, por así decirlo. La manera interactiva utiliza un cuadro de diálogo muy parecido a un mini explorador de archivos. La forma automatizada, en cambio, tiene como objetivo utilizar funciones proporcionadas por MQL5 para acceder a procedimientos del sistema operativo para buscar en el sistema de archivos.

Para empezar, vamos a modificar, de una manera muy simple y fácil de entender, uno de los scripts que vimos en el artículo anterior. Así podremos entender cómo funcionaría el acceso interactivo y la búsqueda de archivos y directorios. El código ya modificado se muestra íntegramente a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     int handle;
07.     const datetime dt = D'31.10.2024 15:30:10';
08.     const int i32 = 356248;
09.     string filenames[];
10. 
11.     if (FileSelectDialog("Save as...", NULL, "All files (*.*)|*.*", FSD_WRITE_FILE, filenames, "Hello Word.txt") <= 0)
12.         return;
13. 
14.     if ((handle = FileOpen(filenames[0], FILE_WRITE| FILE_READ | FILE_ANSI)) == INVALID_HANDLE)
15.     {
16.         Print("Error...");
17.         return;
18.     };
19. 
20.     FileWrite(handle, i32, "Info", dt);
21. 
22.     FileFlush(handle);
23.     
24.     FileSeek(handle, 0, SEEK_SET);
25.     while (!FileIsEnding(handle))
26.         Print(FileTell(handle), " >> ", FileReadString(handle));
27. 
28.     FileClose(handle);
29. }
30. //+------------------------------------------------------------------+

Código 01

No lo entiendo. ¿Dónde está el cambio en el código? A primera vista, es exactamente igual a los códigos que vimos en el artículo anterior. Bien, los cambios son muy sutiles y, a primera vista, no tienen mucho impacto en el código. Muchos creen que, para diseñar un nuevo código, necesitamos implementarlo de forma radical. En la práctica, sin embargo, no siempre lo hacemos así. Básicamente, el cambio aquí es muy fácil de entender y se encuentra en la línea once. Sin embargo, aunque el cambio esté solo en la línea once, cuando se ejecute este código, hará algo diferente. Para empezar, esta función FileSelectDialog abrirá una ventana, como se muestra a continuación.

Imagen 01

En esta ventana que podemos ver en la imagen 01, proveniente del sistema operativo y mantenida por él, podemos visualizar fácilmente algunos elementos. Primero, el título de la ventana. Como puedes notar, es el mismo que declaramos como primer argumento de la función FileSelectDialog. Como el segundo argumento pasado a la función es un valor NULL, comenzaremos en la raíz de la SandBox. Ahora, presta atención, mi estimado lector: como estamos dentro de una SandBox, NO PODREMOS salir del directorio, o mejor dicho, de la raíz actual. Es decir, no tendrás libertad para navegar por todos los directorios de la unidad de disco donde está instalado MetaTrader 5. De esta manera, quedarás restringido al árbol de directorios de la SandBox actual.

En el tercer argumento de la función, pasamos un filtro que podrás utilizar para filtrar la selección en la ventana de búsqueda. Solo podrás seleccionar los filtros indicados aquí, en la línea once. Por lo tanto, no esperes que el sistema operativo permita utilizar filtros no indicados aquí, ya que esto no ocurrirá. El siguiente argumento de la función son los flags de selección. Aquí, es importante que practiques un poco con otros flags para ver el tipo de resultado y el propósito de cada uno, ya que podemos hacer muchas más cosas que simplemente indicar un nombre de archivo o algo similar. Consulta la documentación para saber qué valores pueden utilizarse aquí en los flags.

Bien, ahora nos queda entender los dos últimos argumentos de la función FileSelectDialog. Esta parte puede variar ligeramente, según el tipo de implementación que estés haciendo. Pero, básicamente, el quinto argumento deberá ser siempre un array dinámico de tipo string. Esto ocurre porque la función rellenará este array con datos de interacción del usuario con la ventana que se ve en la imagen 01. El último argumento, por su parte, no tiene por qué aparecer como se ve en el código 01. Sin embargo, si esperas usar algún nombre específico de archivo, deberás indicarlo aquí. Así, tendremos, al final, la indicación de lo que sería el nombre predeterminado esperado por nuestra aplicación. Conviene recordar que el usuario puede cambiar este nombre.

Bien, si todo ocurre sin problemas, la función devolverá un valor mayor que cero. Si esto no ocurre, significa que hubo un error y deberemos interrumpir la aplicación. Esto se hace en la línea doce. Si tenemos éxito, y como queremos guardar un archivo, pasaremos a la línea 14, donde el código vuelve a funcionar como en el artículo anterior. Sin embargo, observa que, al crear o abrir el archivo con la función FileOpen, el primer argumento que se pasa es justamente el primer valor contenido en el array. Este array puede gestionarse de modo que se carguen varios archivos al mismo tiempo. Los archivos serían seleccionados por el usuario durante la llamada de la línea once. Como informé, es necesario que practiques para entender mejor cómo puedes utilizar esta función FileSelectDialog en tus aplicaciones, en MetaTrader 5.

Bien, creo que esta breve explicación ya te da cierta orientación para entender y practicar la navegación interactiva por el árbol de archivos y directorios. Entonces, para separar los temas, veamos en un nuevo tema cómo se realiza la navegación no interactiva.


Navegando mediante código

Existen algunas situaciones en las que no queremos que el usuario interactúe directamente con el sistema de búsqueda. Sin embargo, al mismo tiempo, queremos, por cualquier motivo, saber cómo está estructurado el árbol de directorios, tanto en lo relativo a los archivos como a la propia estructura de directorios. Para lograrlo, dejamos de lado lo que vimos en el código 01 e implementamos algo diferente. Pero lo hacemos con un objetivo muy específico.

Como aquí la idea es ser lo más didáctico posible, sin tener como objetivo la creación de ninguna aplicación en especial, resulta un tanto difícil explicar la motivación por la que podemos llegar a querer navegar por el árbol de directorios. Sin embargo, quiero que, mi estimado lector, intentes abrir la mente y ver más allá de lo que se mostrará aquí como código. Intenta imaginar alguna aplicación interesada en saber cómo está organizada la estructura de archivos. A partir de esto, piensa en una forma de usarlo en la práctica.

Muy bien, para empezar y para que puedas entender cómo funciona este tipo de navegación, vamos a partir de la base de que la SandBox del directorio MQL5\Files está vacía. Es decir, todavía no existe ningún archivo ni directorio dentro de la SandBox. Es importante comenzar con este principio para que todo tenga sentido. A partir de esto, comenzamos con el código que vemos a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     long    handle;
07.     string  szFileName;
08. 
09.     if ((handle = FileFindFirst("*", szFileName)) == INVALID_HANDLE)
10.     {
11.         Print("Failed...");
12.         return;
13.     }
14.     do
15.     {
16.         Print(szFileName, " is a ", FileIsExist(szFileName) ? "file ..." : "directory...");
17.     }while (FileFindNext(handle, szFileName));
18.     FileFindClose(handle);
19. 
20.     Print("Search in directory completed successfully.");
21. }
22. //+------------------------------------------------------------------+

Código 02

Ahora recuerda lo siguiente: todo lo que hagamos estará restringido a la SandBox a la que estemos apuntando. En principio, no puedes ver archivos o directorios fuera de la SandBox. No lo olvides. Entonces, cuando ejecutemos este código 02, obtendremos el resultado que se muestra a continuación.

Imagen 02

Dios mío, ¿qué pasó aquí? ¿Cómo puede ser que el código haya fallado? ¿Qué le hice a DIOS para merecer esto? Esto solo puede ser un castigo divino. ( RISAS ). Calma, mi estimado lector, vayamos con calma. No hay nada malo en el código. Funciona perfectamente bien. ¿Cómo puede ser? ¿No ves que devolvió un error? Nuevamente, vayamos con calma. ¿Recuerdas lo que se dijo antes de empezar? ¿Que, en principio, tendríamos el directorio MQL5\Files, que es la SandBox que estamos usando aquí, completamente vacío?

Pues bien, como FileFindFirst no encontró absolutamente nada en la SandBox, devuelve un valor de identificador inválido. O mejor dicho, dado que no se encontró ninguna coincidencia con el filtro, FileFindFirst devuelve un valor que indica que la búsqueda no tuvo éxito. Por eso vemos el resultado mostrado en la imagen 02. Tanto es así que, si ejecutas nuevamente el código 01 ahora, verás lo siguiente.

Imagen 03

Correcto, creo que lo entendí. Pero ¿y si tenemos algún contenido dentro de la SandBox? ¿Qué ocurrirá? Bien, esto depende de cómo esté estructurado nuestro código para trabajar con el contenido de la SandBox. Como aquí, en este momento, estamos trabajando con algo muy simple y objetivo, el resultado será igualmente simple y objetivo. Sin embargo, puede ser necesaria una solución un poco más avanzada, según el caso. De todos modos, veamos primero qué ocurriría si tuviéramos algún tipo de contenido en la SandBox. Para ello, creamos algunos archivos y directorios solo con fines de prueba. Podemos verlo al ejecutar nuevamente el código 01. En este caso, el resultado es el que se observa en la siguiente imagen.

Imagen 04

Bien, ahora tenemos algo que puede mostrarse. Entonces, cuando ejecutemos nuevamente el código 02, obtendremos el resultado que se muestra a continuación.

Imagen 05

Observa que no cambiamos absolutamente nada en los códigos, solo añadimos contenido en la SandBox. Sin embargo, aquí es donde todo empieza a complicarse un poco más. Esto depende, claro, de lo que quieras implementar. Aunque el código 02 funciona, como pudiste observar en las imágenes anteriores, existe un pequeño detalle. El código 02 queda limitado al directorio inicial de la búsqueda. No puede entrar en otros directorios del árbol para informar qué contenido hay en ellos. Es necesario que indiques que deseas acceder a un directorio específico. Esto, incluso antes de iniciar la búsqueda, que comienza en la línea nueve. Esto, en algunos casos, limita un poco las posibilidades.

Ahora, vamos a detenernos y pensar un poco. La razón es que la solución para navegar por el árbol de directorios está en el propio código 02. Sin embargo, es necesario hacer un pequeño cambio en el código para que funcione como queremos. Es decir, que el código pueda informar todos los archivos que existen en cada directorio del árbol de la SandBox.

Muy bien, sabemos que, al indicar un filtro para la función FileFindFirst, podemos incluir una ruta dentro de la SandBox. Entonces, ¿y si transformáramos este mismo código 02 en un código recursivo? ¿Obtendríamos el comportamiento que queremos? Así, la línea 16 del código 02 podría informarnos el nombre de cada archivo y dónde está ubicado. Bien, esta es la gran cuestión que debemos resolver ahora. Conviene recordar que existen diversas maneras de hacer lo que voy a mostrar aquí. Cada caso es diferente.

Bien, lo primero que hay que hacer es cambiar el código por algo parecido a lo que se muestra a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (FileIsExist(szFileName)) Print(szFileName);
22.     }while (FileFindNext(handle, szFileName));
23.     FileFindClose(handle);
24. }
25. //+------------------------------------------------------------------+

Código 03

Este es el primer paso. Ahora, presta atención, mi estimado lector. Cuando este código se ejecute, el resultado será diferente del mostrado anteriormente. Esto ocurre porque ahora nos centramos solo en visualizar los nombres de los archivos. Es muy importante que entiendas bien esto. Probablemente esperarías ver algo parecido a lo que se muestra en la barra de navegación del explorador de archivos, donde podemos ver la ruta de directorios y el nombre del archivo juntos. Pero lo que ves es solo la forma en que el sistema operativo o el programa te muestra el contenido. Internamente, dentro de la estructura de carpetas y archivos grabada en disco, la disposición no funciona de esa manera.

En realidad, un sistema de archivos se parece mucho a una lista o una agenda. Quizá el problema y toda esta confusión se hayan creado cuando apareció Windows 95. En esa época, se empezó a hablar de usar el árbol de directorios como parte del nombre del archivo. En la práctica, eso no ocurre exactamente así. Pero explicar esto escapa por completo al alcance de este artículo. Volvamos a nuestro tema principal. El resultado de ejecutar este código 03 se muestra en la siguiente imagen.

Imagen 06

Observa que, aquí, vemos solo el nombre de los archivos. Los directorios no se muestran, justamente porque no nos interesan en este momento. Sin embargo, suponiendo que exista algún contenido dentro de los directorios mostrados en la imagen 05, ¿cómo podríamos verlo? Bien, esta es la parte fácil. Pero, antes de ver esto, quiero que observes que, cuando reportemos un directorio, el último carácter será una barra inclinada. Esto es muy importante para lo que veremos a continuación.

Es decir, cuando la string szFileName se refiera a un directorio, habrá una barra inclinada en la string. Así, no necesitamos utilizar la función FileIsExist para analizar si se trata de un directorio o de un archivo. Basta con verificar si, en la string, existe o no una barra inclinada. Si existe, es un directorio. Si no, se trata de un archivo. Así de simple. 

Sin embargo, quiero que observes otro detalle aquí, en este código 03. Observa que el procedimiento de la línea once recibe, como argumento, una string. Este sería el directorio inicial en el que buscaremos. Sin embargo, en la línea seis, no estamos pasando ningún parámetro a este procedimiento de la línea once. Esto significa que la búsqueda se realizará comenzando en la raíz de la SandBox. Entender esto es muy importante, porque ahora viene la parte recursiva del código.

¿Recuerdas que, durante la prueba para verificar si el string tiene o no una barra inclinada, comprobaremos si la string se refiere o no a un directorio? Pues bien, ¿y si modificamos el código para aprovechar esta información? Es decir, en lugar de desperdiciar la información de que la string contiene el nombre de un directorio, hiciéramos un cambio para llamar a SearchIn, de la línea once, con el contenido de esta string que, en este caso, sabemos que es un directorio. ¿Qué ocurre? Bien, veamos esto en la práctica. A partir de esta idea, podemos modificar el código 03 como se muestra a continuación.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (StringFind(szFileName, "\\") > 0)
22.             SearchIn(szFileName);
23.         else
24.             Print(szFileName);
25.     }while (FileFindNext(handle, szFileName));
26.     FileFindClose(handle);
27. }
28. //+------------------------------------------------------------------+

Código 04

Muy bien, en este código 04 podemos ver los cambios que se hicieron en el código para implementar lo que se explicó anteriormente. Por lo tanto, cuando ejecutes este código 04, obtendrás un resultado muy diferente del que vimos en la imagen 06. Sin embargo, aun así, será bastante similar a lo que se aprecia en la imagen 06. A algunos les resultará claro, mientras que otros pueden confundirse con el resultado mostrado. Para dejarlo claro, puedes ver la imagen 07 a continuación.

Imagen 07

Bien, ¿y dónde está la parte confusa? Bien, al mirar esta imagen 07, ¿podrías decirme a qué carpeta pertenece el archivo Backup.zip? Bueno, podrías decir que es la carpeta Sub 02. Pero, al observar detenidamente, puedes notar que algo parecido ocurrió con las carpetas Sub 01 y Sub 11. Pero espera un momento. Esto es mucho más confuso de lo que imaginaba. Al mirar la imagen 04, noto que la carpeta Sub 02 está en la raíz, al igual que la carpeta Sub 01. Pero, al verla representada así, como se muestra en la imagen 07, tengo la impresión de que, en realidad, el archivo Backup.zip estaría en la ruta Sub 01\Sub 11\Sub 02. Eso no parece ser correcto. Bien, ahora estoy un tanto perdido.

Al verlo así, resulta un tanto confuso saber exactamente cómo está estructurado el árbol dentro de la SandBox. Entonces, voy a mostrarte cómo está estructurado, mi estimado lector. Así podrás entender cómo debería presentarse el resultado. La siguiente animación lo muestra.

Animación 01

En esta animación 01, se ve claramente una estructura de carpetas muy simple y un archivo que no aparece en la imagen 07. A primera vista, esto parece bastante extraño. Podemos notar que Backup.zip se muestra en la imagen 07, aunque esté dentro de un directorio. Entonces, ¿dónde está el error? El error está en que, en la línea 22 del código 04, ignoramos el árbol de directorios. En realidad, solo accedemos a los directorios, sin tener en cuenta la estructura del árbol. Resolver este tipo de problema es muy simple e incluso algo trivial, si lo piensas bien.

Sin embargo, haremos algo más en el código que vamos a modificar. Vamos a añadir, al imprimir el nombre del archivo, la ruta recorrida hasta encontrar el archivo. Así tendremos una estructura más fácil de entender, al menos en principio. Con esto, tenemos el siguiente código.

01. //+------------------------------------------------------------------+
02. #property copyright "Daniel Jose"
03. //+------------------------------------------------------------------+
04. void OnStart(void)
05. {
06.     SearchIn("");
07. 
08.     Print("== Research completed. ==");
09. }
10. //+------------------------------------------------------------------+
11. void SearchIn(const string szDir)
12. {
13.     long    handle;
14.     string  szFileName;
15. 
16.     Print("[",szDir,"]");
17.     if ((handle = FileFindFirst(szDir + "*", szFileName)) == INVALID_HANDLE)
18.         return;
19.     do
20.     {
21.         if (StringFind(szFileName, "\\") > 0)
22.             SearchIn(szDir + szFileName);
23.         else
24.             Print(szDir, szFileName);
25.     }while (FileFindNext(handle, szFileName));
26.     FileFindClose(handle);
27. }
28. //+------------------------------------------------------------------+

Código 05

Perfecto, entonces vamos a ejecutar este nuevo código mostrado anteriormente. Al hacerlo, el resultado es el siguiente.

Imagen 08

Ahora sí, logramos algo bastante interesante. Observa que, con un simple cambio en el código 04, para producir lo que se muestra en el código 05, tuvimos un resultado completamente diferente e incluso mucho más interesante. Tanto es así que, si lo deseas, incluso puedes eliminar la línea dieciséis del código y aun así podrás entender cómo está construida la estructura de directorios. Y visualizar dónde se encuentra cada archivo. Eso sí que es interesante. Sin embargo, existe un problema pequeño, pero bastante molesto en este código 05, por decirlo de alguna manera. El código en sí funciona, como puedes notar claramente. Sin embargo, existe un tipo muy específico de situación en la que pueden mostrarse directorios y archivos de forma mezclada. Esto no es una falla del código ni un defecto en la programación. Es un problema de otra naturaleza.

Esto se debe precisamente a cómo interactúan FileFindFirst y FileFindNext. El detalle es que, cuando se ejecuta FileFindFirst, le pedirá al sistema operativo que le devuelva algo que coincida con el filtro indicado. Ese resultado puede corresponder a un archivo o a un directorio. En teoría, tú no controlas qué vendrá primero. Quien determina esto es el sistema operativo. Pero el problema en sí ocurre cuando pedimos de nuevo saber cuál es el siguiente elemento. Esto lo hace la función FileFindNext. ¿Y cuál es el problema? Bien, suponiendo que quieras visualizar todos los archivos antes que los directorios, o viceversa. ¿Cómo podrías hacerlo? Recuerda que no tienes control sobre qué tipo de elemento te devolverá el sistema operativo. Solo recibirás ese elemento y decidirás qué hacer con él.

Bien, mi estimado lector, para resolver este tipo de problema, necesitaremos utilizar otro enfoque. Empezaremos a explorar este tema en el próximo artículo.


Consideraciones finales

En este artículo, vimos cómo observar, de manera simple, fácil y práctica, qué hay dentro de una SandBox usando MetaTrader 5. Aunque, a primera vista, lo visto aquí no tenga mucho sentido ni un objetivo bien definido, al menos en este primer momento. Saber, pero sobre todo comprender cómo visualizar, mediante código, el contenido de una carpeta o de una raíz completa, puede ayudarte a encontrar, de manera muy rápida, determinados datos perdidos en medio de una infinidad de archivos y carpetas.

El objetivo principal de aprender a trabajar con lo visto aquí será entender otro tema del que hablaremos en el próximo artículo. Entonces, mi estimado lector, procura estudiar con calma lo visto hasta aquí en este artículo, para que puedas comprender lo que veremos desde el próximo artículo. A partir de ahora abordaremos un tema muy divertido, aunque pueda ser aterrador para quien está empezando a aprender programación. Nos vemos en el próximo artículo.

Archivo Descripción
Code 01  Demostración de navegación entre carpetas
Code 02   Demostración de navegación entre carpetas 
Code 03   Demostración de navegación entre carpetas

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

Archivos adjuntos |
Anexo.zip (1.59 KB)
Utilizando redes neuronales en MetaTrader Utilizando redes neuronales en MetaTrader
En el artículo se muestra la aplicación de las redes neuronales en los programas de MQL, usando la biblioteca de libre difusión FANN. Usando como ejemplo una estrategia que utiliza el indicador MACD se ha construido un experto que usa el filtrado con red neuronal de las operaciones. Dicho filtrado ha mejorado las características del sistema comercial.
Simulación de mercado: Position View (VI) Simulación de mercado: Position View (VI)
En este artículo, haremos diversas mejoras para que el indicador de posición refleje lo que realmente ocurre en el servidor de trading, en términos de posiciones y del estado actual de estas. Debo recordar que estas aplicaciones, que se mostrarán aquí, no pretenden en ningún caso sustituir ningún elemento disponible en MetaTrader 5. Tampoco deben usarse sin los debidos cuidados y criterios, ya que su objetivo es presentar un código didáctico, es decir, con fines de aprendizaje sobre cómo funciona el sistema. El motivo por el que digo que el código es didáctico es que el uso de mensajes, en algunos casos, no es la mejor forma de implementar ciertas funcionalidades.
Particularidades del trabajo con números del tipo double en MQL4 Particularidades del trabajo con números del tipo double en MQL4
En estos apuntes hemos reunido consejos para resolver los errores más frecuentes al trabajar con números del tipo double en los programas en MQL4.
Redes neuronales en el trading: Previsión probabilística de series temporales (Final) Redes neuronales en el trading: Previsión probabilística de series temporales (Final)
Le invitamos a explorar el framework K²VAE y a descubrir cómo integrar los enfoques propuestos en su sistema de negociación. Hoy aprenderá cómo el enfoque híbrido Koopman-Kalman-VAE ayuda a construir modelos adaptativos e interpretables. Al final del artículo le presentaremos los resultados prácticos del uso de las soluciones implementadas.