English Русский 中文 Deutsch 日本語 Português
preview
La magia de los intervalos comerciales de tiempo con Frames Analyzer

La magia de los intervalos comerciales de tiempo con Frames Analyzer

MetaTrader 5Probador | 10 febrero 2023, 16:33
643 1
Anatoli Kazharski
Anatoli Kazharski

Contenido


Introducción

En este artículo, queremos mostrarle una herramienta bastante interesante que nos permite profundizar en los resultados de la optimización de cualquier algoritmo comercial, e incluso posibilitar la mejora de los resultados de nuestro comercio automatizado real con un mínimo de esfuerzo y costes.

¿Qué es Frames Analyzer? Frames Analyzer es una biblioteca de complementos para que cualquier experto comercial analice marcos de optimización durante la optimización de parámetros en el simulador, así como fuera del mismo mediante la lectura de un archivo MQD o una base de datos creada inmediatamente después de la optimización de parámetros.

Se trata de un desarrollo exclusivo que nunca se ha mostrado en ninguna parte de esta forma, aunque se implementó casi por completo hace más de tres años. Por primera vez, la idea fue formulada con detalle e implementada en código por un miembro activo de la comunidad MQL, fxsaber.

Algunas implementaciones intermedias de aplicaciones de análisis de marcos de optimización se han tratado en algunos de mis artículos:

Tras combinar todas estas ideas, hemos obtenido una herramienta bastante interesante e informativa que se tratará con detalle en este artículo.


Descripción de la herramienta

El módulo contiene una interfaz gráfica integrada creada con la biblioteca EasyAndFastGUI v2.0, que no requiere codificación adicional. Esta deberá conectarse a varias funciones principales de la aplicación MQL (se mostrarán a continuación).

La interfaz gráfica consta de varios apartados. Vamos a analizarlos más a fondo.


La pestaña Frames

Elementos:

  • El botón Open DB, para abrir una base de datos que contenga marcos de optimización. Este botón aparecerá solo en la aplicación Frames Analyzer, es decir, fuera del simulador, este asesor funcionará en el modo de lectura del archivo DB creado por el asesor experto después de la optimización de parámetros. 
  • El botón Open MQD-file, para abrir el archivo MQD que contiene los marcos de optimización. Este botón aparecerá solo en la aplicación Frames Analyzer, es decir, fuera del simulador, este asesor funcionará en el modo de lectura del archivo MQD creado por el simulador tras optimizar los parámetros (se eliminará en la versión para la venta).
  • El campo de entrada Curves total, para especificar el número de balances mostrados en el gráfico al mismo tiempo.
  • El botón Replay frames, para comenzar a reproducir marcos.
  • El gráfico de balances (Optimization result).
  • El gráfico de todos los resultados (Profit/Loss).

Si el módulo Frames Analyzer está conectado al asesor como una biblioteca, durante la optimización de parámetros, el simulador abrirá un gráfico con el asesor Frames Analyzer y podremos observar inmediatamente todos los resultados intermedios (balances). 

Visualización de resultados durante la optimización de parámetros

Visualización de resultados durante la optimización de parámetros


La pestaña Results

En la parte superior hay dos recuadros:

  • El botón Add to favorites, para añadir los resultados a favoritos.
  • El campo de entrada Removed intervals, para especificar el número de intervalos excluidos con series no rentables.
  • El cuadro combinado con lista desplegable Criterion, para seleccionar resultados según el criterio especificado:
    • Profit: del número total (y también en otros criterios), se seleccionan 100 resultados según el balance máximo.
    • Trades: se seleccionan 100 resultados según el número máximo de transacciones.
    • DD (drawdown): se seleccionan 100 resultados según la reducción mínima.
    • RF (recovery factor): se seleccionan 100 resultados según el factor de recuperación máximo.
    • Los mismos criterios con el prefijo BI_ tienen el mismo sentido, pero después de excluir las series de transacciones no rentables.
  • El recuadro con cien de los mejores resultados para el balance máximo. Las celdas de la columna relacionadas con los resultados mejorados (con el prefijo BI_) tienen un color diferente para distinguirlas rápidamente de forma visual (vea la captura de pantalla a continuación). Las celdas de la columna con parámetros externos también se resaltan en su propio color para poder identificarlas rápidamente.
  • El recuadro con los resultados después de eliminar los periodos perdedores de la historia comercial con todos los resultados intermedios.

Cuando el cursor del ratón se encuentra sobre un recuadro concreto, podemos alternar las filas usando las teclas: UP, DOWN, PAGE UP, PAGE DOWN, HOME, END. Las teclas LEFT y RIGHT nos permitirán movernos rápidamente en los recuadros de principio a fin horizontalmente.

