English Русский 中文 Deutsch 日本語 Português
Interacción entre MetaTrader 4 y Matlab a través de archivos CSV

Interacción entre MetaTrader 4 y Matlab a través de archivos CSV

MetaTrader 4Ejemplos | 30 marzo 2016, 13:08
1 348 0
Dmitriy
Dmitriy

Introducción

La potencia computacional del ámbito Metlab es conocido por ser superior a cualquier lenguaje de programación, incluso que MQL4. La amplia gama de funciones matemáticas que ofrece Metlab, permite realizar computaciones complejas, olvidando por completo las bases teóricas de las operaciones realizadas.

Sin embargo, la interacción en tiempo real entre una terminal de trading y Metlab, resulta una tarea nada trivia. En este artículo, propongo una manera de organizar el intercambio de datos entre MetaTrader 4 y Metlab a través de archivos CSV.


1. Interfuncionamiento

Suponga que a la entrada de cada nueva barra, MetaTrader 4 tiene que enviar los datos de, aproximadamente, las últimas 100 barras a Metlab y dar respuestas con los resultados de sus procesamientos.

Para solucionar este problema, se necesitará crear un indicador en MetaTrader 4 que escribiría los datos en un archivo de texto y leer los resultados del procesamiento de otro archivo de texto creado por Metlab.

MetaTrader 4 debe formar su archivo de datos a la entrada de cada nueva barra. También debe intentar leer los resutados a cada tick. Para no leer los resultados antes de que Metab os actualice, se habrán borrado los archivos que contentan los resultados antes de crear el archivo de salida. En este caso, el intento de lectura sólo tendrá éxito después de que Metlab termine su computación y forme un nuevo archivo.

Metlab debe analizar los atributos del archivo creado en MetaTrader 4 cada segundo y empezar el procesamiento cuando cambie la hora de creación. Una vez terminado el proceso, el archivo que MetaTrader 4 borró antes de comenzar con la grabación de datos, se crea de nuevo. MetaTrader 4 lo borra satisfactoriamente, carga los nuevos datos y espera la respuesta.


2. Crear un archivo de datos de salida

Hay muchos artículos destinados a guardar datos como archivos, por lo que no trataré aquí ese tema. Sólo aclararé que escribimos datos en 7 columnas: "FECHA", "HORA", "HOLA", "BAJO", "CERRAR", "ABRIR", "VOLUMEN". La "," es el separador. La prioridad de barras es de las más recientes a las más longevas, es decir, la línea que tiene las características de la barra cero, debe ser la última en grabarse. El archivo se proporcionará con una línea que tenga los nombres de las columnas. El nombre del archivo consiste en el nombre del símbolo y el periodo de tiempo.

#property indicator_chart_window
extern int length = 100;   // The amount of bars sent to be processed
double ExtMap[];           // Chart buffer
string nameData;
int init()
{
   nameData = Symbol()+".txt";         // name of the data file to be sent
   return(0);
}
int start()
{
   static int old_bars = 0;   // remember the amount of bars already known   
   if (old_bars != Bars)      // if a new bar is received 
   {
      write_data();                             // write the data file                              
   }      
   old_bars = Bars;              // remember how many bars are known
   return(0);
}
//+------------------------------------------------------------------+
void write_data()
{
  int handle;
  handle = FileOpen(nameData, FILE_CSV|FILE_WRITE,';');
  if(handle < 1)
  {
    Comment("Creation of "+nameData+" failed. Error #", GetLastError());
    return(0);
  }
  FileWrite(handle, ServerAddress(), Symbol(), Period());                  // heading
  FileWrite(handle, "DATE","TIME","HIGH","LOW","CLOSE","OPEN","VOLUME");   // heading
  int i;
  for (i=length-1; i>=0; i--)
  {
    FileWrite(handle, TimeToStr(Time[i], TIME_DATE), TimeToStr(Time[i], TIME_SECONDS),
                      High[i], Low[i], Close[i], Open[i], Volume[i]);
  }
  FileClose(handle);
  Comment("File "+nameData+" has been created. "+TimeToStr(TimeCurrent(), TIME_SECONDS) );
  return(0);
}

No se necesitarán estos datos, por supuesto, pero siempre es mejor tener un archivo sin importancia que sólo un set de columnas con figuras desconocidas.


3. Crear una interfaz de usuario gráfico (IUG)

El archivo está listo. Inicie Matlab.

