Experto comercial con interfaz gráfica: Creación del panel (Parte I)
Contenido
- Introducción
- Elementos de la interfaz gráfica
- Montaje de la interfaz gráfica
- Formulario para los elementos de control
- Barra de estado
- Grupo de pestañas
- Campo de edición
- Botón
- Cuadro combinado con lista desplegable
- Casilla de verificación
- Recuadro
- Gráfico estándar
- Barra de progreso
- Actualizaciones de la biblioteca EasyAndFast
- Conclusión
Introducción
A pesar del activo desarrollo del trading algorítmico, muchos tráders hasta ahora prefieren el comercio manual. Pero en nuestro caso, difícilmente podremos evitar la automatización de operaciones rutinarias.
En el artículo se muestra la creación de un experto de señal multisímbolo para el comercio manual. Como ejemplo, analizaremos las señales del indicador Stochastic del paquete estándar de la biblioteca. Este código podemos utilizarlo para crear nuestros propios expertos con interfaz gráfica: podemos conectarle cualquier otro indicador o usar los resultados de ciertos cálculos para tomar decisiones.
Para aquellos que ejecutan trabajos por encargo, este artículo puede ser útil como ejemplo de tarea técnica para mostrar a los clientes. Es posible que el ejemplo les ayude a ahorrar tiempo al preparar una tarea técnica comprensible para el programador a la hora de desarrollar un programa de interfaz gráfica.
Vamos a enumerar las cuestiones a analizar con detalle en este trabajo.
- Creación de la interfaz gráfica.
- Obtención de una lista de símbolos con las propiedades indicadas.
- Elementos de control de las operaciones comerciales.
- Alternancia rápida de símbolos y marcos temporales en los gráficos sin reinicializar el experto.
- Gestión de las propiedades de los gráficos con la ayuda de la interfaz gráfica.
- Obtención de señales del indicador a partir de multitud de símbolos con indicación de color.
- Trabajo con posiciones abiertas.
- Actualizaciones de la biblioteca EasyAndFast.
El artículo se publicará en dos partes. En el presente artículo se analizará la creación de un panel, mientras que en la segunda parte se
describirá la funcionalidad que lo llenará.
Elementos de la interfaz gráfica
Comenzaremos el desarrollo del experto por la construcción de la interfaz gráfica, con cuya ayuda se implementará la interacción con el usuario y la visualización de los datos. Podemos crear la interfaz gráfica usando las posibilidades de la bilioteca estándar, pero en nuestro ejemplo, se implementará sobre la base de EasyAndFast. Sus amplias posibilidades permiten concentrarse en la funcionalidad del propio programa sin distraerse en la mejora de su parte gráfica.
Primero dibujaremos el esquema general de la interfaz gráfica. En el esquema de abajo mostramos que en la ventana de la interfaz gráfica hay un grupo de dos pestañas. En las listas se muestran las funciones que debemos ubicar en ellas. Se trata de un ejemplo simplificado: el cliente y el ejecutor podrán trabajarlo con más detalle durante la discusión.
Fig. 1. Esquema general de la interfaz gráfica con aclaraciones.
Puede haber muchos elementos de control para la interfaz gráfica. Por eso, primero vamos a enumerarlos de forma jerárquica:
- Formulario para los elementos de control
- Barra de estado para mostrar la información adicional final
- Grupo de pestañas:
- Trade:
- Campo de edición con casilla de verificación para filtrar la lista de símbolos
- Botón para solicitar el inicio de la formación de la lista de símbolos
- Botón para la operación comercial SELL
- Botón para la operación comercial BUY
- Campo de edición para establecer el volumen de la transacción
- Botón para el cierre de todas las posiciones abiertas
- Campo de edición para establecer el nivel de la señal de venta
- Campo de edición para establecer el nivel de la señal de compra
- Recuadro de símbolos para el comercio
- Gráfico para visualizar los datos de los símbolos. Para mayor comodidad, haremos que varias propiedades del gráfico se puedan controlar con la ayuda del siguiente grupo de elementos:
- Cuadro combinado con lista desplegable para seleccionar la alternancia del marco temporal
- Casilla de verificación para activar/desactivar la escala temporal
- Casilla de verificación para activar/desactivar la escala de precio
- Campo de edición para controlar la escala
- Botón para activar la sangría
- Casilla de verificación para mostrar el indicador
- Positions:
- Recuadro de posiciones
- Indicador para el proceso de reproducción de frames
En la clase principal del programa (CProgram) declaramos los métodos y ejemplares de las clases de los elementos enumerados más arriba. El código de los métodos para la creación de elementos se muestra en un archivo aparte y se incluye en el archivo con la clase del programa MQL:
//+------------------------------------------------------------------+ //| Clase para crear la aplicación | //+------------------------------------------------------------------+ class CProgram : public CWndEvents { private: //--- Ventana CWindow m_window1; //--- Barra de estado CStatusBar m_status_bar; //--- Pestañas CTabs m_tabs1; //--- Campo de edición CTextEdit m_symb_filter; CTextEdit m_lot; CTextEdit m_up_level; CTextEdit m_down_level; CTextEdit m_chart_scale; //--- Botones CButton m_request; CButton m_chart_shift; CButton m_buy; CButton m_sell; CButton m_close_all; //--- Cuadros combinados CComboBox m_timeframes; //--- Casilla de verificación CCheckBox m_date_scale; CCheckBox m_price_scale; CCheckBox m_show_indicator; //--- Recuadros CTable m_table_positions; CTable m_table_symb; //--- Gráfico estándar CStandardChart m_sub_chart1; //--- Barra de progreso CProgressBar m_progress_bar; //--- public: //---Crea una interfaz gráfica bool CreateGUI(void); //--- private: //--- Formulario bool CreateWindow(const string text); //--- Barra de estado bool CreateStatusBar(const int x_gap,const int y_gap); //--- Pestañas bool CreateTabs1(const int x_gap,const int y_gap); //--- Campo de edición bool CreateSymbFilter(const int x_gap,const int y_gap,const string text); bool CreateLot(const int x_gap,const int y_gap,const string text); bool CreateUpLevel(const int x_gap,const int y_gap,const string text); bool CreateDownLevel(const int x_gap,const int y_gap,const string text); bool CreateChartScale(const int x_gap,const int y_gap,const string text); //--- Botones bool CreateRequest(const int x_gap,const int y_gap,const string text); bool CreateChartShift(const int x_gap,const int y_gap,const string text); bool CreateBuy(const int x_gap,const int y_gap,const string text); bool CreateSell(const int x_gap,const int y_gap,const string text); bool CreateCloseAll(const int x_gap,const int y_gap,const string text); //--- Cuadro combinado bool CreateComboBoxTF(const int x_gap,const int y_gap,const string text); //--- Casilla de verificación bool CreateDateScale(const int x_gap,const int y_gap,const string text); bool CreatePriceScale(const int x_gap,const int y_gap,const string text); bool CreateShowIndicator(const int x_gap,const int y_gap,const string text); //--- Recuadros bool CreatePositionsTable(const int x_gap,const int y_gap); bool CreateSymbolsTable(const int x_gap,const int y_gap); //--- Gráfico estándar bool CreateSubChart1(const int x_gap,const int y_gap); //--- Barra de progreso bool CreateProgressBar(const int x_gap,const int y_gap,const string text); }; //+------------------------------------------------------------------+ //| Métodos para crear los elementos de control | //+------------------------------------------------------------------+ #include "CreateGUI.mqh" //+------------------------------------------------------------------+
A continuación, vamos a analizar el montaje de la interfaz gráfica, los métodos para crear sus elementos y sus propiedades.
Montaje de la interfaz gráfica
Bien, en la interfaz gráfica de la aplicación desarrollada se usarán elementos de diez tipos diferentes.
- Formulario para los elementos de control (CWindow)
- Barra de estado (CStatusBar)
- Grupo de pestañas (CTabs)
- Campo de edición (CTextEdit)
- Botón (CButton)
- Cuadro combinado con lista desplegable (CComboBox)
- Casilla de verificación (CCheckBox)
- Recuadro (CTable)
- Gráfico estándar (CStandardChart)
- Barra de progreso (CProgressBar)
Vamos a necesitar más de un elemento en algunas categorías de esta lista, por eso analizaremos uno solo de cada grupo. En el mismo orden vamos a estudiar los métodos para crearlos.
Formulario para los elementos de control
Más abajo mostramos el código del método para crear el formulario en el que se ubicarán los demás elementos. Al principio hay que añadir el formulario a la lista de elementos de la interfaz gráfica del programa. Para ello, debemos llamar el método CWndContainer::AddWindow(), transmitiendo al mismo el objeto del elemento del tipo CWindow. A continuación, antes de crear un formulario, establecemos sus propiedades. Indicamos las siguientes propiedades (en el mismo orden que en la lista de abajo):
- Dimensiones del formulario (anchura y altura)
- Tamaño de la fuente en el encabezado
- Modo de desplazamiento del formulario (dentro del gráfico)
- Modo de cambio manual del tamaño del formulario (arrastrando los bordes)
- Botones del formulario. La visibilidad de cada botón se activa por separado. En este caso, se implican los siguientes:
- Cierre del formulario. En el formulario principal del programa, al pulsar este botón, saldrá una ventana de diálogo en la que se preguntará si queremos cerrar el programa.
- Maximizar y minimizar el formulario.
- Pistas emergentes para los elementos. Este botón tiene también dos estados. Cuando está pulsado, en los elementos de control se mostrarán pistas emergentes (con la condición de que estas hayan sido establecidas).
- Expansión del formulario por todo el área del gráfico del terminal. Tras maximizar el formulario, es posible devolverlo a sus anteriores dimensiones con solo pulsar de nuevo este botón.
- Para cada botón del formulario se puede establece una descripción emergente.
Después de que las propiedades hayan sido establecidas, hay que llamar el método de creación del formulario CWindow::CreateWindow() y transmitir al mismo:
- el identificador del gráfico,
- el número de la subventana del gráfico,
- el texto del encabezado,
- las coordenadas iniciales de la ubicación para el formulario.
//+------------------------------------------------------------------+ //| Crea el formulario para los elementos de control | //+------------------------------------------------------------------+ bool CProgram::CreateWindow(const string caption_text) { //--- Añadimos el puntero de la ventana a la matriz de ventanas CWndContainer::AddWindow(m_window1); //--- Propiedades m_window1.XSize(750); m_window1.YSize(450); m_window1.FontSize(9); m_window1.IsMovable(true); m_window1.ResizeMode(true); m_window1.CloseButtonIsUsed(true); m_window1.CollapseButtonIsUsed(true); m_window1.TooltipsButtonIsUsed(true); m_window1.FullscreenButtonIsUsed(true); //--- Establecemos las pistas emergentes m_window1.GetCloseButtonPointer().Tooltip("Close"); m_window1.GetTooltipButtonPointer().Tooltip("Tooltips"); m_window1.GetFullscreenButtonPointer().Tooltip("Fullscreen"); m_window1.GetCollapseButtonPointer().Tooltip("Collapse/Expand"); //--- Creando el formulario if(!m_window1.CreateWindow(m_chart_id,m_subwin,caption_text,1,1)) return(false); //--- return(true); }
Cada vez que se añada un nuevo elemento de la interfaz gráfica, sería deseable compilar el programa y ver qué resultado obtenemos:
Fig. 2. Formulario para los elementos de control.
Más abajo se mostrarán las capturas de pantalla de todos los resultados intermedios.
Barra de estado
El código del método para la creación de la barra comienza por la indicación del elemento principal. A partir de él, se calcularán el posicionamiento y la alineación según el tamaño de los elementos asociados al mismo. Esto ahorrará tiempo a la hora de desarrollar la aplicación: será posible desplazar un grupo completo de elementos relacionados con solo modificar las coordenadas del principal. Para anclar un elemento, su puntero se transmite al método CElement::MainPointer(). En este ejemplo, estamos anclando la barra de estado al formulario, por eso transmitimos el objeto del formulario al método.
A continuación, establecemos las propiedades de la barra de estado. En esta, crearemos tres puntos en los que se mostrará la información para el ususario.
- Para no indicar el tamaño con respecto al formulario, indicaremos que la anchura debe cambiar automáticamente con cada cambio del formulario.
- La sangría del borde derecho del elemento con respecto al borde derecho del formulario será de 1 píxel.
- Anclaremos la barra de estado a la parte inferior del formulario, para que, al cambiar la altura del formulario, este se corrija automáticamente con respecto a la parte inferior.
- A continuación, al añadir los puntos, indicamos su anchura.
Después de que hayamos indicado las propiedades, creamos el elemento. Ahora que ya está preparado para el trabajo, podemos cambiar el texto en sus puntos mientras se ejecuta el programa. En nuestro ejemplo, definimos en el primer punto el texto «For Help, press F1».
Al final del método, tenemos que guardar necesariamente el puntero del elemento creado en la lista general de elementos de la interfaz gráfica. Para ello, llamamos el método CWndContainer::AddToElementsArray() y le transmitimos el índice del formulario y el objeto de elemento. Puesto que solo tenemos un formulario, su índice será 0.
//+------------------------------------------------------------------+ //| Crea la barra de estado | //+------------------------------------------------------------------+ bool CProgram::CreateStatusBar(const int x_gap,const int y_gap) { #define STATUS_LABELS_TOTAL 3 //--- Guardamos el puntero a la ventana m_status_bar.MainPointer(m_window1); //--- Propiedades m_status_bar.AutoXResizeMode(true); m_status_bar.AutoXResizeRightOffset(1); m_status_bar.AnchorBottomWindowSide(true); //--- Indicamos cuántas partes debe haber y definimos sus propiedades int width[STATUS_LABELS_TOTAL]={0,200,110}; for(int i=0; i<STATUS_LABELS_TOTAL; i++) m_status_bar.AddItem(width[i]); //--- Creamos el elemento de control if(!m_status_bar.CreateStatusBar(x_gap,y_gap)) return(false); //--- Definimos el texto en los puntos de la barra de estado m_status_bar.SetValue(0,"For Help, press F1"); //--- Añadimos el objeto a la matriz general de grupos de objetos CWndContainer::AddToElementsArray(0,m_status_bar); return(true); }
Los demás elementos de la biblioteca EasyAndFast se crean según el mismo principio. Por eso, a continuación, analizaremos solo las propiedades establecidas que se usarán en nuestro experto.
Fig. 3. Adición de la barra de estado.
Grupo de pestañas
En el método para crear el grupo de pestañas, establecemos las siguientes propiedades para el elemento:
- Centramos el texto en las pestañas.
- Ubicamos las pestañas en la parte superior del área de trabajo.
- El tamaño se ajustará automáticamente según el área del elemento principal (el formulario). En este caso, no es obligatorio indicar el tamaño del área del grupo de pestañas.
- Indicamos las sangrías con respecto el borde derecho e inferior del elemento principal. Al cambiar el tamaño del formulario, estas sangrías se guardarán.
- Al añadir las siguientes pestañas, al método también se transmite el nombre de la pestaña y su anchura.
Aquí tenemos el código del método:
//+------------------------------------------------------------------+ //| Crea el grupo con pestañas 1 | //+------------------------------------------------------------------+ bool CProgram::CreateTabs1(const int x_gap,const int y_gap) { #define TABS1_TOTAL 2 //--- Guardamos el puntero al elemento principal m_tabs1.MainPointer(m_window1); //--- Propiedades m_tabs1.IsCenterText(true); m_tabs1.PositionMode(TABS_TOP); m_tabs1.AutoXResizeMode(true); m_tabs1.AutoYResizeMode(true); m_tabs1.AutoXResizeRightOffset(3); m_tabs1.AutoYResizeBottomOffset(25); //--- Añadimos las pestañas con las propiedades indicadas string tabs_names[TABS1_TOTAL]={"Trade","Positions"}; for(int i=0; i<TABS1_TOTAL; i++) m_tabs1.AddTab(tabs_names[i],100); //--- Creamos el elemento de control if(!m_tabs1.CreateTabs(x_gap,y_gap)) return(false); //--- Añadimos el objeto a la matriz general de grupos de objetos CWndContainer::AddToElementsArray(0,m_tabs1); return(true); }
Fig. 4. Adición del grupo de pestañas.
Campo de edición
Como ejemplo, analizaremos el campo de edición en el que el usuario puede indicar las divisas y/o parejas de divisas para formar la lista de símbolos en el recuadro. El elemento principal para el mismo será un grupo de pestañas. Aquí tenemos que indicar en qué pestaña debemos representar este campo de edición. Para ello, llamaremos el método CTabs::AddToElementsArray(), transmitiremos al mismo el índice de la pestaña y el objeto del elemento unido.
A continuación, analizaremos las propiedades indicadas para este campo de edición.
- Por defecto, en el campo de edición se introducirá el texto "USD": el programa recopilará en un recuadro los símbolos en los que haya USD. En este campo de edición se deben indicar las divisas y/o símbolos con una coma. Más abajo, mostramos el método con cuya ayuda se forma la lista de símbolos (según las líneas separadas con coma) en este campo de edición.
- El campo de edición tendrá una casilla de verificación. Al desactivar la casilla de verificación, el texto en el campo de edición será ignorado, y en la lista de símbolos entrarán todas las parejas de divisas encontradas.
- La anchura del campo de edición ocupará todo el ancho del elemento principal; al cambiar la anchura del área, también se corregirá.
- A la derecha del campo de edición se encontrará el botón Request. Mientras el programa está funcionando, en el campo de edición se pueden indicar otras parejas de divisas y/o símbolos; para que la lista se forme, deberemos pulsar este botón. Puesto que se supone que la anchura del campo de edición cambia de forma automática, y el botón Request deberá hallarse siempre a su derecha, necesitaremos que siempre haya un espacio libre con respecto al borde derecho del elemento.
El elemento del tipo CTextEdit consta de varios elementos. Por eso, si es necesario cambiar sus propiedades, existe la posibilidad de obtener los punteros al mismo. Necesitaremos cambiar ciertaspropiedades del campo de edición de texto (CTextBox). Vamos a analizarlas en el mismo orden en que se realiza en la lista de código más abajo.
- Sangría del campo de edición con respecto al borde izquierdo del elemento principal (CTextEdit).
- Cambio automático de la anchura con respecto al elemento principal.
- Al activar el campo de edición (clic derecho sobre el campo de edición), el texto se seleccionará por completo de forma automática para una posible sustitución rápida.
- Si en el campo de edición no hay texto en absoluto, se mostrará la sugerencia: «Example: EURUSD, GBP, NOK».
Por defecto, la casilla de verificación del campo de edición se encuentra activada. Para hacer esto, debemos activarla justo después de crear el elemento.
//+--------------------------------------------------------------------------+ //| Crea la casilla de verificación con el campo de edición "Symbols filter" | //+--------------------------------------------------------------------------+ bool CProgram::CreateSymbolsFilter(const int x_gap,const int y_gap,const string text) { //--- Guardamos el puntero al elemento principal m_symb_filter.MainPointer(m_tabs1); //--- Fijar para la pestaña m_tabs1.AddToElementsArray(0,m_symb_filter); //--- Propiedades m_symb_filter.SetValue("USD"); // "EUR,USD" "EURUSD,GBPUSD" "EURUSD,GBPUSD,AUDUSD,NZDUSD,USDCHF" m_symb_filter.CheckBoxMode(true); m_symb_filter.AutoXResizeMode(true); m_symb_filter.AutoXResizeRightOffset(90); m_symb_filter.GetTextBoxPointer().XGap(100); m_symb_filter.GetTextBoxPointer().AutoXResizeMode(true); m_symb_filter.GetTextBoxPointer().AutoSelectionMode(true); m_symb_filter.GetTextBoxPointer().DefaultText("Example: EURUSD,GBP,NOK"); //--- Creamos el elemento de control if(!m_symb_filter.CreateTextEdit(text,x_gap,y_gap)) return(false); //--- Activamos la casilla de verificación m_symb_filter.IsPressed(true); //--- Añadimos el objeto a la matriz general de grupos de objetos CWndContainer::AddToElementsArray(0,m_symb_filter); return(true); }
Aparte del campo de edición de texto, en la interfaz gráfica también tendremos campos de edición numéricos. Por ejemplo, el campo Lot (volumen
para la apertura de posición). Para los campos de edición de este tipo hay que indicar otras propiedades.
- Anchura total del elemento.
- Valor máximo a introducir.
- Valor mínimo a introducir.
- Salto al alternar los botones de incremento y decremento.
- Número de dígitos decimales.
- Para que el campo de edición sea numérico, tenemos que indicarlo con la ayuda del método CTextEdit::SpinEditMode().
- Valor por defecto tras la carga del programa en el gráfico en el terminal.
- Anchura del campo de edición.
- Selección automática del texto en el campo de edición al clicar sobre él.
- Acoplamiento del campo de edición al borde derecho del elemento.
Aquí tenemos el código de este método:
//+------------------------------------------------------------------+ //| Crea el campo de edición "Lot" | //+------------------------------------------------------------------+ bool CProgram::CreateLot(const int x_gap,const int y_gap,const string text) { //--- Guardamos el puntero al elemento principal m_lot.MainPointer(m_tabs1); //--- Fijar para la pestaña m_tabs1.AddToElementsArray(0,m_lot); //--- Propiedades m_lot.XSize(80); m_lot.MaxValue(1000); m_lot.MinValue(0.01); m_lot.StepValue(0.01); m_lot.SetDigits(2); m_lot.SpinEditMode(true); m_lot.SetValue((string)0.1); m_lot.GetTextBoxPointer().XSize(50); m_lot.GetTextBoxPointer().AutoSelectionMode(true); m_lot.GetTextBoxPointer().AnchorRightWindowSide(true); //--- Creamos el elemento de control if(!m_lot.CreateTextEdit(text,x_gap,y_gap)) return(false); //--- Añadimos el objeto a la matriz general de grupos de objetos CWndContainer::AddToElementsArray(0,m_lot); return(true); }
Fig. 5. Adición de los campos de edición.
La imagen tiene un aspecto bastante lógico, pero al añadir los demás elementos, todo resultará en su sitio.
Botón
Añadimos a la interfaz gráfica de nuestro experto varios botones. Analizaremos aquel de ellos en el se han implicado más propiedades: el botón para la apertura de posiciones SELL.
- Anchura del botón.
- El texto del botón se encontrará en el centro, tanto en vertical, como en horizontal.
- Color del fondo del botón.
- Color de fondo al poner el cursor.
- Color de fondo al clicar con el botón izquierdo.
- Color del texto del botón.
- Color del texto al poner el cursor.
- Color del texto al clicar con el botón izquierdo.
- Color del marco del botón.
- Color del marco al poner el cursor.
- Color del marco al clicar con el botón izquierdo.
Las mismas propiedades se cambian también en el botón BUY, con la única diferencia de los matices establecidos para el fondo.
//+------------------------------------------------------------------+ //| Crea el botón 'Sell' | //+------------------------------------------------------------------+ bool CProgram::CreateSell(const int x_gap,const int y_gap,const string text) { //--- Guardar el puntero al elemento principal m_sell.MainPointer(m_tabs1); //--- Fijar para la pestaña m_tabs1.AddToElementsArray(0,m_sell); //--- Propiedades m_sell.XSize(80); m_sell.IsCenterText(true); m_sell.BackColor(C'255,51,51'); m_sell.BackColorHover(C'255,100,100'); m_sell.BackColorPressed(C'195,0,0'); m_sell.LabelColor(clrWhite); m_sell.LabelColorHover(clrWhite); m_sell.LabelColorPressed(clrWhite); m_sell.BorderColor(clrBlack); m_sell.BorderColorHover(clrBlack); m_sell.BorderColorPressed(clrBlack); //--- Creamos el elemento de control if(!m_sell.CreateButton(text,x_gap,y_gap)) return(false); //--- Añadimos el puntero al elemento en la base CWndContainer::AddToElementsArray(0,m_sell); return(true); }
Fig. 6. Adición de botones.
Cuadro combinado con lista desplegable
Para cambiar el marco temporal, haremos un cuadro combinado con lista desplegable. Enumeramos las propiedades para su ajustes.
- Anchura total del elemento.
- Cantidad de puntos en la lista (en nuestro caso, 21, de acuerdo con el número de marcos temporales en el terminal).
- El elemento se anclará a la parte derecha del área de pestañas.
- Anchura del botón del cuadro combinado.
- El botón está anclado a la parte derecha del elemento.
A continuación, a cada punto en la lista se le asignan valores, y después, se le asignan ciertas propiedades a la lista con la ayuda del puntero.
- Destacar los puntos con la ayuda del cursor.
- Punto destacado. En este caso, se tratará del punto con el índice 18 (marco temporal D1).
Aquí tenemos el código del método para crear este cuadro combinado:
//+------------------------------------------------------------------+ //| Creamos el cuadro combinado para elegir marcos temporales | //+------------------------------------------------------------------+ bool CProgram::CreateComboBoxTF(const int x_gap,const int y_gap,const string text) { //--- Número total de puntos en la lista #define ITEMS_TOTAL2 21 //--- Transmitir el objeto del panel m_timeframes.MainPointer(m_tabs1); //--- Fijar para la pestaña m_tabs1.AddToElementsArray(0,m_timeframes); //--- Propiedades m_timeframes.XSize(115); m_timeframes.ItemsTotal(ITEMS_TOTAL2); m_timeframes.AnchorRightWindowSide(true); m_timeframes.GetButtonPointer().XSize(50); m_timeframes.GetButtonPointer().AnchorRightWindowSide(true); //--- Guardamos los valores de los puntos en la lista del cuadro combinado string items_text[ITEMS_TOTAL2]={"M1","M2","M3","M4","M5","M6","M10","M12","M15","M20","M30","H1","H2","H3","H4","H6","H8","H12","D1","W1","MN"}; for(int i=0; i<ITEMS_TOTAL2; i++) m_timeframes.SetValue(i,items_text[i]); //--- Obtenemos el puntero de la lista CListView *lv=m_timeframes.GetListViewPointer(); //--- Establecemos las propiedades de la lista lv.LightsHover(true); lv.SelectItem(18); //--- Creamos el elemento de control if(!m_timeframes.CreateComboBox(text,x_gap,y_gap)) return(false); //--- Añadimos el puntero al elemento en la base CWndContainer::AddToElementsArray(0,m_timeframes); return(true); }
Fig. 7. Añadir cuadro combinado.
Casilla de verificación
La casilla de verificación es el elemento más sencillo. Para este, basta con indicar dos propiedades.
- La anchura.
- La ubicación en la parte derecha del elemento principal.
Después de crear el elemento, podemos activar la casilla de verificación de forma programática.
//+------------------------------------------------------------------+ //| Crea la casilla de verificación "Date scale" | //+------------------------------------------------------------------+ bool CProgram::CreateDateScale(const int x_gap,const int y_gap,const string text) { //--- Guardamos el puntero a la ventana m_date_scale.MainPointer(m_tabs1); //--- Fijar para la pestaña m_tabs1.AddToElementsArray(0,m_date_scale); //--- Propiedades m_date_scale.XSize(70); m_date_scale.AnchorRightWindowSide(true); //--- Creamos el elemento de control if(!m_date_scale.CreateCheckBox(text,x_gap,y_gap)) return(false); //--- Activar la casilla de verificación m_date_scale.IsPressed(true); //--- Añadimos el objeto a la matriz general de grupos de objetos CWndContainer::AddToElementsArray(0,m_date_scale); return(true); }
Fig. 8. Añadir casillas de verificación.
Recuadro
En la interfaz gráfica tendremos dos recuadros. Analizaremos aquel que hace visible la lista formada de símbolos y señales para la apertura
de posiciones. Se ubicará en la primera pestaña. Primero declaramos e inicializamos las matrices para establecer las propiedades del
recuadro. Ajustamos las siguientes propiedades.
- Anchura del elemento.
- Dimensión del recuadro (número de columnas y líneas).
- Anchura de las columnas (los valores se transmiten en la matriz).
- Alineamiento del texto (los valores se transmiten en la matriz).
- Sangría para el texto con respecto a los bordes de las celdas.
- Mostrar los encabezados.
- Posibilidad de destacar líneas.
- Posibilidad de cambiar el tamaño de las columnas manualmente, abarcando el límite del encabezado.
- Mostrar con el formato en el estilo «Zebra».
- Cambio automático del tamaño en vertical con respecto al elemento principal.
- Sangría con respecto al borde inferior del elemento principal.
El texto para los encabezados se puede indicar después de crear el recuadro:
//+------------------------------------------------------------------+ //| Crea el recuadro de símbolos | //+------------------------------------------------------------------+ bool CProgram::CreateSymbolsTable(const int x_gap,const int y_gap) { #define COLUMNS1_TOTAL 2 #define ROWS1_TOTAL 1 //--- Guardamos el puntero al elemento principal m_table_symb.MainPointer(m_tabs1); //--- Fijar para la pestaña m_tabs1.AddToElementsArray(0,m_table_symb); //--- Matriz de anchura de las columnas int width[COLUMNS1_TOTAL]={95,58}; //--- Matriz de alineamiento del texto en columnas ENUM_ALIGN_MODE align[COLUMNS1_TOTAL]={ALIGN_LEFT,ALIGN_RIGHT}; //--- Matriz de sangría del texto en las columnas según el eje X int text_x_offset[COLUMNS1_TOTAL]={5,5}; //--- Propiedades m_table_symb.XSize(168); m_table_symb.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL); m_table_symb.ColumnsWidth(width); m_table_symb.TextAlign(align); m_table_symb.TextXOffset(text_x_offset); m_table_symb.ShowHeaders(true); m_table_symb.SelectableRow(true); m_table_symb.ColumnResizeMode(true); m_table_symb.IsZebraFormatRows(clrWhiteSmoke); m_table_symb.AutoYResizeMode(true); m_table_symb.AutoYResizeBottomOffset(2); //--- Creamos el elemento de control if(!m_table_symb.CreateTable(x_gap,y_gap)) return(false); //--- Establecemos los nombres de los encabezados m_table_symb.SetHeaderText(0,"Symbol"); m_table_symb.SetHeaderText(1,"Values"); //--- Añadimos el objeto a la matriz general de grupos de objetos CWndContainer::AddToElementsArray(0,m_table_symb); return(true); }
El segundo recuadro representa algunas propiedades de las posiciones abiertas. Sus diez columnas representarán los siguientes datos.
- Símbolo de la posición.
- Número de posiciones.
- Volumen total de todas las posiciones abiertas.
- Volumen de las posiciones BUY.
- Volumen de las posiciones SELL.
- Resultado total actual de todas las posiciones abiertas.
- Resultado actual de todas las posiciones abiertas BUY.
- Resultado actual de todas las posiciones abiertas SELL.
- Carga del depósito de cada símbolo por separado.
- Precio medio.
En el segundo recuadro hay que configurar de forma adicional las siguientes propiedades.
- Sangría para las imágenes con respecto a los bordes derecho y superior de las celdas.
- Posibilidad de clasificar los valores.
- Cambio automático del tamaño en horizontal con respecto al elemento principal.
- Sangría con respecto al límite derecho del elemento principal.
Las imágenes en las celdas de la primera columna simbolizarán los botones: al pulsar estos, podremos cerrar una posición o todas las posiciones - si se trata de una cuenta con cobertura - en el símbolo indicado.
//+------------------------------------------------------------------+ //| Crea un recuadro de posiciones | //+------------------------------------------------------------------+ bool CProgram::CreatePositionsTable(const int x_gap,const int y_gap) { ... //--- Propiedades m_table_positions.TableSize(COLUMNS2_TOTAL,ROWS2_TOTAL); m_table_positions.ColumnsWidth(width); m_table_positions.TextAlign(align); m_table_positions.TextXOffset(text_x_offset); m_table_positions.ImageXOffset(image_x_offset); m_table_positions.ImageYOffset(image_y_offset); m_table_positions.ShowHeaders(true); m_table_positions.IsSortMode(true); m_table_positions.SelectableRow(true); m_table_positions.ColumnResizeMode(true); m_table_positions.IsZebraFormatRows(clrWhiteSmoke); m_table_positions.AutoXResizeMode(true); m_table_positions.AutoYResizeMode(true); m_table_positions.AutoXResizeRightOffset(2); m_table_positions.AutoYResizeBottomOffset(2); ... return(true); }
Fig. 9. Añadir un recuadro en la primera pestaña.
Fig. 10. Añadir un recuadro en la segunda pestaña.
Hablaremos sobre cómo trabajar con recuadros en el archivo principal del programa (CProgram) en uno de los siguientes apartados del artículo.
Gráfico estándar
Para visualizar los datos de los símbolos se ha pensado un elemento del tipo CStandardChart. Por defecto, se mostrará el gráfico EURUSD en el marco temporal diario. Tiene las siguientes propiedades.
- Desplazamiento horizontal.
- Ajuste automático de la anchura.
- Ajuste automático de la altura.
- Sangría con respecto al límite derecho del elemento principal.
- Sangría con respecto al borde inferior del elemento principal.
En caso necesario, podemos crear una matriz de gráficos construidos en la fila horizontal. Para ello, use el método CStandardChart::AddSubChart(), transmitiendo en el mismo el símbolo y el marco temporal como argumentos. Pero en este caso, necesitaremos solo un gráfico; los símbolos y marcos temporales los alternaremos con la ayuda de otros elementos de control.
//+------------------------------------------------------------------+ //| Crea el gráfico estándar 1 | //+------------------------------------------------------------------+ bool CProgram::CreateSubChart1(const int x_gap,const int y_gap) { //--- Guardamos el puntero a la ventana m_sub_chart1.MainPointer(m_tabs1); //--- Fijar para la 1-era pestaña m_tabs1.AddToElementsArray(0,m_sub_chart1); //--- Propiedades m_sub_chart1.XScrollMode(true); m_sub_chart1.AutoXResizeMode(true); m_sub_chart1.AutoYResizeMode(true); m_sub_chart1.AutoXResizeRightOffset(125); m_sub_chart1.AutoYResizeBottomOffset(2); //--- Añadimos los gráficos m_sub_chart1.AddSubChart("EURUSD",PERIOD_D1); //--- Creamos el elemento de control if(!m_sub_chart1.CreateStandardChart(x_gap,y_gap)) return(false); //--- Añadimos el objeto a la matriz general de grupos de objetos CWndContainer::AddToElementsArray(0,m_sub_chart1); return(true); }
Fig. 11. Adición del gráfico.
Barra de progreso
Para que el usuario entienda qué está haciendo ahora el programa, añadiremos a la interfaz gráfica el indicador de progreso. Aquí tenemos las
propiedades de nuestro ejemplo (en el mismo orden que en el código).
- Altura total del elemento.
- Altura del indicador (barra de progreso).
- Sangría del indicador con respecto al eje X.
- Sangría del indicador con respecto al eje Y.
- Sangría de la etiqueta principal con respecto al eje X.
- Sangría de la etiqueta principal con respecto al eje Y.
- Sangría de la etiqueta de porcentaje con respecto al eje X.
- Sangría de la etiqueta de porcentaje con respecto al eje Y.
- Atributo del elemento desplegado (para el ocultamiento automático).
- Fuente.
- Color del marco del indicador.
- Color del fondo del indicador.
- Color de la barra de progreso del indicador.
- Ajuste automático de la anchura.
- Sangría con respecto al límite derecho del elemento principal.
Más abajo, mostramos ejemplos del uso del indicador de progreso.
//+------------------------------------------------------------------+ //| Crea una barra de progreso | //+------------------------------------------------------------------+ bool CProgram::CreateProgressBar(const int x_gap,const int y_gap,const string text) { //--- Guardamos el puntero al elemento principal m_progress_bar.MainPointer(m_status_bar); //--- Propiedades m_progress_bar.YSize(17); m_progress_bar.BarYSize(14); m_progress_bar.BarXGap(0); m_progress_bar.BarYGap(1); m_progress_bar.LabelXGap(5); m_progress_bar.LabelYGap(2); m_progress_bar.PercentXGap(5); m_progress_bar.PercentYGap(2); m_progress_bar.IsDropdown(true); m_progress_bar.Font("Consolas"); m_progress_bar.BorderColor(clrSilver); m_progress_bar.IndicatorBackColor(clrWhiteSmoke); m_progress_bar.IndicatorColor(clrLightGreen); m_progress_bar.AutoXResizeMode(true); m_progress_bar.AutoXResizeRightOffset(2); //--- Creación del elemento if(!m_progress_bar.CreateProgressBar(text,x_gap,y_gap)) return(false); //--- Añadimos el puntero al elemento en la base CWndContainer::AddToElementsArray(0,m_progress_bar); return(true); }
Hemos analizado todos los elementos de control que se usarán en la interfaz gráfica de nuestro experto. En este momento, se trata simplemente de un envoltorio gráfico. Pero, más tarde, escribiremos los métodos necesarios para que todo funcione de acuerdo con la idea incial.
Actualizaciones de la biblioteca EasyAndFast
En la biblioteca EasyAndFast, en la clase CTable, se ha desarrollado por completo el método público CTable::SortData(). Ahora, como segundo argumento podemos indicar la dirección de clasificación del recuadro (parámetro no obligatorio). Antes, una nueva llamada del método CTable::SortData() comenzaba la clasificación en la dirección opuesta a la actual. Asimismo, se han añadido los métodos para obtener la dirección de clasificación actual y el índice de la columna clasificada. Ahora, si el recuadro ha sido clasificado por el usuario manualmente (con un clic en el encabezado), y a continuación los datos del recuadro no han sido actualizados en el mismo orden, entonces, tras aclarar la dirección de clasificación actual, podemos restablecerlo.
//+------------------------------------------------------------------+ //| Clase para crear el recuadro dibujado | //+------------------------------------------------------------------+ class CTable : public CElement { public: ... //--- Clasificar los datos de la columna indicada void SortData(const uint column_index=0,const int direction=WRONG_VALUE); //--- (1) Dirección de clasificación actual, (2) índice de la matriz clasificada int IsSortDirection(void) const { return(m_last_sort_direction); } int IsSortedColumnIndex(void) const { return(m_is_sorted_column_index); } ... }; //+------------------------------------------------------------------+ //| Clasificar los datos de la columna indicada | //+------------------------------------------------------------------+ void CTable::SortData(const uint column_index=0,const int direction=WRONG_VALUE) { //--- Salir, si salimos de los límites del recuadro if(column_index>=m_columns_total) return; //--- Índice a partir del cual hay que comenzar la clasificación uint first_index=0; //--- Último índice uint last_index=m_rows_total-1; //--- Sin control de dirección por parte del usuario if(direction==WRONG_VALUE) { //--- La primera vez se clasificará en orden creciente, y a continuación, todas las veces en dirección opuesta if(m_is_sorted_column_index==WRONG_VALUE || column_index!=m_is_sorted_column_index || m_last_sort_direction==SORT_DESCEND) m_last_sort_direction=SORT_ASCEND; else m_last_sort_direction=SORT_DESCEND; } else { m_last_sort_direction=(ENUM_SORT_MODE)direction; } //--- Recordamos el índice de la última columna de datos clasificada m_is_sorted_column_index=(int)column_index; //--- Clasificando QuickSort(first_index,last_index,column_index,m_last_sort_direction); }
Se ha hecho otra pequeña adición a la clase CKeys en el método CKeys::KeySymbol(). Anteriormente, el teclado numérico (un bloque de teclas aparte en la zona derecha del teclado) no se procesaba. Ahora podemos introducir cifras desde esta parte del teclado, y también símbolos especiales.
//+------------------------------------------------------------------+ //| Retorna el símbolo de la tecla pulsada | //+------------------------------------------------------------------+ string CKeys::KeySymbol(const long key_code) { string key_symbol=""; //--- Si hay que introducir un espacio (la tecla "Space") if(key_code==KEY_SPACE) { key_symbol=" "; } //--- Si hay que introducir (1) un símbolo alfabético o (2) un símbolo del teclado numérico o (3) un símbolo especial else if((key_code>=KEY_A && key_code<=KEY_Z) || (key_code>=KEY_0 && key_code<=KEY_9) || (key_code>=KEY_NUMLOCK_0 && key_code<=KEY_NUMLOCK_SLASH) || (key_code>=KEY_SEMICOLON && key_code<=KEY_SINGLE_QUOTE)) { key_symbol=::ShortToString(::TranslateKey((int)key_code)); } //--- Retornar símbolo return(key_symbol); }
Las nuevas versiones de las clases CTable y CKeys podemos descargarlas al final del artículo.
Conclusión
Usted ya ha leído la primera parte del artículo. En esta hemos analizado cómo podemos crear sin grandes esfuerzos interfaces gráficas de cualquier nivel de complejidad para nuestros programas. Usted puede seguir desarrollado este programa y usarlo para sus propios propósitos. En la segunda parte del artículo mostraremos cómo trabajar con la interfaz gráfica y, lo más importante, cómo llenarla con una funcionalidad.
Más abajo podrá descargar a su computadora los archivos para realizar las pruebas y analizar con más detalle el código adjunto al artículo.
Nombre del archivo | Comentarios |
---|---|
MQL5\Experts\TradePanel\TradePanel.mq5 | Experto comercial para el comercio manual con la interfaz gráfica |
MQL5\Experts\TradePanel\Program.mqh | Archivo con la clase del programa |
MQL5\Experts\TradePanel\CreateGUI.mqh | Archivo con la implementación de los métodos para crear una interfaz gráfica a partir de la clase de programa en el archivo Program.mqh |
MQL5\Include\EasyAndFastGUI\Controls\Table.mqh | Clase actualizada CTable |
MQL5\Include\EasyAndFastGUI\Keys.mqh | Clase actualizada CKeys |
Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/4715
- Aplicaciones de trading gratuitas
- 8 000+ señales para copiar
- Noticias económicas para analizar los mercados financieros
Usted acepta la política del sitio web y las condiciones de uso