En la parte inferior hay un área con dos pestañas: Balances, Top 100 results. Vamos a analizarlas más a fondo.


La pestaña Balances

Aquí tenemos dos gráficos:

  • A la izquierda está el gráfico con el balance inicial y con todos los resultados intermedios mejorados después de eliminar la serie de transacciones perdedoras. Por lo tanto, podemos ver cómo cambia el gráfico de balance después de excluir la siguiente serie no rentable.
  • A la derecha tenemos un gráfico con el resultado final mejorado del balance (que es el mejor en el gráfico de la izquierda) y todos los balances para cada periodo comercial por separado.

Al resaltar las filas en los recuadros, los gráficos también se actualizarán.

Balances finales de los resultados y balances mejorados tras eliminar los intervalos no rentables

Balances finales de los resultados y balances mejorados tras eliminar los intervalos no rentables


La pestaña Top 100 results

También tenemos dos gráficos aquí:

  • A la izquierda hay un gráfico con los 100 mejores resultados de beneficio.
  • A la derecha hay un gráfico con los 100 mejores resultados para el criterio especificado: Profit, Trades, DD, RF, BI_Profit, BI_Trades, BI_DD, BI_RF.

Si resaltamos las filas en los recuadros, se actualizarán los resultados en los gráficos. Por ejemplo, a continuación podemos ver qué resultado se resalta a la izquierda (curva de balance negra) y cuál es el resultado después de excluir la serie de transacciones perdedoras en el gráfico de la derecha.

Los 100 mejores balances finales y mejorados después de eliminar los intervalos no rentables

Los 100 mejores balances finales y mejorados después de eliminar los intervalos no rentables

También podemos especificar el número de intervalos no rentables que se eliminarán de la historia para mejorar el resultado.

Se supone que si continuamos comerciando con estos parámetros del asesor experto, excluyendo en este caso de la negociación los intervalos de tiempo en los que se han encontrado series de transacciones no rentables, podremos mejorar significativamente los resultados comerciales. De hecho, a veces incluso un algoritmo comercial aparentemente no rentable puede resultar rentable con este enfoque.

Como hemos mencionado anteriormente, podemos guardar nuestros resultados favoritos en un recuadro de resultados favoritos. Para ello, deberemos usa el botón Add to favorites. Los resultados añadidos se resaltarán en un color distinto en el recuadro de resultados generales.

Los resultados añadidos a favoritos se resaltarán en un color distinto

Los resultados añadidos a favoritos se resaltarán en un color distinto


La pestaña Favorites

Esta pestaña también tendrá dos recuadros y dos gráficos. El significado de todos los indicadores será el mismo que en la pestaña Results La única diferencia será que estos resultados seleccionados se podrán guardar en archivos (conjuntos de ajustes para el experto) y en una base de datos. Aquí, además de recuadros y gráficos, encontraremos los siguientes botones en la parte superior de la ventana:

  • Delete selected - borrar el resultado seleccionado de los favoritos en el recuadro de la izquierda y de la base de datos.
  • Delete all - borrar todos los resultados de favoritos en el recuadro de la izquierda y de la base de datos.
  • Save parameters - guardar parámetros en un archivo y en la base de datos.

Datos y gráficos de resultados seleccionados

Datos y gráficos de resultados seleccionados

Clicando en el botón Save parameterstodos los resultados favoritos se guardarán:

  • en la base de datos en el recuadro FAVORITE_RESULTS
  • en los archivos en el directorio MQL5/Files/Reports/FramesA/[CURRENT_TIME], si nos encontramos en modo de lectura de archivos MQD
  • en MQL5/Files/Reports/[CURRENT_TIME] [EXPERT_NAME], si estamos en el modo FRAME_MODE (inmediatamente después de la optimización)

Todos los resultados se guardarán en carpetas separadas; como nombre de la carpeta, se usará el número de pasada. Se tratará de un archivo set con los parámetros externos del asesor experto y varias capturas de pantalla de los recuadros y gráficos analizados anteriormente. Como prefijo en el nombre de todos los archivos, tendremos el número de pasada:

  • 422462.set - archivo  set con los parámetros externos del asesor experto.
  • 422462.set - será una captura de pantalla del balance tras excluir todos los intervalos de tiempo con series de transacciones no rentables, así como todos los balances por separado para cada intervalo de tiempo restante.
  • 422462_balances_bi.png - una captura de pantalla con todos los balances después de excluir todos los intervalos de tiempo con series de transacciones no rentables.
  • 422462_bi_table.png - una captura de pantalla del recuadro con todos los resultados finales después de excluir todos los intervalos de tiempo con series de transacciones no rentables.
  • 422462_gui.png - una captura de pantalla completa de la interfaz.