Se debería desarrollar una aplicación que leyera datos de texto del archivo, y procese y grabe los resultados en otro archivo. Habrá que crear una IUG para especificar el nombre del archivo, ver los gráficos y empezar el procesamiento. Empecemos.

Para crear la IUG, hay que iniciar a "GUÍA de inicio rápido" haciendo clic en "guía" en la consola o presionando en el panel principal de Matlab, La caja de diálogos que aparece, haga clic en "Crear IUG nueva" --> "IUG vacía (por defecto)". Ahora puede ver la interfaz para la creación de una IUG con un formulario en blanco. En este formulario se colocarán los siguientes objetos: "Editar texto", "Presionar botón", "Texto estático", "Ejes", "Presionar botón". El resultado debe parecerse a esto:

Ahora se debería llamar al constructor de propiedad visual de cada objeto y establecer las propiedades de la siguiente manera:

Texto estático: AlineamientoHorizontal: izquierda, Etiqueta: textInfo, Serie: Info.
Texto editado: AlineamientoHorizontal: izquierda, Etiqueta: editPath, Serie: Path selected.
Presionar botón: Etiqueta: pushBrowse, Serie: Browse.
Ejes: Box: on, FontName: MS Sans Serif, FontSize: 8, Etiqueta: axesChart.
Presionar botón: Etiqueta: pushStart, Serie: Start.

Cambiando las propiedades de la Etiqueta, se selecciona un nombre único para cada objeto. Cambiando los otros, se modifica la apariencia.

Cuando todo esté listo, se inicia la interfaz haciendo clic en "Iniciar", se confirma que el archivo de la interfaz se ha guardado y se guarda el archivo M, dándole un nombre (por ejemplo "FromTo") y haciendo clic en "Guardar". Después de esto, la IUG se iniciará y aparecerá como aparece durante su funcionamiento. Matlab genera el archivo M para que sea la base del futuro programa y lo abre en el editor integrado.

Si la apariencia no encaja por algún motivo, cierre la IUG activa y corrija la disposición del objeto utilizando el editor. Mi distributivo, por ejemplo, no mostraba correctamente la MS Sans Serif. Así que tuve que cambiarla por "Sans Serif".


4. Construcción de la interfaz de usuario

El comportamiento de la interfaz se puede programar con el editor del arichivo M utilizando el lenguaje Matlab. El programa esqueleto que genera Matlab muestra una lista de funciones a las que el usuario tiene que llamar cuando trabaja con los objetos de la interfaz. Las funciones están vacías, por lo que la IUG todavía no hace nada. Es tarea del usuario rellenar las funciones con los contenidos necesarios.


4.1 Programar el botón de búsqueda


Lo primero que se necesita, es acceso al archivo generado por MetaTrader 4, por lo que se iniciará con la función a la que se llama haciendo clic en "Buscar".

El nombre de la función a la que se llama haciendo clic en el botón, consiste en el nombre del botón (establecido por la propiedad "Etiqueta") y el sufijo "_Callback". Se busca la función "pushBrowse_Callback" en el archivo de texto o se hace clic en "Mostrar funciones" en la barra de herramientas y se selecciona "pushBrowse_Callback" en la lista.

La sintaxis del lenguaje de programación de Matlab es diferente de las reglas convencionales de codificación en los lenguajes C y similares. No es necesario marcar el cuerpo de la función con corchetes o especificar el tipo de datos que se pasan a la función, los índices de gama (vector) empiezan con uno, y el caracter de comentario es "%". Por lo que el texto verde de arriba no es un programa, sino un comentario hecho por los desarrolladores de Matlab para permitir que se entienda el caso.

Habrá que crear un diálogo para introducir el nombre completo del archivo. Para ello, se utilizará la función "uigetfile".

% --- Executes on button press in pushBrowse.
function pushBrowse_Callback(hObject, eventdata, handles)
[fileName, filePath] = uigetfile('*.txt'); % receive and the path from the user
if fileName==0          % if it is canceled
    fileName='';        % create an empty name
    filePath='';        % create an empty path
end
fullname = [filePath fileName] % form a new name
set(handles.editPath,'String', fullname); % write in the editPath

"handles" es una estructura que almacena descriptores de todos los objetos en a IUG, incluso los datos del formuario en los que se colocaron. La estructura se pasa de una función a otra y permite acceder a los objetos.
"hObject" es un descriptor del objeto que tiene la función a la que se llama.
"set" ayuda a establecer el valor del objeto en un valor concreto y tiene la siguiente sintaxis: set(object_descriptor, object_property_name, property_value).

Puede encontrar e valor de las propiedades del objeto utilizando la siguiente función: property_value = get(object_descriptor, object_descriptor_name).
Pero no olvide que el nombre es un valor de tipo serie, por lo que debe ir con comillas simples.

Lo último que hay que saber sobre los objetos y sus propiedades. El formulario, en el que se encuentran los elementos IUG, es un objeto colocado en el objeto "raíz" (es su descendiente). También tiene un conjunto de propiedades que se pueden modificar. Las propiedades pueden verse utilizando la herramienta "Editor de objeto" a la que se llama desde la barra de herramientas principal del editor de la interfaz. El objeto "raíz", como el propio nombre sugiere, es la raíz de la jerarquía de los objetos gráficos y no tiene predecesores.

Comprobemos el resultado. Ahora se iniciará el IUG haciendo clic en Iniciar en la barra de herramientas principal del editor de arhivo M. Intente hacer clic en "Bluscar" y seleccione el archivo. ¿Está activado? Luego elija la IUG activa y continúe.


4.2 Programar el botón de inicio, dibujar el gráfico


Ahora se asignará el botón Inicio con la llamada de la función que leerá los datos del archivo y los mostrará en el gráfico.

Primero, creemos la función. Se necesitará la estructura de los descriptores de objetos 'handles' como entradas. Una vez que se tenga acceso a los objetos, se podrán leer y establecer sus propiedades.

% data reading, chart drawing, processing, storage
function process(handles)
fullname = get(handles.editPath, 'String'); % read the name from editPath
data = dlmread(fullname, ';', 2, 2);    % read the matrix from file
info = ['Last update: ' datestr(now)];  % form an informative message
set(handles.textInfo, 'String',info);   % write info into the status bar
 
high = data(:,1);   % it is now high where the first column of the data matrix is
low = data(:,2);    % d low -- the second
close = data(:,3);  % --/--
open = data(:,4);   %
len = length(open); % the amount of elements in open
 
axes(handles.axesChart); % make the axes active
hold off; % clean axes off before adding a new chart
candle(high, low, close, open); % draw candlesticks (in the current axes)
set(handles.axesChart,'XLim',[1 len]); % set limits for charting

Algunas explicaciones necesarias:

"dlmrear" lee los datos del archivo de texto con separadores y tiene la siguiente sintaxis: dlmread(full_file_name, separator, skip_strings, skip_columns);
“length(qqq)”: el tamaño más grande de matrix qqq;
"now": la fecha y hora actual;
"dates(noiw)": transforma la hora y la fecha y en un texto;

Debe saber también, que Matlab ofrece mucha información de ayuda con teorías y ejemplos.

Se coloca la función en el final del programa (será más fácil de encontrarlo ahí) y se añade la llamada en "pushStart_Callback":

% --- Executes on button press in pushStart.
function pushStart_Callback(hObject, eventdata, handles)
process(handles);

Inícielo con "Arrancar", seeccione un archivo, haga clic en "Inicio" y disfrute del resultado.


4.3 Guardar la ruta en un archivo


Ya está todo correcto, pero es un poco molesto estar haciendo clic con el ratón todo el tiempo para seleccionar un archivo después de hacer clic en "Buscar". Vamos a guardar la ruta una vez que la seleccionemos.
Empezaremos con la lectura. El nombre de un archivo que contenga una ruta, será el nombre de la IUG y el sufijo "_saveparam" y tiene la extensión ".mat".
La función "FromTo_OpeningFcn" se ejecuta directamente después de crear la forma IUG. Ahí se añadirá el intento de lectura de la ruta desde el archivo. Si el intento falla, se usará el valor por defecto.

% --- Executes just before FromTo is made visible.
function FromTo_OpeningFcn(hObject, eventdata, handles, varargin)
guiName = get(handles.figure1, 'Name'); % get the name of our GUI
name = [guiName '_saveparam.mat']       % define the file name
h=fopen(name);                          % try to open the file
if h==-1                                % if the file does not open
    path='D:\';                         % the default value
else
    load(name);                         % read the file    
    fclose(h);                          % close the file
end
set(handles.editPath,'String', path);   % write the name into object "editPath"

El resto de series de la función "FromTo_OpeningFcn" se dejarán sin modificar.


Se modificará la función "pushBrowse_Callback" de la siguiente manera:

% --- Executes on button press in pushBrowse.
function pushBrowse_Callback(hObject, eventdata, handles)
path = get(handles.editPath,'String'); % read the path from object editPath 
[partPath, partName, partExt] = fileparts(path);    % divide the path into parts
template = [partPath '\*.txt'];                     % create a template of parts
[userName, userPath] = uigetfile(template);         % get the user name and the path from the user
if userName~=0                                      % if "Cancel" is not pressed        
    path = [userPath userName];                     % reassemble the path
end
set(handles.editPath,'String', path);               % write the path into object "editPath"
guiName = get(handles.figure1, 'Name');             % get to know the name of our GUI
save([guiName '_saveparam.mat'], 'path');           % save the path

4.4 Procesamiento de datos


Como proceso ejemplar, se interpola la columna "ABIERTO" a través de una función polinominal de cuarta orden.
Se añade el siguiente código al final de la función "proceso":

fitPoly2 = fit((1:len)',open,'poly4'); % get the polynomial formula
fresult = fitPoly2(1:len); % calculate Y values for X=(from 1 to len)
hold on; % a new chart has been added to the old one
stairs(fresult,'r'); % plot stepwise by color - 'r'- red


Intentemos iniciarlo y hacer clic en "Inicio".


Si sus resultados se parecen algo a lo que se muestra a continuación, ya puede comenzar a guardar datos como archivos.


4.5 Guardar datos como archivos


Guardar datos no es más complicado que leerlos. La única diferencia es que el vector "fresult" se debe contar hacia abajo, es decir, desde el último al primero. Esto se hace para simplificar la lectura del archivo en MetaTrader 4, empezando desde la barra cero hasta que el archivo termina.

Completemos la función "proceso" con el siguiente código:

[pathstr,name,ext,versn] = fileparts(fullname); % divide the full name
                                                % of the file into parts
newName = [pathstr '\' name '_result' ext];     % re-compose the new file name
fresult = flipud(fresult);  % turn vector fresult
dlmwrite(newName, fresult);    % write in the file

Ahora asegúrese de que el archivo que contiene el resultado se ha creado, se ha colocado en el mismo lugar en el que estaba el archivo inicial, y que tiene el mismo nombre con el sufijo "_result".


4.6 Control del temporizador


Es la parte más difícil. Habrá que crear un temporizador que compruebe la hora del archivo que se ha creado en MetaTrader 4 a cada segundo. Si la hora cambia, debe iniciarse la función "proceso". El temporizador se iniciará y se detendrá utilizando "Inicio". Cuando una IUG se abre, se borrarán todos los temporizadores utilizados con anterioridad.

Cree un temporizador colocando el siguiente código dentro de la función "FromTo_OpenFcn":

timers = timerfind; % find timers
if ~isempty(timers) % if timers are available
    delete(timers); % delete all timers
end
handles.t = timer('TimerFcn',{@checktime, handles},'ExecutionMode','fixedRate','Period',1.0,'UserData', 'NONE');

El siguiente código debe insertarse inmediatamente después de la inserción previa en esta función, es decir, antes de las series "hadles.outpu = hObject;" y "guidata(hObjects, handles);".

Ejecutando este código, Matlab comprobará la disponibilidad de los temporizadores inmediatamente después de la creación de la IUG, borre los temporizadores existentes y cree uno nuevo. El temporizador llamará a la función "checktime" cada segundo, y le pasará la lista de descriptores "handles". A parte de "handles", el temporizador pasará su propio descriptor a la función, así como a la estructura que contiene la hora y el motivo de la llamada. Esto no se puede influenciar, pero se debe tener en cuenta cuando se codifique la función para que el temporizador la llame.

Debe colocar la propia función donde quiera. Deje que se escriba la hora a la que se le llamó en la barra de estado de Matab :

% function called by the timer
function checktime(obj, event, handles)
set(handles.textInfo,'String',datestr(now));

En el momento de su creación, el temporizador está parado, y debe iniciarse. Busque la función "pushStart_Callback". Llame al "process(handles)" que hay en ella y escriba la gestión del temporizador:

% --- Executes on button press in pushStart.
function pushStart_Callback(hObject, eventdata, handles)
% process(handles);
statusT = get(handles.t, 'Running'); % Get to know the timer status
if strcmp(statusT,'on')     % If it is enabled - 
    stop(handles.t);        % disable it
    set(hObject,'ForegroundColor','b'); % change color of pushStart marking
    set(hObject,'String',['Start' datestr(now)]); % change the button top marking
end     
if strcmp(statusT,'off')    % If it is disabled - 
    start(handles.t);       % enable it
    set(hObject,'ForegroundColor','r');% change color of pushStart marking
    set(hObject,'String',['Stop' datestr(now)]); % change the button top marking
end 

Compruebe cómo funciona todo. Intente habilitar y deshabilitar el temporizador utilizando "Inicio". Si el temporizador está habilitado, el reloj que está sobre el campo de la entrada de la ruta debe funcionar.

Sería más correcto borrar el temporizador utilizando el botón "X" al cerrar la IUG. Si quiere hacerlo, añada

stop(handles.t) ; % stop the timer
delete(handles.t); % delete the timer

al principio de la función la función "figure1_CoseRequestFcn". Se llamará a esta función al cerrar la IUG. Puede acceder a ella desde el editor de la IUG.

Pero por favor, tenga en cuenta que si pulsa "Arrancar" en el editor sin haber cerrado la IUG en funcionamiento, el temporizador anterior no se borrará mientras se crea el nuevo. Y la próxima vez habrá uno más, etc. Puede lidiar con los temporizadores "pendientes" utilizando las órdenes "delete(timerfind)" desde la consola Matlab.


Si todo funciona bien, se creará una función para comprobar la hora la modificación del último archivo de MetaTrader 4.

% function to be called by the timer
function checktime(obj, event, handles)
filename = get(handles.editPath, 'String'); % get to know the file name 
fileInfo = dir(filename);        % get info about the file
oldTime = get(obj, 'UserData');  % recall the time
if ~strcmp(fileInfo.date, oldTime) % if the time has changed
    process(handles);
end
set(obj,'UserData',fileInfo.date); % save the time
set(handles.pushStart,'String',['Stop ' datestr(now)]); % override the time

La función "dir(full_file_name)", devuelve una estructura que contiene la información del archivo (nombre, fecha, btes, isdir). La información sobre la hora de creación del archivo anterior se almacenará en la propiedad "Userdata" del objeto. Su descriptor pasa a la función "checktime" como obj.

Ahora, cuando cambie un archivo creado por MetaTrader 4, el programa sobreescribirá el resultado. Puede comprobarlo modificando el archivo manualmente (por ejemplo, borrando las últimas series) y haciendo un seguimiento de los cambios en el gráfico o archivo resultante. Por supuesto, debe hacer clic en el botón "Inicio" en ese momento.

Si durante el funcionamiento del programa se crea una ventana extra con la copia del gráfico, añada la siguiente serie al inicio de la función "proceso":

set(handles.figure1,'HandleVisibility','on');

5. Dibujar los resultados en MetaTrader 4


Volvamos a MetaTrader 4. Hay que complementar el indicador con una función que lea el resultado del archivo y lo dibuje en un gráfico. El comportamiento del programa se describirá de la siguiente manera:

1. Si se recibe una nueva barra: Elimine el archivo resultante anterior, borre el gráfico, guarde el archivo de datos.
2. Si el resultado se puede leer: Lea el archivo, dibuje el gráfico, elimine el archivo resultante.

No voy a describir cómo funciona el código de abajo, ya que hay otros artículos sobre la lectura de archivos y el dibujo de indicadores. Sólo voy a mencionar que el archivo resultante aquí se borra inmediatamente después de que se haya colocado en el gráfico. Así que no se preocupe si ve varios mensajes de error de lectura.

Los errores de lectura pueden ocurrir en dos ocasiones:
1. Inmediatamente después de la entrada de una nueva barra, ya que el archivo resultante no se ha creado aún.
2. Inmediatamente después de la lectura del resultado y del dibujo del gráfico, ya que el archivo se eliminó para que no se volvieran a leer los mismos datos.

Por lo tanto, el programa mantiene su "error de lectura" prácticamente todo el tiempo. :)

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_width1 2
#property indicator_color1 Tomato
extern int length = 100;   // The amount of bars to be sent for processing
double ExtMap[];           // Chart buffer
string nameData;
string nameResult;

int init()
{
   nameData = Symbol()+".txt";         // the name of the data file to be sent
   nameResult = Symbol()+"_result.txt";// the name of the received file containing results
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, ExtMap);
   return(0);
}
int deinit()
  {
   Comment("");
   return(0);
  }