Ejemplo de archivo set con los parámetros del experto:

; this file contains last used input parameters for testing/optimizing FA expert advisor
; Experts\Advisors\ExpertMACD.ex5
;
Inp_Expert_Title=ExpertMACD||0.0||0.0||0.0||N
Inp_Signal_MACD_PeriodFast=15||5.0||5.0||30.0||Y
Inp_Signal_MACD_PeriodSlow=25||5.0||5.0||30.0||Y
Inp_Signal_MACD_PeriodSignal=25||5.0||5.0||30.0||Y
Inp_Signal_MACD_TakeProfit=270||30.0||5.0||300.0||Y
Inp_Signal_MACD_StopLoss=115||20.0||5.0||200.0||Y


Base de datos con los resultados de la optimización

Como hemos mencionado anteriormente, Frames Analyzer, justo después de optimizar los parámetros en el simulador, guardará todos los resultados de la optimización en una base de datos. ¡Y no solo los resultados! Después de cada optimización de los parámetros, se creará una nueva base de datos en el directorio local del terminal MQL5/Files/DB. El nombre de la base de datos consta de la hora actual en el momento de la creación y el nombre del experto: [CURRENT_TIME] [EXPERT_NAME].db.

Hay tres recuadros en total:

El recuadro OPTIMIZATION_RESULTS, que almacenará los siguientes datos (columnas):

  • Pass - número de pasada.
  • Profit - beneficio obtenido.
  • Trades - número de transacciones.
  • PF - factor de beneficio.
  • DD - reducción.
  • RF - factor de recuperación.
  • Columnas con todos los parámetros externos del experto:
    • Parámetro 1
    • Parámetro 2
    • etc.
  • Deals - historia de las transacciones para las que se calculan los balances de cada pasada.

Recuadro con los datos de todas las pasadas de optimización

Recuadro con los datos de todas las pasadas de optimización

El recuadro EXPERT_PARAMETERS contendrá los parámetros externos del asesor experto, así como su nombre y la ruta al directorio donde se encontraba durante la optimización de los parámetros. Este recuadro tiene dos columnas:

  • Parameter - nombre del parámetro
  • Value - valor del parámetro.

A continuación, mostramos un ejemplo del experto ExpertMACD del paquete estándar del terminal. Para los parámetros externos (INPUT_n), la columna Value almacenará el nombre del parámetro externo y los parámetros de optimización (delimitados por ||) que se han usado para esta optimización.

Recuadro con los datos de los expertos

Recuadro con los datos de los expertos

En el futuro, también podremos añadir a este recuadro algunos otros parámetros necesarios para el funcionamiento del asesor experto.

En el recuadro FAVORITE_RESULTS se guardarán los resultados de optimización seleccionados. Aquí solo tendremos tres columnas:

  • FavoriteID - identificador de la posición.
  • Pass - número de la pasada con la que se podrán obtener todos los datos en el recuadro OPTIMIZATION_RESULTS.
  • RemovedIntervals - intervalos de tiempo eliminados durante los que se supone que no se comercia en operaciones reales.

Recuadro de resultados de optimización seleccionados con intervalos de tiempo remotos

Recuadro de resultados de optimización seleccionados con intervalos de tiempo eliminados

Por lo tanto, podremos obtener todo lo que necesitamos de la base de datos después de optimizar y analizar los resultados obtenidos para el trabajo del asesor experto en el futuro.


¿Cómo utilizar la herramienta Frames Analyzer?

Primero necesitaremos descargar Frames Analyzer a nuestra computadora desde esta página. Si ejecutamos este asesor experto en nuestro terminal ahora, todos los gráficos y recuadros en Frames Analyzer estarán vacíos. No es de extrañar, porque esta herramienta necesita resultados de optimización: está diseñada para trabajar con ellos. Si no puede esperar a probarla, tendrá la posibilidad de descargar el archivo de la base de datos con los resultados de optimización que hemos preparado para usted ahora mismo al final del artículo. Coloque este archivo en el directorio MQL5/Files/DB, ahora podrá cargarlo a través de la interfaz del experto Frames Analyzer. En la pestaña Frames, clique en el botón Open DB. Se abrirá una ventana de diálogo para seleccionar el archivo de base de datos como se muestra a continuación. En este caso, ya tenemos varios archivos de base de datos en este directorio.