int start()
{
   static int attempt = 0;    // the amount of attempts to read the result
   static int old_bars = 0;   // remember the amount of the known bars
   
   if (old_bars != Bars)      // if a new bar has income 
   {
      FileDelete(nameResult);                   // delete the result file
      ArrayInitialize( ExtMap, EMPTY_VALUE);    // empty the chart
      write_data();                             // save the data file
      
      old_bars = Bars; return(0);               // nothing should be done this time                           
   }
   //
   int handle_read = FileOpen(nameResult,
                              FILE_CSV|FILE_READ,
                              ';'); // try to open the result file
   attempt++;                       // count the attempt to open
   
   if(handle_read >= 0)             // if the file has opened for reading
   { 
      Comment(nameResult+". Opened with attempt #"+ attempt); // opening report
      read_n_draw(handle_read);  // read the result and draw a chart
      FileClose(handle_read);    // close the file
      FileDelete(nameResult);    // delete the result file
      attempt=0;                 // zeroize the amount of attempts to read
   }
   else                          // if we cannot open the result file
   {
      Comment( "Failed reading "+nameResult+
               ". Amount of attempts: "+attempt+
               ". Error #"+GetLastError()); //Report about failed reading
   }
   old_bars = Bars;              // remember how many bars are known
   return(0);
}
//+------------------------------------------------------------------+
void read_n_draw(int handle_read)
{
   int i=0;
   while ( !FileIsEnding(handle_read)) 
   {
      ExtMap[i] = FileReadNumber(handle_read);
      i++;     
   }
   ExtMap[i-1] = EMPTY_VALUE;
}

 
void write_data()
{
  int handle;
  handle = FileOpen(nameData, FILE_CSV|FILE_WRITE,';');
  if(handle < 1)
  {
    Comment("Failed creating "+nameData+". Error #", GetLastError());
    return(0);
  }
  FileWrite(handle, ServerAddress(), Symbol(), Period());                  // header
  FileWrite(handle, "DATE","TIME","HIGH","LOW","CLOSE","OPEN","VOLUME");   // header
  int i;
  for (i=length-1; i>=0; i--)
  {
    FileWrite(handle, TimeToStr(Time[i], TIME_DATE), TimeToStr(Time[i], TIME_SECONDS),
                      High[i], Low[i], Close[i], Open[i], Volume[i]);
  }
  FileClose(handle);
  Comment("File "+nameData+" has been created. "+TimeToStr(TimeCurrent(), TIME_SECONDS) );
  return(0);
}