Seleccionando el archivo de base de datos en la ventana de diálogo

Seleccionando el archivo de base de datos en la ventana de diálogo

Sin embargo, para que Frames Analyzer guarde los resultados de optimización de su asesor experto, deberá incluirlo como una biblioteca en el código de su asesor. Esto es bastante simple de hacer: más abajo, le presentaremos un ejemplo detallado.

Después de descargar Frames Analyzer a su computadora, este se encontrará en el directorio MQL5/Experts/Market. Luego podrá conectarlo al archivo principal (*.mq5) de su asesor experto de la forma siguiente:

#import "..\Experts\Market\FramesA.ex5"
  void OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
  void OnTesterEvent(void);
  void OnTesterInitEvent(void);
  void OnTesterPassEvent(void);
  void OnTesterDeinitEvent(void);
#import

Como hemos visto antes, deberemos importar varias funciones desde el experto Frames Analyzer, las necesitaremos para procesar los eventos durante el funcionamiento de la interfaz gráfica, y también para recopilar los datos durante la optimización de los parámetros del asesor en el simulador. Todo lo que deberemos hacer es llamar a estas funciones en las funciones similares en el asesor experto, como mostramos a continuación:

//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
  FramesA::OnEvent(id, lparam, dparam, sparam);
}
//+------------------------------------------------------------------+
//| Test completion event handler                                    |
//+------------------------------------------------------------------+
double OnTester(void) {
  FramesA::OnTesterEvent();
  return(0.0);
}
//+------------------------------------------------------------------+
//| TesterInit function                                              |
//+------------------------------------------------------------------+
void OnTesterInit(void) {
  FramesA::OnTesterInitEvent();
}
//+------------------------------------------------------------------+
//| TesterPass function                                              |
//+------------------------------------------------------------------+
void OnTesterPass(void) {
  FramesA::OnTesterPassEvent();
}
//+------------------------------------------------------------------+
//| TesterDeinit function                                            |
//+------------------------------------------------------------------+
void OnTesterDeinit(void) {
  FramesA::OnTesterDeinitEvent();
}
//+------------------------------------------------------------------+

Todo es muy simple, ¿no?

Por cierto, si usamos en nuestros proyectos para crear interfaces gráficas la biblioteca EasyAndFastGUI v2.0 usada en la herramienta Frames Analyzer, no necesitaremos hacer nada adicional para que funcionen juntos en una aplicación MQL. El programa Frames Analyzer integrado en su asesor experto funciona aparte en el modo marco (FRAME_MODE) y no interferirá con la interfaz gráfica de su aplicación de ninguna forma.

Es posible que usted no tenga la biblioteca EasyAndFastGUI v2.0, y Frames Analyzer funcionará de todos modos.

Podrá descargar un ejemplo del asesor experto ExpertMACD del paquete estándar con el módulo Frames Analyzer ya conectado al final del artículo.


Aplicación de intervalos remotos en asesores comerciales

Bien, ya tiene la herramienta Frames Analyzer. La ha conectado a su asesor comercial, ha realizado la optimización de los parámetros y ahora tiene una base de datos con los resultados de todas las pasadas para las que existen valores de todos los parámetros externos. Asimismo, ha guardado en un recuadro aparte sus resultados de optimización favoritos con intervalos de tiempo eliminados, que ahora se pueden aplicar a su estrategia comercial.

Veamos un ejemplo sobre cómo se puede implementar esto.

Supongamos que desea implementar una selección de rangos comerciales de tiempo a través de una interfaz gráfica de usuario. Sería bueno tener un elemento en la interfaz gráfica que representara los intervalos de tiempo remotos durante los cuales no se recomienda comerciar. Si es el feliz propietario de una biblioteca EasyAndFastGUI 2.0 para crear interfaces gráficas avanzadas, entonces ya dispondrá de esta oportunidad. En una de las últimas actualizaciones, se ha añadido otro elemento único: CTimeRanges, que permite trabajar con intervalos de tiempo. A continuación, crearemos una interfaz gráfica con este elemento y lo analizaremos con mayor detalle.

La interfaz gráfica constará de los siguientes elementos:

  • El formulario para los controles será CWindow.
  • El botón para abrir el archivo de la base de datos será CButton.
  • La lista desplegable con los números de las pasadas del recuadro de resultados de optimización seleccionadas será CComboBox.
  • La escala de tiempo que mostrará los intervalos no recomendados para operar será CTimeRanges.

Para crear una interfaz gráfica de este tipo, solo necesitaremos unas pocas líneas de código:

void CApp::CreateGUI(void) {

//--- Form
  m_window1.ResizeMode(true);
  m_window1.ThemeButtonIsUsed(true);
  CCoreCreate::CreateWindow(m_window1, "TIME TRADE RANGES", 1, 1, 350, 100, true, true, true, true);
  
//--- Button
  CCoreCreate::CreateButton(m_button1, m_window1, 0, "Open DB...", 10, 30, 100);
  
//--- Combobox
  string items1[] = {"12345", "19876", "45678", "23456", "67890"};
  CCoreCreate::CreateCombobox(m_combobox1, m_window1, 0, "Passes: ", 120, 30, 135, 90, items1, 103, 0);
  
//--- Time ranges
  string time_ranges[] = {
    "00:45:00 - 01:20:01",
    "08:55:00 - 09:25:01",
    "12:55:00 - 13:50:01",
    "15:30:00 - 17:39:59",
    "20:10:00 - 21:05:00"
  };
  m_time_ranges1.SetTimeRanges(time_ranges);
  m_time_ranges1.AutoXResizeMode(true);
  m_time_ranges1.AutoXResizeRightOffset(5);
  CCoreCreate::CreateTimeRanges(m_time_ranges1, m_window1, 0, 5, 60, 390);
}

El ejemplo anterior muestra cómo podemos establecer los intervalos de tiempoen el elemento TimeRanges durante los cuales no se debe operar.

Al iniciar una aplicación MQL con una interfaz gráfica de este tipo, veremos el siguiente resultado en el gráfico:

Demostración del elemento TimeRanges de la biblioteca EasyAndFastGUI v2.0

Demostración del elemento TimeRanges de la biblioteca EasyAndFastGUI v2.0

La captura de pantalla anterior muestra un elemento de la interfaz que supone una línea de tiempo intradía. Este es un elemento dinámico que podrá ajustarse automáticamente a la anchura del elemento principal (en este caso, el formulario). La línea de puntos y guiones marca la hora actual cerca de la cual se muestra una etiqueta de texto con la hora actual. Si colocamos el cursor del ratón sobre la línea de la hora, se dibujará una línea sólida vertical debajo del cursor del ratón con una etiqueta de texto de la hora a la que apunta el cursor. 

Nos ha salido una característica bastante informativa, ¡pero eso no es todo! Si clicamos en la escala, el elemento generará un evento personalizado con el identificador ON_CLICK_TIME_RANGE, que puede procesarse en nuestra propia aplicación MQL. El parámetro dparam contendrá el número de segundos transcurridos desde el comienzo del día, mientras que el parámetro sparam contendrá el rango de tiempo eliminado o una cadena vacía si ninguno de los rangos establecidos ha caído bajo el cursor durante el clic. Además, podremos activar el modo en el que se puede abrir el elemento TimeRanges clicando en todo el gráfico.

Aquí está el código que nos permitirá capturar y procesar este evento:

void CApp::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

  if(id == CHARTEVENT_CUSTOM + ON_CLICK_TIME_RANGE) {
    
    if(m_time_ranges1.Id() == lparam) {
      Print(__FUNCTION__, " > pressed time: ", ::TimeToString((datetime)dparam, TIME_MINUTES|TIME_SECONDS), "; pressed time range: ", sparam);
      
      string time_ranges[];
      m_time_ranges1.GetTimeRanges(time_ranges);
      
      ArrayPrint(time_ranges);
      return;
    }
    return;
  }
}

Como podemos ver en la lista de códigos anterior, primero se verificará el ID del evento y, si se trata de un evento personalizado ON_CLICK_TIME_RANGE, verificaremos el identificador del elemento transmitido en el evento en el parámetro lparam. A continuación, enviaremos los datos obtenidos al diario de registro. Como ejemplo, también mostraremos cómo obtener los intervalos establecidos en un elemento usando el método CTimeRanges::GetTimeRanges() y también enviaremos la matriz resultante al diario de registro.

En los logs de los expertos (pestaña Experts) veremos algo así:

CApp::OnEvent > pressed time: 16:34:54; pressed time range: 15:30:00 - 17:39:59
"00:45:00-01:20:01" "08:55:00-09:25:01" "12:55:00-13:50:01" "15:30:00-17:39:59" "20:10:00-21:05:00"

El siguiente ejemplo muestra cómo obtener el array de número de pasadas del recuadro de resultados favoritos (FAVORITE_RESULTS) en la base de datos.