Abajo puede encontrar mi resultado final. Espero no haber cometido ningún error y que pueda reproducirlo.





Conclusión

En este artículo, he descrito la manera de organizar una interacción entre MetaTrader 4 y Metlab a través de archivos CSV. Este método no es ni único ni el mejor. El valor de este acercamiento es que ayuda a intercambiar gamas de datos sin tener habilidades especiales de programación que no sea MetaTrader 4 ni Matlab.

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

Archivos adjuntos |
work.zip (9.98 KB)
El tester en la terminal MetaTrader 4: Debería saberse El tester en la terminal MetaTrader 4: Debería saberse
La interfaz elaborada de la terminal MetaTrader 4 es de vanguardia, pero además esta terminal incluye un tester de estrategias cuidadosamente realizado. Y aunque el valor de MetaTrader 4 como terminal de trading es obvio, la calidad de la estrategia del tester puede evaluarse sólo con su uso. Este artículo muestra las ventajas e inconvenientes de hacer pruebas en MetaTrader 4.
MT4TerminalSyn: Sistema para la Sincronización de Terminales MetaTrader 4 MT4TerminalSyn: Sistema para la Sincronización de Terminales MetaTrader 4
Este artículo está dedicado al tema "Ampliar las posibilidades de los programas MQL4 utilizando funciones de sistemas operativos y otros medios de desarrollo de programas". El artículo describe un ejemplo de un sistema que integra la tarea de la sincronización de varias copias de terminales basada en una única plantilla de base.
Matemáticas de trading. Cómo evaluar los resultados de las transacciones comerciales Matemáticas de trading. Cómo evaluar los resultados de las transacciones comerciales
Todos somos conscientes de que "No obtener beneficios en el pasado garantizará el éxito en el futuro". Sin embargo, todavía es muy actual el poder estimar los sistemas de trading. Este artículo trata sobre algunos métodos simples y convenientes que ayudarán a estimar los resultados de trade.
Representación gráfica de las pruebas: Gráficos de estados de las cuentas Representación gráfica de las pruebas: Gráficos de estados de las cuentas
Disfrute del proceso de prueba con gráficos que muestran el balance: ¡ahora toda la información necesaria está siempre a la vista!