void CApp::GetPassNumbersOfFavoriteResults(const string db_filename, ulong &passes[]) {

  ::ResetLastError();
  uint flags = DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
  int db_handle = ::DatabaseOpen(db_filename, flags);
  if(db_handle == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", db_filename, " open failed with code: ", ::GetLastError());
    return;
  }
  
  string command = "SELECT (Pass) FROM FAVORITE_RESULTS;";
  
  int db_query = ::DatabasePrepare(db_handle, command);
  if(db_query == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", db_filename, " request failed with code ", ::GetLastError());
    ::DatabaseClose(db_handle);
    return;
  }

  for(int i = 0; ::DatabaseRead(db_query); i++) {
    int pass_number;
    ::ResetLastError();
    if(::DatabaseColumnInteger(db_query, 0, pass_number)) {
      int prev_size = ::ArraySize(passes);
      ::ArrayResize(passes, prev_size + 1);
      passes[prev_size] = (ulong)pass_number;
    } 
    else {
      ::Print(__FUNCTION__, " > DatabaseColumnInteger() error: ", ::GetLastError());
    }
  }
//--- Finish working with the database
  ::DatabaseFinalize(db_query);
  ::DatabaseClose(db_handle);
}

Una vez que tengamos los números de pasadas, podremos obtener los intervalos eliminados indicando el número de pasada con la ayuda del método GetFavoriteRemovedIntervalsByPassNumber():

string CApp::GetFavoriteRemovedIntervalsByPassNumber(const ulong pass_number) {

  ::ResetLastError();
  uint flags = DATABASE_OPEN_READWRITE | DATABASE_OPEN_CREATE;
  int db_handle = ::DatabaseOpen(m_db_filename, flags);
  if(db_handle == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", m_db_filename, " open failed with code: ", ::GetLastError());
    return(NULL);
  }
  
  string command = "SELECT (RemovedIntervals) FROM FAVORITE_RESULTS WHERE Pass=" + (string)pass_number + ";";
  
  int db_query = ::DatabasePrepare(db_handle, command);
  if(db_query == INVALID_HANDLE) {
    ::Print(__FUNCTION__, " > DB: ", m_db_filename, " request failed with code ", ::GetLastError());
    ::DatabaseClose(db_handle);
    return(NULL);
  }
  
  string time_ranges = "";
  
  if(::DatabaseRead(db_query)) {
    ::ResetLastError();
    if(!::DatabaseColumnText(db_query, 0, time_ranges)) {
      ::Print(__FUNCTION__, " > DatabaseColumnText() error: ", ::GetLastError());
    }
  }
//--- Finish working with the database
  ::DatabaseFinalize(db_query);
  ::DatabaseClose(db_handle);
  
  return(time_ranges);
}

Clicando en el botón Open DB... para abrir un archivo con una base de datos, se llamará al método OnClickOpenDB(), en el que el programa abrirá una ventana de diálogo para seleccionar un archivo en el directorio MQL5/Files/DB. Si seleccionamos el archivo, se guardará para su uso posterior en otros métodos. Luego, utilizando el método GetPassNumbersOfFavoriteResults(), cuyo código hemos ofrecido en la lista anterior, obtendremos en un array los números de pasada del recuadro de resultados favoritos. Luego añadiremos estos datos a la lista desplegable y seleccionaremos el primer elemento.

bool CApp::OnClickOpenDB(const int id) {

  if(m_button1.Id() != id) {
    return(false);
  }

  string filenames[];
  string folder = "DB";
  string filter = "DB files (*.db)|*.db|SQLite files (*.sqlite)|*.sqlite|All files (*.*)|*.*";
  if(::FileSelectDialog("Select database file to upload", folder, filter,
                        FSD_FILE_MUST_EXIST, filenames) > 0) {
    
    int filenames_total = ::ArraySize(filenames);
    if(filenames_total < 1) {
      return(false);
    }
    
    m_db_filename = filenames[0];
    
    ::Print(__FUNCTION__, " > m_db_filename: ", m_db_filename);
    
    ulong passes[];
    GetPassNumbersOfFavoriteResults(m_db_filename, passes);
    
    ::ArrayPrint(passes);
    
    CListView *list_view = m_combobox1.GetListViewPointer();
    
    int passes_total = ::ArraySize(passes);
    if(passes_total > 0) {
      list_view.Clear();
      for(int i = 0; i < passes_total; i++) {
        list_view.AddItem(i, (string)passes[i]);
      }
      m_combobox1.SelectItem(0);
      m_combobox1.GetButtonPointer().Update(true);
      list_view.Update(true);
    }
  }
  return(true);
}

Seleccionando el número de pasada en la lista desplegable, obtendremos los intervalos remotos relacionados con él en el método SetTimeRange(), guardándolos después en un array global y configurándolos en un elemento gráfico del tipo CTimeRanges.

void CApp::SetTimeRange(void) {

  CListView *list_view = m_combobox1.GetListViewPointer();
  
  int   index       = list_view.SelectedItemIndex();
  ulong pass_number = (int)list_view.GetValue(index);
  
  string removed_intervals = GetFavoriteRemovedIntervalsByPassNumber(pass_number);
  
  ::ArrayFree(m_time_ranges_str);
  ::StringSplit(removed_intervals, ::StringGetCharacter("|", 0), m_time_ranges_str);
  
  int ranges_total = ::ArraySize(m_time_ranges_str);
  for(int i = 0; i < ranges_total; i++) {
    ::StringReplace(m_time_ranges_str[i], " - ", "-");
  }
  
  ::ArrayPrint(m_time_ranges_str);
  
  m_time_ranges1.SetTimeRanges(m_time_ranges_str);
  m_time_ranges1.Update();
}

A continuación, necesitaremos una estructura para almacenar los rangos de tiempo. Si estamos utilizando la biblioteca EasyAndFastGUI 2.0, esta estructura (TimeRange) ya estará en el archivo de elementos CTimeRanges:

struct TimeRange {
  MqlDateTime start;
  MqlDateTime end;
};

Si no utilizamos esta biblioteca gráfica, podremos declarar dicha estructura en su código por separado.

Como los rangos de tiempo eliminados ya están almacenados en forma de cadena en el método SetTimeRange(), ahora deberemos colocarlos en un array de estructuras para que resulte cómodo trabajar con ellos en el futuro. Para hacer esto, usaremos el método GetTimeRanges():

void CApp::GetTimeRanges(TimeRange &ranges[]) {
  
  ::ArrayFree(ranges);
  
  int ranges_total = ::ArraySize(m_time_ranges_str);
  for(int i = 0; i < ranges_total; i++) {
    
    string tr[];
    ::StringSplit(m_time_ranges_str[i], ::StringGetCharacter("-", 0), tr);
  
    int size = ::ArraySize(ranges);
    ::ArrayResize(ranges, size + 1);
    
    MqlDateTime start, end;
    ::TimeToStruct(::StringToTime(tr[0]), start);
    ::TimeToStruct(::StringToTime(tr[1]), end);
    
    datetime time1 = HourSeconds(start.hour) + MinuteSeconds(start.min) + start.sec;
    datetime time2 = HourSeconds(end.hour) + MinuteSeconds(end.min) + end.sec;
    ::TimeToStruct(time1, ranges[size].start);
    ::TimeToStruct(time2, ranges[size].end);
  }
}

Por ejemplo, estos métodos se podrán usar al procesar los eventos correspondientes (una versión abreviada de la clase de aplicación):

class CApp : public CCoreCreate {
 private:
  TimeRange         m_time_ranges[];
  string            m_time_ranges_str[];
  
...

  virtual void      OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);

  void              SetTimeRange(void);
  void              GetTimeRanges(TimeRange &ranges[]);
  
  int               HourSeconds(const int hour)     { return(hour * 60 * 60); }
  int               MinuteSeconds(const int minute) { return(minute * 60);    }
};

void CApp::OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {

  if(id == CHARTEVENT_CUSTOM + ON_CLICK_BUTTON) {
    if(OnClickOpenDB((int)lparam)) {
      SetTimeRange();
      GetTimeRanges(m_time_ranges);
      return;
    }
    return;
  }
  
  if(id == CHARTEVENT_CUSTOM + ON_CLICK_COMBOBOX_ITEM) {
    if(OnSelectPass((int)lparam)) {
      SetTimeRange();
      GetTimeRanges(m_time_ranges);
      return;
    }
    return;
  }
}

Ahora podremos escribir el método CheckTradeTime() para verificar las condiciones para comerciar solo en el rango de tiempo permitido:

bool CApp::CheckTradeTime(void) {

  bool     is_trade_time = true;
  datetime current_time  = ::TimeCurrent();
  
  MqlDateTime time;
  ::TimeToStruct(current_time, time);
  
  int ranges_total = ::ArraySize(m_time_ranges);
  for(int i = 0; i < ranges_total; i++) {
  
    MqlDateTime start = m_time_ranges[i].start;
    MqlDateTime end   = m_time_ranges[i].end;
    
    datetime time_c = HourSeconds(time.hour) + MinuteSeconds(time.min) + time.sec;
    datetime time_s = HourSeconds(start.hour) + MinuteSeconds(start.min) + start.sec;
    datetime time_e = HourSeconds(end.hour) + MinuteSeconds(end.min) + end.sec;
    
    if(time_c >= time_s && time_c <= time_e) {
      is_trade_time = false;
      break;
    }
  }
  return(is_trade_time);
}

Todo lo que deberemos hacer ahora es configurar la llamada al método CheckTradeTime(), por ejemplo, en la función OnTick():

  if(CheckTradeTime()) {
    Print(__FUNCTION__, " > trade time!");
  }

Podrá descargar una aplicación lista para usar al final del artículo con una demostración de lo que hemos descrito anteriormente.

Demostración de la obtención de intervalos de tiempo excluidos de la negociación

Demostración de la obtención de intervalos de tiempo excluidos de la negociación


Conclusión

Resumamos.

Cuando optimizamos los parámetros en el simulador de estrategias, para ver cada resultado debemos ejecutar pruebas individuales por turno, lo cual resulta laborioso e ineficiente a la hora de encontrar los parámetros que nos gustaría elegir para nuestras operaciones en una cuenta real.

¿Qué es Frames Analyzer? Se trata de un complemento para que cualquier experto comercial analice marcos de optimización durante la optimización de parámetros en el simulador de estrategias, así como fuera del simulador mediante la lectura de un archivo MQD o una base de datos creada inmediatamente después de la optimización de parámetros. Podrá compartir estos resultados de optimización con otros usuarios que tengan "Frames Analyzer" para analizar juntos los resultados de optimización.

"Frames Analyzer" nos permite ver los 100 mejores resultados de optimización simultáneamente en forma de gráficos. Estos 100 mejores resultados se podrán obtener aplicando varios criterios: Profit, Trades, Drawdown, Profit Factor, Recovery Factor. Además, la herramienta "Frames Analyzer" incorpora el módulo Best Intervals para determinar los intervalos de tiempo no rentables, permitiéndonos desactivarlos de la historia de transacciones para ver cuál habría sido el resultado si no se hubiera comerciado durante estos periodos.

Todos los resultados necesarios se pueden guardar en la base de datos, y también en forma de archivos set listos para usar con los parámetros externos del experto. Los intervalos de tiempo eliminados también se almacenan en la base de datos. Por lo tanto, podremos aplicarlos al comerciar para mejorar los resultados, tratando así de maximizar los beneficios. ¡"Frames Analyzer" dejará solo aquellos intervalos de tiempo para comerciar que estadísticamente hayan demostrado ser los más seguros!


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

Archivos adjuntos |
MQL5.zip (5545.43 KB)
Miguel Angel Diaz Oviedo
Miguel Angel Diaz Oviedo | 11 feb. 2023 en 12:42
Pero como se hace funcionar?, porque no me funciona..no puedo ver los parámetros del robot en el Probador de Estrategias
Algoritmos de optimización de la población: Optimización de colonias de hormigas (ACO) Algoritmos de optimización de la población: Optimización de colonias de hormigas (ACO)
En esta ocasión, analizaremos el algoritmo de optimización de colonias de hormigas (ACO). El algoritmo es bastante interesante y ambiguo al mismo tiempo. Intentaremos crear un nuevo tipo de ACO.
DoEasy. Elementos de control (Parte 24): El objeto auxiliar WinForms "Pista" DoEasy. Elementos de control (Parte 24): El objeto auxiliar WinForms "Pista"
En este artículo, elaboraremos nuevamente la lógica de especificación de los objetos principal y básico para todos los objetos de la biblioteca WinForms; asimismo, desarrollaremos el nuevo objeto básico "Pista" y varias de sus clases derivadas para indicar la posible dirección de movimiento de la línea separadora.
DoEasy. Elementos de control (Parte 25): El objeto WinForms «Tooltip» DoEasy. Elementos de control (Parte 25): El objeto WinForms «Tooltip»
En este artículo, comenzaremos a desarrollar el control Tooltip ("pista emergente") y comenzaremos a crear nuevas primitivas gráficas para la biblioteca. Obviamente, no todos los elementos tendrán sugerencias emergentes, pero cada objeto gráfico poseerá la capacidad de configurarla.
Indicadores adaptativos Indicadores adaptativos
En este artículo, analizaremos varios enfoques posibles en la creación de indicadores adaptativos. Los indicadores adaptativos se distinguen por la presencia de retroalimentación entre los valores de las señales de entrada y salida. Esta relación permite que el indicador se ajuste de forma independiente al procesamiento óptimo de los valores de las series temporales financieras.